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

Commitb8840cf

Browse files
committed
BUGFIX: use true bbox for rasters in backend_mixed
1 parent52e04f5 commitb8840cf

File tree

8 files changed

+123
-18
lines changed

8 files changed

+123
-18
lines changed

‎lib/matplotlib/backends/backend_cairo.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ def draw_markers(self, gc, marker_path, marker_trans, path, transform,
217217
self._fill_and_stroke(
218218
ctx,rgbFace,gc.get_alpha(),gc.get_forced_alpha())
219219

220-
defdraw_image(self,gc,x,y,im):
220+
defdraw_image(self,gc,x,y,im,bbox=None):
221221
im=cbook._unmultiplied_rgba8888_to_premultiplied_argb32(im[::-1])
222222
surface=cairo.ImageSurface.create_for_data(
223223
im.ravel().data,cairo.FORMAT_ARGB32,

‎lib/matplotlib/backends/backend_mixed.py

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
frommatplotlib.backends.backend_aggimportRendererAgg
44
frommatplotlib.tight_bboximportprocess_figure_for_rasterizing
5+
frommatplotlib.transformsimportBbox,Affine2D,IdentityTransform
56

67

78
classMixedModeRenderer:
@@ -73,6 +74,56 @@ def __getattr__(self, attr):
7374
# to the underlying C implementation).
7475
returngetattr(self._renderer,attr)
7576

77+
# need to wrap each drawing function that might be called on the rasterized
78+
# version of the renderer to save what the "true" bbox is for scaling the
79+
# output correctly
80+
# the functions we might want to overwrite are:
81+
# `draw_path`, `draw_image`, `draw_gouraud_triangle`, `draw_text`,
82+
# `draw_markers`, `draw_path_collection`, `draw_quad_mesh`
83+
84+
def_update_true_bbox(self,bbox,transform=None):
85+
"""Convert to real units and update"""
86+
iftransformisNone:
87+
transform=IdentityTransform()
88+
bbox=bbox.transformed(transform+Affine2D().scale(
89+
self._figdpi/self.dpi))
90+
ifself._true_bboxisNone:
91+
self._true_bbox=bbox
92+
else:
93+
self._true_bbox=Bbox.union([self._true_bbox,bbox])
94+
95+
defdraw_path_collection(self,gc,master_transform,paths,all_transforms,
96+
offsets,offsetTrans,facecolors,edgecolors,
97+
linewidths,linestyles,antialiaseds,urls,
98+
offset_position):
99+
ifself._rasterizing>0:
100+
bbox=Bbox.null()
101+
#TODO probably faster to merge all coordinates from path using
102+
# numpy for large lists of paths, such as the one produced by the
103+
# test case tests/test_backed_pgf.py:test_mixed_mode
104+
forpathinpaths:
105+
bbox.update_from_path(path,ignore=False)
106+
self._update_true_bbox(bbox,master_transform)
107+
returnself._renderer.draw_path_collection(
108+
gc,master_transform,paths,all_transforms,offsets,
109+
offsetTrans,facecolors,edgecolors,linewidths,linestyles,
110+
antialiaseds,urls,offset_position)
111+
112+
defdraw_quad_mesh(self,gc,master_transform,meshWidth,meshHeight,
113+
coordinates,offsets,offsetTrans,facecolors,
114+
antialiased,edgecolors):
115+
ifself._rasterizing>0:
116+
#TODO should check if this is always Bbox.unit for efficiency
117+
bbox=Bbox.null()
118+
cshape=coordinates.shape
119+
flat_coords=coordinates.reshape((cshape[0]*cshape[1],cshape[2]))
120+
bbox.update_from_data_xy(flat_coords,ignore=True)
121+
self._update_true_bbox(bbox,master_transform)
122+
123+
returnself._renderer.draw_quad_mesh(
124+
gc,master_transform,meshWidth,meshHeight,coordinates,
125+
offsets,offsetTrans,facecolors,antialiased,edgecolors)
126+
76127
defstart_rasterizing(self):
77128
"""
78129
Enter "raster" mode. All subsequent drawing commands (until
@@ -88,6 +139,7 @@ def start_rasterizing(self):
88139
self._raster_renderer=self._raster_renderer_class(
89140
self._width*self.dpi,self._height*self.dpi,self.dpi)
90141
self._renderer=self._raster_renderer
142+
self._true_bbox=None
91143
self._rasterizing+=1
92144

93145
defstop_rasterizing(self):
@@ -105,21 +157,36 @@ def stop_rasterizing(self):
105157
self._renderer=self._vector_renderer
106158

107159
height=self._height*self.dpi
160+
# these bounds are in pixels, relative to the figure when pixelated
161+
# at the requested DPI. However, the vectorized backends draw at a
162+
# fixed DPI of 72, and typically aren't snapped to the
163+
# requested-DPI pixel grid, so we have to grab the actual bounds to
164+
# put the image into some other way
108165
buffer,bounds=self._raster_renderer.tostring_rgba_minimized()
109166
l,b,w,h=bounds
110167
ifw>0andh>0:
168+
ifself._true_bboxisNone:
169+
raiseNotImplementedError(
170+
"Something was drawn using a method not wrapped by "
171+
"MixedModeRenderer.")
111172
image=np.frombuffer(buffer,dtype=np.uint8)
112173
image=image.reshape((h,w,4))
113174
image=image[::-1]
175+
114176
gc=self._renderer.new_gc()
115177
# TODO: If the mixedmode resolution differs from the figure's
116178
# dpi, the image must be scaled (dpi->_figdpi). Not all
117179
# backends support this.
180+
# because rasterizing will have rounded size to nearest
181+
# pixel, we need to rescale our drawing to fit the original
182+
# intended Bbox. This results in a slightly different DPI than
183+
# requested, but that's better than the drawing not fitting
184+
# into the space requested, see Issue #6827
118185
self._renderer.draw_image(
119186
gc,
120-
l*self._figdpi/self.dpi,
121-
(height-b-h)*self._figdpi/self.dpi,
122-
image)
187+
self._true_bbox.x0,
188+
self._true_bbox.y0,
189+
image,bbox=self._true_bbox)
123190
self._raster_renderer=None
124191
self._rasterizing=False
125192

‎lib/matplotlib/backends/backend_pdf.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1735,21 +1735,26 @@ def merge_used_characters(self, *args, **kwargs):
17351735
defget_image_magnification(self):
17361736
returnself.image_dpi/72.0
17371737

1738-
defdraw_image(self,gc,x,y,im,transform=None):
1738+
defdraw_image(self,gc,x,y,im,transform=None,bbox=None):
17391739
# docstring inherited
17401740

17411741
h,w=im.shape[:2]
17421742
ifw==0orh==0:
17431743
return
17441744

1745+
ifbboxisnotNone:
1746+
h=bbox.height
1747+
w=bbox.width
1748+
17451749
iftransformisNone:
17461750
# If there's no transform, alpha has already been applied
17471751
gc.set_alpha(1.0)
17481752

17491753
self.check_gc(gc)
17501754

1751-
w=72.0*w/self.image_dpi
1752-
h=72.0*h/self.image_dpi
1755+
ifbboxisNone:
1756+
w=72.0*w/self.image_dpi
1757+
h=72.0*h/self.image_dpi
17531758

17541759
imob=self.file.imageObject(im)
17551760

‎lib/matplotlib/backends/backend_pgf.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -639,13 +639,17 @@ def option_image_nocomposite(self):
639639
# docstring inherited
640640
returnnotmpl.rcParams['image.composite_image']
641641

642-
defdraw_image(self,gc,x,y,im,transform=None):
642+
defdraw_image(self,gc,x,y,im,transform=None,bbox=None):
643643
# docstring inherited
644644

645645
h,w=im.shape[:2]
646646
ifw==0orh==0:
647647
return
648648

649+
ifbboxisnotNone:
650+
h=bbox.height
651+
w=bbox.width
652+
649653
ifnotos.path.exists(getattr(self.fh,"name","")):
650654
cbook._warn_external(
651655
"streamed pgf-code does not support raster graphics, consider "

‎lib/matplotlib/backends/backend_ps.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -280,10 +280,15 @@ def get_image_magnification(self):
280280
"""
281281
returnself.image_magnification
282282

283-
defdraw_image(self,gc,x,y,im,transform=None):
283+
defdraw_image(self,gc,x,y,im,transform=None,bbox=None):
284284
# docstring inherited
285285

286286
h,w=im.shape[:2]
287+
ifh==0orw==0:
288+
return
289+
ifbboxisnotNone:
290+
h=bbox.height
291+
w=bbox.width
287292
imagecmd="false 3 colorimage"
288293
data=im[::-1, :, :3]# Vertically flipped rgb values.
289294
# data.tobytes().hex() has no spaces, so can be linewrapped by relying
@@ -292,8 +297,9 @@ def draw_image(self, gc, x, y, im, transform=None):
292297

293298
iftransformisNone:
294299
matrix="1 0 0 1 0 0"
295-
xscale=w/self.image_magnification
296-
yscale=h/self.image_magnification
300+
ifbboxisNone:
301+
xscale=w/self.image_magnification
302+
yscale=h/self.image_magnification
297303
else:
298304
matrix=" ".join(map(str,transform.frozen().to_values()))
299305
xscale=1.0

‎lib/matplotlib/backends/backend_svg.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -807,7 +807,7 @@ def option_scale_image(self):
807807
defget_image_magnification(self):
808808
returnself.image_dpi/72.0
809809

810-
defdraw_image(self,gc,x,y,im,transform=None):
810+
defdraw_image(self,gc,x,y,im,transform=None,bbox=None):
811811
# docstring inherited
812812

813813
h,w=im.shape[:2]
@@ -851,12 +851,27 @@ def draw_image(self, gc, x, y, im, transform=None):
851851
w=72.0*w/self.image_dpi
852852
h=72.0*h/self.image_dpi
853853

854+
ifbboxisnotNone:
855+
# because rasterization happens only for integer pixels, the
856+
# round-trip width w = # int(width/72*image_dpi)*72/image_dpi
857+
# need not match the "real" width
858+
scale_x=bbox.width/w
859+
scale_y=bbox.height/h
860+
real_h=bbox.height
861+
else:
862+
scale_x=1
863+
scale_y=1
864+
real_h=h
865+
854866
self.writer.element(
855867
'image',
856868
transform=generate_transform([
857-
('scale', (1,-1)), ('translate', (0,-h))]),
869+
('translate', (x*(1-scale_x),
870+
y*(1-scale_y)+real_h)),
871+
('scale', (scale_x,-scale_y))
872+
]),
858873
x=short_float_fmt(x),
859-
y=short_float_fmt(-(self.height-y-h)),
874+
y=short_float_fmt(-(self.height-y-real_h)),
860875
width=short_float_fmt(w),height=short_float_fmt(h),
861876
attrib=attrib)
862877
else:

‎lib/matplotlib/backends/backend_wx.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,9 @@ def draw_path(self, gc, path, transform, rgbFace=None):
227227
gfx_ctx.StrokePath(wxpath)
228228
gc.unselect()
229229

230-
defdraw_image(self,gc,x,y,im):
231-
bbox=gc.get_clip_rectangle()
230+
defdraw_image(self,gc,x,y,im,bbox=None):
231+
ifbboxisNone:
232+
bbox=gc.get_clip_rectangle()
232233
ifbboxisnotNone:
233234
l,b,w,h=bbox.bounds
234235
else:

‎lib/matplotlib/image.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,11 @@ def flush_images():
144144
gc=renderer.new_gc()
145145
gc.set_clip_rectangle(parent.bbox)
146146
gc.set_clip_path(parent.get_clip_path())
147-
renderer.draw_image(gc,round(l),round(b),data)
147+
iftype(renderer)==mpl.backends.backend_agg.RendererAgg:
148+
renderer.draw_image(gc,l,b,im)
149+
else:
150+
renderer.draw_image(gc,round(l),round(b),data,
151+
bbox=parent.bbox)
148152
gc.restore()
149153
delimage_group[:]
150154

@@ -620,7 +624,10 @@ def draw(self, renderer, *args, **kwargs):
620624
im,l,b,trans=self.make_image(
621625
renderer,renderer.get_image_magnification())
622626
ifimisnotNone:
623-
renderer.draw_image(gc,l,b,im)
627+
iftype(renderer)==mpl.backends.backend_agg.RendererAgg:
628+
renderer.draw_image(gc,l,b,im)
629+
else:
630+
renderer.draw_image(gc,l,b,im,bbox=self.get_clip_box())
624631
gc.restore()
625632
self.stale=False
626633

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp