Tuesday, January 19, 2010

customized legend


Legend in matplotlib is a collection of OffsetBox instances. And with some knowledge of offsetbox module, you can create a customized version of the legend, etc.

While the current offsetbox module does not have something like table, but one can emulate table by using the offsetboxes of fixed size.


import matplotlib.pyplot as plt
import matplotlib.offsetbox as moffsetbox
from matplotlib.text import Text
from matplotlib.lines import Line2D

ax = plt.subplot(111)
l1, = ax.plot([1,2,3])
l2, = ax.plot([1,3,2])

# below is code for legend-like box

headers = ["Line", r"$\alpha$", r"$\beta$"]
lines = [l1, l2]
label_1 = ["$0.31$", "$0.23$"]
label_2 = ["$0.12$", "$1.23$"]

###
fontsize = 12
height = fontsize



def get_hbox(widths):
boxes = []
for width in widths:
xdescent, ydescent = width/2., fontsize*0.1
c = moffsetbox.DrawingArea(width, height, xdescent, ydescent)
boxes.append(c)
hbox = moffsetbox.HPacker(pad=0, sep=0.5*fontsize, align="baseline",
children=boxes)
return hbox

widths = [fontsize * 3, fontsize * 4, fontsize * 4]

# header

hb_header = get_hbox(widths)

for ob, s in zip(hb_header.get_children(), headers) :
txt = Text(0, 0, s, ha="center", va="baseline",
size=fontsize)
ob.add_artist(txt)

# rows

def get_row(handle, label1, label2):
hb_row0 = get_hbox(widths)
hb_row = hb_row0.get_children()

width = widths[0]
l = Line2D([-width*0.4, width*0.4], [0.3*height, 0.3*height])
l.update_from(handle)
hb_row[0].add_artist(l)

t = Text(0, 0, label1, ha="center", va="baseline")
hb_row[1].add_artist(t)

t = Text(0, 0, label2, ha="center", va="baseline")
hb_row[2].add_artist(t)

return hb_row0

rows = [get_row(handle, lab1, lab2) for handle, lab1, lab2 in zip(lines, label_1, label_2)]

vbox = moffsetbox.VPacker(pad=0, sep=0.5*fontsize, align="baseline",
children=[hb_header]+rows)

mybox = moffsetbox.AnchoredOffsetbox(loc=1, pad=0.4, borderpad=0.5,
child=vbox, frameon=True,
bbox_to_anchor=ax.bbox,
bbox_transform=None,
)


ax.add_artist(mybox)


plt.show()


Wednesday, September 9, 2009

grid bug in axes_grid

axes_grid in MPL 0.99 has a bug that it does not draw gridlines (only for rectlinear coordinate. it does draw gridlines for curvelinear coordinates). While this is fixed in the trunk, here is a work around.



ax.grid(True)
ax.gridlines.set_visible(False) # this is just to make code works with future mpl.
ax.xaxis.set_visible(True)
ax.xaxis.set_zorder(2.6)
ax.yaxis.set_zorder(2.6)
ax.yaxis.set_visible(True)
for t in ax.xaxis.majorTicks + ax.yaxis.majorTicks:
t.gridOn = True
t.tick1On = False
t.tick2On = False
t.label1On = False
t.label2On = False

plt.show()


Here is a complete example, a modified version of simple_axisline2.py


import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid.axislines import SubplotZero
import numpy as np

fig = plt.figure(1, (4,3))

# a subplot with two additiona axis, "xzero" and "yzero". "xzero" is
# y=0 line, and "yzero" is x=0 line.
ax = SubplotZero(fig, 1, 1, 1)
fig.add_subplot(ax)

# axes.toggle_axisline(False)
# make xzero axis (horizontal axis line through y=0) visible.
ax.axis["xzero"].set_visible(True)
ax.axis["xzero"].label.set_text("Axis Zero")
ax.axis["xzero"].label.set_bbox(dict(boxstyle="round",ec="r", fc="w"))
ax.axis["xzero"].major_ticklabels.set_bbox(dict(boxstyle="square",
ec="none", fc="w", alpha=0.5))

# make other axis (bottom, top, right) invisible.
for n in ["bottom", "top", "right"]:
ax.axis[n].set_visible(False)

xx = np.arange(0, 2*np.pi, 0.01)
ax.plot(xx, np.sin(xx))

ax.grid(True)
ax.gridlines.set_visible(False) # this is just to make code works with future mpl.
ax.xaxis.set_visible(True)
ax.xaxis.set_zorder(2.6)
ax.yaxis.set_zorder(2.6)
ax.yaxis.set_visible(True)
for t in ax.xaxis.majorTicks + ax.yaxis.majorTicks:
t.gridOn = True
t.tick1On = False
t.tick2On = False
t.label1On = False
t.label2On = False

plt.show()

Monday, August 24, 2009

compiling sherpa for standalone python

Download tarball from hea-www Sherpa Home and compile.

Here is sample setup.


#! /bin/sh
CIAO=/usr/astro/ciao-4.1
CIAO_OTS=/usr/astro/ciao-4.1/ots
CIAO_LIB=$CIAO/lib
CIAO_INC=$CIAO/include
CIAO_OTS_LIB=$CIAO_OTS/lib
CIAO_OTS_INC=$CIAO_OTS/include

python setup.py \
xspec_library_dir=/usr/astro/heasoft/i686-pc-linux-gnu/lib \
reg_include_dir=$CIAO_INC \
reg_library_dir=$CIAO_LIB \
wcs_include_dir=$CIAO_OTS_INC \
wcs_library_dir=$CIAO_OTS_LIB \
cfitsio_library_dir=$CIAO_OTS_LIB \
install --prefix=$HOME/local



But the import will give a few warnings, which is not very critical though.

  • You need to copy libregion.so from $CIAO_LIB to somewhere in you library path.
  • A tricky part is group module, and ore about it later.

Saturday, August 22, 2009

Creating a color bar using inset axes


An example to create an inset axes outside the axes area, and use it as a colorbar axes.



import matplotlib.pyplot as plt

from mpl_toolkits.axes_grid.inset_locator import inset_axes

fig = plt.figure(1, [5.5, 3])

# first subplot
ax = fig.add_subplot(111)
ax.set_aspect(1.)

axins = inset_axes(ax,
width="5%", # width = 10% of parent_bbox width
height="50%", # height : 50%
loc=3)

# Unfortunately, inset_axes currently ignores bbox_to_anchor and
# borderpad parameters, which is a bug.
# As a workaround, set these values after axes creation.

locator=axins.get_axes_locator()
locator.set_bbox_to_anchor((1.05, 0, 1, 1), ax.transAxes)
locator.borderpad = 0.
# Controlling the placement of the inset axes is basically same as that
# of the legend. you may want to play with the borderpad value and
# the bbox_to_anchor coordinate.

im=ax.imshow([[1,2],[2, 3]])
plt.colorbar(im, cax=axins)

plt.draw()
plt.show()

Friday, August 14, 2009

A few new things in MPL svn

[BboxImage]

Similar to AxesImage, but image occupies the area specified by the bbox parameter.

example 1 : demo_bboximage.py



example 2 : demo_ribbon_box.py - making the image on the fly



[AnnotationBbox]

similar to annotation, but works with OffsetBox instead of text. Can be used to place a BboxImage(e.g., clip art image) or a TextPatch object (see below)

example : demo_annotation_box.py


[TextPatch]

A patch class with outline of the text. I'm still experimenting with the api and It is currently included as an example.

example : demo_text_path.py


[agg_filter]

a simple framework for image filtering effects (only for agg backend).

example : demo_agg_filter.py

Sunday, May 10, 2009

MPL multicolor text




from pylab import figure, show

from matplotlib.offsetbox import AnchoredOffsetbox, HPacker, TextArea


f = figure(1)
ax = f.add_subplot(111)

txt1 = TextArea("A$^3$", textprops=dict(color="r", size=150))
txt2 = TextArea("gb", textprops=dict(color="k", size=150))

txt = HPacker(children=[txt1, txt2],
align="baseline",
pad=0, sep=0)

def txt_offset(*kl):
return ax.transData.transform_point((0.2, 0.2))
txt.set_offset(txt_offset)

# box = AnchoredOffsetbox(loc=3, pad=0, borderpad=0,
# bbox_to_anchor=(0.5, 0.5),
# bbox_transform=ax.transData,
# child=txt,
# frameon=False)

ax.add_artist(txt)

show()

Wednesday, April 1, 2009

Inset axes

A little script to have your inset axes to adjust its position relative to the parent axes. The inset position is calculated in the drawing time, thus it works even if the parent axes change its position (e.g., aspect=1).


import matplotlib.transforms

class InsetPosition(object):
def __init__(self, parent, lbwh):
self.parent = parent
self.lbwh = lbwh # position of the inset axes in the
normalized coordinate of the parent axes

def __call__(self, ax, renderer):
bbox_parent = self.parent.get_position(original=False)
trans = matplotlib.transforms.BboxTransformTo(bbox_parent)
bbox_inset = matplotlib.transforms.Bbox.from_bounds(*self.lbwh)
bb = matplotlib.transforms.TransformedBbox(bbox_inset, trans)
return bb

ax = gca()
ax.set_aspect(1.)
axins = axes([0, 0, 1, 1])
ip = InsetPosition(ax, [0.5, 0.1, 0.4, 0.2])
axins.set_axes_locator(ip)


TODO:
  • anchor to the parent axes
  • adjust the inset size according to its data limits

Followers