8

I have generated some data in Python using matplotlib.hist2d. An example of the data is seen below. data

As you can see this data has some contours in it found by tracing the same color throughout the plot. I see a gamma distribution centered around 0.015. I would like to take this data and gather these contours so I can see a line trace through each color level. I tried playing around with the contour function as here

counts, xedges, yedges, Image = hist2d(x, y, bins=bins, norm=LogNorm(), range=[[0, 1], [0, 400]])
contour(counts)

but that didn't seem to produce anything.

Does anyone know the best way to get these contours? Ideally I'd like to take these contours and fit a function (like a gamma function) to them and then get the function parameters.

Thanks

Jon
  • 3,985
  • 7
  • 48
  • 80

2 Answers2

13

So the problem is that the image created by hist2d is plotted in data coordinates, but the contours you are trying to create are in pixel coordinates. The simple way around this is to specify the extent of the contours (i.e. rescale/reposition them in the x and y axes).

For example:

from matplotlib.colors import LogNorm
from matplotlib.pyplot import *

x = np.random.normal(5,10,100000)
y = np.random.normal(5,10,100000)
counts,ybins,xbins,image = hist2d(x,y,bins=100,norm=LogNorm())
contour(counts,extent=[xbins.min(),xbins.max(),ybins.min(),ybins.max()],linewidths=3)

Will produce:

enter image description here

ebarr
  • 7,704
  • 1
  • 29
  • 40
  • 3
    Thanks, this was exactly what I needed to see. The only tweak I had to make was instead of calling contour(counts,extent=[xbins.min(),xbins.max(),ybins.min(),ybins.max()],linewidths=3), I needed the call contour(counts.transpose(),extent=[xbins.min(),xbins.max(),ybins.min(),ybins.max()],linewidths=3) – Jon Oct 14 '14 at 13:46
  • @ebarr that's nice. But If I got a 3D random-dataset(x,y,z), then how can it be possible to apply this method ? – diffracteD Jun 10 '15 at 08:21
  • @ebarr in mine the returned `xbins` <-> `ybins` – jtlz2 Jun 15 '21 at 11:56
  • @diffracteD - you need to replace `x` and `y` with your real data..? What is your `z`? – jtlz2 Jun 15 '21 at 11:57
10

Would prefer to post this as a comment, but don't have the reputation, so ...

@ebarr has a nice solution with one small correction: the xbins and ybins coming from the 2d plot should be reversed (see matplotlib documentation, https://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.hist2d
)

Also, only mildly annoying, but the contour lines colors won't line up with the colors in the 2d histogram since the histogram colorscale has been log transformed. To fix this you can manually specify levels for the contour plot.

Making these changes, and separating the plots for clarity yields:

from matplotlib.colors import LogNorm
import matplotlib.pyplot as plt

x = np.random.normal(5,10,100000)
y = np.random.normal(5,10,100000)
plt.subplot(121)
counts,xbins,ybins,image = plt.hist2d(x,y,bins=100
                                      ,norm=LogNorm()
                                      , cmap = plt.cm.rainbow)
plt.colorbar()
plt.subplot(122)
plt.contour(counts.transpose(),extent=[xbins[0],xbins[-1],ybins[0],ybins[-1]],
    linewidths=3, cmap = plt.cm.rainbow, levels = [1,5,10,25,50,70,80,100])

This produces: Histogram and contour map Histogram and contour map

Mr. T
  • 11,960
  • 10
  • 32
  • 54