Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit186df24

Browse files
committed
ENH: add new layout engine for tight_layout and constrained_layout
1 parentd001ed1 commit186df24

File tree

9 files changed

+261
-132
lines changed

9 files changed

+261
-132
lines changed

‎lib/matplotlib/_constrained_layout.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
frommatplotlibimport_api
2121
importmatplotlib.transformsasmtransforms
2222
importmatplotlib._layoutgridaslayoutgrid
23-
23+
frommatplotlib.backend_basesimport_get_renderer
2424

2525
_log=logging.getLogger(__name__)
2626

@@ -62,7 +62,7 @@
6262

6363

6464
######################################################
65-
defdo_constrained_layout(fig,renderer,h_pad,w_pad,
65+
defdo_constrained_layout(fig,h_pad,w_pad,
6666
hspace=None,wspace=None):
6767
"""
6868
Do the constrained_layout. Called at draw time in
@@ -92,6 +92,7 @@ def do_constrained_layout(fig, renderer, h_pad, w_pad,
9292
layoutgrid: useful for debugging.
9393
"""
9494

95+
renderer=_get_renderer(fig)
9596
# make layoutgrid tree...
9697
_layoutgrids=_make_layoutgrids(fig,None)
9798
ifnot_layoutgrids['hasgrids']:

‎lib/matplotlib/_layoutgrid.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,7 @@ def plot_children(fig, lg=None, level=0, printit=False):
513513
importmatplotlib.patchesasmpatches
514514

515515
iflgisNone:
516-
_layoutgrids=fig.execute_constrained_layout()
516+
_layoutgrids=fig.layout_engine.execute()
517517
lg=_layoutgrids[fig]
518518
colors=plt.rcParams["axes.prop_cycle"].by_key()["color"]
519519
col=colors[level]

‎lib/matplotlib/backend_bases.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2259,7 +2259,7 @@ def print_figure(
22592259
ifbbox_inchesisNone:
22602260
bbox_inches=rcParams['savefig.bbox']
22612261

2262-
if (self.figure.get_constrained_layout()or
2262+
if (self.figure.layout_engineisnotNoneor
22632263
bbox_inches=="tight"):
22642264
# we need to trigger a draw before printing to make sure
22652265
# CL works. "tight" also needs a draw to get the right
@@ -2288,8 +2288,8 @@ def print_figure(
22882288
else:
22892289
_bbox_inches_restore=None
22902290

2291-
# we have alreadydone CL above, so turn it off:
2292-
stack.enter_context(self.figure._cm_set(constrained_layout=False))
2291+
# we have alreadylayout above, so turn it off:
2292+
stack.enter_context(self.figure._cm_set(layout_engine=None))
22932293
try:
22942294
# _get_renderer may change the figure dpi (as vector formats
22952295
# force the figure dpi to 72), so we need to set it again here.

‎lib/matplotlib/figure.py

Lines changed: 91 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
frommatplotlib.textimportText
4040
frommatplotlib.transformsimport (Affine2D,Bbox,BboxTransformTo,
4141
TransformedBbox)
42+
frommatplotlib.layout_engineimport (constrained_layout_engine,
43+
tight_layout_engine,LayoutEngine)
4244

4345
_log=logging.getLogger(__name__)
4446

@@ -1144,12 +1146,15 @@ def colorbar(self, mappable, cax=None, ax=None, use_gridspec=True, **kw):
11441146
"silence this warning, explicitly pass the 'ax' argument "
11451147
"to colorbar().")
11461148

1149+
ifuse_gridspec:
1150+
if (self.layout_engineisnotNoneand
1151+
notself.layout_engine.colorbar_gridspec):
1152+
use_gridspec=False
11471153
# Store the value of gca so that we can set it back later on.
11481154
ifcaxisNone:
11491155
current_ax=self.gca()
11501156
kw['userax']=False
1151-
if (use_gridspecandisinstance(ax,SubplotBase)
1152-
andnotself.get_constrained_layout()):
1157+
if (use_gridspecandisinstance(ax,SubplotBase)):
11531158
cax,kw=cbar.make_axes_gridspec(ax,**kw)
11541159
else:
11551160
cax,kw=cbar.make_axes(ax,**kw)
@@ -1197,12 +1202,13 @@ def subplots_adjust(self, left=None, bottom=None, right=None, top=None,
11971202
The height of the padding between subplots,
11981203
as a fraction of the average Axes height.
11991204
"""
1200-
ifself.get_constrained_layout():
1201-
self.set_constrained_layout(False)
1205+
if(self.layout_engineand
1206+
notself.layout_engine.adjust_compatible):
12021207
_api.warn_external(
1203-
"This figure was usingconstrained_layout, but that is "
1208+
"This figure was usinga layout engine that is "
12041209
"incompatible with subplots_adjust and/or tight_layout; "
1205-
"disabling constrained_layout.")
1210+
"not calling subplots_adjust")
1211+
return
12061212
self.subplotpars.update(left,bottom,right,top,wspace,hspace)
12071213
foraxinself.axes:
12081214
ifisinstance(ax,SubplotBase):
@@ -2207,6 +2213,7 @@ def __init__(self,
22072213
"""
22082214
super().__init__()
22092215

2216+
self.layout_engine=None
22102217
iflayoutisnotNone:
22112218
iftight_layoutisnotNone:
22122219
_api.warn_external(
@@ -2216,14 +2223,15 @@ def __init__(self,
22162223
_api.warn_external(
22172224
"The Figure parameters 'layout' and 'constrained_layout' "
22182225
"cannot be used together. Please use 'layout' only.")
2219-
iflayout=='constrained':
2220-
tight_layout=False
2221-
constrained_layout=True
2222-
eliflayout=='tight':
2223-
tight_layout=True
2224-
constrained_layout=False
2225-
else:
2226-
raiseValueError(f"Invalid value for 'layout':{layout!r}")
2226+
self.set_layout_engine(layout)
2227+
eliftight_layoutisnotNone:
2228+
self.set_layout_engine(layout='tight')
2229+
ifisinstance(tight_layout,dict):
2230+
self.get_layout_engine().set_info(tight_layout)
2231+
elifconstrained_layoutisnotNone:
2232+
self.set_layout_engine(layout='constrained')
2233+
ifisinstance(constrained_layout,dict):
2234+
self.get_layout_engine().set_info(constrained_layout)
22272235

22282236
self.callbacks=cbook.CallbackRegistry()
22292237
# Callbacks traditionally associated with the canvas (and exposed with
@@ -2274,20 +2282,37 @@ def __init__(self,
22742282

22752283
self.subplotpars=subplotpars
22762284

2277-
# constrained_layout:
2278-
self._constrained=False
2279-
2280-
self.set_tight_layout(tight_layout)
2281-
22822285
self._axstack=_AxesStack()# track all figure axes and current axes
22832286
self.clf()
22842287
self._cachedRenderer=None
22852288

2286-
self.set_constrained_layout(constrained_layout)
2287-
22882289
# list of child gridspecs for this figure
22892290
self._gridspecs= []
22902291

2292+
defset_layout_engine(self,layout=None,**kwargs):
2293+
"""
2294+
Set the layout engine... FIXME
2295+
"""
2296+
iflayoutisNone:
2297+
ifmpl.rcParams['figure.autolayout']:
2298+
layout='tight'
2299+
elifmpl.rcParams['figure.constrained_layout.use']:
2300+
layout='constrained'
2301+
else:
2302+
self.layout_engine=None
2303+
return
2304+
iflayout=='tight':
2305+
self.layout_engine=tight_layout_engine(self,**kwargs)
2306+
eliflayout=='constrained':
2307+
self.layout_engine=constrained_layout_engine(self,**kwargs)
2308+
elifisinstance(layout,LayoutEngine):
2309+
self.layout_engine=layout
2310+
else:
2311+
raiseValueError(f"Invalid value for 'layout':{layout!r}")
2312+
2313+
defget_layout_engine(self):
2314+
returnself.layout_engine
2315+
22912316
# TODO: I'd like to dynamically add the _repr_html_ method
22922317
# to the figure in the right context, but then IPython doesn't
22932318
# use it, for some reason.
@@ -2377,8 +2402,10 @@ def _set_dpi(self, dpi, forward=True):
23772402

23782403
defget_tight_layout(self):
23792404
"""Return whether `.tight_layout` is called when drawing."""
2380-
returnself._tight
2405+
returnisinstance(self.layout_engine,tight_layout_engine)
23812406

2407+
@_api.deprecated(
2408+
"3.5",alternative="set_layout_engine")
23822409
defset_tight_layout(self,tight):
23832410
"""
23842411
Set whether and how `.tight_layout` is called when drawing.
@@ -2393,8 +2420,9 @@ def set_tight_layout(self, tight):
23932420
"""
23942421
iftightisNone:
23952422
tight=mpl.rcParams['figure.autolayout']
2396-
self._tight=bool(tight)
2397-
self._tight_parameters=tightifisinstance(tight,dict)else {}
2423+
_tight_parameters=tightifisinstance(tight,dict)else {}
2424+
ifbool(tight):
2425+
self.layout_engine=tight_layout_engine(self,_tight_parameters)
23982426
self.stale=True
23992427

24002428
defget_constrained_layout(self):
@@ -2403,8 +2431,10 @@ def get_constrained_layout(self):
24032431
24042432
See :doc:`/tutorials/intermediate/constrainedlayout_guide`.
24052433
"""
2406-
returnself._constrained
2434+
returnisinstance(self.layout_engine,constrained_layout_engine)
24072435

2436+
@_api.deprecated(
2437+
"3.5",alternative="set_layout_engine('constrained')")
24082438
defset_constrained_layout(self,constrained):
24092439
"""
24102440
Set whether ``constrained_layout`` is used upon drawing. If None,
@@ -2421,20 +2451,16 @@ def set_constrained_layout(self, constrained):
24212451
----------
24222452
constrained : bool or dict or None
24232453
"""
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
24292454
ifconstrainedisNone:
24302455
constrained=mpl.rcParams['figure.constrained_layout.use']
2431-
self._constrained=bool(constrained)
2432-
ifisinstance(constrained,dict):
2433-
self.set_constrained_layout_pads(**constrained)
2434-
else:
2435-
self.set_constrained_layout_pads()
2456+
_constrained=bool(constrained)
2457+
_parameters=constrainedifisinstance(constrained,dict)else {}
2458+
if_constrained:
2459+
self.layout_engine=constrained_layout_engine(self,_parameters)
24362460
self.stale=True
24372461

2462+
@_api.deprecated(
2463+
"3.5",alternative="figure.layout_engine.set_info()")
24382464
defset_constrained_layout_pads(self,**kwargs):
24392465
"""
24402466
Set padding for ``constrained_layout``. Note the kwargs can be passed
@@ -2461,18 +2487,15 @@ def set_constrained_layout_pads(self, **kwargs):
24612487
subplot width. The total padding ends up being h_pad + hspace.
24622488
24632489
"""
2490+
ifisinstance(self.layout_engine,constrained_layout_engine):
2491+
self.layout_engine.set_info(**kwargs)
24642492

2465-
todo= ['w_pad','h_pad','wspace','hspace']
2466-
fortdintodo:
2467-
iftdinkwargsandkwargs[td]isnotNone:
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()")
24732495
defget_constrained_layout_pads(self,relative=False):
24742496
"""
2475-
Get padding for ``constrained_layout``.
2497+
Get padding for ``constrained_layout`` if it is the
2498+
``layout_engine``.
24762499
24772500
Returns a list of ``w_pad, h_pad`` in inches and
24782501
``wspace`` and ``hspace`` as fractions of the subplot.
@@ -2484,10 +2507,14 @@ def get_constrained_layout_pads(self, relative=False):
24842507
relative : bool
24852508
If `True`, then convert from inches to figure relative.
24862509
"""
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+
ifnotisinstance(self.layout_engine,constrained_layout_engine):
2512+
returnNone,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']
24912518

24922519
ifrelativeand (w_padisnotNoneorh_padisnotNone):
24932520
renderer=_get_renderer(self)
@@ -2765,14 +2792,12 @@ def draw(self, renderer):
27652792

27662793
try:
27672794
renderer.open_group('figure',gid=self.get_gid())
2768-
ifself.get_constrained_layout()andself.axes:
2769-
self.execute_constrained_layout(renderer)
2770-
ifself.get_tight_layout()andself.axes:
2795+
ifself.axesandself.layout_engineisnotNone:
27712796
try:
2772-
self.tight_layout(**self._tight_parameters)
2797+
pass
2798+
self.layout_engine.execute()
27732799
exceptValueError:
27742800
pass
2775-
# ValueError can occur when resizing a window.
27762801

27772802
self.patch.draw(renderer)
27782803
mimage._draw_list_compositing_images(
@@ -3102,6 +3127,8 @@ def handler(ev):
31023127

31033128
returnNoneifeventisNoneelseevent.name=="key_press_event"
31043129

3130+
@_api.deprecated(
3131+
"3.5",alternative="figure.layout_engine.execute()")
31053132
defexecute_constrained_layout(self,renderer=None):
31063133
"""
31073134
Use ``layoutgrid`` to determine pos positions within Axes.
@@ -3112,22 +3139,12 @@ def execute_constrained_layout(self, renderer=None):
31123139
-------
31133140
layoutgrid : private debugging object
31143141
"""
3142+
ifnotisinstance(self.layout_engine,constrained_layout_engine):
3143+
returnNone
31153144

3116-
frommatplotlib._constrained_layoutimportdo_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-
ifrendererisNone:
3126-
renderer=_get_renderer(fig)
3127-
returndo_constrained_layout(fig,renderer,h_pad,w_pad,
3128-
hspace,wspace)
3145+
returnself.layout_engine.execute()
31293146

3130-
deftight_layout(self,*,pad=1.08,h_pad=None,w_pad=None,rect=None):
3147+
deftight_layout(self,**kwargs):
31313148
"""
31323149
Adjust the padding between and around subplots.
31333150
@@ -3149,25 +3166,20 @@ def tight_layout(self, *, pad=1.08, h_pad=None, w_pad=None, rect=None):
31493166
31503167
See Also
31513168
--------
3152-
.Figure.set_tight_layout
3169+
.Figure.set_layout_engine
31533170
.pyplot.tight_layout
31543171
"""
3155-
fromcontextlibimportnullcontext
3156-
from .tight_layoutimport (
3157-
get_subplotspec_list,get_tight_layout_figure)
3172+
from .tight_layoutimportget_subplotspec_list
3173+
31583174
subplotspec_list=get_subplotspec_list(self.axes)
31593175
ifNoneinsubplotspec_list:
31603176
_api.warn_external("This figure includes Axes that are not "
31613177
"compatible with tight_layout, so results "
31623178
"might be incorrect.")
3163-
renderer=_get_renderer(self)
3164-
withgetattr(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-
ifkwargs:
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()
31713183

31723184
deffigaspect(arg):
31733185
"""

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp