Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork7.9k
DOC: manually placing images example#28775
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
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 seems good to me (and also familiar… 😉). Just a few minor comments.
galleries/examples/images_contours_and_fields/image_exact_placement.py OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
galleries/examples/images_contours_and_fields/image_exact_placement.py OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
galleries/examples/images_contours_and_fields/image_exact_placement.py OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
galleries/examples/images_contours_and_fields/image_exact_placement.py OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
galleries/examples/images_contours_and_fields/image_exact_placement.py OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
galleries/examples/images_contours_and_fields/image_exact_placement.py OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
Thanks@rcomer - yes this came from the latest stack overflow to ask for this. It is asked periodically, and I did not see that we had a good example to point to. |
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 suggest to add# sphinx_gallery_thumbnail_number = -1
so that the last image will be used as thumbnail.
Yes, good idea - I also toyed with the idea of making the default figure size more appropriate, but I think it's reasonable to use the default so folks can see how it can "go wrong". |
galleries/examples/images_contours_and_fields/image_exact_placement.py OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
galleries/examples/images_contours_and_fields/image_exact_placement.py OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
galleries/examples/images_contours_and_fields/image_exact_placement.py OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
galleries/examples/images_contours_and_fields/image_exact_placement.py OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
dpi = 100 # 100 pixels is one inch | ||
buffer = 0.35 * dpi # pixels | ||
left = buffer | ||
bottom = buffer | ||
ny, nx = np.shape(A) | ||
posA = [left, bottom, nx, ny] | ||
# we know this is tallest, so we can get the fig height: | ||
figh = bottom + ny + buffer | ||
# place the B axes | ||
left = left + nx + buffer | ||
ny, nx = np.shape(B) | ||
posB = [left, figh - buffer - ny, nx, ny] | ||
# get the fig width | ||
figw = left + nx + buffer | ||
fig = plt.figure(figsize=(figw / dpi, figh / dpi), facecolor='aliceblue') | ||
ax = fig.add_axes([posA[0] / figw, posA[1] / figh, posA[2] / figw, posA[3] / figh]) | ||
ax.imshow(A, vmin=-1, vmax=1) | ||
rect = mpatches.Rectangle((0, 0), 200, 40, linewidth=1, edgecolor='r', facecolor='none') | ||
ax.add_patch(rect) | ||
ax = fig.add_axes([posB[0] / figw, posB[1] / figh, posB[2] / figw, posB[3] / figh]) | ||
ax.imshow(B, vmin=-1, vmax=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.
Suggestion structuring to make the calculations more understandable:
- Calculate desired figure height and width in pixel
- Create figure (needs calculation of figure size in inches)
- Add axes (needs calculation of dimensions in figure coordinates)
dpi=100# 100 pixels is one inch | |
buffer=0.35*dpi# pixels | |
left=buffer | |
bottom=buffer | |
ny,nx=np.shape(A) | |
posA= [left,bottom,nx,ny] | |
# we know this is tallest, so we can get the fig height: | |
figh=bottom+ny+buffer | |
# place the B axes | |
left=left+nx+buffer | |
ny,nx=np.shape(B) | |
posB= [left,figh-buffer-ny,nx,ny] | |
# get the fig width | |
figw=left+nx+buffer | |
fig=plt.figure(figsize=(figw/dpi,figh/dpi),facecolor='aliceblue') | |
ax=fig.add_axes([posA[0]/figw,posA[1]/figh,posA[2]/figw,posA[3]/figh]) | |
ax.imshow(A,vmin=-1,vmax=1) | |
rect=mpatches.Rectangle((0,0),200,40,linewidth=1,edgecolor='r',facecolor='none') | |
ax.add_patch(rect) | |
ax=fig.add_axes([posB[0]/figw,posB[1]/figh,posB[2]/figw,posB[3]/figh]) | |
ax.imshow(B,vmin=-1,vmax=1) | |
margin_px=35# in pixels | |
ny_A,nx_A=np.shape(A) | |
ny_B,nx_B=np.shape(B) | |
fig_height_px=max(ny_A,ny_B)+2*margin_px | |
fig_width_px=nx_A+nx_B+2*margin_px | |
# calculate figsize in inches | |
figsize= (fig_width_px/dpi,fig_height_px/dpi) | |
fig=plt.figure(figsize=figsize,facecolor='aliceblue') | |
# add axes in figure coordinates | |
ax1=fig.add_axes([ | |
margin_px/fig_width_px,# left | |
margin_px/fig_height_px,# bottom | |
nx_A/fig_width_px,# width | |
ny_A/fig_height_px# height | |
]) | |
ax2=fig.add_axes([ | |
margin_px/fig_width_px,# left | |
(fig_height_px-margin_px-ny)/fig_height_px,# bottom | |
nx_B/fig_width_px,# width | |
ny_B/fig_height_px# height | |
]) | |
ax1.imshow(A,vmin=-1,vmax=1) | |
rect=mpatches.Rectangle((0,0),200,40,linewidth=1,edgecolor='r',facecolor='none') | |
ax.add_patch(rect) | |
ax2.imshow(B,vmin=-1,vmax=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.
A and B are purposefully different widths, so I don't think this is correct.
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.
You are right. The numbers / expressions are not correct. Still the idea (which possibly can be communicated more explicitly) is that you can place everything at exact pixel positions. And to do that, you have to follow the three steps above.
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 now correct. - I don't have an interpreter at hand, so can't check, but I hope you get the idea.
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 do get the idea, but not convinced pre-calculating the figure dimensions buys you anything. Also, imagine we were to add a third or fourth image in there, we would need to change the code in two places.
Just for context, I originally wrote as a for-loop to allow flexibility, but backed off on that as perhaps too magical.
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.
Just for context, I originally wrote as a for-loop to allow flexibility, but backed off on that as perhaps too magical.
👍 Examples must show the pattern, not necessarily a generic solution if that makes the code harder to understand.
I had difficulty following your code. Reflecting on it, the reasons were
- lines 100-115 define a lot of variables, which are sometimes
a) tersely named (figh
)
b) cryptic data structuresposB = [left, figh - buffer - ny, nx, ny]
c) a mixture of definitions for later use (e.g.figh
) and temporary local variables that are reassigned (left
,nx
, `ny´) - It's unclear that these are all in pixels
- Transformation calculations to inches (for figsize) and figure units (for add_axes) are hard to understand, because both the input units (see 2.) and the resulting units are not clear.
I tried a more minimal refactor of your code to alleviate these points, but I ended up with almost the same code as I've proposed above 🤷♂️.
The doc build is failing with
|
Please rebase.#28779 fixes the doc build. |
timhoffm commentedSep 4, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
I'm +1 on adjusting the figure size right away for all figures. Adjusting the figsize is something one would always do if the default aspect is not a good fit for the content. This is something wejust do as needed without talking about it (example:https://matplotlib.org/stable/gallery/lines_bars_and_markers/categorical_variables.html). Just looking at the figures, one could get the impression, that it's a feature of the "manual" approach that you don't have the large figure whitespace. To take this effect out,all figures should have the same (or similar) size. |
I'm not sure I agree with that. Of course peopleshould change the figure size, but there is endless confusion about fixed ratio images and why there is so much white space. If we show the white space, I think on the balance we are helping folks understand this is not something matplotlib will do for them automagically. |
galleries/examples/images_contours_and_fields/image_exact_placement.py OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
# helped because the axes are wider than they are tall. For more complicated | ||
# situations it is necessary to place the axes manually. | ||
# | ||
# Manual placement |
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'm a bit torn on the motivation for this: You can get away without by using an appropriate figsize (which is much simpler).
The advantages I see is
- pixel-perfect positioning (if you need that)
- in this case 1:1 mapping from data points to visual pixels.
Maybe these should be highlighted more.
@timhoffm perhaps this is worse, but this change Idon't set the figsize for the first "default" plot, but thendo set it for the customized plots, with a bit of explanation. That doesn't make the narrative shorter, but it does go through the steps in the way a user may go through them. |
I like this. It's clear without making too much fuss about the figsize topic. |
galleries/examples/images_contours_and_fields/image_exact_placement.py OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
galleries/examples/images_contours_and_fields/image_exact_placement.py OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
galleries/examples/images_contours_and_fields/image_exact_placement.py OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
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.
Take or leave the comments. May self-merge afterwards.
fit inside the parent `~.axes.Axes`. This can mean that images that have very | ||
different original sizes can end up appearing similar in 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.
Optional: Slightly more concise wording:
fitinsidetheparent`~.axes.Axes`.Thiscanmeanthatimagesthathavevery | |
differentoriginalsizescanendupappearingsimilarinsize. | |
fitinsidetheparent`~.axes.Axes`.Asaresult,imageswithverydifferent | |
originalsizesmayendupappearingsimilarinsize. |
galleries/examples/images_contours_and_fields/image_exact_placement.py OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
galleries/examples/images_contours_and_fields/image_exact_placement.py OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
6119c12
intomatplotlib:mainUh oh!
There was an error while loading.Please reload this page.
New example showing a couple of methods for dealing with images that you want to keep the samereelative size.