tight_bbox.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. """
  2. This module is to support *bbox_inches* option in savefig command.
  3. """
  4. from matplotlib.transforms import Bbox, TransformedBbox, Affine2D
  5. def adjust_bbox(fig, bbox_inches, fixed_dpi=None):
  6. """
  7. Temporarily adjust the figure so that only the specified area
  8. (bbox_inches) is saved.
  9. It modifies fig.bbox, fig.bbox_inches,
  10. fig.transFigure._boxout, and fig.patch. While the figure size
  11. changes, the scale of the original figure is conserved. A
  12. function which restores the original values are returned.
  13. """
  14. origBbox = fig.bbox
  15. origBboxInches = fig.bbox_inches
  16. orig_tight_layout = fig.get_tight_layout()
  17. _boxout = fig.transFigure._boxout
  18. fig.set_tight_layout(False)
  19. asp_list = []
  20. locator_list = []
  21. for ax in fig.axes:
  22. pos = ax.get_position(original=False).frozen()
  23. locator_list.append(ax.get_axes_locator())
  24. asp_list.append(ax.get_aspect())
  25. def _l(a, r, pos=pos):
  26. return pos
  27. ax.set_axes_locator(_l)
  28. ax.set_aspect("auto")
  29. def restore_bbox():
  30. for ax, asp, loc in zip(fig.axes, asp_list, locator_list):
  31. ax.set_aspect(asp)
  32. ax.set_axes_locator(loc)
  33. fig.bbox = origBbox
  34. fig.bbox_inches = origBboxInches
  35. fig.set_tight_layout(orig_tight_layout)
  36. fig.transFigure._boxout = _boxout
  37. fig.transFigure.invalidate()
  38. fig.patch.set_bounds(0, 0, 1, 1)
  39. if fixed_dpi is not None:
  40. tr = Affine2D().scale(fixed_dpi)
  41. dpi_scale = fixed_dpi / fig.dpi
  42. else:
  43. tr = Affine2D().scale(fig.dpi)
  44. dpi_scale = 1.
  45. _bbox = TransformedBbox(bbox_inches, tr)
  46. fig.bbox_inches = Bbox.from_bounds(0, 0,
  47. bbox_inches.width, bbox_inches.height)
  48. x0, y0 = _bbox.x0, _bbox.y0
  49. w1, h1 = fig.bbox.width * dpi_scale, fig.bbox.height * dpi_scale
  50. fig.transFigure._boxout = Bbox.from_bounds(-x0, -y0, w1, h1)
  51. fig.transFigure.invalidate()
  52. fig.bbox = TransformedBbox(fig.bbox_inches, tr)
  53. fig.patch.set_bounds(x0 / w1, y0 / h1,
  54. fig.bbox.width / w1, fig.bbox.height / h1)
  55. return restore_bbox
  56. def process_figure_for_rasterizing(fig, bbox_inches_restore, fixed_dpi=None):
  57. """
  58. This need to be called when figure dpi changes during the drawing
  59. (e.g., rasterizing). It recovers the bbox and re-adjust it with
  60. the new dpi.
  61. """
  62. bbox_inches, restore_bbox = bbox_inches_restore
  63. restore_bbox()
  64. r = adjust_bbox(fig, bbox_inches, fixed_dpi)
  65. return bbox_inches, r