Skip to content

Commit 1cf7539

Browse files
fourpointsImportanceOfBeingErnest
authored andcommitted
Add lightsource parameter to bar3d (matplotlib#15099)
* Add lightsource parameter to bar3d Bar3d now allows the user to define the user to define the origin of the lightsource. * Copy lightsource parameter documentation Uses `plot_trisurface`'s documentation for `bar3d`'s lightsource parameter. * Removed redundant #'s for flake8 complicancy Failed Travis CI test for flake8. * Changed indentation for flake8 compliancy Fixed over- and under-indentation. * Remove whitespace in blank line * Add test for bar3d lightsource Compares the computed colors of the bar tops with the user-defined colors. * Add support for lightsource parameter in bar3d * Extend line length in rst * Fix rst formatting * Fix rst formatting * Add test description * Update test description Make the comment more obvious * Fix typo
1 parent 07f08de commit 1cf7539

File tree

3 files changed

+48
-12
lines changed

3 files changed

+48
-12
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
bar3d gained support for the ``lightsource`` parameter
2+
------------------------------------------------------
3+
4+
bar3d now supports lighting from different angles when the *shade* parameter is
5+
True.

lib/mpl_toolkits/mplot3d/axes3d.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ def autoscale(self, enable=True, axis='both', tight=None):
488488
else:
489489
scalez = False
490490
self.autoscale_view(tight=tight, scalex=scalex, scaley=scaley,
491-
scalez=scalez)
491+
scalez=scalez)
492492

493493
def auto_scale_xyz(self, X, Y, Z=None, had_data=None):
494494
# This updates the bounding boxes as to keep a record as to what the
@@ -505,7 +505,7 @@ def auto_scale_xyz(self, X, Y, Z=None, had_data=None):
505505
self.autoscale_view()
506506

507507
def autoscale_view(self, tight=None, scalex=True, scaley=True,
508-
scalez=True):
508+
scalez=True):
509509
"""
510510
Autoscale the view limits using the data limits.
511511
See :meth:`matplotlib.axes.Axes.autoscale_view` for documentation.
@@ -631,7 +631,7 @@ def set_xlim3d(self, left=None, right=None, emit=True, auto=False,
631631
for other in self._shared_x_axes.get_siblings(self):
632632
if other is not self:
633633
other.set_xlim(self.xy_viewLim.intervalx,
634-
emit=False, auto=auto)
634+
emit=False, auto=auto)
635635
if other.figure != self.figure:
636636
other.figure.canvas.draw_idle()
637637
self.stale = True
@@ -692,7 +692,7 @@ def set_ylim3d(self, bottom=None, top=None, emit=True, auto=False,
692692
for other in self._shared_y_axes.get_siblings(self):
693693
if other is not self:
694694
other.set_ylim(self.xy_viewLim.intervaly,
695-
emit=False, auto=auto)
695+
emit=False, auto=auto)
696696
if other.figure != self.figure:
697697
other.figure.canvas.draw_idle()
698698
self.stale = True
@@ -753,7 +753,7 @@ def set_zlim3d(self, bottom=None, top=None, emit=True, auto=False,
753753
for other in self._shared_z_axes.get_siblings(self):
754754
if other is not self:
755755
other.set_zlim(self.zz_viewLim.intervalx,
756-
emit=False, auto=auto)
756+
emit=False, auto=auto)
757757
if other.figure != self.figure:
758758
other.figure.canvas.draw_idle()
759759
self.stale = True
@@ -1241,7 +1241,7 @@ def get_zlabel(self):
12411241
label = self.zaxis.get_label()
12421242
return label.get_text()
12431243

1244-
#### Axes rectangle characteristics
1244+
# Axes rectangle characteristics
12451245

12461246
def get_frame_on(self):
12471247
"""
@@ -1344,7 +1344,7 @@ def tick_params(self, axis='both', **kwargs):
13441344
zkw.pop('labelbottom', None)
13451345
self.zaxis.set_tick_params(**zkw)
13461346

1347-
### data limits, ticks, tick labels, and formatting
1347+
# data limits, ticks, tick labels, and formatting
13481348

13491349
def invert_zaxis(self):
13501350
"""
@@ -1820,9 +1820,9 @@ def plot_wireframe(self, X, Y, Z, *args, **kwargs):
18201820
tzlines = [tZ[i] for i in cii]
18211821

18221822
lines = ([list(zip(xl, yl, zl))
1823-
for xl, yl, zl in zip(xlines, ylines, zlines)]
1824-
+ [list(zip(xl, yl, zl))
1825-
for xl, yl, zl in zip(txlines, tylines, tzlines)])
1823+
for xl, yl, zl in zip(xlines, ylines, zlines)]
1824+
+ [list(zip(xl, yl, zl))
1825+
for xl, yl, zl in zip(txlines, tylines, tzlines)])
18261826

18271827
linec = art3d.Line3DCollection(lines, *args, **kwargs)
18281828
self.add_collection(linec)
@@ -2333,7 +2333,7 @@ def bar(self, left, height, zs=0, zdir='z', *args, **kwargs):
23332333
return patches
23342334

23352335
def bar3d(self, x, y, z, dx, dy, dz, color=None,
2336-
zsort='average', shade=True, *args, **kwargs):
2336+
zsort='average', shade=True, lightsource=None, *args, **kwargs):
23372337
"""Generate a 3D barplot.
23382338
23392339
This method creates three dimensional barplot where the width,
@@ -2376,6 +2376,9 @@ def bar3d(self, x, y, z, dx, dy, dz, color=None,
23762376
When true, this shades the dark sides of the bars (relative
23772377
to the plot's source of light).
23782378
2379+
lightsource : `~matplotlib.colors.LightSource`
2380+
The lightsource to use when *shade* is True.
2381+
23792382
**kwargs
23802383
Any additional keyword arguments are passed onto
23812384
`~.art3d.Poly3DCollection`.
@@ -2474,7 +2477,7 @@ def bar3d(self, x, y, z, dx, dy, dz, color=None,
24742477

24752478
if shade:
24762479
normals = self._generate_normals(polys)
2477-
sfacecolors = self._shade_colors(facecolors, normals)
2480+
sfacecolors = self._shade_colors(facecolors, normals, lightsource)
24782481
else:
24792482
sfacecolors = facecolors
24802483

lib/mpl_toolkits/tests/test_mplot3d.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import matplotlib as mpl
55
from matplotlib import cm
66
from matplotlib import path as mpath
7+
from matplotlib import colors as mcolors
78
from matplotlib.testing.decorators import image_comparison, check_figures_equal
89
from matplotlib.cbook.deprecation import MatplotlibDeprecationWarning
910
from matplotlib.collections import LineCollection, PolyCollection
@@ -64,6 +65,33 @@ def test_bar3d_notshaded():
6465
fig.canvas.draw()
6566

6667

68+
def test_bar3d_lightsource():
69+
fig = plt.figure()
70+
ax = fig.add_subplot(1, 1, 1, projection="3d")
71+
72+
ls = mcolors.LightSource(azdeg=0, altdeg=90)
73+
74+
length, width = 3, 4
75+
area = length * width
76+
77+
x, y = np.meshgrid(np.arange(length), np.arange(width))
78+
x = x.ravel()
79+
y = y.ravel()
80+
dz = x + y
81+
82+
color = [cm.coolwarm(i/area) for i in range(area)]
83+
84+
collection = ax.bar3d(x=x, y=y, z=0,
85+
dx=1, dy=1, dz=dz,
86+
color=color, shade=True, lightsource=ls)
87+
88+
# Testing that the custom 90° lightsource produces different shading on
89+
# the top facecolors compared to the default, and that those colors are
90+
# precisely the colors from the colormap, due to the illumination parallel
91+
# to the z-axis.
92+
np.testing.assert_array_equal(color, collection._facecolors3d[1::6])
93+
94+
6795
@image_comparison(['contour3d.png'], remove_text=True, style='mpl20')
6896
def test_contour3d():
6997
fig = plt.figure()

0 commit comments

Comments
 (0)