Python’s matplotlib rocks. It is, by itself, the fundamental reason I stay with Python (JVM-based JFreeChart is powerful but – as most JVM libraries – an over-engineered, complex piece of software).
Doing multiple charts in matplotlib is not trivial, though. Well, it is trivial, but the end result is not perfect. Here I will present a step-by-step guide to creating better subplots. “Better” is, of course, a matter of taste, therefore every change will be presented separately, so that you can pick and chose whichever you prefer.
We start with this (as with all charts presented here, you will need to click to enlarge):
OK, the space between charts is wasted. Also the outside border is too big. Outside borders are less of a problem with a single chart, but when you have lots of stuff to present, then all space that you can get is important. So, we add this:
fig = pylab.figure() fig.subplots_adjust(hspace=0.0001, wspace=0.0001, bottom=0.07, top=0.96, left=0.04, right=0.96)
The fig variable might have been initialized before, so use your own. Notice that subplots_adjust allows you to control both external borders (left, right, bottom, top) and space between charts (hspace, wspace). The result is this:
Before we discuss what obviously looks bad, we need to discuss something that looks good but is, in fact, problematic: The fonts. The fonts look of a proper size and (at least some of them) appear properly positioned. This apparent “goodness” is dependent on figure size and resolution (check the parameters of figure). If you develop this on screen and then want to generate an eps version at the end (say, to publish a scientific paper) you might be going for a rough ride and just detect the problem way later (when you generate the final, production version)! Suggestion: Try adjusting the figure parameters from the start (use both pylab.show and pylab.savefig – png and eps – to test the results). Here I will not spend time with more details about this (the same applies to line thickness, by the way).
OK, irrespective of the point above, the figure clearly has other problems. I opt to remove all titles (just remove the title lines) and remove the unnecessary X and Y axis labels. Note that we have 2 Y axis (one on the left, and one on the right). So, we apply the following code:
#We assume that sp comes from #sp = pylab.subplot()... #You should have this line if you have an extra Y-axis #Ignore this if you do not have one (most cases won't have one) par1 = sp.twinx() #Apply this line to all subplots NOT on the extreme left pylab.setp(sp.get_yticklabels(), visible=False) #Apply this line to all subplots NOT on the bottom pylab.setp(sp.get_xticklabels(), visible=False) #Apply this line to all subplots NOT on the extreme right pylab.setp(par1, visible=False)
Remember that we also removed the titles, so the result is:
Before we re-instate the titles (and put some legends), notice that the Y-axis labels slightly overlap from one chart to the other (this also happens with the X-axis labels, but it is less visible). For this we will redo the labels:
1 2 3 4 5 6 7 8 | #if left and not bottom: pylab.yticks((0,.2,.4,.6,.8,1),("","0.2","0.4","0.6", "0.8","1.0")) ... #if right and not bottom: pylab.yticks((0,0.5,1,1.5,2,2.5,3,3.5,4,), ("", "0.5", "1", "1.5", "2", "2.5" , "3", "3.5", "4")) #if bottom and not left: pylab.xticks((0,20,40,60,80,100),("","20","40","60", "08","100")) |
Now, you might be confused: Lines 2 and 5 call the same function. Well line 2 is called before the creation of the second axe, line 5 after. There might be a more general way of doing this, but I was lazy enough to try and discover it. Result:
OK, now titles and axis labels. I will do this in a non-standard way: By hard-coding everything! You can, if you prefer activate the calls to .set_xlabel, and .title in the right position. In any case, the following example might serve to illustrate fig.text:
1 2 3 4 5 6 7 8 | fig.text(0.5, 0.01, "Generations", ha="center", va="bottom", size="medium") fig.text(0.20, 0.99, "Full epistasis", ha="center", va="top", size="medium") fig.text(0.52, 0.99, "Mixed mode", ha="center", va="top", size="medium") fig.text(0.83, 0.99, "DGF", ha="center", va="top", size="medium") fig.text(0.015, 0.52, "Fst / LD(r)", ha="right", va="center", size="medium", rotation="vertical") fig.text(0.99, 0.52, "Ratio", ha="right", va="center", size="medium", rotation=270) |
ha is horizontal alignment (I will leave up to you to discover what va is
). Note that the last 2 texts have different rotations. It is possible to put math notation in the text (LaTeX). Something like this: $\frac{1}{n}$. You need 2 things for this to work: add matplotlib.rc(‘text’, usetex = True) and have LaTex installed.
The end result is then:
Not fantastic, but you now have the techniques to alter at will. Just a final reminder that changing size and resolution will have a strong impact on font and line thickness. You might want to check your chart with all final media (screen, eps to print, …). For instance the example above would clearly benefit from thicker lines and larger fonts.















