Skip to content
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

Figure.shift_origin() does not work #514

Closed
MarkWieczorek opened this issue Jul 11, 2020 · 16 comments · Fixed by #580
Closed

Figure.shift_origin() does not work #514

MarkWieczorek opened this issue Jul 11, 2020 · 16 comments · Fixed by #580
Labels
bug Something isn't working upstream Bug or missing feature of upstream core GMT

Comments

@MarkWieczorek
Copy link
Contributor

The method shift origin does not work. This simple example never terminates in ipython

import pygmt
fig = pygmt.Figure()
fig.shift_origin(xshift='1i', yshift='2i')

In a jupyter notebook, using shift origin instead kills the kernel and provides this message:

gmtinfo [ERROR]: No input data found!

In addition to this, there is a broken link in the web documentation to a this page in gmt:

pygmt: last commit
gmt: 6.1

@seisman
Copy link
Member

seisman commented Jul 11, 2020

Yes, that's a big limitation of the shift_origin() function. You can't use it as your first plot command, because it needs to know projection (-J) and region (-R) from the history.

@seisman seisman added the bug Something isn't working label Jul 11, 2020
@seisman
Copy link
Member

seisman commented Jul 11, 2020

shift_origin() is a wrapper of GMT command gmt plot -T -Xxshift -Yyshift, so it required -J and -R set before calling the function.

I thought the function can be improved by wrapping another GMT command

gmt plot -JX1c -R0/1/0/1 -T -Xxshift -Yyshift

then shift_origin() will have its own -J and -R, so it can be used as the first call of a PyGMT figure. However, the command above will overwrite the -J and -R* settings in gmt.history.

Setting GMT_HISTORY to false, i.e., the command below, should avoid overwriting the old settings, but it doesn't works as I expect.

gmt plot -JX1c -R0/1/0/1 -T -Xxshift -Yyshift --GMT_HISTORY=false

I've opened an issue (GenericMappingTools/gmt#3643) and see if it's a GMT bug.

@MarkWieczorek
Copy link
Contributor Author

For my use case, I would be ok if shift_origin did nothing if it was operating on a blank figure for the first time.

I have a custom plotting routine, and it takes as input a prexisting fig and optional X and Y offsets. In practice, whenever you would call the function the first time, X and Y would be None, or zero. Of course, I can easily work around this in my own code, but as a fallback option, pygmt doing nothing would be better than crashing!

@seisman
Copy link
Member

seisman commented Jul 11, 2020

Yes, I agree. It need to be improved. Let's wait for the feedback from upstream GMT first.

@seisman seisman added the upstream Bug or missing feature of upstream core GMT label Jul 18, 2020
@seisman
Copy link
Member

seisman commented Jul 18, 2020

There is no workaround for GMT 6.1.0. PR #536 fixes the broken link in the documentation and also documents the limitation of this function.

In GMT>=6.1.1, gmt plot -T no longer required -R and -J (see the fix in GenericMappingTools/gmt#3672), then it should work as expected.

This issue is marked as "upstream". When PyGMT bumps the minimum required GMT version to GMT>=6.1.1, we should add a test for it and close the issue.

@MarkWieczorek
Copy link
Contributor Author

I just tested shift_origin using the new GMT PRs, and it is mostly working. Nevertheless, there is still a problem when calling shift origin with values of zero before creating the first image. In essence, it appears that shift_origin() in this case performs an absolute shift, as opposed to a relative shift. Even when you append r to force this to be a relative shift, shift_origin performs an absolute shift.

And as far as I know, the current origin of the first plot is not (0, 0), but is rather shifted a small amount (0+dx, 0+dy) so that the labels aren't cropped. The documentation states that

prepend r [Default] to move the origin relative to its current location.

fig = pygmt.Figure()
fig.basemap(J='X10/5', R='0/360/-90/90', B='a30f30')

fig2 = pygmt.Figure()
fig2.shift_origin(xshift='0i', yshift='0i')
fig2.basemap(J='X10/5', R='0/360/-90/90', B='a30f30')

fig3 = pygmt.Figure()
fig3.shift_origin(xshift='r0i', yshift='r0i')
fig3.basemap(J='X10/5', R='0/360/-90/90', B='a30f30')

fig.savefig('default.png')
fig2.savefig('shift-zero.png')
fig3.savefig('shift-zero-r.png')

No shift

default

Shift '0i' before creating image

shift-zero

Shift 'r0i' before creating image

shift-zero-r

@seisman
Copy link
Member

seisman commented Aug 6, 2020

And as far as I know, the current origin of the first plot is not (0, 0), but is rather shifted a small amount (0+dx, 0+dy) so that the labels aren't cropped.

You're right. In classic mode, the dx and dy are 72 points (i.e., 1 inch). In modern mode, I believe they're 5 inches.

The three figures you shown are expected from GMT CLI.

For GMT, the first plotting command is very special. If no -X and -Y are used, the default origin is (72p, 72p). You can think that -Xr1i and -Yr1i are automatically added to the first plotting command in this case. However, if you gives -X and/or -Y in the first plotting command, they override the default values. So your -Xr0i and -Yr0i actually put the plot origin at (0,0), and the left and bottom labels are all cropped.

This is how GMT does for a long time. PyGMT can do nothing here, because PyGMT don't know if this is the first plotting command or not (although maybe we can add the counter). I'm not sure what GMT can do without backward incompatibility. @PaulWessel

@PaulWessel
Copy link
Member

Yep. Classic GMT is tied to the concept of a sheet of paper, and if you move off it that things get clipped. With modern mode we basically have no paper size (but it is there, just limited to 11x11 meters by ghostscript) and we decided to let the origin be at (5i,5i) to ensure no surprises. But even that is not foolproof. If you make your first plot and then move negatively down/left you will eventually hit the paper edge, and 5 inches is not particularly large if you are thinking in terms of paper dimensions. Perhaps we should use (1m,1m) instead so any surprise would only affect people making plots that are several meters in dimensions. We also had trouble with various bugs in ghostscript that defeated our margin settings but I think we are past that now. I think the GMT developers should consider setting that margin to (1m,1m).

@MarkWieczorek
Copy link
Contributor Author

However, if you gives -X and/or -Y in the first plotting command, they override the default values.

Ok. But that behavior is undocumented and not consistent with the documentation:

Prepend r for shift relative to current point (default)... prepend f to position relative to lower left corner of page.

The default is thus to always use relative offsets, so why not just use relative offsets with respect to the default origin for the first plot ? If you really wanted to place the plot at (0, 0), you would use -Xf0 -Yf0.

@PaulWessel
Copy link
Member

I just looked at the docs and to me I think we state the case that the default shift is 0,0 unless it is the first command and then it is 72p. Those are the defaults. If you give -X0 - Y0 on the first plot then stuff fill fall off the page in classic mode.
Your suggestion is not wrong, but it would be a major backwards compatibility break. We dealt with many of those breaks by introducing modern mode.

@seisman
Copy link
Member

seisman commented Aug 6, 2020

Your suggestion is not wrong, but it would be a major backwards compatibility break. We dealt with many of those breaks by introducing modern mode.

Can we introduce the change for modern mode (non-PS output) only?

@PaulWessel
Copy link
Member

Sorry if I missed the point but with a 5 inch margin already being cropped when making non-PS output, the initial origin is arbitrary anyway now so what would be achieved?

@seisman
Copy link
Member

seisman commented Aug 6, 2020

the initial origin is arbitrary anyway

I believe that's not true if you use -X0 and -Y0 in the first command. -X0 -Y0 moves the default plot origin from (5i,5i) to (0,0) in modern mode.

@PaulWessel
Copy link
Member

OK, if that is the case then we have a problem.

@MarkWieczorek
Copy link
Contributor Author

I just looked at the docs and to me I think we state the case that the default shift is 0,0 unless it is the first command and then it is 72p. Those are the defaults. If you give -X0 - Y0 on the first plot then stuff fill fall off the page in classic mode.
Your suggestion is not wrong, but it would be a major backwards compatibility break. We dealt with many of those breaks by introducing modern mode.

Ok. I think I understand what is happening. For the first plot, the default origin is set to (0,0). Then, if you don't specify -X and -Y (which you probably wouldn't under normal circumstances) the values of -Xr72p -Yr72p are passed in order to shift the plot origin to (72p, 72p).

My mistake was thinking that the default origin of the first plot was set to (72p, 72p), and that by specifying -Xr0 nothing would happen as there would be a 0p relative shift with respect to (72p, 72p).

Let me stress that this issue is not important to me! Nevertheless, one potential way to clarify things might be to (1) set the default origin to (72p, 72p), and (2) not to pass -Xr72p -Yr72p as default values for the first plot. Please don't waste your time on this unless you think it is important :)

@PaulWessel
Copy link
Member

No worries, Mark.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working upstream Bug or missing feature of upstream core GMT
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants