Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create Matplotlib figure with image and profile plots that fit together?

I would like to plot 2d data as an image, with profile plots through along the x and y axis displayed below and to the side. It's a pretty common way to display data so there may be an easier way to approach this. I would like to find the most simple and robust way that does so correctly, and without using anything outside of matplotlib (though I would be interested in knowing of other packages that may be particularly relevant). In particular, the method should work without changing anything if the shape (aspect ratio) of the data changes.

My main issue is getting the side plots to scale correctly so their borders match up with main plot.

Example code:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
# generate grid and test data
x, y = np.linspace(-3,3,300), np.linspace(-1,1,100)
X, Y = np.meshgrid(x,y)
def f(x,y) :
    return np.exp(-(x**2/4+y**2)/.2)*np.cos((x**2+y**2)*10)**2
data = f(X,Y)

# 2d image plot with profiles
h, w = data.shape
gs = gridspec.GridSpec(2, 2,width_ratios=[w,w*.2], height_ratios=[h,h*.2])
ax = [plt.subplot(gs[0]),plt.subplot(gs[1]),plt.subplot(gs[2])]
bounds = [x.min(),x.max(),y.min(),y.max()]
ax[0].imshow(data, cmap='gray', extent = bounds, origin='lower')
ax[1].plot(data[:,w/2],Y[:,w/2],'.',data[:,w/2],Y[:,w/2])
ax[1].axis([data[:,w/2].max(), data[:,w/2].min(), Y.min(), Y.max()])
ax[2].plot(X[h/2,:],data[h/2,:],'.',X[h/2,:],data[h/2,:])
plt.show()

As you can see from the output below, the way things are scaled the image to the right does not properly match the boundaries.

Partial solutions:

1) Manually play with the figure size to find the right aspect ratio so that it appears correctly (could do automatically using the image ratio + padding + the width ratios used?). Seems tacky when there are already so many options for packing that are supposed to take care of these things automatically. EDIT: plt.gcf().set_figheight(f.get_figwidth()*h/w) seems to work if padding is not changed.

2) Add ax[0].set_aspect('auto') , which then makes boundaries line up, but the image no longer has the correct aspect ratio.

Output from code sample above: Example output

like image 725
argentum2f Avatar asked Aug 07 '15 16:08

argentum2f


People also ask

How do I show multiple plots in MatPlotLib?

In Matplotlib, we can draw multiple graphs in a single plot in two ways. One is by using subplot() function and other by superimposition of second graph on the first i.e, all graphs will appear on the same plot.


1 Answers

you can use sharex and sharey to do this, replace your ax= line with this:

ax = [plt.subplot(gs[0]),]
ax.append(plt.subplot(gs[1], sharey=ax[0]))
ax.append(plt.subplot(gs[2], sharex=ax[0]))

enter image description here

like image 187
CT Zhu Avatar answered Oct 03 '22 18:10

CT Zhu