-
-
Notifications
You must be signed in to change notification settings - Fork 8k
DOC: add tutorial explaining imshow *origin* and *extent* #10947
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
519c1dc
to
1124ec9
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.
A couple of suggestions for improvement.
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.
Might be worth having these as keyword arguments? When I read the tutorial I scrolled past this big block of code, and then was confused as to what generate_imshow_demo_grid(True...)
did, but I think generate_imshow_demo_grid(auto_limits=True...)
would be much better.
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.
There isn't a massive change in these images from L --> R, but a clear different from top to bottom. Maybe a good place to use a colourmap that isn't perceptually uniform to illustrate changes in orientation?
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.
At least when I look a these what I see is the direction of highest-lowest vector, changed to a diagonal gradient.
Geat tutorial! I did suggest to have such example around in #10982 without seeing this one being created.
I used triangular shaped data to explain a point I wanted to make in that PR, something like
This would make it easier to grasp at which corner the data is shown compared to the original array. Would this be an option 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.
👍 yes, that's what I meant!
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.
Possibly better as a bullet list or table than plain text:
Generally, for an array of shape (M,N), the first index runs along the vertical, the second index runs along the horizontal. origin determines how to the data is filled in the bounding box.
For origin='lower'
:
- [0, 0] is at
(left, bottom)
- [M, 0] is at
(left, top)
- [0, N] is at
(right, bottom)
- [M, N] is at
(right, top)
origin='upper'
reverses the vertical filling:
- [0, 0] is at
(left, top)
- [M, 0] is at
(left, bottom)
- [0, N] is at
(right, top)
- [M, N] is at
(right, bottom)
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 simpler to understand if this was a table with colums 'origin == upper', 'origin == lower' and rows
- [0, 0] pixel position
- default extent
- maybe more.
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.
Backticks don't work here. We can just leave them out.
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.
man, talk about muscle memory....
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 find it more natural with a reversed logic that uses explicit_limits=False
instead of auto_limits
, or alternatively, xlims=None, ylims=None
.
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.
If we fix the axes limits by explicity setting set_xlim
/ set_ylim
, we force a certain orientation of the axes. This can decouple the 'left-right' and 'top-bottom' sense of the image from the orientation on the screen.
In the example below (0, 0) is explicitly put at the bottom left and values increase to up and to the right (from the viewer point of view). We can see that:
Also it helps to display the indices in the plots:
def index_to_coordinate(index, extent, origin):
left, right, bottom, top = extent
# convert from extent to corner pixel centers
hshift = 0.5 if left < right else -0.5
left, right = left + hshift, right - hshift
vshift = 0.5 if bottom < top else -0.5
bottom, top = bottom + vshift, top - vshift
# handle vertical fill order
if origin == 'upper':
bottom, top = top, bottom
return {
'0, 0': (left, bottom),
'M, 0': (left, top),
'0, N': (right, bottom),
'M, N': (right, top),
}[index]
and in the inner for loop:
for index in ['0, 0', '0, N', 'M, 0', 'M, N']:
ax.text(*index_to_coordinate(index, extent, origin),
index, color='white', ha='center', va='center')
Just mind the notation. In the imshow docs (#10982), arrays are of shape (N,M)
. (削除) This is consistent with widely used conventions. (削除ここまで) So if updating the coordinates as proposed above, it would make sense to use this convention as well, and not suddenly chage it to (M,N)
. Independently something seems to be wrong in the above suggestion.
- For a tuple
a,b
one needs to decide if this is a cartesian point(x,y)
or an array index[i,j]
- In either case, the last coordinate or index should be
N-1
andM-1
respectively.
@ImportanceOfBeingErnest Agreed on all points.
- Should use (N,M).
- The exact notation would be
[N-1, M-1]
, but there is no way of fitting that in square pixels while maintaining a reasonably small figure size. I could discuss away the square brackets with a sentence: "Values in pixels describe their indices". No good idea how to cope with the-1
issue. One could define them one-smaller by "array of shape (N+1,M+1)". That would be consistent within the example, but other than the original docstring notation (N, M).
Probably the best solution is using boxes for the indices as well:
where
N' = N-1
andM' = M-1
and code:
def get_color(index, data, cmap):
val = {
"[0, 0]": data[0, 0],
"[0, M']": data[0, -1],
"[N', 0]": data[-1, 0],
"[N', M']": data[-1, -1],
}[index]
return cmap(val / data.max())
for index in ["[0, 0]", "[0, M']", "[N', 0]", "[N', M']"]:
ax.text(*index_to_coordinate(index, extent, origin),
index, color='white', ha='center', va='center',
bbox={'boxstyle': 'square',
'facecolor': get_color(index, d, im.get_cmap())}
)
@timhoffm @ImportanceOfBeingErnest feel free to push directly to this branch, I think all of these suggestions are great 👍
Would probably push the index labels in a bit or give them some alpha, they are covering the tick labels and the arrow. The index labels make also make the arrow superfluous.
@ImportanceOfBeingErnest Why is the convention (N, M)? Is this only for images? I find it quite confusing--why use reversed-alphabetical order? What about indices--are they (i, j), or (j, i)?
@efiring Good point. For some reason we're using this convention, but upon reflection and googling, I did not find profound evidence for it being "widely used". I was then somehow confirmed by the recently proposed changes to the imshow docs (#10982). (@timhoffm Might this be a typical german thing?)
So restart from scratch: the imshow
docs need to decide for one convention (#10323, #10982), this convention needs to be documented (#10225). This guide here needs to use the same convention.
From a bit of googling and also looking at wikipedia it seems (m,n)
/ (M,N)
/ M x N
could be preferable above (n,m)
/ (N,M)
/ N x M
.
f1b481b
to
d1e307a
Compare
You are right. (M, N)
is common, e.g.
https://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.lstsq.html#numpy.linalg.lstsq
http://scikit-image.org/docs/dev/api/skimage.filters.html#skimage.filters.inverse
Changed.
I think this is good to go.
For reviewers, here's how it looks like:
https://9315-1385122-gh.circle-artifacts.com/0/home/circleci/project/doc/build/html/tutorials/intermediate/imshow_extent.html?highlight=extent
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 set of examples doesn't really help me because the "extents" is still the same as the extents I'd expect from the underlying data array size. Wouldn't it be more illustrative to go from 0-15 or something? The phrase "...a bounding box in data space" is also mysterious. I think of the matrix as being the data and a bounding box on the data means a clip to me. But what you mean is that the extents are the x and y co-ordinates over which the matrix is placed.
The docs say "The location, in data-coordinates, of the lower-left and upper-right corners" ; I prefer "data-coordinates"
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 point is to show how inverting the left vs right or top vs bottom changes the image around. Using different limits would make that a harder apples-to-apples comparison.
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.
yes But it didn’t help me understand what extents actually is on the first place
I’ll admit this flipping the axes seems like the wrong behaviour. I’d have expected the matrix to flip. But I doubt I’ll get that changed here. ;-)
I really like the changes! Thanks @ImportanceOfBeingErnest and @timhoffm !
I am 👍 on merging this, but don't want to push the button as I have commits in this and can not approve is github things this is my PR.
d1e307a
to
dcb18e0
Compare
dcb18e0
to
206c3ca
Compare
- Rephrased the section with "bounding box in data space".
- Fixed some typos.
Probably this example could be improved even further, but that would require significant restructuring of code and description. I'm pushing this forward to have a reference to point to from the imshow docstring and get my associated PR #10982 approved. As a first step this PR is now good enough for that. Further improvements can be added later.
I merged as a stand-alone improvement. Can be refined upon...
Backport PR #10947 on branch v2.2.2-doc
PR Summary
Sort out how origin and 'extent interact.
attn @efiring
PR Checklist