[GRASS-user] Horizontal legend font size

Paul Moen wrote:

I want to create a horizontal legend for a raster.

The docs say,

> When using the mouse or at to size & place the
  legend, a user may create a horizontal legend by making
  the box wider than it is tall.

I read the previous line to mean the only way to create a
legend is to use at and make the box wider than it is tall.
Is that correct?

Yes.

Can I make a legend horizontal without using at=bottom,top,left,right

From the command line and xmons you can use 'd.legend -m' to place the

legend with the mouse. I am not sure if you get the same chance from
the GUIs or if the only option there is filling in at=.

The docs also say,

> Vertical legends produced with d.legend will place text
  labels to the right of the legend box, horizontal legends
  will place text below. This text will be auto-scaled to fit
  within the frame, reducing the size of the legend if
  necessary. Legends positioned with the mouse or with
  the at option will not auto-scale text, in order to provide
  more control to the user.

The last line that says that the text will not auto-scale
when using at,

correct. Only d.legend without at= or -m will autoscale. If manually
placed it will assume you know what you are doing and give you exactly
what you requested.

WRT horizontal scales, I think it only autoscales from the right side of the window, not the bottom. But anyway, full labels are useless in a
horiz legend, they just fall on top of each other.

but see below- what is being autoscaled is the category label.

e.g. "d.legend -n landcover.30m" in the spearfish dataset then adjust
the window so it is narrower and watch it autoscale.

which means that a horizontal legend¹s text will never auto-scale
since the horizontal legend can only be made by using at to create
a box that is wider than it is tall. Am I misinterpreting anything?

a couple of things:
you can make a box wider than it is tall on an xmon using the -m "place
with mouse" command line flag. The GUIs don't use xmons, which forces the
use of at=.

But what I meant by "text labels" is for categorical legends not tick numbers. e.g.:
[red] pine forest
[blue] deciduous forest
[grey] urban area
in this case the "pine forest" text would automatically shrink if it would
fall off the right side of the window.

For horizontal legends font size is purely a function of legend width.
(for vertical legends it is the legend height)
I guess for horiz legends I could look at rotating the font 90deg for
categorical legends with text labels (set with r.cats/r.category). But
I'd wait for strong user demand before spending any time on that.

My problem is that I get a horizontal legend that looks great except
the text is huge and looks awful.

you mean numbers (category or value) or text labels of categories?
could you provide a screenshot?

is this a floating point (FCELL or DCELL) or categorical (CELL) map?
[r.info]

How can I change the size of the text in the legend?

you need to recompile d.legend with the following patch:

Index: display/d.legend/main.c

--- display/d.legend/main.c (revision 32734)
+++ display/d.legend/main.c (working copy)
@@ -672,7 +672,7 @@
            if (!horiz)
                txsiz = (int)((y1 - y0) / 20);
            else
- txsiz = (int)((x1 - x0) / 20);
+ txsiz = (int)((x1 - x0) / 25);

            /* scale text to fit in window if position not manually set */
            /* usually not needed, except when frame is really narrow */

adjust the divisor to suit. The above patch makes the font super tiny
for legends which are around 2-3 inches wide, so I am loathe to apply
it in SVN. Maybe it would be better to make textsize it a fn of width^2
so the rate of change was not so dramatic.

The following are my commands.

d.rast raster@Temp
d.frame -c frame=leg at=1,10,5,95
d.legend -s range=0,13.5 labelnum=5 at=80,100,5,95 map=raster@Temp

after changing the scaling with the above patch, this looks nice for me:
  d.legend -s range=0,13.5 labelnum=4 at=50,90,5,95 map=

regards,
Hamish

On 13/08/08 09:42, Hamish wrote:

Paul Moen wrote:

How can I change the size of the text in the legend?

you need to recompile d.legend with the following patch:

Index: display/d.legend/main.c

--- display/d.legend/main.c (revision 32734)
+++ display/d.legend/main.c (working copy)
@@ -672,7 +672,7 @@
            if (!horiz)
                txsiz = (int)((y1 - y0) / 20);
            else
- txsiz = (int)((x1 - x0) / 20);
+ txsiz = (int)((x1 - x0) / 25);
             /* scale text to fit in window if position not manually set */
            /* usually not needed, except when frame is really narrow */

adjust the divisor to suit. The above patch makes the font super tiny
for legends which are around 2-3 inches wide, so I am loathe to apply
it in SVN. Maybe it would be better to make textsize it a fn of width^2
so the rate of change was not so dramatic.

How about making font and fontsize parameters of d.legend, so that the user can adjust ?

Moritz

Moritz wrote:

How about making font and fontsize parameters of d.legend,
so that the user can adjust ?

font is controlled by d.font and GRASS_FONT, so no need to set that from
the module.

I have a dark memory that in the past someone hacked in such an option for fontsize=. Perhaps it was for another module. To avoid feature creep, and keep the module from getting overwhelmingly complicated, I would prefer in the first instance to get the auto-scaling right by default. I think we are close with that. Then the user doesn't have to mess around with a million controls and it forces us to do a better job picking those defaults. If we get it right, they never even consider to change it.

My thoughts on adding new features to ps.map are similar; but neither are
set in stone, I just want to somewhat dampen the hacker urge to have massive .rcfiles everywhere.

shrug,
Hamish

What I am doing is creating a map dynamically for our web. The grass part
of the script is,
            g.mapset mapset=Temp 2>>$errtext
            v.in.ascii input=$textFile output=$RasName fs='tab' x=3 y=4
skip=0 cat=1 2>>$errtext
            v.surf.rst input=$RasName@Temp layer=1 zcolumn=dbl_3 tension=40.
elev=$RasName2 dmax=5 dmin=2 2>>$errtext
            g.remove vect=$RasName 2>>$errtext
            r.colors map=$RasName2@Temp color=arb-precip 2>>$errtext
            r.out.tiff input=$RasName2@Temp compression=lzw -t
output=\"".$workingdir."/".$RasName."\" 2>>$errtext
            d.mon start=PNG 2>>$errtext
            d.frame -c frame=map at=11,100,0,100
            d.rast $RasName2@Temp 2>>$errtext
            d.vect counties@Temp fcolor=none type=boundary 2>>$errtext
            d.frame -c frame=leg at=1,10,5,95 2>>$errtext
            d.legend -s range=0,15.0 labelnum=5 at=70,99,7,93
map=$RasName2@Temp 2>>$errtext
            d.mon stop=PNG 2>>$errtext
            g.remove rast=$RasName2 2>>$errtext

On 8/13/08 2:42 AM, "Hamish" <hamish_b@yahoo.com> wrote:

Paul Moen wrote:

I want to create a horizontal legend for a raster.

The docs say,

When using the mouse or at to size & place the

  legend, a user may create a horizontal legend by making
  the box wider than it is tall.

I read the previous line to mean the only way to create a
legend is to use at and make the box wider than it is tall.
Is that correct?

Yes.

Can I make a legend horizontal without using at=bottom,top,left,right

From the command line and xmons you can use 'd.legend -m' to place the
legend with the mouse. I am not sure if you get the same chance from
the GUIs or if the only option there is filling in at=.

The docs also say,

Vertical legends produced with d.legend will place text

  labels to the right of the legend box, horizontal legends
  will place text below. This text will be auto-scaled to fit
  within the frame, reducing the size of the legend if
  necessary. Legends positioned with the mouse or with
  the at option will not auto-scale text, in order to provide
  more control to the user.

The last line that says that the text will not auto-scale
when using at,

correct. Only d.legend without at= or -m will autoscale. If manually
placed it will assume you know what you are doing and give you exactly
what you requested.

WRT horizontal scales, I think it only autoscales from the right side of the
window, not the bottom. But anyway, full labels are useless in a
horiz legend, they just fall on top of each other.

but see below- what is being autoscaled is the category label.

e.g. "d.legend -n landcover.30m" in the spearfish dataset then adjust
the window so it is narrower and watch it autoscale.

which means that a horizontal legend¹s text will never auto-scale
since the horizontal legend can only be made by using at to create
a box that is wider than it is tall. Am I misinterpreting anything?

a couple of things:
you can make a box wider than it is tall on an xmon using the -m "place
with mouse" command line flag. The GUIs don't use xmons, which forces the
use of at=.

But what I meant by "text labels" is for categorical legends not tick numbers.
e.g.:
[red] pine forest
[blue] deciduous forest
[grey] urban area
in this case the "pine forest" text would automatically shrink if it would
fall off the right side of the window.

For horizontal legends font size is purely a function of legend width.
(for vertical legends it is the legend height)
I guess for horiz legends I could look at rotating the font 90deg for
categorical legends with text labels (set with r.cats/r.category). But
I'd wait for strong user demand before spending any time on that.

My problem is that I get a horizontal legend that looks great except
the text is huge and looks awful.

you mean numbers (category or value) or text labels of categories?
could you provide a screenshot?

I have no categories, so it would be the values. You can see the output at
http://www.swc.state.nd.us/getPrecipMap.php
I would like to add a few more labels labelnum=7 with smaller text.

It would also be nice to turn off the borders on the frames, although that
is another topic.

is this a floating point (FCELL or DCELL) or categorical (CELL) map?
[r.info]

FCELL

How can I change the size of the text in the legend?

you need to recompile d.legend with the following patch:

Index: display/d.legend/main.c

--- display/d.legend/main.c (revision 32734)
+++ display/d.legend/main.c (working copy)
@@ -672,7 +672,7 @@
            if (!horiz)
                txsiz = (int)((y1 - y0) / 20);
            else
- txsiz = (int)((x1 - x0) / 20);
+ txsiz = (int)((x1 - x0) / 25);

            /* scale text to fit in window if position not manually set */
            /* usually not needed, except when frame is really narrow */

adjust the divisor to suit. The above patch makes the font super tiny
for legends which are around 2-3 inches wide, so I am loathe to apply
it in SVN. Maybe it would be better to make textsize it a fn of width^2
so the rate of change was not so dramatic.

I will see if I can figure out the recompiling to see how it works.

The following are my commands.

d.rast raster@Temp
d.frame -c frame=leg at=1,10,5,95
d.legend -s range=0,13.5 labelnum=5 at=80,100,5,95 map=raster@Temp

after changing the scaling with the above patch, this looks nice for me:
  d.legend -s range=0,13.5 labelnum=4 at=50,90,5,95 map=

regards,
Hamish

Paul T. Moen
pmoen@nd.gov
701-328-2434
701-328-3696 (fax)
ND State Water Commission

Moritz wrote:
> How about making font and fontsize parameters of d.legend,
> so that the user can adjust ?

Hamish:

font is controlled by d.font and GRASS_FONT, so no need to
set that from the module.

As a general solution, I wonder if we should add a new enviro var
GRASS_TEXT_SIZE, which R_text_size() would look for. If it was set
it would override whatever was passed to that fn. (use for both width
and height options which are usually the same)

?,
Hamish

Hamish wrote:

> > How about making font and fontsize parameters of d.legend,
> > so that the user can adjust ?

Hamish:
> font is controlled by d.font and GRASS_FONT, so no need to
> set that from the module.

As a general solution, I wonder if we should add a new enviro var
GRASS_TEXT_SIZE, which R_text_size() would look for. If it was set
it would override whatever was passed to that fn. (use for both width
and height options which are usually the same)

And also GRASS_LINE_WIDTH. And maybe GRASS_FRAME=t,b,l,r. But not text
rotation.

And then change all of these environment variables into GRASS
variables, and provide a d.config program to set/get them.

R_font(), R_text_size(), R_line_width() etc would still exist, but
would only change the settings for the current process, not
persistently.

We probably also want a global scale setting, which would affect
various dimensions which are currently hard-coded, e.g. the size of
axis ticks, etc.

--
Glynn Clements <glynn@gclements.plus.com>

The ability to set the text size and frame borders with environment
variables would be great and would solve my issues, which are merely
cosmetic.

On 8/14/08 8:39 AM, "Glynn Clements" <glynn@gclements.plus.com> wrote:

Hamish wrote:

How about making font and fontsize parameters of d.legend,
so that the user can adjust ?

Hamish:

font is controlled by d.font and GRASS_FONT, so no need to
set that from the module.

As a general solution, I wonder if we should add a new enviro var
GRASS_TEXT_SIZE, which R_text_size() would look for. If it was set
it would override whatever was passed to that fn. (use for both width
and height options which are usually the same)

And also GRASS_LINE_WIDTH. And maybe GRASS_FRAME=t,b,l,r. But not text
rotation.

And then change all of these environment variables into GRASS
variables, and provide a d.config program to set/get them.

R_font(), R_text_size(), R_line_width() etc would still exist, but
would only change the settings for the current process, not
persistently.

We probably also want a global scale setting, which would affect
various dimensions which are currently hard-coded, e.g. the size of
axis ticks, etc.

Hamish wrote:
> As a general solution, I wonder if we should add a new enviro var
> GRASS_TEXT_SIZE, which R_text_size() would look for. If it was set
> it would override whatever was passed to that fn. (use for both width
> and height options which are usually the same)

Glynn:

And also GRASS_LINE_WIDTH.

ok

And maybe GRASS_FRAME=t,b,l,r.

what about current frame name?
will frames even survive in some form for GRASS 7?

But not text rotation.

what's different about that one?

And then change all of these environment variables into
GRASS variables, and provide a d.config program to set/get them.
R_font(), R_text_size(), R_line_width() etc would still exist, but
would only change the settings for the current process, not
persistently.

and thus knock away a few more global variables from libgis...
I would wait to make them GRASS variables (and remove global) until
grass7.

We probably also want a global scale setting, which would affect
various dimensions which are currently hard-coded, e.g. the size of
axis ticks, etc.

I'll have to think about that more.

about d.legend's auto font auto-sizing based on legend length- I was
thinking about changing the calculation to be non-linear & so more even
a size from both a 250 pixel wide legend and a full width legend. Which
for normal use at current monitor size and resolution is great, but for
things like oversampling 4x then cubic rescale in GIMP for pretty output
or for the PS/SVG/etc drivers I wonder if it is better to keep it
perfectly scaled to the frame size rather than expecting the view to
always be targeted to the same number of pixels on the monitor.

e.g. the GpsDrive software (www.gpsdrive.de) was written some years ago
and uses a scale factor as a main part of the map tiles' georeferencing
meta data to show how big 1:50,000 should be on the screen. Trouble is it
was written when 15" 800x600 SVGA was the norm and these days that
calculation becomes an odd historical artifact. I'd like to avoid that.

Hamish

Hamish wrote:

> > As a general solution, I wonder if we should add a new enviro var
> > GRASS_TEXT_SIZE, which R_text_size() would look for. If it was set
> > it would override whatever was passed to that fn. (use for both width
> > and height options which are usually the same)

Glynn:
> And also GRASS_LINE_WIDTH.

ok

> And maybe GRASS_FRAME=t,b,l,r.

what about current frame name?
will frames even survive in some form for GRASS 7?

The display library maintains a single active frame. Frames don't
persist from one command to the next (hence d.frame no longer exists),
and a program can't create multiple named frames then switch between
them by name (which is one of the reasons why d.profile doesn't
compile).

But a program can choose to use a portion of the "screen" rather than
all of it, by using D_new_window[_percent]() (the name parameter is
kept for compatibility, but is ignored).

> But not text rotation.

what's different about that one?

I can't see any situation where the user would want to set it. Rotated
text only really makes sense if the program decides that it wants
rotated text, and allows for the rotation when positioning it.

Most programs arrange text based upon the text size and number of
characters, with an implicit assumption that it will be drawn
horizontally. The few that use rotated text set the rotation
themselves.

> And then change all of these environment variables into
> GRASS variables, and provide a d.config program to set/get them.
> R_font(), R_text_size(), R_line_width() etc would still exist, but
> would only change the settings for the current process, not
> persistently.

and thus knock away a few more global variables from libgis...
I would wait to make them GRASS variables (and remove global) until
grass7.

Everything which I'm proposing or actively working on is in relation
to GRASS 7.

I don't see much point to trying to add minor enhancements to the
display architecture for 6.x. And even if there was some point, it's
too much work.

Making even minor changes is a lot of work with the old architecture,
which is why I've gutted it for 7.x (e.g.: lib/raster is now precisely
one file, and 90% of that is wrappers; there's only 25 lines of "real"
code in total).

> We probably also want a global scale setting, which would affect
> various dimensions which are currently hard-coded, e.g. the size of
> axis ticks, etc.

I'll have to think about that more.

about d.legend's auto font auto-sizing based on legend length- I was
thinking about changing the calculation to be non-linear & so more even
a size from both a 250 pixel wide legend and a full width legend. Which
for normal use at current monitor size and resolution is great, but for
things like oversampling 4x then cubic rescale in GIMP for pretty output
or for the PS/SVG/etc drivers I wonder if it is better to keep it
perfectly scaled to the frame size rather than expecting the view to
always be targeted to the same number of pixels on the monitor.

Yes. Using fixed sizes is meaningless, due to vector output,
oversampling, 250dpi monitors, etc.

At some point I may add a global scale variable, so that a 640x480
image could be 6400x4800 units (scale=10) or 64x48 units (scale=0.1)
or anything. The idea is to catch any code which hard-codes
dimensions.

Even scaling to "screen" size (i.e. using percentages) isn't always a
solution. You probably don't want the same relative proportions for
both a 640x480 PNG file and an A0 poster.

--
Glynn Clements <glynn@gclements.plus.com>