multiple legends

It is certainly useful at times to break your legend up into multiple parts, but doing so in python (matplotlib) can be a pain in the neck. Luckily there’s a quick and fairly simple solution!

First thing you need to do, is actually name your plotted lines like so:
 fig=figure()
 ax1=fig.add_subplot(111)

l1 = ax1.plot(x, y, 'bo', label='ONE')
 l2 = ax1.plot(i, j, 'rx', label='TWO')
we now separate these lines and their labels into different variables
legendlines1 = l1
legendlabels1 = [l.get_label() for l in legendlines1]
legendlines2 = l2
legendlabels2 = [l.get_label() for l in legendlines2]
at this point we can’t just plot a legend, then another legend. The second legend always takes precedence and essentially erases the first. So in order to get around this, we name the first legend, and render the second:
legend1 = ax1.legend(legendlines1,legendlabels1,loc=1)
ax1.legend(legendlines2,legendlabels2,loc=3)
if you run the script up until this point, you’ll only have the second legend showing in location 3. In order to get the second legend we add the object via gca():
gca().add_artist(legend1)
and that should do it!
multilegend
full script below:
 from pylab import *
 from numpy import *

x=linspace(0,5,20)
 y=-x

fig=figure()
 ax1=fig.add_subplot(111)

l1=ax1.plot(x,y,label='ONE')
 l2=ax1.plot(y,x,label='TWO')

legendlines1 = l1
 legendlabels1 = [l.get_label() for l in legendlines1]
 legendlines2 = l2
 legendlabels2 = [l.get_label() for l in legendlines2]

legend1=ax1.legend(legendlines1,legendlabels1,loc=1)
ax1.legend(legendlines2,legendlabels2,loc=3)

gca().add_artist(legend1)

show()

frameless legend()

I keep forgetting how to turn the bounding box OFF for matplotlib’s legend(). It quite simple but I can’t stop forgetting =(

legend(frameon=False)

colorbar for a multipanel plot

I was having some issues tonight getting a colorbar to function properly. If my script simply looked like so:
fig=figure(figsize=(12,6))
p1=fig.add_subplot(121)
column_render(datasets[0],PICKER,logData=LOG,
minIn=datasets[COLOR_SCALE].MIN, maxIn=datasets[COLOR_SCALE].MAX)
axis([XL,XH,YL,YH])
title(r'VSPH')
p2=fig.add_subplot(122)
column_render(datasets[1],PICKER,logData=LOG,
minIn=datasets[COLOR_SCALE].MIN, maxIn=datasets[COLOR_SCALE].MAX)
p2.set_yticklabels([])
axis([XL,XH,YL,YH])
title(r'DISPH')
subplots_adjust(wspace=0,hspace=0,right=0.85,left=0.07)
cb = colorbar()
cb.set_label(r'%s' % datasets[COLOR_SCALE].LABEL,fontsize=18)
show()
I got something that looked like this:
which is obviously not what I was looking for. Apparently I need to add an axis where I will place the colorbar. Tips from stackoverflow and checking out python’s website itself led me to the proper conclusion:
fig=figure(figsize=(12,6))
p1=fig.add_subplot(121)
column_render(datasets[0],PICKER,logData=LOG,
minIn=datasets[COLOR_SCALE].MIN, maxIn=datasets[COLOR_SCALE].MAX)
axis([XL,XH,YL,YH])
title(r'VSPH')
p2=fig.add_subplot(122)
column_render(datasets[1],PICKER,logData=LOG,
minIn=datasets[COLOR_SCALE].MIN, maxIn=datasets[COLOR_SCALE].MAX)
p2.set_yticklabels([])
axis([XL,XH,YL,YH])
title(r'DISPH')
subplots_adjust(wspace=0,hspace=0,right=0.85,left=0.07)
cax = fig.add_axes([0.86, 0.1, 0.03, 0.8])
cb = colorbar(cax=cax)
cb.set_label(r'%s' % datasets[COLOR_SCALE].LABEL,fontsize=18)
show()
by adding an axis for the colorbar to live on lets me customize its location, width, and height. The parameters in add_axis([left,bottom,width,height]) as in it’s drawing a rectangle. With this slight change the plot now looks like this:
GALCOMPARE

bounding box for text in matplotlib

More often than not nowadays I find myself having to add text to my figures. The problem that often arise is how do I make it stand out? Creating a bounding box for the text is not necessarily straight forward and I’m tired of searching for it:
text(-7.5,7.5,DIRS[i],bbox={'edgecolor':'k', 'facecolor':color[i],
'alpha':0.5})

customizing matplotlib’s legend()

I am constantly needing to customize the legend() in python. Whether it be changing the marker size, the line width, or the fontsize I’m constantly looking things up. There’s an easy way to set this at the beginning of your script; as an example:
params = {'legend.fontsize' : 16,
'legend.linewidth' : 1.5,
'legend.markerscale' : 3}
rcParams.update(params)
You could easily add other options such as modifying the handlelen (line width), font, etc etc. All options can be found via matplotlib’s legend() api site.

mass-weighted Sobolev/HSML column values

Ken suggested I revisit the particles per grid-cell comparison - i.e. Grid vs. Sob, Sob vs. HSML, and Grid vs. HSML. In order to do this so that each grid corresponds to one value, I have to take the mass-weighted average of the Sobolev/HSML values within a given grid-cell:
\begin{equation*} <\Sigma_{\rm{Sob}}>_{\rm{MW}} = \Sigma_\rm{((Sob,or,HSML)}\times \rm{mass})/\Sigma_\rm{mass} \end{equation*}

I then have a single \(\Sigma\) value per grid-cell and can make a direct comparison:

sobolevpixels
(plot made with gal_reduction/tools/sigmacompare.py via PIXELPLOT==1)

In an ideal situation, each line would lie on the one-to-one dotted black line. Unfortunately both Sobolev and HSML values under estimate the grid values. The good news is that there isn’t much difference due to the resolution. We might have to examine more galaxies within our sims in a similar fashion to see if this under prediction takes place at the same surface densities; if that is the case we can easily incorporate some sort of correction factor. But that leads to the question - how many galaxies do we have to look at?

In making this plot I learned how to stick the legend outside of the plot. It’s as simple as passing bbox_to_anchor to the legend() call:
legend(bbox_to_anchor=(0.1,1.05),loc=3,shadow=True,fancybox=True)
this is a tiny bit tricky in that the anchor is attached to the loc. So if loc=3 then the anchor for the box is attached to the bottom left corner of the legend box. Also the x,y coordinates are in absolute figure positions. This is thanks to matplotlib and stack overflow.

Next up was Ken’s concern about the histograms I was sending him. Further inspection showed that simply passing ‘bins=50’ is not necessarily the best idea to properly represent the data. By default hist() takes the min & max of the data then splits it into N bins. The problem here is that if you’re comparing two different datasets then if they span a different range then the binsizes will differ. To circumvent this issues I simply specified the binsize manually via altering my histo() function call a tiny bit:
def histoit(values,COLOR,LABEL,HLS,BINSIZE=0.1):
indexes = where(values>0)[0] ##prevents -inf
vals = log10(values[indexes])
binner = arange(min(vals),max(vals),BINSIZE)
hist(vals,color=COLOR,log=True,
bins=binner,
label=LABEL,histtype='step',lw=1.5,ls=HLS)
With this quick fix the data looks much more comparable, here’s the before and after:

[table] Before,After [/table] better right? hello?


And last but not least, I’ve plotted the gas particle positions for this galaxy at all three resolutions for visual inspection:
ledisks
we go from slightly compressed cloud, to fluffy pancake, to regular pancake!