Dynamic font color selection

I’m looking for suggestions & tips on a sensible way to automatically select a font color, black or white in my case, for place names to be written on top of a colorized surface (I.e.made with grdimage). I’m using the color scale, roma, and the deeper reds and blues (at both ends of the color scales) are where white lettering would work best, and the lighter greens, yellows and powder blue hues (in the middle of the scale) is where black lettering would work best.

Given that the -T specification is known (used in makecpt), and given the location of the text, all that needs doing is to use grdtrack to sample the grid for the elevation (or Z parameter), then pass it through a simple decision tree that would choose to write each place name in a black or white font color

Does that seem to be a reasonable approach? Just need to study the Roma scale carefully to set how far into the scale it would need to be in order to switch from white to black, and from black back to white at the higher end of the color scale.

Any other ideas are most welcome.

1 Like

Interesting question - my first guess would likewise be to determine which Z values should correspond to white/black and then pipe the pstext string with its location values through grdtrack to then use awk to determine color depending.

That is very helpful.

In my case, it makes sense to first select place names (which are distributed globally) that fall inside the map boundaries. Then, send those coordinates through grdtrack to get elevations (Z-values), then run that list through an awk command which does the decision making before routing to pstext. Should be fast and compact!

I’ve been in similar situations and adopted a different approach – to use the “outline” facility in pstext which draws the outline of the characters. So do that with a white pen a few points wise, then repeat drawing the characters normally, an extract of the code:

# labels

DOTFONT="16,Times-Italic"
DOTOUTLINE="$DOTFONT,-=2p,white"

gmt pstext dots.dat -Dj4p -F+a0+f$DOTOUTLINE+j $PRJ $RNG -K -O >> $PS
gmt pstext dots.dat -Dj4p -F+a0+f$DOTFONT+j $PRJ $RNG -K -O >> $PS

and the result:

Screenshot from 2024-05-16 19-32-59

Full script here.

Cheers

1 Like

That is a nice alternative, too, JJ. Thanks for the suggestion. Very professional appearance. Very nice how the black line continues through the inside of the lower lobe of the B.

I’ve used repeated calls to pstext to imitate a drop shadow.

In the present case, adapting your suggestion would work, but I’d prefer not to obscure things any more than I have to. Just want the text to show up better in light and dark regions of the map. White text looks great on dark backgrounds, but is too hard to discern, or nearly disappears, in light shades.

Would also apply a divergent-grayscale cpt to the text work?

Edit: sorry, I had a dynamic visualization in mind instead of a surface

Edit2 : isn’t there a way to « clip » the letter and apply a surface color on it? The doc says that it is possible to do so with the textbox at least… but maybe « clip » can go further ?
plus this

After some experimentation, using Becker’s approach, I ultimately chose to go with JJ’s solution. This seemed to show feature names well enough.

Thanks for all the suggestions!

This should be a showcase and/or an example in the docs.

This also works with e.g. grdcontour (maybe all modules dealing with text?).

Crude example:

gmt begin font-test png

DOTFONT="6,Times-Italic"
DOTOUTLINE="$DOTFONT,-=2p,white"

gmt grdimage @earth_relief_03m -RIHO6 -JM10c
gmt grdcontour @earth_relief_03m -C500 -Ln -A+a0+f$DOTOUTLINE
gmt grdcontour @earth_relief_03m -C500 -Ln -A+a0+f$DOTFONT

gmt end show

2 Likes

looks good!

the first grdcontour call can be modified with -W1.5p,white so these black contours also get some sort of white outline and become more visible in the deeper areas.

1 Like

Funny, tastes. That hurts my eyes and I remember the discussions I had with Paul to allow contour labels to follow the contours and not to draw on a white box, which is how it was at the beginning.

yeah white background maybe looks like too much contrast. But it does not have to be white. Some sort of light grey, light blue, whatever fits the selected color scale.

Sounds good but I have this doubt. The name occupies a surface, not a point. So, maybe you select a good color for center but not the borders.

I think this “warner” user is some sort of a spam bot

see an irrelevant web link in this comment X,Y to Lon, Lat conversion for New Zealand Transverse Mercator 2000 - #6 by warner

bullshit comments in some other threads

Yes, I agree and just deleted the user.

1 Like

Playing around with the text-outline option and looking into the filled_font.sh test, I found that with a ~ (is it documented?) we can do it in a single pstext call. It needs a -F+f and the outline setting like in this example (where we can still drop the 48p,Helvetica-Bold, if we want to use defaults).

echo 7 7 48p,Helvetica-Bold,black=~3p,green blue | gmt text -R0/18/0/15 -Jx1c -B5g1 -BWSne  -F+f+jBL -png lixo

1 Like

outline fonts sometimes look very sexy!

There is some documentation here text — GMT 6.5.0 documentation : To draw outline fonts you append =pen to the font specification

no idea why ~ is needed, the below code produces visually very similar result without ~ with pen size reduced to 1p (with ~3p,green the outline looks approx 3x thicker):

echo 7 7 48p,Helvetica-Bold,black=1p,green blue | gmt text -R0/18/0/15 -Jx1c -B5g1 -BWSne  -F+f+jBL -png lixo

UPD oh, the ~ seems drawing the black letters on top of the outline, thus adding outline only outside the black letters, while without ~ the outline is drawn on top of the text party (or completely) covering the black letters:

echo 7 7 48p,Helvetica,black=20p,green blue | gmt text -R0/18/0/15 -Jx1c -B5g1 -BWSne  -F+f+jBL -png lixo

echo 7 7 48p,Helvetica,black=~20p,green blue | gmt text -R0/18/0/15 -Jx1c -B5g1 -BWSne  -F+f+jBL -png lixo

Yes, that’s it. Using the ~ makes a lot of effect.