0

I have a set of three-dimensional spectral data in (x, y, z) coordinate form. The x-axis corresponds to spectral frequencies, the y-axis corresponds to a calculated coefficient based on my data for each frequency, and the z-axis corresponds to the measured peak intensity for each frequency. Essentially, I would like to use matplotlib to produce a contour plot with individual localized contours for each cluster, like what can be seen in this image:

Style of contour plot I would like to replicate for my data (Quanten et. al., Inorganics, 2018)

To provide a better idea of what my data looks like, I implemented an algorithm to ignore any data points below a certain intensity, divided the "filtered" data into a series of 2D lists grouped by intensity, and then used the **matplotlib.pyplot.scatter** method to plot each a different color. This can be seen here, where mi is denoted as the maximum peak intensity observed in my data:

Scatterplot in which all data have intensities at or above mi/100,000

Scatterplot in which all data have intensities at or above mi/25

Having read previous answers to similar issues, it seems that the two major issues preventing me from implementing common solutions are that 1) all three of my data axes are one-dimensional and 2) my data is clustered and so does not approximate a "gridded" distribution. I did, however, attempt to implement the solution from this question, which seemed to address clustered and irregularly-gridded data with one-dimensional axes. Below is my implemented code:

def plot_dosy_spectra(chemical_shifts_ppm, diffusion_coefficients, max_peak_intensities):
    #FILTERING AND SORTING DATA BY INTENSITY NOT SHOWN#
    ###################################################
    ###################################################
    #### IMPLEMENTED SOLUTION ATTEMPT #################
    matplotlib. pyplot.yscale("log")
    ax = matplotlib.pyplot.gca()
    ax.set_ylim([10**-16,10**-2])
    ax.set_xlim([-0.1,14])
    ax.invert_xaxis()
    xx, yy = numpy.mgrid[min(filtered_chemical_shifts):max(filtered_chemical_shifts):1000j, min(filtered_diffusion_coefficients):max(filtered_diffusion_coefficients):1000j]
    points = [[shift,coeff] for shift, coeff in zip(filtered_chemical_shifts, filtered_diffusion_coefficients)]
    zz = scipy.interpolate.griddata(points, filtered_peak_intensities, (xx, yy), method='linear')
    matplotlib. pyplot.scatter(filtered_chemical_shifts, filtered_diffusion_coefficients, c='black')
    matplotlib. pyplot.contour(xx, yy, zz)
    matplotlib. pyplot.show()  

This produced an odd-looking contour plot, which does not seem to fit well with my clustered data. The plot can be seen here:

Contour plot which poorly fits individual clusters

I also utilized the solution from this question, which suggested the use of triangular surface interpolation. My code for that is below:

def plot_dosy_spectra(chemical_shifts_ppm, diffusion_coefficients, max_peak_intensities):
    #FILTERING AND SORTING DATA BY INTENSITY NOT SHOWN#
    ###################################################
    ###################################################
    #### IMPLEMENTED SOLUTION ATTEMPT #################
    matplotlib. pyplot.yscale("log")
    ax = matplotlib.pyplot.gca()
    ax.set_ylim([10**-16,10**-2])
    ax.set_xlim([-0.1,14])
    ax.invert_xaxis()
    xx, yy = numpy.mgrid[min(filtered_chemical_shifts):max(filtered_chemical_shifts):1000j, min(filtered_diffusion_coefficients):max(filtered_diffusion_coefficients):1000j]
    triangles = matplotlib. tri.Triangulation(filtered_chemical_shifts, filtered_diffusion_coefficients)
    tri_interp = matplotlib.tri.CubicTriInterpolator(triangles, filtered_peak_intensities)
    zz = tri_interp(xx, yy)
    matplotlib. pyplot.scatter(filtered_chemical_shifts, filtered_diffusion_coefficients, c='black')
    matplotlib. pyplot.contour(xx, yy, zz)
    matplotlib. pyplot.show()  

Unfortunately, this also yielded similar results as can be seen:

Contour plot from triangular surface interpolation, which led to similarly poor results

Does anyone know of a way I could achieve the intended contour plot style?

  • 2
    For a ``(xx, yy, zz)`` dataset, it might be best to reshape the `zz` 1d array into a 2d array and plot the contour levels as described in the nmrglue documentation (https://nmrglue.readthedocs.io/en/latest/jbnmr_examples/s4_2d_plotting.html). The 'filtering' can be done by setting the appropriate `levels` in the `ax.contour` call. The x and y scales can be adjusted using the `extent` keyword. – krm Jul 26 '23 at 06:55

0 Answers0