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

Commit957a5a1

Browse files
committed
Force clipped-log for hist/errorbar/fill_between.
1 parenta5c0164 commit957a5a1

File tree

5 files changed

+66
-5
lines changed

5 files changed

+66
-5
lines changed

‎lib/matplotlib/artist.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
importsix
55

66
fromcollectionsimportOrderedDict,namedtuple
7+
importcontextlib
78
fromfunctoolsimportwraps
89
importinspect
910
importre
@@ -120,6 +121,22 @@ def __init__(self):
120121
self._path_effects=rcParams['path.effects']
121122
self._sticky_edges=_XYPair([], [])
122123

124+
# When plotting in log-scale, force the use of clip mode instead of
125+
# mask. The typical (internal) use case is log-scaled bar plots and
126+
# error bars. Ideally we'd want BarContainers / ErrorbarContainers
127+
# to have their own show() method which takes care of the patching,
128+
# but right now Containers are not taken into account during
129+
# the draw; instead their components (in the case of bar plots,
130+
# these are Rectangle patches; in the case of ErrorbarContainers,
131+
# LineCollections) are drawn individually, so tracking the force_clip
132+
# state must be done by the component artists. Note that handling of
133+
# _force_clip_in_log_scale must be done by the individual artists'
134+
# draw implementation; right now only Patches and Collections support
135+
# it. The `_forcing_clip_in_log_scale` decorator may be helpful to
136+
# implement such support, it should typically be applied around a call
137+
# to `transform_path_non_affine`.
138+
self._force_clip_in_log_scale=False
139+
123140
def__getstate__(self):
124141
d=self.__dict__.copy()
125142
# remove the unpicklable remove method, this will get re-added on load
@@ -779,6 +796,21 @@ def draw(self, renderer, *args, **kwargs):
779796
return
780797
self.stale=False
781798

799+
@contextlib.contextmanager
800+
def_forcing_clip_in_log_scale(self):
801+
# See _force_clip_in_log_scale for explanation.
802+
fvs= {}
803+
ifself._force_clip_in_log_scaleandself.axes:
804+
foraxisinself.axes._get_axis_list():
805+
ifaxis.get_scale()=="log":
806+
fvs[axis]=axis._scale._transform._fill_value
807+
axis._scale._transform._fill_value=1e-300
808+
try:
809+
yield
810+
finally:
811+
foraxis,fvinfvs.items():
812+
axis._scale._transform._fill_value=fv
813+
782814
defset_alpha(self,alpha):
783815
"""
784816
Set the alpha value used for blending - not supported on

‎lib/matplotlib/axes/_axes.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2158,6 +2158,7 @@ def bar(self, *args, **kwargs):
21582158
r.sticky_edges.y.append(b)
21592159
eliforientation=='horizontal':
21602160
r.sticky_edges.x.append(l)
2161+
r._force_clip_in_log_scale=True
21612162
self.add_patch(r)
21622163
patches.append(r)
21632164

@@ -3053,7 +3054,9 @@ def extract_err(err, data):
30533054
ifxlolims.any():
30543055
yo,_=xywhere(y,right,xlolims&everymask)
30553056
lo,ro=xywhere(x,right,xlolims&everymask)
3056-
barcols.append(self.hlines(yo,lo,ro,**eb_lines_style))
3057+
ebs=self.hlines(yo,lo,ro,**eb_lines_style)
3058+
ebs._force_clip_in_log_scale=True
3059+
barcols.append(ebs)
30573060
rightup,yup=xywhere(right,y,xlolims&everymask)
30583061
ifself.xaxis_inverted():
30593062
marker=mlines.CARETLEFTBASE
@@ -3092,7 +3095,9 @@ def extract_err(err, data):
30923095
ifnoylims.any():
30933096
xo,_=xywhere(x,lower,noylims&everymask)
30943097
lo,uo=xywhere(lower,upper,noylims&everymask)
3095-
barcols.append(self.vlines(xo,lo,uo,**eb_lines_style))
3098+
ebs=self.vlines(xo,lo,uo,**eb_lines_style)
3099+
ebs._force_clip_in_log_scale=True
3100+
barcols.append(ebs)
30963101
ifcapsize>0:
30973102
caplines.append(mlines.Line2D(xo,lo,marker='_',
30983103
**eb_cap_style))
@@ -4905,6 +4910,7 @@ def get_interp_point(ind):
49054910
polys.append(X)
49064911

49074912
collection=mcoll.PolyCollection(polys,**kwargs)
4913+
collection._force_clip_in_log_scale=True
49084914

49094915
# now update the datalim and autoscale
49104916
XY1=np.array([x[where],y1[where]]).T
@@ -5057,6 +5063,7 @@ def get_interp_point(ind):
50575063
polys.append(Y)
50585064

50595065
collection=mcoll.PolyCollection(polys,**kwargs)
5066+
collection._force_clip_in_log_scale=True
50605067

50615068
# now update the datalim and autoscale
50625069
X1Y=np.array([x1[where],y[where]]).T

‎lib/matplotlib/collections.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,8 +232,9 @@ def _prepare_points(self):
232232
offsets=np.column_stack([xs,ys])
233233

234234
ifnottransform.is_affine:
235-
paths= [transform.transform_path_non_affine(path)
236-
forpathinpaths]
235+
withself._forcing_clip_in_log_scale():
236+
paths= [transform.transform_path_non_affine(path)
237+
forpathinpaths]
237238
transform=transform.get_affine()
238239
ifnottransOffset.is_affine:
239240
offsets=transOffset.transform_non_affine(offsets)

‎lib/matplotlib/patches.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,10 @@ def draw(self, renderer):
564564

565565
path=self.get_path()
566566
transform=self.get_transform()
567-
tpath=transform.transform_path_non_affine(path)
567+
568+
withself._forcing_clip_in_log_scale():
569+
tpath=transform.transform_path_non_affine(path)
570+
568571
affine=transform.get_affine()
569572

570573
ifself.get_path_effects():

‎lib/matplotlib/tests/test_axes.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5412,3 +5412,21 @@ def test_patch_deprecations():
54125412
assertfig.patch==fig.figurePatch
54135413

54145414
assertlen(w)==2
5415+
5416+
5417+
@pytest.mark.parametrize("plotter",
5418+
[lambdaax:ax.bar([0,1], [1,2]),
5419+
lambdaax:ax.errorbar([0,1], [2,2], [1,3]),
5420+
lambdaax:ax.fill_between([0,1], [1,2], [1,0])])
5421+
deftest_clipped_log_zero(plotter):
5422+
fig,ax=plt.subplots()
5423+
plotter(ax)
5424+
ax.set_yscale("log")
5425+
png1=io.BytesIO()
5426+
fig.savefig(png1,format="png")
5427+
fig,ax=plt.subplots()
5428+
plotter(ax)
5429+
ax.set_yscale("log",nonposy="clip")
5430+
png2=io.BytesIO()
5431+
fig.savefig(png2,format="png")
5432+
assertpng1.getvalue()==png2.getvalue()

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp