Closed MarkWieczorek closed 3 years ago
This is neither a pygmt bug nor a GMT bug. This is how GMT works. For GMT modern mode, the paper size is about 10 meters by 10 meters, and the plot origin is located at the lower-left corner of the large paper, with offsets of 10 cm in both x and y directions. Giving X=0 and Y=0 means you're shifting the plot origin to the exactly lower-left corner of the paper, and there are no spaces for labels of the left and bottom sides.
GMT says the following
-X -Y Shift origin of plot to (
, ). Prepend r for shift relative to current point (default), prepend a for temporary adjustment of origin, prepend f to position relative to lower left corner of page, prepend c for offset of center of plot to center of page.
To me, this means that X=0 and Y=0 should not change the origin, because you are adding 0 to the current value.
Could you tell me what the default values of X and Y are if they are not zero?
In classic mode, the default paper size is A4 or US letter. If X and Y options are not used, the default plot origin for a new plot is controlled by these two settings. But, the default values for overlays are 0.
In modern mode, it's almost the same, but MAP_ORGIN_X and MAP_ORIGIN_Y are hard-coded in the source codes. I remember the defaults values are ~10 cm for modern mode.
Also see the explanations in the cookbook https://docs.generic-mapping-tools.org/latest/cookbook/options.html#plot-positioning-and-layout-the-x-y-options.
I just realized that the link above isn't updated for modern mode. So if you're not familiar with GMT classic mode, it may make you more confused.
I confirm that GMT has the same behavior as pygmt, but I am still not convinced that this should be the expected behavior for pygmt. Let me see if I can make my case.
Let's take a method like basemap
. In the present configuration, X and Y have different meanings between the first and second call of this method. In the first call
fig = pygmt.Figure()
fig.basesmap(projection='Q0/6i', region=[0, 360, -90, 90], frame='afg', X=0, Y=0)
X and Y set the absolute origin at (0, 0): i.e., the bottom-left of the page. However, if I call basemap again
fig.basesmap(projection='Q0/6i', region=[0, 360, -90, 90], frame='afg', X=0, Y=0)
X and Y shift the origin with respect to the current value. To me, it would be more loigical to do the following:
# create a figure, and set the origin to MAP_ORIGIN_X and MAP_ORIGIN_Y
fig = pygmt.Figure()
# create a figure, and set the map origin to arbitrary values
fig2 = pygmt.Figure(X=10, Y=5)
Then when you call
fig.basesmap(projection='Q0/6i', region=[0, 360, -90, 90], frame='afg', X=0, Y=0)
the X and Y offsets would be relative to the origin specified when creating the figure.
The reason I care is because I am writing my own plotting function that takes as input a preexisting pygmt figure and optional values for the X and Y offsets. The idea was to set the default values of the X and Y offsets to zero, and then pass these to pygmt if these weren't specified. However, with the way pygmt is set up now I would need to set the default offsets to None and then do something like
if xoffset is None:
fig.basesmap(projection=proj, region=region, frame=frame_str)
else:
fig.basesmap(projection=proj, region=region, frame=frame_str, X=xoffset)
I agree that the behavior of X and Y is not intuitive. What we can do in pygmt is limited by the core GMT. Currently I don't see a way to implement the behavior similar to what you just described. Let's see if others have better thoughts.
For your use case, a workaround is to set the default offsets to False
, then you can always use
fig.basesmap(projection=proj, region=region, frame=frame_str, X=xoffset)
As a start, I think that X=False
and X=None
should return the same result. Now, build_arg_string()
returns '-X=None'
for the latter, which I would say is a bug. This would solve most problems.
As discussed in #514, the behavior of -X0 and -Y0 is correct. We can do nothing unless GMT changes how -X and -Y works in modern mode. So I believe we can almost close the issue.
As a start, I think that
X=False
andX=None
should return the same result. Now,build_arg_string()
returns'-X=None'
for the latter, which I would say is a bug. This would solve most problems.
But this comment is interesting. Like True
or False
, None
makes no sense for GMT. build_arg_string()
should never returns arguments like '-XNone'
.
Everything works fine when making a single plot using
grdimage
when the offsetsX
andY
are not provided. Here is an example:However, if I provide the options
X=0, Y=0
, the plot is shifted to the lower left, and the left and bottom labels are cut off the plot:It appears that the left and bottom of the image are perfectly aligned with the bottom of the plot, suggesting that the size of the left and bottom labels has not been taken into account correctly.