Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

matplotlib subplots with same 'settings'

I'm plotting the same data in two different formats: log scale and linear scale.

Basically I want to have exactly the same plot, but with different scales, one on the top of the other.

What I have right now is this:

import matplotlib.pyplot as plt

# These are the plot 'settings'
plt.xlabel('Size')
plt.ylabel('Time(s)');
plt.title('Matrix multiplication')

plt.xticks(xl, rotation=30, size='small')
plt.grid(True)

# Settings are ignored when using two subplots

plt.subplot(211)
plt.plot(xl, serial_full, 'r--')
plt.plot(xl, acc, 'bs')
plt.plot(xl, cublas, 'g^')

plt.subplot(212)
plt.yscale('log')
plt.plot(xl, serial_full, 'r--')
plt.plot(xl, acc, 'bs')
plt.plot(xl, cublas, 'g^')

All 'settings' before plt.subplot are ignored.

I can get this to work the way I want, but I have to duplicate all the settings after each subplot declaration.

Is there a way to do configure both subplots at once?

like image 337
leo Avatar asked Oct 18 '12 03:10

leo


2 Answers

The plt.* settings usually apply to matplotlib's current plot; with plt.subplot, you're starting a new plot, hence the settings no longer apply to it. You can share labels, ticks, etc., by going through the Axes objects associated with the plots (see examples here), but IMHO this would be overkill here. Instead, I would propose putting the common "styling" into one function and call that per plot:

def applyPlotStyle():
    plt.xlabel('Size')
    plt.ylabel('Time(s)');
    plt.title('Matrix multiplication')

    plt.xticks(range(100), rotation=30, size='small')
    plt.grid(True)

plt.subplot(211)
applyPlotStyle()
plt.plot(xl, serial_full, 'r--')
plt.plot(xl, acc, 'bs')
plt.plot(xl, cublas, 'g^')

plt.subplot(212)
applyPlotStyle()
plt.yscale('log')
plt.plot(xl, serial_full, 'r--')
plt.plot(xl, acc, 'bs')
plt.plot(xl, cublas, 'g^')

On a side note, you could root out more duplication by extracting your plot commands into such a function:

def applyPlotStyle():
    plt.xlabel('Size')
    plt.ylabel('Time(s)');
    plt.title('Matrix multiplication')

    plt.xticks(range(100), rotation=30, size='small')
    plt.grid(True)

def plotSeries():
    applyPlotStyle()
    plt.plot(xl, serial_full, 'r--')
    plt.plot(xl, acc, 'bs')
    plt.plot(xl, cublas, 'g^')

plt.subplot(211)
plotSeries()

plt.subplot(212)
plt.yscale('log')
plotSeries()

On another side note, it might suffice to put the title at the top of the figure (instead of over each plot), e.g., using suptitle. Similary, it might be sufficient for the xlabel to only appear beneath the second plot:

def applyPlotStyle():
    plt.ylabel('Time(s)');

    plt.xticks(range(100), rotation=30, size='small')
    plt.grid(True)

def plotSeries():
    applyPlotStyle()
    plt.plot(xl, serial_full, 'r--')
    plt.plot(xl, acc, 'bs')
    plt.plot(xl, cublas, 'g^')

plt.suptitle('Matrix multiplication')
plt.subplot(211)
plotSeries()

plt.subplot(212)
plt.yscale('log')
plt.xlabel('Size')
plotSeries()

plt.show()
like image 78
Hans Avatar answered Oct 29 '22 03:10

Hans


Hans' answer is probably the recommended approach. But in case you still want to go about copying the axis properties to another axis, here is a method I've found:

fig = figure()
ax1 = fig.add_subplot(2,1,1)
ax1.plot([1,2,3],[4,5,6])
title('Test')
xlabel('LabelX')
ylabel('Labely')

ax2 = fig.add_subplot(2,1,2)
ax2.plot([4,5,6],[7,8,9])


for prop in ['title','xlabel','ylabel']:
    setp(ax2,prop,getp(ax1,prop))

show()
fig.show()

enter image description here

This lets you set a white-list for which properties to set, currently I have the title, xlabel and ylabel, but you can just use getp(ax1) to print out a list of all the available properties.

You can copy all of the properties using something like the following, but I recommend against it since some of the property settings will mess up the second plot. I've tried to use a black-list to exclude some, but you'll would need to fiddle with it to get it working:

insp = matplotlib.artist.ArtistInspector(ax1)
props = insp.properties()
for key, value in props.iteritems():
    if key not in ['position','yticklabels','xticklabels','subplotspec']:
        try:
            setp(ax2,key,value)
        except AttributeError:
            pass

(The except/pass is to skip properties which are gettable, but not settable)

like image 22
Chris Zeh Avatar answered Oct 29 '22 04:10

Chris Zeh