[Matplotlib-users] Hints on sizing plot elements?
I'm making a strip chart widget (which I plan to make publicly available when finished). The basics are working fine, but the automatic sizing is not doing so well. Strip charts are typically short, and when suitably short the X axis annotations are partially truncated. So...can I convince the automatic sizer to always show the full X (time) axis annotations and put all the variable sizing into the data area? Or do I have to manually set them somehow? Also, is there a way from my software (not a .matplotlibrc file) to globally make the default background color white for axis annotation areas? Right now the background is gray for annotations and while for plot area and I'd prefer it was all white. -- Russell -- This SF.net email is sponsored by Make an app they can't live without Enter the BlackBerry Developer Challenge http://p.sf.net/sfu/RIM-dev2dev ___ Matplotlib-users mailing list Matplotlib-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-users
Re: [Matplotlib-users] Hints on sizing plot elements?
On Aug 12, 2010, at 1:08 AM, Russell E. Owen wrote: > I'm making a strip chart widget (which I plan to make publicly available > when finished). The basics are working fine, but the automatic sizing is > not doing so well. Strip charts are typically short, and when suitably > short the X axis annotations are partially truncated. > > So...can I convince the automatic sizer to always show the full X (time) > axis annotations and put all the variable sizing into the data area? Or > do I have to manually set them somehow? As far as I know, there's nothing to automatically resize the padding around the the axes. (The manual way to do it is to call `fig.subplots_adjust`). I wrote a helper script (attached below) to adjust the layout so that there's a specified amount of padding around the axes. Unfortunately, this resizer doesn't function correctly when using the GTK backend. It apparently works fine with TkAgg, MacOSX, and Qt4Agg backends. > Also, is there a way from my software (not a .matplotlibrc file) to > globally make the default background color white for axis annotation > areas? Right now the background is gray for annotations and while for > plot area and I'd prefer it was all white. > > -- Russell Just set plt.rc('figure', facecolor='w') in your code (assuming you've imported matplotlib.pyplot as plt). Best, -Tony import numpy as np import matplotlib.pyplot as plt from matplotlib.transforms import TransformedBbox, Affine2D PAD_INCHES = 0.1 def tight_layout(pad_inches=PAD_INCHES, h_pad_inches=None, w_pad_inches=None): """Adjust subplot parameters to give specified padding. Parameters -- pad_inches : float minimum padding between the figure edge and the edges of subplots. h_pad_inches, w_pad_inches : float minimum padding (height/width) between edges of adjacent subplots. Defaults to `pad_inches`. """ if h_pad_inches is None: h_pad_inches = pad_inches if w_pad_inches is None: w_pad_inches = pad_inches fig = plt.gcf() tight_borders(fig, pad_inches=pad_inches) # NOTE: border padding affects subplot spacing; tighten border first tight_subplot_spacing(fig, h_pad_inches, w_pad_inches) def tight_borders(fig, pad_inches=PAD_INCHES): """Stretch subplot boundaries to figure edges plus padding.""" # call draw to update the renderer and get accurate bboxes. fig.canvas.draw() bbox_original = fig.bbox_inches bbox_tight = _get_tightbbox(fig, pad_inches) # figure dimensions ordered like bbox.extents: x0, y0, x1, y1 lengths = np.array([bbox_original.width, bbox_original.height, bbox_original.width, bbox_original.height]) whitespace = (bbox_tight.extents - bbox_original.extents) / lengths # border padding ordered like bbox.extents: x0, y0, x1, y1 current_borders = np.array([fig.subplotpars.left, fig.subplotpars.bottom, fig.subplotpars.right, fig.subplotpars.top]) left, bottom, right, top = current_borders - whitespace fig.subplots_adjust(bottom=bottom, top=top, left=left, right=right) def _get_tightbbox(fig, pad_inches): renderer = fig.canvas.get_renderer() bbox_inches = fig.get_tightbbox(renderer) return bbox_inches.padded(pad_inches) def tight_subplot_spacing(fig, h_pad_inches, w_pad_inches): """Stretch subplots so adjacent subplots are separated by given padding.""" # Zero hspace and wspace to make it easier to calculate the spacing. fig.subplots_adjust(hspace=0, wspace=0) fig.canvas.draw() figbox = fig.bbox_inches ax_bottom, ax_top, ax_left, ax_right = _get_grid_boundaries(fig) nrows, ncols = ax_bottom.shape subplots_height = fig.subplotpars.top - fig.subplotpars.bottom if nrows > 1: h_overlap_inches = ax_top[1:] - ax_bottom[:-1] hspace_inches = h_overlap_inches.max() + h_pad_inches hspace_fig_frac = hspace_inches / figbox.height hspace = _fig_frac_to_cell_frac(hspace_fig_frac, subplots_height, nrows) fig.subplots_adjust(hspace=hspace) subplots_width = fig.subplotpars.right - fig.subplotpars.left if ncols > 1: w_overlap_inches = ax_right[:,:-1] - ax_left[:,1:] wspace_inches = w_overlap_inches.max() + w_pad_inches wspace_fig_frac = wspace_inches / figbox.width wspace = _fig_frac_to_cell_frac(wspace_fig_frac, subplots_width, ncols) fig.subplots_adjust(wspace=wspace) def _get_grid_boundaries(fig): """Return grid boundaries for bboxes of subplots Returns --- ax_bottom, ax_top, ax_left, ax_right : array bbox cell-boundaries of subplot grid. If a subplot spans cells, the grid boundaries cutting through that subplot will be masked. """ nrows, ncols, n = fig.axes[0].get_geometry() # Initialize boundaries as masked arrays; in the future, support subplots # that span
Re: [Matplotlib-users] Hints on sizing plot elements?
On Aug 12, 2010, at 7:37 AM, Tony S Yu wrote: On Aug 12, 2010, at 1:08 AM, Russell E. Owen wrote: I'm making a strip chart widget (which I plan to make publicly available when finished). The basics are working fine, but the automatic sizing is not doing so well. Strip charts are typically short, and when suitably short the X axis annotations are partially truncated. So...can I convince the automatic sizer to always show the full X (time) axis annotations and put all the variable sizing into the data area? Or do I have to manually set them somehow? As far as I know, there's nothing to automatically resize the padding around the the axes. (The manual way to do it is to call `fig.subplots_adjust`). I wrote a helper script (attached below) to adjust the layout so that there's a specified amount of padding around the axes. Unfortunately, this resizer doesn't function correctly when using the GTK backend. It apparently works fine with TkAgg, MacOSX, and Qt4Agg backends. Fortunately I'm using TkAgg. I'm sorry (though not surprised) I'll have to size it manually (especially since users of my application can change the font size), but I very much appreciate the code. Also, is there a way from my software (not a .matplotlibrc file) to globally make the default background color white for axis annotation areas? Right now the background is gray for annotations and while for plot area and I'd prefer it was all white. Just set plt.rc('figure', facecolor='w') in your code (assuming you've imported matplotlib.pyplot as plt). Perfect. Thanks! Usage note: Since it sounds like you're not creating subplots, you can just use the `tight_borders` function, instead of the `tight_layout` function; the later requires two redraws while the first requires only one. Thank you very much for the advice and script! I do plan to support strip charts stacked atop each other (all using the same time range, with tick labels only along the bottom x axis), which I suspect will need subplots (unless there is now a better way) but so far all I have is multiple lines (including dynamic and static -- e.g. to display limits) one one plot. -- Russell -- This SF.net email is sponsored by Make an app they can't live without Enter the BlackBerry Developer Challenge http://p.sf.net/sfu/RIM-dev2dev ___ Matplotlib-users mailing list Matplotlib-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-users
Re: [Matplotlib-users] Hints on sizing plot elements?
On Thu, Aug 12, 2010 at 2:08 PM, Russell E. Owen wrote: > So...can I convince the automatic sizer to always show the full X (time) > axis annotations and put all the variable sizing into the data area? Or > do I have to manually set them somehow? > Another option you may try is to use axes_grid1 toolkit. Attached is a simplified version of the script I have been using. matplotlib v1.0 is required. IHTH, -JJ import matplotlib.pyplot as plt from mpl_toolkits.axes_grid1 import SubplotDivider import mpl_toolkits.axes_grid1.axes_size as axes_size class SizeFromFunc(axes_size._Base): def __init__(self, func): self._func = func def get_size(self, renderer): rel_size = 0. bb = self._func(renderer) dpi = renderer.points_to_pixels(72.) abs_size = bb/dpi return rel_size, abs_size class GetExtentHelper(object): def __init__(self, ax): self._ax = ax def __call__(self, renderer): # return width of ticklabels on the left side of axes return self._ax.yaxis.get_ticklabel_extents(renderer)[0].width fig = plt.figure() ax = fig.add_subplot(111) ax.set_yticks([0.5]) ax.set_yticklabels(["very long label"]) helper = GetExtentHelper(ax) divider = SubplotDivider(fig, 1, 1, 1, horizontal=[SizeFromFunc(helper), axes_size.Scaled(1.)], vertical=[axes_size.Scaled(1.)], aspect=False) ax.set_axes_locator(divider.new_locator(nx=1, ny=0)) plt.show() -- This SF.net email is sponsored by Make an app they can't live without Enter the BlackBerry Developer Challenge http://p.sf.net/sfu/RIM-dev2dev ___ Matplotlib-users mailing list Matplotlib-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-users