10000 Merge pull request #18302 from QuLogic/3d-renderer-attrib · matplotlib/matplotlib@22c6cce · GitHub
[go: up one dir, main page]

Skip to content

Commit 22c6cce

Browse files
authored
Merge pull request #18302 from QuLogic/3d-renderer-attrib
Remove 3D attributes from renderer
2 parents 433b05c + a769837 commit 22c6cce

File tree

4 files changed

+119
-63
lines changed

4 files changed

+119
-63
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
3D properties on renderers
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
4+
The properties of the 3D Axes that were placed on the Renderer during draw are
5+
now deprecated:
6+
7+
* ``renderer.M``
8+
* ``renderer.eye``
9+
* ``renderer.vvec``
10+
* ``renderer.get_axis_position``
11+
12+
These attributes are all available via `.Axes3D`, which can be accessed via
13+
``self.axes`` on all `.Artist`\s.
14+
15+
``renderer`` argument of ``do_3d_projection`` method for ``Collection3D``/``Patch3D``
16+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17+
18+
The ``renderer`` argument for the ``do_3d_projection`` method on
19+
``Collection3D`` and ``Patch3D`` is no longer necessary, and passing it during
20+
draw is deprecated.

lib/mpl_toolkits/mplot3d/art3d.py

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,7 @@ def set_3d_properties(self, z=0, zdir='z'):
135135
def draw(self, renderer):
136136
position3d = np.array((self._x, self._y, self._z))
137137
proj = proj3d.proj_trans_points(
138-
[position3d, position3d + self._dir_vec],
139-
renderer.M)
138+
[position3d, position3d + self._dir_vec], self.axes.M)
140139
dx = proj[0][1] - proj[0][0]
141140
dy = proj[1][1] - proj[1][0]
142141
angle = math.degrees(math.atan2(dy, dx))
@@ -213,7 +212,7 @@ def get_data_3d(self):
213212
@artist.allow_rasterization
214213
def draw(self, renderer):
215214
xs3d, ys3d, zs3d = self._verts3d
216-
xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, renderer.M)
215+
xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, self.axes.M)
217216
self.set_data(xs, ys)
218217
super().draw(renderer)
219218
self.stale = False
@@ -297,13 +296,13 @@ def set_segments(self, segments):
297296
self._segments3d = segments
298297
super().set_segments([])
299298

300-
def do_3d_projection(self, renderer):
299+
@cbook._delete_parameter('3.4', 'renderer')
300+
def do_3d_projection(self, renderer=None):
301301
"""
302302
Project the points according to renderer matrix.
303303
"""
304-
xyslist = [
305-
proj3d.proj_trans_points(points, renderer.M) for points in
306-
self._segments3d]
304+
xyslist = [proj3d.proj_trans_points(points, self.axes.M)
305+
for points in self._segments3d]
307306
segments_2d = [np.column_stack([xs, ys]) for xs, ys, zs in xyslist]
308307
LineCollection.set_segments(self, segments_2d)
309308

@@ -316,7 +315,7 @@ def do_3d_projection(self, renderer):
316315
@artist.allow_rasterization
317316
def draw(self, renderer, project=False):
318317
if project:
319-
self.do_3d_projection(renderer)
318+
self.do_3d_projection()
320319
super().draw(renderer)
321320

322321

@@ -348,10 +347,12 @@ def get_path(self):
348347
def get_facecolor(self):
349348
return self._facecolor2d
350349

351-
def do_3d_projection(self, renderer):
350+
@cbook._delete_parameter('3.4', 'renderer')
351+
def do_3d_projection(self, renderer=None):
352352
s = self._segment3d
353353
xs, ys, zs = zip(*s)
354-
vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs, renderer.M)
354+
vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs,
355+
self.axes.M)
355356
self._path2d = mpath.Path(np.column_stack([vxs, vys]))
356357
# FIXME: coloring
357358
self._facecolor2d = self._facecolor3d
@@ -372,10 +373,12 @@ def set_3d_properties(self, path, zs=0, zdir='z'):
372373
Patch3D.set_3d_properties(self, path.vertices, zs=zs, zdir=zdir)
373374
self._code3d = path.codes
374375

375-
def do_3d_projection(self, renderer):
376+
@cbook._delete_parameter('3.4', 'renderer')
377+
def do_3d_projection(self, renderer=None):
376378
s = self._segment3d
377379
xs, ys, zs = zip(*s)
378-
vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs, renderer.M)
380+
vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs,
381+
self.axes.M)
379382
self._path2d = mpath.Path(np.column_stack([vxs, vys]), self._code3d)
380383
# FIXME: coloring
381384
self._facecolor2d = self._facecolor3d
@@ -481,9 +484,11 @@ def set_3d_properties(self, zs, zdir):
481484
self._edgecolor3d = self.get_edgecolor()
482485
self.stale = True
483486

484-
def do_3d_projection(self, renderer):
487+
@cbook._delete_parameter('3.4', 'renderer')
488+
def do_3d_projection(self, renderer=None):
485489
xs, ys, zs = self._offsets3d
486-
vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs, renderer.M)
490+
vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs,
491+
self.axes.M)
487492

488493
fcs = (_zalpha(self._facecolor3d, vzs) if self._depthshade else
489494
self._facecolor3d)
@@ -585,9 +590,11 @@ def set_linewidth(self, lw):
585590
super().set_linewidth(lw)
586591
self._linewidth3d = self.get_linewidth()
587592

588-
def do_3d_projection(self, renderer):
593+
@cbook._delete_parameter('3.4', 'renderer')
594+
def do_3d_projection(self, renderer=None):
589595
xs, ys, zs = self._offsets3d
590-
vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs, renderer.M)
596+
vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs,
597+
self.axes.M)
591598

592599
fcs = (_zalpha(self._facecolor3d, vzs) if self._depthshade else
593600
self._facecolor3d)
@@ -760,7 +767,8 @@ def set_sort_zpos(self, val):
760767
self._sort_zpos = val
761768
self.stale = True
762769

763-
def do_3d_projection(self, renderer):
770+
@cbook._delete_parameter('3.4', 'renderer')
771+
def do_3d_projection(self, renderer=None):
764772
"""
765773
Perform the 3D projection for this object.
766774
"""
@@ -769,7 +777,7 @@ def do_3d_projection(self, renderer):
769777
self.update_scalarmappable()
770778
self._facecolors3d = self._facecolors
771779

772-
txs, tys, tzs = proj3d._proj_transform_vec(self._vec, renderer.M)
780+
txs, tys, tzs = proj3d._proj_transform_vec(self._vec, self.axes.M)
773781
xyzlist = [(txs[sl], tys[sl], tzs[sl]) for sl in self._segslices]
774782

775783
# This extra fuss is to re-order face / edge colors
@@ -805,7 +813,7 @@ def do_3d_projection(self, renderer):
805813
# Return zorder value
806814
if self._sort_zpos is not None:
807815
zvec = np.array([[0], [0], [self._sort_zpos], [1]])
808-
ztrans = proj3d._proj_transform_vec(zvec, renderer.M)
816+
ztrans = proj3d._proj_transform_vec(zvec, self.axes.M)
809817
return ztrans[2][0]
810818
elif tzs.size > 0:
811819
# FIXME: Some results still don't look quite right.
@@ -892,13 +900,6 @@ def rotate_axes(xs, ys, zs, zdir):
892900
return xs, ys, zs
893901

894902

895-
def _get_colors(c, num):
896-
"""Stretch the color argument to provide the required number *num*."""
897-
return np.broadcast_to(
898-
mcolors.to_rgba_array(c) if len(c) else [0, 0, 0, 0],
899-
(num, 4))
900-
901-
902903
def _zalpha(colors, zs):
903904
"""Modify the alphas of the color list according to depth."""
904905
# FIXME: This only works well if the points for *zs* are well-spaced

lib/mpl_toolkits/mplot3d/axes3d.py

Lines changed: 64 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -399,36 +399,71 @@ def draw(self, renderer):
399399

400400
# add the projection matrix to the renderer
401401
self.M = self.get_proj()
402-
renderer.M = self.M
403-
renderer.vvec = self.vvec
404-
renderer.eye = self.eye
405-
renderer.get_axis_position = self.get_axis_position
406-
407-
# Calculate projection of collections and patches and zorder them.
408-
# Make sure they are drawn above the grids.
409-
zorder_offset = max(axis.get_zorder()
410-
for axis in self._get_axis_list()) + 1
411-
for i, col in enumerate(
412-
sorted(self.collections,
413-
key=lambda col: col.do_3d_projection(renderer),
414-
reverse=True)):
415-
col.zorder = zorder_offset + i
416-
for i, patch in enumerate(
417-
sorted(self.patches,
418-
key=lambda patch: patch.do_3d_projection(renderer),
419-
reverse=True)):
420-
patch.zorder = zorder_offset + i
421-
422-
if self._axis3don:
423-
# Draw panes first
424-
for axis in self._get_axis_list():
425-
axis.draw_pane(renderer)
426-
# Then axes
427-
for axis in self._get_axis_list():
428-
axis.draw(renderer)
402+
props3d = {
403+
# To raise a deprecation, we need to wrap the attribute in a
404+
# function, but binding that to an instance does not work, 8912 as you
405+
# would end up with an instance-specific method. Properties are
406+
# class-level attributes which *are* functions, so we do that
407+
# instead.
408+
# This dictionary comprehension creates deprecated properties for
409+
# the attributes listed below, and they are temporarily attached to
410+
# the _class_ in the `_setattr_cm` call. These can both be removed
411+
# once the deprecation expires
412+
name: cbook.deprecated('3.4', name=name,
413+
alternative=f'self.axes.{name}')(
414+
property(lambda self, _value=getattr(self, name): _value))
415+
for name in ['M', 'vvec', 'eye', 'get_axis_position']
416+
}
429417

430-
# Then rest
431-
super().draw(renderer)
418+
with cbook._setattr_cm(type(renderer), **props3d):
419+
def do_3d_projection(artist):
420+
"""
421+
Call `do_3d_projection` on an *artist*, and warn if passing
422+
*renderer*.
423+
424+
For our Artists, never pass *renderer*. For external Artists,
425+
in lieu of more complicated signature parsing, always pass
426+
*renderer* and raise a warning.
427+
"""
428+
429+
if artist.__module__ == 'mpl_toolkits.mplot3d.art3d':
430+
# Our 3D Artists have deprecated the renderer parameter, so
431+
# avoid passing it to them; call this directly once the
432+
# deprecation has expired.
433+
return artist.do_3d_projection()
434+
435+
cbook.warn_deprecated(
436+
"3.4",
437+
message="The 'renderer' parameter of "
438+
"do_3d_projection() was deprecated in Matplotlib "
439+
"%(since)s and will be removed %(removal)s.")
440+
return artist.do_3d_projection(renderer)
441+
442+
# Calculate projection of collections and patches and zorder them.
443+
# Make sure they are drawn above the grids.
444+
zorder_offset = max(axis.get_zorder()
445+
for axis in self._get_axis_list()) + 1
446+
for i, col in enumerate(
447+
sorted(self.collections,
448+
key=do_3d_projection,
449+
reverse=True)):
450+
col.zorder = zorder_offset + i
451+
for i, patch in enumerate(
452+
sorted(self.patches,
453+
key=do_3d_projection,
454+
reverse=True)):
455+
patch.zorder = zorder_offset + i
456+
457+
if self._axis3don:
458+
# Draw panes first
459+
for axis in self._get_axis_list():
460+
axis.draw_pane(renderer)
461+
# Then axes
462+
for axis in self._get_axis_list():
463+
axis.draw(renderer)
464+
465+
# Then rest
466+
super().draw(renderer)
432467

433468
def get_axis_position(self):
434469
vals = self.get_w_lims()

lib/mpl_toolkits/mplot3d/axis3d.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ def _get_coord_info(self, renderer):
189189
maxs = maxs + deltas / 4.
190190

191191
vals = mins[0], maxs[0], mins[1], maxs[1], mins[2], maxs[2]
192-
tc = self.axes.tunit_cube(vals, renderer.M)
192+
tc = self.axes.tunit_cube(vals, self.axes.M)
193193
avgz = [tc[p1][2] + tc[p2][2] + tc[p3][2] + tc[p4][2]
194194
for p1, p2, p3, p4 in self._PLANES]
195195
highs = np.array([avgz[2*i] < avgz[2*i+1] for i in range(3)])
@@ -237,8 +237,8 @@ def draw(self, renderer):
237237
edgep2 = edgep1.copy()
238238
edgep2[juggled[1]] = maxmin[juggled[1]]
239239
pep = np.asarray(
240-
proj3d.proj_trans_points([edgep1, edgep2], renderer.M))
241-
centpt = proj3d.proj_transform(*centers, renderer.M)
240+
proj3d.proj_trans_points([edgep1, edgep2], self.axes.M))
241+
centpt = proj3d.proj_transform(*centers, self.axes.M)
242242
self.line.set_data(pep[0], pep[1])
243243
self.line.draw(renderer)
244244

@@ -270,7 +270,7 @@ def draw(self, renderer):
270270
axmask = [True, True, True]
271271
axmask[index] = False
272272
lxyz = move_from_center(lxyz, centers, labeldeltas, axmask)
273-
tlx, tly, tlz = proj3d.proj_transform(*lxyz, renderer.M)
273+
tlx, tly, tlz = proj3d.proj_transform(*lxyz, self.axes.M)
274274
self.label.set_position((tlx, tly))
275275
if self.get_rotate_label(self.label.get_text()):
276276
angle = art3d._norm_text_angle(np.rad2deg(np.arctan2(dy, dx)))
@@ -291,7 +291,7 @@ def draw(self, renderer):
291291
outerindex = 1
292292

293293
pos = move_from_center(outeredgep, centers, labeldeltas, axmask)
294-
olx, oly, olz = proj3d.proj_transform(*pos, renderer.M)
294+
olx, oly, olz = proj3d.proj_transform(*pos, D58A self.axes.M)
295295
self.offsetText.set_text(self.major.formatter.get_offset())
296296
self.offsetText.set_position((olx, oly))
297297
angle = art3d._norm_text_angle(np.rad2deg(np.arctan2(dy, dx)))
@@ -374,11 +374,11 @@ def draw(self, renderer):
374374
pos[tickdir] = (
375375
edgep1[tickdir]
376376
+ info['tick']['outward_factor'] * ticksign * tickdelta)
377-
x1, y1, z1 = proj3d.proj_transform(*pos, renderer.M)
377+
x1, y1, z1 = proj3d.proj_transform(*pos, self.axes.M)
378378
pos[tickdir] = (
379379
edgep1[tickdir]
380380
- info['tick']['inward_factor'] * ticksign * tickdelta)
381-
x2, y2, z2 = proj3d.proj_transform(*pos, renderer.M)
381+
x2, y2, z2 = proj3d.proj_transform(*pos, self.axes.M)
382382

383383
# Get position of label
384384
default_offset = 8. # A rough estimate
@@ -389,7 +389,7 @@ def draw(self, renderer):
389389
axmask[index] = False
390390
pos[tickdir] = edgep1[tickdir]
391391
pos = move_from_center(pos, centers, labeldeltas, axmask)
392-
lx, ly, lz = proj3d.proj_transform(*pos, renderer.M)
392+
lx, ly, lz = proj3d.proj_transform(*pos, self.axes.M)
393393

394394
tick_update_position(tick, (x1, x2), (y1, y2), (lx, ly))
395395
tick.tick1line.set_linewidth(

0 commit comments

Comments
 (0)
0