Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

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

Merged
jklymak merged 2 commits intomatplotlib:mainfromjklymak:doc-place-images
Dec 5, 2024

Conversation

jklymak
Copy link
Member

New example showing a couple of methods for dealing with images that you want to keep the samereelative size.

@github-actionsgithub-actionsbot added the Documentation: examplesfiles in galleries/examples labelSep 2, 2024
@jklymakjklymak marked this pull request as ready for reviewSeptember 2, 2024 02:42
Copy link
Member

@rcomerrcomer left a 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.

@jklymak
Copy link
MemberAuthor

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.

rcomer reacted with thumbs up emoji

Copy link
Member

@timhoffmtimhoffm left a 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.

jklymak reacted with thumbs up emoji
@jklymak
Copy link
MemberAuthor

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".

Comment on lines 100 to 146
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)
Copy link
Member

@timhoffmtimhoffmSep 2, 2024
edited
Loading

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:

  1. Calculate desired figure height and width in pixel
  2. Create figure (needs calculation of figure size in inches)
  3. Add axes (needs calculation of dimensions in figure coordinates)
Suggested change
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)

Copy link
MemberAuthor

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.

Copy link
Member

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.

Copy link
Member

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.

Copy link
MemberAuthor

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.

Copy link
Member

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

  1. 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´)
  2. It's unclear that these are all in pixels
  3. 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 🤷‍♂️.

@jklymak
Copy link
MemberAuthor

The doc build is failing with

File "/home/circleci/project/galleries/examples/units/radian_demo.py", line 26, in <module>        axs[0].plot(x, cos(x), xunits=radians)                       ^^^^^^      File "/home/circleci/project/galleries/examples/units/basic_units.py", line 382, in cos        return [math.cos(val.convert_to(radians).get_value()) for val in x]                         ^^^^^^^^^^^^^^    AttributeError: 'numpy.float64' object has no attribute 'convert_to'

@timhoffm
Copy link
Member

Please rebase.#28779 fixes the doc build.

@timhoffm
Copy link
Member

timhoffm commentedSep 4, 2024
edited
Loading

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".

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.

@jklymak
Copy link
MemberAuthor

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.

# helped because the axes are wider than they are tall. For more complicated
# situations it is necessary to place the axes manually.
#
# Manual placement
Copy link
Member

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

  1. pixel-perfect positioning (if you need that)
  2. in this case 1:1 mapping from data points to visual pixels.

Maybe these should be highlighted more.

@jklymak
Copy link
MemberAuthor

@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.

https://output.circle-artifacts.com/output/job/d67643fd-551a-4486-8c8a-409ddbdef5ba/artifacts/0/doc/build/html/gallery/images_contours_and_fields/image_exact_placement.html#sphx-glr-gallery-images-contours-and-fields-image-exact-placement-py

timhoffm reacted with thumbs up emoji

@timhoffm
Copy link
Member

I like this. It's clear without making too much fuss about the figsize topic.

Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
Copy link
Member

@timhoffmtimhoffm left a 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.

Comment on lines +7 to +8
fit inside the parent `~.axes.Axes`. This can mean that images that have very
different original sizes can end up appearing similar in size.
Copy link
Member

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:

Suggested change
fitinsidetheparent`~.axes.Axes`.Thiscanmeanthatimagesthathavevery
differentoriginalsizescanendupappearingsimilarinsize.
fitinsidetheparent`~.axes.Axes`.Asaresult,imageswithverydifferent
originalsizesmayendupappearingsimilarinsize.

Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
@jklymakjklymak merged commit6119c12 intomatplotlib:mainDec 5, 2024
22 checks passed
@QuLogicQuLogic added this to thev3.11.0 milestoneDec 5, 2024
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@rcomerrcomerrcomer left review comments

@timhoffmtimhoffmtimhoffm approved these changes

Assignees
No one assigned
Labels
Documentation: examplesfiles in galleries/examples
Projects
None yet
Milestone
v3.11.0
Development

Successfully merging this pull request may close these issues.

4 participants
@jklymak@timhoffm@rcomer@QuLogic

[8]ページ先頭

©2009-2025 Movatter.jp