| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -20,7 +20,7 @@ | |||
| 20 | 20 | from matplotlib import _api | |
| 21 | 21 | import matplotlib.transforms as mtransforms | |
| 22 | 22 | import matplotlib._layoutgrid as layoutgrid | |
| 23 | - | ||
| 23 | + from matplotlib.backend_bases import _get_renderer | ||
| 24 | 24 | ||
| 25 | 25 | _log = logging.getLogger(__name__) | |
| 26 | 26 | ||
@@ -62,7 +62,7 @@ | |||
| 62 | 62 | ||
| 63 | 63 | ||
| 64 | 64 | ###################################################### | |
| 65 | - def do_constrained_layout(fig, renderer, h_pad, w_pad, | ||
| 65 | + def do_constrained_layout(fig, h_pad, w_pad, | ||
| 66 | 66 | hspace=None, wspace=None): | |
| 67 | 67 | """ | |
| 68 | 68 | Do the constrained_layout. Called at draw time in | |
@@ -92,6 +92,7 @@ def do_constrained_layout(fig, renderer, h_pad, w_pad, | |||
| 92 | 92 | layoutgrid: useful for debugging. | |
| 93 | 93 | """ | |
| 94 | 94 | ||
| 95 | + renderer = _get_renderer(fig) | ||
| 95 | 96 | # make layoutgrid tree... | |
| 96 | 97 | _layoutgrids = _make_layoutgrids(fig, None) | |
| 97 | 98 | if not _layoutgrids['hasgrids']: | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -513,7 +513,7 @@ def plot_children(fig, lg=None, level=0, printit=False): | |||
| 513 | 513 | import matplotlib.patches as mpatches | |
| 514 | 514 | ||
| 515 | 515 | if lg is None: | |
| 516 | - _layoutgrids = fig.execute_constrained_layout() | ||
| 516 | + _layoutgrids = fig.layout_engine.execute() | ||
| 517 | 517 | lg = _layoutgrids[fig] | |
| 518 | 518 | colors = plt.rcParams["axes.prop_cycle"].by_key()["color"] | |
| 519 | 519 | col = colors[level] | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2259,7 +2259,7 @@ def print_figure( | |||
| 2259 | 2259 | if bbox_inches is None: | |
| 2260 | 2260 | bbox_inches = rcParams['savefig.bbox'] | |
| 2261 | 2261 | ||
| 2262 | - if (self.figure.get_constrained_layout() or | ||
| 2262 | + if (self.figure.layout_engine is not None or | ||
| 2263 | 2263 | bbox_inches == "tight"): | |
| 2264 | 2264 | # we need to trigger a draw before printing to make sure | |
| 2265 | 2265 | # CL works. "tight" also needs a draw to get the right | |
@@ -2288,8 +2288,8 @@ def print_figure( | |||
| 2288 | 2288 | else: | |
| 2289 | 2289 | _bbox_inches_restore = None | |
| 2290 | 2290 | ||
| 2291 | - # we have already done CL above, so turn it off: | ||
| 2292 | - stack.enter_context(self.figure._cm_set(constrained_layout=False)) | ||
| 2291 | + # we have already layout above, so turn it off: | ||
| 2292 | + stack.enter_context(self.figure._cm_set(layout_engine=None)) | ||
| 2293 | 2293 | try: | |
| 2294 | 2294 | # _get_renderer may change the figure dpi (as vector formats | |
| 2295 | 2295 | # force the figure dpi to 72), so we need to set it again here. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -39,6 +39,8 @@ | |||
| 39 | 39 | from matplotlib.text import Text | |
| 40 | 40 | from matplotlib.transforms import (Affine2D, Bbox, BboxTransformTo, | |
| 41 | 41 | TransformedBbox) | |
| 42 | + from matplotlib.layout_engine import (constrained_layout_engine, | ||
| 43 | + tight_layout_engine, LayoutEngine) | ||
| 42 | 44 | ||
| 43 | 45 | _log = logging.getLogger(__name__) | |
| 44 | 46 | ||
@@ -1144,12 +1146,15 @@ def colorbar(self, mappable, cax=None, ax=None, use_gridspec=True, **kw): | |||
| 1144 | 1146 | "silence this warning, explicitly pass the 'ax' argument " | |
| 1145 | 1147 | "to colorbar().") | |
| 1146 | 1148 | ||
| 1149 | + if use_gridspec: | ||
| 1150 | + if (self.layout_engine is not None and | ||
| 1151 | + not self.layout_engine.colorbar_gridspec): | ||
| 1152 | + use_gridspec = False | ||
| 1147 | 1153 | # Store the value of gca so that we can set it back later on. | |
| 1148 | 1154 | if cax is None: | |
| 1149 | 1155 | current_ax = self.gca() | |
| 1150 | 1156 | kw['userax'] = False | |
| 1151 | - if (use_gridspec and isinstance(ax, SubplotBase) | ||
| 1152 | - and not self.get_constrained_layout()): | ||
| 1157 | + if (use_gridspec and isinstance(ax, SubplotBase)): | ||
| 1153 | 1158 | cax, kw = cbar.make_axes_gridspec(ax, **kw) | |
| 1154 | 1159 | else: | |
| 1155 | 1160 | cax, kw = cbar.make_axes(ax, **kw) | |
@@ -1197,12 +1202,13 @@ def subplots_adjust(self, left=None, bottom=None, right=None, top=None, | |||
| 1197 | 1202 | The height of the padding between subplots, | |
| 1198 | 1203 | as a fraction of the average Axes height. | |
| 1199 | 1204 | """ | |
| 1200 | - if self.get_constrained_layout(): | ||
| 1201 | - self.set_constrained_layout(False) | ||
| 1205 | + if (self.layout_engine and | ||
| 1206 | + not self.layout_engine.adjust_compatible): | ||
| 1202 | 1207 | _api.warn_external( | |
| 1203 | - "This figure was using constrained_layout, but that is " | ||
| 1208 | + "This figure was using a layout engine that is " | ||
| 1204 | 1209 | "incompatible with subplots_adjust and/or tight_layout; " | |
| 1205 | - "disabling constrained_layout.") | ||
| 1210 | + "not calling subplots_adjust") | ||
| 1211 | + return | ||
| 1206 | 1212 | self.subplotpars.update(left, bottom, right, top, wspace, hspace) | |
| 1207 | 1213 | for ax in self.axes: | |
| 1208 | 1214 | if isinstance(ax, SubplotBase): | |
@@ -2207,6 +2213,7 @@ def __init__(self, | |||
| 2207 | 2213 | """ | |
| 2208 | 2214 | super().__init__() | |
| 2209 | 2215 | ||
| 2216 | + self.layout_engine = None | ||
| 2210 | 2217 | if layout is not None: | |
| 2211 | 2218 | if tight_layout is not None: | |
| 2212 | 2219 | _api.warn_external( | |
@@ -2216,14 +2223,15 @@ def __init__(self, | |||
| 2216 | 2223 | _api.warn_external( | |
| 2217 | 2224 | "The Figure parameters 'layout' and 'constrained_layout' " | |
| 2218 | 2225 | "cannot be used together. Please use 'layout' only.") | |
| 2219 | - if layout == 'constrained': | ||
| 2220 | - tight_layout = False | ||
| 2221 | - constrained_layout = True | ||
| 2222 | - elif layout == 'tight': | ||
| 2223 | - tight_layout = True | ||
| 2224 | - constrained_layout = False | ||
| 2225 | - else: | ||
| 2226 | - raise ValueError(f"Invalid value for 'layout': {layout!r}") | ||
| 2226 | + self.set_layout_engine(layout) | ||
| 2227 | + elif tight_layout is not None: | ||
| 2228 | + self.set_layout_engine(layout='tight') | ||
| 2229 | + if isinstance(tight_layout, dict): | ||
| 2230 | + self.get_layout_engine().set_info(tight_layout) | ||
| 2231 | + elif constrained_layout is not None: | ||
| 2232 | + self.set_layout_engine(layout='constrained') | ||
| 2233 | + if isinstance(constrained_layout, dict): | ||
| 2234 | + self.get_layout_engine().set_info(constrained_layout) | ||
| 2227 | 2235 | ||
| 2228 | 2236 | self.callbacks = cbook.CallbackRegistry() | |
| 2229 | 2237 | # Callbacks traditionally associated with the canvas (and exposed with | |
@@ -2274,20 +2282,37 @@ def __init__(self, | |||
| 2274 | 2282 | ||
| 2275 | 2283 | self.subplotpars = subplotpars | |
| 2276 | 2284 | ||
| 2277 | - # constrained_layout: | ||
| 2278 | - self._constrained = False | ||
| 2279 | - | ||
| 2280 | - self.set_tight_layout(tight_layout) | ||
| 2281 | - | ||
| 2282 | 2285 | self._axstack = _AxesStack() # track all figure axes and current axes | |
| 2283 | 2286 | self.clf() | |
| 2284 | 2287 | self._cachedRenderer = None | |
| 2285 | 2288 | ||
| 2286 | - self.set_constrained_layout(constrained_layout) | ||
| 2287 | - | ||
| 2288 | 2289 | # list of child gridspecs for this figure | |
| 2289 | 2290 | self._gridspecs = [] | |
| 2290 | 2291 | ||
| 2292 | + def set_layout_engine(self, layout=None, **kwargs): | ||
| 2293 | + """ | ||
| 2294 | + Set the layout engine... FIXME | ||
| 2295 | + """ | ||
| 2296 | + if layout is None: | ||
| 2297 | + if mpl.rcParams['figure.autolayout']: | ||
| 2298 | + layout = 'tight' | ||
| 2299 | + elif mpl.rcParams['figure.constrained_layout.use']: | ||
| 2300 | + layout = 'constrained' | ||
| 2301 | + else: | ||
| 2302 | + self.layout_engine = None | ||
| 2303 | + return | ||
| 2304 | + if layout == 'tight': | ||
| 2305 | + self.layout_engine = tight_layout_engine(self, **kwargs) | ||
| 2306 | + elif layout == 'constrained': | ||
| 2307 | + self.layout_engine = constrained_layout_engine(self, **kwargs) | ||
| 2308 | + elif isinstance(layout, LayoutEngine): | ||
| 2309 | + self.layout_engine = layout | ||
| 2310 | + else: | ||
| 2311 | + raise ValueError(f"Invalid value for 'layout': {layout!r}") | ||
| 2312 | + | ||
| 2313 | + def get_layout_engine(self): | ||
| 2314 | + return self.layout_engine | ||
| 2315 | + | ||
| 2291 | 2316 | # TODO: I'd like to dynamically add the _repr_html_ method | |
| 2292 | 2317 | # to the figure in the right context, but then IPython doesn't | |
| 2293 | 2318 | # use it, for some reason. | |
@@ -2377,8 +2402,10 @@ def _set_dpi(self, dpi, forward=True): | |||
| 2377 | 2402 | ||
| 2378 | 2403 | def get_tight_layout(self): | |
| 2379 | 2404 | """Return whether `.tight_layout` is called when drawing.""" | |
| 2380 | - return self._tight | ||
| 2405 | + return isinstance(self.layout_engine, tight_layout_engine) | ||
| 2381 | 2406 | ||
| 2407 | + @_api.deprecated( | ||
| 2408 | + "3.5", alternative="set_layout_engine") | ||
| 2382 | 2409 | def set_tight_layout(self, tight): | |
| 2383 | 2410 | """ | |
| 2384 | 2411 | Set whether and how `.tight_layout` is called when drawing. | |
@@ -2393,8 +2420,9 @@ def set_tight_layout(self, tight): | |||
| 2393 | 2420 | """ | |
| 2394 | 2421 | if tight is None: | |
| 2395 | 2422 | tight = mpl.rcParams['figure.autolayout'] | |
| 2396 | - self._tight = bool(tight) | ||
| 2397 | - self._tight_parameters = tight if isinstance(tight, dict) else {} | ||
| 2423 | + _tight_parameters = tight if isinstance(tight, dict) else {} | ||
| 2424 | + if bool(tight): | ||
| 2425 | + self.layout_engine = tight_layout_engine(self, _tight_parameters) | ||
| 2398 | 2426 | self.stale = True | |
| 2399 | 2427 | ||
| 2400 | 2428 | def get_constrained_layout(self): | |
@@ -2403,8 +2431,10 @@ def get_constrained_layout(self): | |||
| 2403 | 2431 | ||
| 2404 | 2432 | See :doc:`/tutorials/intermediate/constrainedlayout_guide`. | |
| 2405 | 2433 | """ | |
| 2406 | - return self._constrained | ||
| 2434 | + return isinstance(self.layout_engine, constrained_layout_engine) | ||
| 2407 | 2435 | ||
| 2436 | + @_api.deprecated( | ||
| 2437 | + "3.5", alternative="set_layout_engine('constrained')") | ||
| 2408 | 2438 | def set_constrained_layout(self, constrained): | |
| 2409 | 2439 | """ | |
| 2410 | 2440 | Set whether ``constrained_layout`` is used upon drawing. If None, | |
@@ -2421,20 +2451,16 @@ def set_constrained_layout(self, constrained): | |||
| 2421 | 2451 | ---------- | |
| 2422 | 2452 | constrained : bool or dict or None | |
| 2423 | 2453 | """ | |
| 2424 | - self._constrained_layout_pads = dict() | ||
| 2425 | - self._constrained_layout_pads['w_pad'] = None | ||
| 2426 | - self._constrained_layout_pads['h_pad'] = None | ||
| 2427 | - self._constrained_layout_pads['wspace'] = None | ||
| 2428 | - self._constrained_layout_pads['hspace'] = None | ||
| 2429 | 2454 | if constrained is None: | |
| 2430 | 2455 | constrained = mpl.rcParams['figure.constrained_layout.use'] | |
| 2431 | - self._constrained = bool(constrained) | ||
| 2432 | - if isinstance(constrained, dict): | ||
| 2433 | - self.set_constrained_layout_pads(**constrained) | ||
| 2434 | - else: | ||
| 2435 | - self.set_constrained_layout_pads() | ||
| 2456 | + _constrained = bool(constrained) | ||
| 2457 | + _parameters = constrained if isinstance(constrained, dict) else {} | ||
| 2458 | + if _constrained: | ||
| 2459 | + self.layout_engine = constrained_layout_engine(self, _parameters) | ||
| 2436 | 2460 | self.stale = True | |
| 2437 | 2461 | ||
| 2462 | + @_api.deprecated( | ||
| 2463 | + "3.5", alternative="figure.layout_engine.set_info()") | ||
| 2438 | 2464 | def set_constrained_layout_pads(self, **kwargs): | |
| 2439 | 2465 | """ | |
| 2440 | 2466 | Set padding for ``constrained_layout``. Note the kwargs can be passed | |
@@ -2461,18 +2487,15 @@ def set_constrained_layout_pads(self, **kwargs): | |||
| 2461 | 2487 | subplot width. The total padding ends up being h_pad + hspace. | |
| 2462 | 2488 | ||
| 2463 | 2489 | """ | |
| 2490 | + if isinstance(self.layout_engine, constrained_layout_engine): | ||
| 2491 | + self.layout_engine.set_info(**kwargs) | ||
| 2464 | 2492 | ||
| 2465 | - todo = ['w_pad', 'h_pad', 'wspace', 'hspace'] | ||
| 2466 | - for td in todo: | ||
| 2467 | - if td in kwargs and kwargs[td] is not None: | ||
| 2468 | - self._constrained_layout_pads[td] = kwargs[td] | ||
| 2469 | - else: | ||
| 2470 | - self._constrained_layout_pads[td] = ( | ||
| 2471 | - mpl.rcParams['figure.constrained_layout.' + td]) | ||
| 2472 | - | ||
| 2493 | + @_api.deprecated( | ||
| 2494 | + "3.5", alternative="fig.layout_engine.get_info()") | ||
| 2473 | 2495 | def get_constrained_layout_pads(self, relative=False): | |
| 2474 | 2496 | """ | |
| 2475 | - Get padding for ``constrained_layout``. | ||
| 2497 | + Get padding for ``constrained_layout`` if it is the | ||
| 2498 | + ``layout_engine``. | ||
| 2476 | 2499 | ||
| 2477 | 2500 | Returns a list of ``w_pad, h_pad`` in inches and | |
| 2478 | 2501 | ``wspace`` and ``hspace`` as fractions of the subplot. | |
@@ -2484,10 +2507,14 @@ def get_constrained_layout_pads(self, relative=False): | |||
| 2484 | 2507 | relative : bool | |
| 2485 | 2508 | If `True`, then convert from inches to figure relative. | |
| 2486 | 2509 | """ | |
| 2487 | - w_pad = self._constrained_layout_pads['w_pad'] | ||
| 2488 | - h_pad = self._constrained_layout_pads['h_pad'] | ||
| 2489 | - wspace = self._constrained_layout_pads['wspace'] | ||
| 2490 | - hspace = self._constrained_layout_pads['hspace'] | ||
| 2510 | + | ||
| 2511 | + if not isinstance(self.layout_engine, constrained_layout_engine): | ||
| 2512 | + return None, None, None, None | ||
| 2513 | + info = self.layout_engine.get_info() | ||
| 2514 | + w_pad = info['w_pad'] | ||
| 2515 | + h_pad = info['h_pad'] | ||
| 2516 | + wspace = info['wspace'] | ||
| 2517 | + hspace = info['hspace'] | ||
| 2491 | 2518 | ||
| 2492 | 2519 | if relative and (w_pad is not None or h_pad is not None): | |
| 2493 | 2520 | renderer = _get_renderer(self) | |
@@ -2765,14 +2792,12 @@ def draw(self, renderer): | |||
| 2765 | 2792 | ||
| 2766 | 2793 | try: | |
| 2767 | 2794 | renderer.open_group('figure', gid=self.get_gid()) | |
| 2768 | - if self.get_constrained_layout() and self.axes: | ||
| 2769 | - self.execute_constrained_layout(renderer) | ||
| 2770 | - if self.get_tight_layout() and self.axes: | ||
| 2795 | + if self.axes and self.layout_engine is not None: | ||
| 2771 | 2796 | try: | |
| 2772 | - self.tight_layout(**self._tight_parameters) | ||
| 2797 | + pass | ||
| 2798 | + self.layout_engine.execute() | ||
| 2773 | 2799 | except ValueError: | |
| 2774 | 2800 | pass | |
| 2775 | - # ValueError can occur when resizing a window. | ||
| 2776 | 2801 | ||
| 2777 | 2802 | self.patch.draw(renderer) | |
| 2778 | 2803 | mimage._draw_list_compositing_images( | |
@@ -3102,6 +3127,8 @@ def handler(ev): | |||
| 3102 | 3127 | ||
| 3103 | 3128 | return None if event is None else event.name == "key_press_event" | |
| 3104 | 3129 | ||
| 3130 | + @_api.deprecated( | ||
| 3131 | + "3.5", alternative="figure.layout_engine.execute()") | ||
| 3105 | 3132 | def execute_constrained_layout(self, renderer=None): | |
| 3106 | 3133 | """ | |
| 3107 | 3134 | Use ``layoutgrid`` to determine pos positions within Axes. | |
@@ -3112,22 +3139,12 @@ def execute_constrained_layout(self, renderer=None): | |||
| 3112 | 3139 | ------- | |
| 3113 | 3140 | layoutgrid : private debugging object | |
| 3114 | 3141 | """ | |
| 3142 | + if not isinstance(self.layout_engine, constrained_layout_engine): | ||
| 3143 | + return None | ||
| 3115 | 3144 | ||
| 3116 | - from matplotlib._constrained_layout import do_constrained_layout | ||
| 3117 | - | ||
| 3118 | - _log.debug('Executing constrainedlayout') | ||
| 3119 | - w_pad, h_pad, wspace, hspace = self.get_constrained_layout_pads() | ||
| 3120 | - # convert to unit-relative lengths | ||
| 3121 | - fig = self | ||
| 3122 | - width, height = fig.get_size_inches() | ||
| 3123 | - w_pad = w_pad / width | ||
| 3124 | - h_pad = h_pad / height | ||
| 3125 | - if renderer is None: | ||
| 3126 | - renderer = _get_renderer(fig) | ||
| 3127 | - return do_constrained_layout(fig, renderer, h_pad, w_pad, | ||
| 3128 | - hspace, wspace) | ||
| 3145 | + return self.layout_engine.execute() | ||
| 3129 | 3146 | ||
| 3130 | - def tight_layout(self, *, pad=1.08, h_pad=None, w_pad=None, rect=None): | ||
| 3147 | + def tight_layout(self, **kwargs): | ||
| 3131 | 3148 | """ | |
| 3132 | 3149 | Adjust the padding between and around subplots. | |
| 3133 | 3150 | ||
@@ -3149,25 +3166,20 @@ def tight_layout(self, *, pad=1.08, h_pad=None, w_pad=None, rect=None): | |||
| 3149 | 3166 | ||
| 3150 | 3167 | See Also | |
| 3151 | 3168 | -------- | |
| 3152 | - .Figure.set_tight_layout | ||
| 3169 | + .Figure.set_layout_engine | ||
| 3153 | 3170 | .pyplot.tight_layout | |
| 3154 | 3171 | """ | |
| 3155 | - from contextlib import nullcontext | ||
| 3156 | - from .tight_layout import ( | ||
| 3157 | - get_subplotspec_list, get_tight_layout_figure) | ||
| 3172 | + from .tight_layout import get_subplotspec_list | ||
| 3173 | + | ||
| 3158 | 3174 | subplotspec_list = get_subplotspec_list(self.axes) | |
| 3159 | 3175 | if None in subplotspec_list: | |
| 3160 | 3176 | _api.warn_external("This figure includes Axes that are not " | |
| 3161 | 3177 | "compatible with tight_layout, so results " | |
| 3162 | 3178 | "might be incorrect.") | |
| 3163 | - renderer = _get_renderer(self) | ||
| 3164 | - with getattr(renderer, "_draw_disabled", nullcontext)(): | ||
| 3165 | - kwargs = get_tight_layout_figure( | ||
| 3166 | - self, self.axes, subplotspec_list, renderer, | ||
| 3167 | - pad=pad, h_pad=h_pad, w_pad=w_pad, rect=rect) | ||
| 3168 | - if kwargs: | ||
| 3169 | - self.subplots_adjust(**kwargs) | ||
| 3170 | - | ||
| 3179 | + # note that here we do not _set_ the figures engine to tight_layout | ||
| 3180 | + # but rather just perform the layout in place for back compatibility. | ||
| 3181 | + engine = tight_layout_engine(fig=self, **kwargs) | ||
| 3182 | + engine.execute() | ||
| 3171 | 3183 | ||
| 3172 | 3184 | def figaspect(arg): | |
| 3173 | 3185 | """ | |
| Back | FazBrowse Home | New Git URL |
0 commit comments