-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Add lightsource parameter to bar3d #15099
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add lightsource parameter to bar3d #15099
Conversation
Bar3d now allows the user to define the user to define the origin of the lightsource.
lib/mpl_toolkits/mplot3d/axes3d.py
Outdated
@@ -2375,6 +2375,9 @@ def bar3d(self, x, y, z, dx, dy, dz, color=None, | ||
shade : bool, optional (default = True) | ||
When true, this shades the dark sides of the bars (relative | ||
to the plot's source of light). | ||
|
||
lightsource : matplotlib.color.LightSource, optional (default = None) | ||
The lightsource defines the plot's source of light. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The lightsource defines the plot's source of light, if shade=True is set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I noticed that plot_trisurf
already uses this parameter so I copied its line instead:
lightsource : `~matplotlib.colors.LightSource`
The lightsource to use when *shade* is True.
Uses `plot_trisurface`'s documentation for `bar3d`'s lightsource parameter.
Failed Travis CI test for flake8.
In general it would be nice to see the effect of this new parameter. Do you have a small example code with an image you can show in the PR? Also there should be a test that checks that the new parameter does what it should. In the simplest case this can just be a smoke-test, or one could check if a particular face of the bar really has the expected color. |
Fixed over- and under-indentation.
sample code import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.colors as mcolors
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection="3d")
ls = mcolors.LightSource(azdeg=0, altdeg=90)
cmap = plt.get_cmap("coolwarm")
length, width = 3, 4
area = length * width
norm = mcolors.Normalize(0, area-1)
x, y = np.meshgrid(np.arange(length), np.arange(width))
x = x.ravel()
y = y.ravel()
dz = x + y
color = np.array([cmap(norm(i)) for i in range(area)])
collection = ax.bar3d(x=x, y=y, z=0,
dx=1, dy=1, dz=dz,
color=color, shade=True, lightsource=ls)
ax.set_title(f"Azimutal degree = {ls.azdeg}°, altitude degree = {ls.altdeg}°")
plt.show()
# simple color test
assert np.all(color == collection._facecolors3d[1::6]),\
"bar colors doesn't match" Issues:
|
lib/mpl_toolkits/mplot3d/axes3d.py
Outdated
@@ -2375,6 +2375,9 @@ def bar3d(self, x, y, z, dx, dy, dz, color=None, | ||
shade : bool, optional (default = True) | ||
When true, this shades the dark sides of the bars (relative | ||
to the plot's source of light). | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the line that causes the flake hickup. A blank like cannot contain any whitespaces.
A test would need to go into lib/mpl_toolkits/tests/test_mplot3d.py; there are already 3 test for bars. |
Compares the computed colors of the bar tops with the user-defined colors.
dx=1, dy=1, dz=dz, | ||
color=color, shade=True, lightsource=ls) | ||
|
||
np.testing.assert_array_equal(color, collection._facecolors3d[1::6]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I don't understand here is, if the facecolors are actually the same as the colors taken from the colormap, are we really testing that the lightsource works? That is, if there is a lightsource, shouldn't the colors be different from the ones from the coolwarm colormap?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
._facecolors3d[1::6]
should be taking the color of the top surfaces, which with a lightsource coming from the top (altdeg=90
), should leave these unchanged (fully illuminated), as expected.
Changing the altdeg (e.g. default value of 19.4712
) or selecting different sides (e.g. .facecolors3d[2::6]
) fails this test.
A test could be made which computes to expected colors given different angles, or compares to an image, but I thought this simple approach would suffice, as it ensures that the default lightsource is not used.
It's worth mentioning that the test would also pass if no shading were done, but test_bar3d_shaded
should already test for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. So imagine in the future someone unintentionally removes lightsource
from the line self._shade_colors(facecolors, normals, lightsource)
. The test would not detect this, right? But that is what we have tests for.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test would detect this.
Calling self._shade_colors(facecolors, normals)
without a lightsource argument defaults to LightSource(azdeg=225, altdeg=19.4712)
, which would fail the test. This would shade the top surfaces with a different color. It will only pass if the top colors are unchanged, which requires a LightSource(altdeg=90)
to be passed through.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, that is not very obvious. I'd suggest to add that as a comment in the test; else I fear in the future people might be as confused as I was by it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May I suggest the following as comment in the test:
# Testing that the custom 90° lightsource produces different shading than
# the default, and that those colors are precisely the colors from the
# colormap, due to the illumination parallel to the z-axis.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, that sounds much better. I also added that it compares the top facecolors.
#(...) different shading on the top facecolors compared to the default (...)
One final thing. If you think this is a notable feature, people should be made be aware of, you can add a "What's new entry" |
Make the comment more obvious
Bar3d now allows the user to define the user to define the origin of the lightsource.
PR Summary
Note: I have little experience with pull requests, and I have not thouroughly checked the correctness of the code (even though it is two lines of code, anything can go wrong), so I cannot advise a merge just yet. I would like to hear if this change is even needed (is this even the best way to go about it?). I will make the proper adjustments if needed, any advice is appreciated.
This adds a
lightsource
parameter tobar3d
. This is already a documented feature without any implementation (AFAIK). The documentation for theshade
parameter says:However, there is currently no apparent way to set this, as
bar3d
callsself._shade_colors(facecolors, normals)
without a lightsource parameter, which by default usesLightSource(azdeg=225, altdeg=19.4712)
if nolightsource
parameter is set.PR Checklist
Documented in doc/api/api_changes.rst if API changed in a backward-incompatible way