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

Let a signed grid cross size mean centered or asymmetrical grid ticks #2877

Merged
merged 25 commits into from
Mar 23, 2020

Conversation

PaulWessel
Copy link
Member

See #2875 for context. Hope @KristofKoch can give it a test. Alternate giving a small x-grid interval and course y-interval to get the effect. E.g.,

gmt psbasemap -R-5/5/-5/5 -JM6i -P -Bafg1 -K > t.ps
gmt psbasemap -R-5/5/-5/5 -JM6i -P -Bxg1 -Byg5m -O -K --MAP_GRID_CROSS_SIZE=-6p  >> t.ps
gmt psbasemap -R-5/5/-5/5 -JM6i -P -Byg1 -Bxg5m -O --MAP_GRID_CROSS_SIZE=-6p  >> t.ps

@PaulWessel
Copy link
Member Author

Hi @KristofKoch, any luck it testing this branch?

@KristofKoch
Copy link
Contributor

Hi @PaulWessel, please give me another 36h … I'm currently at work in my day job. Will give it a try as soon as I can.

@PaulWessel
Copy link
Member Author

No worries. At my day-job too!

@PaulWessel
Copy link
Member Author

Thinking about possible improvements to this. Clearly, as implemented, it is assumed that there are gridlines present to support the ticks. So in an ideal world this would be one set of -Bs and -Bp to do the course and fine ticks. But your examples has three levels: course grid lines, finer longer ticks, and closely-spaced short ticks. We have no way of doing three settings (yet).

@PaulWessel
Copy link
Member Author

One option is something like this script (which does not do what I want yet, but I will explain below):

gmt begin map
	gmt basemap -R-2/2/-2/2 -JM6i -Bafg1
	gmt basemap  -Bpg2m -Bsg10m --MAP_GRID_CROSS_SIZE=-3p/-6p
gmt end show

Here we are saying that the longer, secondary ticks should occur every 10 minutes and the primary, shorter ticks should be placed every 2 minutes. However, this is all under the assumption that these ticks are only drawn along the earlier 1x1 degree gridlines. As it is now, we would just get lots of ticks every 10m and 2m. A solution would be to remember the previous gridline interval (keep track of last gridline interval used) and then when cross sizes are negative we use the previous gridline interval with the specified gridcross interval(s) to accomplish the desired plot. In the process I would let MAP_GRID_CROSS_SIZE accept the syntax primary/secondary for cross sizes. Currently it expects one item and sets both, but if given two separated by a slash we could assign the two separately. This is a script that gives what I think you want (the hard way):

gmt begin map png
	gmt basemap -R-2/2/-2/2 -JM6i -Bafg1
	gmt basemap  -Bpxg1 -Bpyg2m --MAP_GRID_CROSS_SIZE_PRIMARY=-3p -Bsyg1 -Bsxg2m --MAP_GRID_CROSS_SIZE_SECONDARY=-3p
	gmt basemap  -Bpxg1 -Bpyg10m --MAP_GRID_CROSS_SIZE_PRIMARY=-6p -Bsyg1 -Bsxg10m --MAP_GRID_CROSS_SIZE_SECONDARY=-6p
gmt end show

with result

map

@KristofKoch
Copy link
Contributor

Hi Paul,

that virus is wreaking havoc at work … but finally:

I like your proposed new syntax. Is there a way to get it to work for even more (many!) sets of tick marks?

Something like -Bg1m/g5m/g10m/g30m --MAP_GRID_CROSS_SIZE=-2p/-3p/-6p/-9p

And as I'm already dreaming things up – is there a way to get tick marks extend both sides of the grid line (not a cross)?

I don't know if "=" is a good choice in terms of parsing but in my mind it would be something like "-" = one side, "=" = both sides of the grid line. So this:

-Bg1m/g5m/g10m/g30m --MAP_GRID_CROSS_SIZE=-2p/-3p/=6p/=9p

would lead to something like this:

grids

where you have the single side ticks (1' & 5') mixed with double-sided tick marks (10' & 30').

The reason why I don't want a cross are tick marks at high latitudes with Lambert conic conformal or polar stereographic projections. Here the latitude grid lines bend so much that the crosses become visible.

@KristofKoch
Copy link
Contributor

And while you are on it – any chance to have the tick marks 0°/180° longitude and 0° latitude extend both ways?

Here the example for 0° longitude and 0° latitude taken from ONC M-2:
onc_m-2

And the example for 180° longitude and 0° latitude taken from ONC M-16:
onc_m-16

I guess there are users who are more interested in the looks than in the actual usability case so maybe they might not like to have them extend both ways. Another option?

@KristofKoch
Copy link
Contributor

And another possible improvement … maybe there is a chance to specify pen thickness on a per tick mark basis as well? The 1' ticks having a thinner pen than the 30' ticks?

Maybe I can help by writing the documentation for those features?

@PaulWessel
Copy link
Member Author

Hi @KristofKoch, I will think about this. I don't think we will allow a 3rd tick/pen in one go, so since these maps count for 0.001% of GMT maps it is OK if you have to run a few commands to get it - you can always write a function of alias for something like that if you need it often.

@KristofKoch
Copy link
Contributor

Hi @PaulWessel, I agree with you that more than two ticks are rarely needed and can easily achieved if desired. None the less I take pride in being responsible for 0.001% of all GMT maps ;-)

@PaulWessel
Copy link
Member Author

Hi @KristofKoch. A small update: If grid cross sizes are specified with a leading + then they become symmetrical ticks, a leading - still means asymmetrical ticks, and no leading sign means regular grid cross. Please give this a try and see if you can demonstrate to me how it may fail for high latitudes, then post a short basemap script here so I can test further. I suspect I need to do more work to cover the case you mention.

@KristofKoch
Copy link
Contributor

Hi @PaulWessel, thank you for working on this. I gave 6.1.0_7c0ba1d_2020.03.19 a test. I found a few issues. For ease I just used lon or lat ticks.

Pen stroke:

It gets funny if I use a pen thicker than the grid lines:

gmt begin MAP_GRID_PEN_PRIMARY
  gmt basemap -R-2/2/-2/2 -JM6i -Bafg1
  gmt basemap  -Bpxg1 -Bpyg5m --MAP_GRID_CROSS_SIZE_PRIMARY=-3p --MAP_GRID_PEN_PRIMARY=3p 
gmt end show

MAP_GRID_PEN_PRIMARY

High latitudes:

There seems to be no difference between --MAP_GRID_CROSS_SIZE_PRIMARY=+100p (which are supposedly symmetric ticks) and --MAP_GRID_CROSS_SIZE_PRIMARY=100p (which are supposed to be crosses):

gmt begin symmetric
  gmt basemap -R-10/10/68/72 -JS0/90/60/6i  -Bafg10
  gmt basemap  -Bpyg5 -Bpxg5d --MAP_GRID_CROSS_SIZE_PRIMARY=+100p --MAP_GRID_PEN_PRIMARY=red
gmt end show

symmetric

gmt begin cross
  gmt basemap -R-10/10/68/72 -JS0/90/60/6i  -Bafg10
  gmt basemap  -Bpyg5 -Bpxg5d --MAP_GRID_CROSS_SIZE_PRIMARY=100p --MAP_GRID_PEN_PRIMARY=red
gmt end show

cross

There is a good chance I'm using the -B syntax wrong. How do I get rid of the lon ticks which are peaking out of the lat grid line?

Looking at asymmetric ticks I have a similar problem as with the two above. There still is a lon tick which escapes the grid line:

gmt begin asymmetric
  gmt basemap -R-10/10/68/72 -JS0/90/60/6i  -Bafg10
  gmt basemap  -Bpyg5 -Bpxg5d --MAP_GRID_CROSS_SIZE_PRIMARY=-100p --MAP_GRID_PEN_PRIMARY=red
gmt end show

asymmetric

Is it me again not using -B properly?

For grid ticks one must first lay down a single (primary) set of gridlines, then that spacing sets the line spacing for the denser grid ticks (primary and secondary).  I generalized functions used to set and get current CPT to avoid duplicated code.
@PaulWessel
Copy link
Member Author

PaulWessel commented Mar 21, 2020

Thanks @KristofKoch, I have made many changes to address the shortcomings. Note the grid tick feature below is only available to modern mode:

  1. Gridline ticks are considered a form of embellishments of gridlines. Thus, you must always first lay down the single (primary) set of gridlines you wish to embellish. This dx,dy interval is remembered.
  2. Next, you specify the actual grid tick spacing you want and we will use the saved gridline spacing to select the gridlines along which we do the placement of centered or asymmetric ticks.
  3. We now draw ticks, not crosses.

As an example, this test first lays down a 1x1 degree set of gridlines, then applies both 10m symmetrical and 2m asymmetrical grid ticks with one basemap command.

gmt begin asymm_grid ps
	gmt basemap -R-2/2/-2/2 -JM6i -Bafg1 -B+f
	gmt basemap -Bpg10m -Bsg2m --MAP_GRID_CROSS_SIZE_PRIMARY=+8p --MAP_GRID_CROSS_SIZE_SECONDARY=-4p --MAP_GRID_PEN=default,black
gmt end show

This script produces the plot below. So one call for coarse gridlines, one call to do the two sets of ticks. You can repeat for even more complications. Each graphics item (subplot panel, inset, figure) maintains its own memory for gridlines since you must draw them first for each such item. The memory lasts until another set of gridlines are drawn or the plot completes.

asymm_grid

Please give it a spin for other latitudes and projections. I also compute centered slope so your tick on the vertical central meridian will be horizontal, not tilted.

@KristofKoch
Copy link
Contributor

Hi @PaulWessel these are big improvements. Awesome! I gave 6.1.0_db366d6_2020.03.20 a test and in generally behaves as expected with the "new" syntax. However a small problem remains: At high latitudes the ticks still peak out from the bent latitude grid lines. The placing is logically sound. I want a tick every 1°, I get one. Exaggerated example:

gmt begin asymmetric_high_lat
  gmt basemap -R-10/10/78/87 -JS0/90/60/6i  -Bafg5
  gmt basemap -Bpg1d --MAP_GRID_CROSS_SIZE_PRIMARY=-100p --MAP_GRID_PEN_PRIMARY=red
gmt end show

asymmetric_high_lat

They even make the step down at N85° in lon density. Great! But unfortunately some ugliness when plotted at a lat/lon grid line junction. Maybe there is an easy way to omit them there?

And another thing – any chance to get the functionality in classic mode as well? My workflow relies heavily on just generating those layers with updated data and then sandwich it together with all the other preproduced and stored layers in a second step to keep generation time low.

@PaulWessel
Copy link
Member Author

Hi @KristofKoch. It makes sense not to draw the ticks exactly at the gridlines since the latter are curved and the ticks are straight. I think that is what you mean. I can probably fix that.

As for classic: It cannot do the remembering. However, you should be able to do it the way we started off with, where you alternate course and detailed ticks.

@KristofKoch
Copy link
Contributor

Hi @PaulWessel – good evening to Hawai'i. That's exactly what I meant with my convoluted sentence above. Don't draw the ticks if placed exactly at the grid lines.

@KristofKoch
Copy link
Contributor

66129f4 does what it promises. Thanks!

@KristofKoch
Copy link
Contributor

KristofKoch commented Mar 22, 2020

A thought on the polar cap discussion:

My idea with showing only primary ticks was under the assumption that the primary ticks are those with the wider spacing – a look in the docs showed that the convention seems to be the other way around. I think you understand what I mean – just show the wider spaced ticks.

@PaulWessel
Copy link
Member Author

Will get to this after family FaceTime with remote kids.

@PaulWessel
Copy link
Member Author

I will tick the polar cap parallel(s). For the coarse gridlines toward the poles I think we only do the primary grid ticks, but I will experiment. The grid line spacing up there is controlled by MAP_POLAR_CAP.

@KristofKoch
Copy link
Contributor

The full set of ticks at the cap parallels? Or a reduced (primary ticks only) set?

@PaulWessel
Copy link
Member Author

Full set of ticks on the polar cap - like the other parallels, but only coarser on the meridians. However, perhaps it may make more sense to do just coarser ticks on both.

I write courser because primary and secondary labels is a bit backwards in the sense that for time axis the smallest spacing is called primary and the coarser spacing is called secondary. So above, we may drop to just secondary since space is getting limited. I could also automatically pick the coarsest of the two to avoid any confusion.

@KristofKoch
Copy link
Contributor

I'm not sure if there is a "perfect" solution for the cap parallels – If I look at the full globe (-JG) example above the full set would look ugly as it would be only a thick blue ring. Using -JS the whole thing might look completely different.

Thank you for clarification where the primary and secondary comes from … I was quite a bit surprised to learn this in the docs. I agree for geo purposes it "feels backwards".

@KristofKoch
Copy link
Contributor

Toying around with this a bit further I agree with you that it may make most sense to do just the coarser ticks on both. Because if there is enough space for the denser ticks I can as well move MAP_POLAR_CAP further towards the pole as there is no need for the simplification at the current latitude.

The "auto-pick-coarsest-ticks" would be a nice thing to have as well. Might also suppress some questions in the forums.

@PaulWessel
Copy link
Member Author

PaulWessel commented Mar 23, 2020

Need feedback from @joa-quim and @seisman on this:

The concept of primary and secondary annotations/ticks/gridlines originated with time-axes where it is often required to annotate more than one unit. In these cases, we use the primary term to mean the annotation closest to the axis and the secondary term to be the one further out. For time axes this always meant that primary intervals were smaller than secondary intervals:

GMT_-B_time1

For geographic maps with two sets of annotations (rarely used) we actually do the same:

GMT_-B_geo_2

Thus, for the case at hand (grid ticks) we must stay with the same scheme. Hence, for grid-ticks associated with polar caps I will use the coarser secondary gridline spacing, assuming it is the coarser. However, @KristofKoch example above switched the two and he used the coarser as primary and the detailed as secondary. This can lead to confusion. Possible remedies:

  1. We can impose the syntax rule that primary interval < secondary interval and give an error if that is not followed.
  2. We can simply assume the user did what we say and plot normally. In @KristofKoch example he may be surprised to find his smaller interval being used within the polar caps.
  3. We can check which interval is the smallest and if backwards we simply use an index array PS[2] that by default is {0,1} but can be changed to {1,0} in this case and we use the index array to access the two settings for intervals, pen, etc. I.e., in a loop k = 1,2 over primary, secondary we use the index PS[k] to get pen or interval instead of the current [k]. Alternatively, we simply sort all the primary, secondary parameters (ticks, fonts, intervals, etc., etc.) after parsing -B so we know the order is as anticipated. This would avoid more coding in the plot functions.

I think option 3 is the best since it follows our intention and also handles any user mixup. We may wish to give a warning when this happens. Comments?

@joa-quim
Copy link
Member

The concept of primary and secondary annotations/ticks/gridlines originated with time-axes

Historical correction. This concept was born when I, on board of French ships, saw their maps with double annotations made with their Caraibes Sun software and started bugging you to have the same in GMT (much like Kristof now).

I have not been following this matter closely (busy with GEOS) but yes, option 3 is the more versatile one.

@PaulWessel
Copy link
Member Author

Yes, that is true for maps. I don't remember if geo came before time. Time happened around 2004 (for GMT 4I think).
Looking at implementing option 3.

This uses coarser interval as secondary.  Another PR will deal with sorting primary vs secondary so the -Bs vs -Bp will be less of an issue.
@joa-quim
Copy link
Member

Made a 1 month cruise in 1998 on board of l'Atalant. Probably from around that time.

@PaulWessel
Copy link
Member Author

Hi @KristofKoch, please check this out once more. The changes are:

  1. If you give primary as the larger interval we will swap with secondary, since GMT logic dictates this order. This switches the -Bp and -Bs settings but does not change other things. You get a warning and probably the wrong pens and tick settings.
  2. The secondary tick information is used on the polar cap parallels and the polar cap meridians.

@KristofKoch
Copy link
Contributor

Wow – @PaulWessel that's impressive work. Thank you very much! I feel it is about time to send another beer (maybe a keg would be more adequate) your way for all the work I'm causing.

  1. 1538dd2 does as you say: -Bp and -Bs switch but the pen settings remain the same and I get a warning message.
    • Im not sure if this causes havoc with some existing scripts as it wasn't a problem before this implementation when -Bp was coarser than -Bs.
    • For me the warning message leaves a bit to be desired – maybe you can add the hint that secondary should be coarser than primary and that pens are not switched? Or switch the pen definition as well to get an expected result? Switching pens as well would maintain compatibility with existing scripts with erroneous -B usage which worked until today. I know what we are talking about here but I think if I get this message in a couple of years with a plot where the pens are wrong I'll have little to no idea where to start looking.
  2. Works as expected. Awesome!

@PaulWessel
Copy link
Member Author

I am trying to avoid having to swap ~10 different parameters that have _PRIMARY and _SECONDARY in them - see gmt.conf.rst for all those parameters (pens, tick lengths, colors, etc., etc.).
However, I am OK with just warning and explain what GMT expects but not swap anything. That will let old scripts run but the new polar tick stuff will be wrong so you will want to change new scripts.

@KristofKoch
Copy link
Contributor

KristofKoch commented Mar 23, 2020

@PaulWessel I see your point. I think your proposal is the more sensible way.

Warn and explain always - even if polar cap is not involved - but don't swap anything. Thus old scripts keep working (and get a hint on how to improve them) and there should be no new scripts besides my few test scripts yet. So win-win?

@PaulWessel
Copy link
Member Author

Hi @KristofKoch, I have improved the documentation for -B in usage and rst files to clarify that primary sets the more frequent annotations while secondary sets the less frequent intervals. This was largely missing except in the context of time axes.

I have also changed my test above to just warn and explain, with no forced swapping. This should alley fears of breaking backwards compatibility. I think this PR is good to merge now, yes?

@PaulWessel
Copy link
Member Author

I am answering my question: Yes good to merge. Happening now.

@PaulWessel PaulWessel merged commit e89bfdd into master Mar 23, 2020
@PaulWessel PaulWessel deleted the asymmetrical-grid-ticks branch March 23, 2020 22:19
@KristofKoch
Copy link
Contributor

Good morning from the other side of the blue marble, looks good to me as well. @PaulWessel , thank you for your efforts! This makes my life a lot easier.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants