Search code examples
pythonmatplotlibhistogramcontourhistogram2d

3D histograms and Contour plots Python


I have a problem with contourf function of matplotlib. I have a txt data file from which I am importing my data. I have columns of data (pm1 and pm2) and I am performing a 2D histogram. I want to plot this data as a 3D histogram and as a contour plot to see where is located the maximum values.

This is my code:

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
rows = np.arange(200,1300,10)

hist, xedges, yedges = np.histogram2d (pm1_n, pm2_n, bins = (rows, rows) )
elements = (len(xedges) - 1) * (len(yedges) - 1)


xpos, ypos = np.meshgrid(xedges[:-1], yedges[:-1])

xpos = xpos.flatten()
ypos = ypos.flatten()
zpos = np.zeros(elements)
dx = 0.1 * np.ones_like(zpos)
dy = dx.copy()
dz = hist.flatten()

#####The problem is here#####

#ax.contourf(xpos,ypos,hist)
#ax.bar3d(xpos, ypos, zpos, dx, dy, dz, zsort='average')

plt.show()

I can plot the 3d bar graph but I am not able to plot the contour one, If I place hist in the contourf function I get the error: Length of x must be number of columns in z and if I place dz I get Input z must be a 2D array I also have tried using xedges and yexges but this doesn't solve the problem.

I think that the problem is related with the shape of the return of the function histogram2D. But I don't know how to solve it.

I would also like to perform a 3D bar plot with a colorcode changing form the minimum to the maximum value. Is there anyway to make this?

Thank you


Solution

  • Perhaps I don't understand what exactly you are trying to do since I don't know what your data looks like, but it seems wrong to have your contourf plot sharing the same axis as your bar3d plot. If you add an axis without the 3D projection to a new figure, you should be able to make a contourf plot just fine using hist. An example using data from a random, normal distribution:

    import numpy as np
    import matplotlib.pyplot as plt
    
    n_points = 1000
    x = np.random.normal(0, 2, n_points)
    y = np.random.normal(0, 2, n_points)
    
    hist, xedges, yedges = np.histogram2d(x, y, bins=np.sqrt(n_points))
    
    fig2D = plt.figure()
    ax2D = fig2D.add_subplot(111)
    ax2D.contourf(hist, interpolation='nearest', 
                  extent=(xedges[0], xedges[-1], yedges[0], yedges[-1]))
    plt.show()
    

    returns an image like this.

    As for your second question, regarding a color-coded 3D bar plot, how about this (using the same data as above but with 1/10 the size):

    import numpy as np
    import matplotlib.pyplot as plt
    from mpl_toolkits.mplot3d import Axes3D
    from matplotlib import cm
    import matplotlib.colors as colors
    
    n_points = 100
    x = np.random.normal(0, 2, n_points)
    y = np.random.normal(0, 2, n_points)
    
    hist, xedges, yedges = np.histogram2d(x, y, bins=np.sqrt(n_points))
    
    # Following your data reduction process
    xpos, ypos = np.meshgrid(xedges[:-1], yedges[:-1])
    
    length, width = 0.4, 0.4
    xpos = xpos.flatten()
    ypos = ypos.flatten()
    zpos = np.zeros(n_points)
    dx = np.ones(n_points) * length
    dy = np.ones(n_points) * width
    dz = hist.flatten()
    
    # This is where the colorbar customization comes in
    dz_normed = dz / dz.max()
    normed_cbar = colors.Normalize(dz_normed.min(), dz_normed.max())
    # Using jet, but should work with any colorbar
    color = cm.jet(normed_cbar(dz_normed))
    
    fig3D = plt.figure()
    ax3D = fig3D.add_subplot(111, projection='3d')
    ax3D.bar3d(xpos, ypos, zpos, dx, dy, dz, color=color)
    plt.show()
    

    I get this image.