pythonmatplotlibyt-project

Adding subplots within yt-Project plot


I'm using the yt-Project library to visualize data and create plots. Now, I want to create a plot containing of two subplots. It seems this is not directly possible with yt and you have to use matplotlib for further customization (described here). Being not used to matplotlib (and python in general) I tried something like this:

slc = yt.SlicePlot(ds, 'x', 'density')
dens_plot = slc.plots['density']

fig = dens_plot.figure
ax = dens_plot.axes
#colorbar_axes = dens_plot.cax

new_ax2 = fig.add_subplot(212)

slc.save()

But instead of adding another subplot beneath the first one, it adds it in it. enter image description here

What I'd like to achieve would be another plot from a different data set with the same color bar and the same x and y axes right beneath the first one.

Thank you for your help.


Solution

  • Right now the easiest way to do this is to use an AxesGrid, as in this yt cookbook example as well as this one.

    Here's an example that plots the gas density at two times in a time series, using yt 3.2.1. The example data I'm using can be downloaded from http://yt-project.org/data.

    import yt
    import matplotlib.pyplot as plt
    from mpl_toolkits.axes_grid1 import AxesGrid
    
    fns = ['enzo_tiny_cosmology/DD0005/DD0005', 'enzo_tiny_cosmology/DD0040/DD0040']
    
    fig = plt.figure()
    
    # See http://matplotlib.org/mpl_toolkits/axes_grid/api/axes_grid_api.html
    # These choices of keyword arguments produce a four panel plot with a single
    # shared narrow colorbar on the right hand side of the multipanel plot. Axes
    # labels are drawn for all plots since we're slicing along different directions
    # for each plot.
    grid = AxesGrid(fig, (0.075,0.075,0.85,0.85),
                    nrows_ncols = (2, 1),
                    axes_pad = 0.05,
                    label_mode = "L",
                    share_all = True,
                    cbar_location="right",
                    cbar_mode="single",
                    cbar_size="3%",
                    cbar_pad="0%")
    
    for i, fn in enumerate(fns):
        # Load the data and create a single plot
        ds = yt.load(fn) # load data
    
        # Make a ProjectionPlot with a width of 34 comoving megaparsecs
        p = yt.ProjectionPlot(ds, 'z', 'density', width=(34, 'Mpccm'))
    
        # Ensure the colorbar limits match for all plots
        p.set_zlim('density', 1e-4, 1e-2)
    
        # This forces the ProjectionPlot to redraw itself on the AxesGrid axes.
        plot = p.plots['density']
        plot.figure = fig
        plot.axes = grid[i].axes
        plot.cax = grid.cbar_axes[i]
    
        # Finally, this actually redraws the plot.
        p._setup_plots()
    
    plt.savefig('multiplot_1x2_time_series.png', bbox_inches='tight')
    

    yt multiplot

    You can do it your way too (using fig.add_subplots instead of AxesGrid), but you'll need to manually position the axes and also resize the figure.

    Finally, if you want the figure to be smaller, you can control the size of the figure by passing a figure size in inches when you create the figure via plt.figure(). If you do that, you might want to adjust the font size as well by calling p.set_font_size() on the ProjectionPlot.