-
-
Notifications
You must be signed in to change notification settings - Fork 7.7k
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
ENH: add shading='nearest' and 'auto' to pcolormesh
#16258
Conversation
Note this fails a bunch of tests because apparently we often call x, y, C with same size and the new Deprecation Warning causes the tests to fail. |
lib/matplotlib/axes/_axes.py
Outdated
"Either specify the corners of the quadrilaterals " | ||
"with X and Y, or pass shading='auto', 'nearest' " | ||
"or 'gouraud', or set rcParams['pcolor.shading']") | ||
C = C[:Ny - 1, :Nx - 1] |
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.
It looks like you are missing the mixed cases like C.shape == (Ny+1, Nx)
. Did we handle them before?
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.
No we didn't handle that, and I think thats OK for simplicity's sake. If someone has a more complicated grid I feel they can wrangle it themselves....
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.
Actually, we did handle it, because in the "flat" case we always did the indexing (your line 5661), which "worked" with the mixed case. In the code you have here, the mixed case will fail somewhere downstream instead of being caught with an exception, or simply handled as it was originally.
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 think you could fix it by changing "and" to "or" in your line 5654, and then out-denting line 5661.
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.
Actually, 5654 could also change "and" to "or". Warn if either dimension isn't right.
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.
Yep that now emits the warning for:
ax.pcolormesh(x, y[:-1], C[:-1, :-1], vmin=0, vmax=1, shading='flat')
I've only taken a quick look so far, but I think this is on the right track. I'm OK with keeping the "shading" kwarg and adding the options as you have done. For the test failures, it sounds like the thing to do is modify the tests such that the test images don't change. |
The fact that so many tests are hitting the deprecation warning should tell us that even the folks who write examples and tests for Matplotlib make X, Y and C the same size. |
e05a6ae
to
e9dbec1
Compare
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 think this is a great addition! I agree with your decision to update the shading keyword argument rather than adding another keyword for this use case, I think it makes logical sense.
I've just made some minor comments in the code below, but it is close to being ready in my opinion.
2ea4fe5
to
9241c89
Compare
Though I must admit I was responsible for about half of them 😉 |
@efiring, and anyone else, this is ready for review I think, but happy to make more changes. |
`.axes.Axes.pcolormesh` and `~.axes.Axes.pcolor` have a few options for | ||
how grids are laid out and the shading between the grid points. | ||
|
||
Generally, if *Z* is size *MxN* then the grid *X* and *Y* can be |
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.
size -> shape (for an array t, t.shape is its shape, t.size its number of elements, so it's really not the same thing) ("is size" -> "has shape"
(throughout)
I also prefer (M, N)
to MxN
but won't overly insist on it (but (M+1, N+1)
reads nicer that M+1 x N+1
, in particular, I think).
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 think I got all the shape/size changes...
lib/matplotlib/axes/_axes.py
Outdated
def _interp_grid(X): | ||
# helper for below | ||
dX = np.diff(X, axis=1)/2. | ||
X = np.hstack((X[:, [0]] - dX[:, [0]], |
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.
Symmetrically expanding the first and last pixels seem fine but needs to be documented below. Also I guess this will crash if X or Y has size 1? (Sure it's degenerate, but I guess you can either use a width of 1 (likewise needs doc), or error out more cleanly.)
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 guess we should error. Assuming width 1 seems undesirable....
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.
erroring is certainly fine with me
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 think the general mpl strategy, though, is to try hard not to error out when data are simply missing:
In [2]: plt.plot([])
Out[2]: [<matplotlib.lines.Line2D at 0x119b13898>]
The idea is that if you have a long-running process making plots from a stream of data that might have gaps, it is better to show an empty window during a gap than to require that the user trap the gap condition and handle it manually.
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.
OK, fair enough. Instead of guessing a dX, I just make it [X, X] and nothing visible gets plotted. Anything else seems liable to just be wrong (dX = X/2, has problems if X=0, and just choosing dX=1/2 seems like it could mess with scaling of some plots inadvertently.
5b78d2e
to
3d8700e
Compare
dX = np.diff(X, axis=1)/2. | ||
X = np.hstack((X[:, [0]] - dX[:, [0]], | ||
X[:, :-1] + dX, | ||
X[:, [-1]] + dX[:, [-1]])) |
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 guess the whole thing would read slightly nicer if you interpolated rows instead of columns (and then below did the double transpose in the ncols == Nx
case and not in the nrows = Ny
case):
if len(X) > 1:
dX = np.diff(X, axis=0) / 2
X = np.row_stack([X[0] - dX[0], X[:-1] + dX, X[-1] + dX[-1]])
else:
X = np.row_stack([X, X])
(untested)
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.
That only reads nicer if you can remember the rule as to whether X[a]
refers to that a-th row or column. I prefer the more explicit form.
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 think it's not too hard if you think of X as "list of lists" (then X[a] is just the a-th list, which is clearly the a-th row). Anyways, not insisting on it, this is fine too.
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.
which is clearly the a-th row
Why is that clear?
I think when possible, its helpful to be explicit that we are using a 2-D array versus a 1-D. If I read X[0]-dX[0]
I immediately think X
is 1-D.
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.
Because
[[1, 2, 3],
[4, 5, 6]]
is just
[blah, # row
blah] # row
? i.e. literally how numpy writes out the thing?
Anyways, that's a tangent, not really relevant here.
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.
Yeah, its probably just that I have to switch between python and Fortran too much to keep it straight.
That is also present in master. |
Moved that to #16448. |
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.
lgtm post-ci.
Let's go :) |
Thanks for everyone's help and patience with this! |
- numpy: https://numpy.org/neps/nep-0034-infer-dtype-is-object.html - matplotlib: matplotlib/matplotlib#16258 - Not a deprecation warning, but also taking care of the warning "Matplotlib is currently using agg, which is a non-GUI backend..."
PR Summary
Redo of #9629. Lots of discussion there.
See built example here: https://29535-1385122-gh.circle-artifacts.com/0/home/circleci/project/doc/build/html/gallery/images_contours_and_fields/pcolormesh_grids.html#sphx-glr-gallery-images-contours-and-fields-pcolormesh-grids-py
Se new pcolormesh docs here:
https://29535-1385122-gh.circle-artifacts.com/0/home/circleci/project/doc/build/html/api/_as_gen/matplotlib.axes.Axes.pcolormesh.html#matplotlib.axes.Axes.pcolormesh
Suppose
len(x)
is N,len(y)
is M, andsize(C)
is M, N. Previously, ifshading='flat'
thenpcolor/mesh
would silently drop the last row and column ofC
andx
andy
would specify the edges of the colorer quadrilaterals.While compatible with Matlab, this is both arbitrary, and probably not what the user wanted.
This PR changes a few related things:
shading='flat'
and the dimensions of x, y and C match, a Deprecation Warning is raised the data is no longer silently dropped.shading='nearest'
is provided that only allows for x, y and C to match, and centers the colors on the grid points.shading='auto'
is provided that will choose 'flat' or 'nearest' depending on the size of the data.rcParam['pcolor.shading']
is provided that defaults to 'flat' (for back compatibility).Demo:
The first call emits:
PR Checklist