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 multiple rows/columns, which would have masked values for grid # boundaries that cut through the subplot. ax_bottom, ax_top, ax_left, ax_right = [np.ma.masked_all((nrows, ncols)) for n in range(4)] renderer = fig.canvas.get_renderer() px2inches_trans = Affine2D().scale(1./fig.dpi) for ax in fig.axes: ax_bbox = ax.get_tightbbox(renderer) x0, y0, x1, y1 = TransformedBbox(ax_bbox, px2inches_trans).extents nrows, ncols, n = ax.get_geometry() # subplot number starts at 1, matrix index starts at 0 i = n - 1 ax_bottom.flat[i] = y0 ax_top.flat[i] = y1 ax_left.flat[i] = x0 ax_right.flat[i] = x1 return ax_bottom, ax_top, ax_left, ax_right def _fig_frac_to_cell_frac(fig_frac, subplots_frac, num_cells): """Return fraction of cell (row/column) from a given fraction of the figure Parameters ---------- fig_frac : float length given as a fraction of figure height or width subplots_frac : float fraction of figure (height or width) occupied by subplots num_cells : int number of rows or columns. """ # This function is reverse engineered from the calculation of `sepH` and # `sepW` in `GridSpecBase.get_grid_positions`. return (fig_frac * num_cells) / (subplots_frac - fig_frac*(num_cells-1)) if __name__ == '__main__': import random fontsizes = [8, 16, 24, 32] def example_plot(ax): ax.plot([1, 2]) ax.set_xlabel('x-label', fontsize=random.choice(fontsizes)) ax.set_ylabel('y-label', fontsize=random.choice(fontsizes)) ax.set_title('Title', fontsize=random.choice(fontsizes)) fig, ax = plt.subplots() example_plot(ax) tight_layout() fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2) example_plot(ax1) example_plot(ax2) example_plot(ax3) example_plot(ax4) tight_layout() fig, (ax1, ax2) = plt.subplots(nrows=2, ncols=1) example_plot(ax1) example_plot(ax2) tight_layout() fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2) example_plot(ax1) example_plot(ax2) tight_layout() fig, axes = plt.subplots(nrows=3, ncols=3) for row in axes: for ax in row: example_plot(ax) tight_layout() plt.show()
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.
------------------------------------------------------------------------------ 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