-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Update lib/mpl_toolkits/mplot3d/axes3d.py #1294
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
Conversation
Axes3D.scatter: raise exception in case z.size neither being 1 nor equaling x.size and y.size (according to documentation).
On Friday, September 21, 2012, Jan-Philip Gehrcke wrote:
Seems reasonable. I'll try it out when I get home. If it feels ok, I'll Thanks for your contribution! Damon McDougall |
I tried this out; it's totally reasonable. I'll merge this in 24 hours. |
zs = np.array(zs[0] * xs.size) | ||
if xs.size != zs.size: | ||
if zs.size == 1: | ||
zs = np.array(zs[0] * xs.size) |
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.
Was the logic faulty in the first place? I can't see that multiplying the z value by the size of x is a sensible thing to be doing... I would have thought the purpose of this line was more along the lines of: np.array([z[0]] * x.size)
.
Better yet would be np.tile(z[0], x.size)
.
@WeatherGod : Any thoughts?
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.
On Saturday, September 22, 2012, Phil Elson wrote:
In lib/mpl_toolkits/mplot3d/axes3d.py:
@@ -1937,8 +1937,11 @@ def scatter(self, xs, ys, zs=0, zdir='z', s=20, c='b', _args, *_kwargs):
zs = np.ma.ravel(zs)
if xs.size != ys.size:
raise ValueError("x and y must be the same size")
if xs.size != zs.size and zs.size == 1:
zs = np.array(zs[0] \* xs.size)
if xs.size != zs.size:
if zs.size == 1:
zs = np.array(zs[0] \* xs.size)
Was the logic faulty in the first place? I can't see that multiplying the
z value by the size of x is a sensible thing to be doing... I would have
thought the purpose of this line was more along the lines of: np.array([z[0]]
- x.size).
Better yet would be np.tile(z[0], x.size).
@WeatherGod https://github.com/WeatherGod : Any thoughts?
Good catch. Probably should use something like np.broadcast_arrays()?
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 wow. Yes, good eye. Well spotted. np.repeat
is another option.
Edit: Or, np.ones(xs.size) * zs[0]
. That does the broadcasting for you.
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.
Right, should've also looked closer; who wrote that in the first place? :)
zs, xs = np.broadcast_arrays(zs, xs)
zs = np.tile(zs[0], xs.size)
zs = np.ones(xs.size) * zs[0]
all work (and there probably are a lot more solutions). I'd vote for tile
in this case. It is well-readable and super fast (enough for this purpose). In my opionion broadcasting is OTT at this point. However, I am quite inexperienced with numpy and matplotlib, so the decision is up to you and I'll respect it.
Can I somehow change the pull request or should I revoke 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.
The PR is a request to merge this branch. So if you add commits and push them to your fork, the PR will automatically be updated appropriately.
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.
@jgehrcke You don't need to revoke it! Just add another commit to your patch-1 branch:
git checkout patch-1
.. hack hack hack..
git add axes3d.py
git commit
git push origin patch-1
And this page will automagically update to reflect your branch's commit history.
I'd vote for either np.tile
or np.ones
. Let's see what @pelson and @WeatherGod have to say first, though.
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.
My vote:
Fixed > Broken
:-) i.e. I don't really mind which goes. They are both readable enough in my eyes, and I don't expect performance to make any difference in choosing in this case (compared to other operations, microseconds aren't worth counting).
Match argument names in error messages to argument names in documentation.
Make Axes3D.scatter properly deal with `zs` being of size 1.
Thanks for your help. I added two new changesets to this pull request. Have tested those with the following code: from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import traceback
testsets = [([1,2], [1,2], [1,2]), # pass
([1,2], [1,2], [1]), # pass
([1,2], [1,2], 1), # pass
([1,2], [1,2], [1,2,3]), # error
([1,2], [1,2], []), # error
([1], [1,2], [1,2])] # error
for x, y, z in testsets:
ax = plt.figure().add_subplot(111, projection='3d')
try:
ax.scatter(x, y, z)
plt.show()
except ValueError:
print traceback.format_exc()
finally:
plt.close() |
@@ -1936,9 +1936,13 @@ def scatter(self, xs, ys, zs=0, zdir='z', s=20, c='b', *args, **kwargs): | |||
ys = np.ma.ravel(ys) | |||
zs = np.ma.ravel(zs) | |||
if xs.size != ys.size: |
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.
Let xs = [1, 2]
and ys = [[1], [2]]
. This will evaluate to true. Does it make sense to pass xs
and ys
with different shapes?
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 am not entirely sure if that would make sense and did not look at the internals of this method so far. Let's for now suppose that input with a higher dimensionality than 1 does not make sense here. If so, I would add a dimensionality check and document that x, y, z are required to be 1D. This would have to be done for all the other plotting methods in the Axes3D module as well.
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.
.ravel() flatten things out, iirc.
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.
@WeatherGod Good spot, I didn't notice those.
@jgehrcke As Ben points out, it looks like it passes because they're already ravel
d, so you can disregard my previous concern.
@jgehrcke Are you happy for this change to be merged or are there other things you would like to add? |
If you are happy now, I am also happy :) |
Update lib/mpl_toolkits/mplot3d/axes3d.py
@pelson @WeatherGod Should I also merge this into
I added a remote called |
The above lines will not do the right thing, since it will also pull in things on |
@mdboom Cheers! |
So one solution might be to rebase before merging. Cherry-picking sounds easier, though. |
Ok, I think that worked. |
Axes3D.scatter: raise exception in case z.size neither being 1 nor equaling x.size and y.size (according to documentation)