Opened 6 years ago

Closed 6 years ago

Last modified 6 years ago

#2382 closed defect (wontfix)

d.legend: integer map legends should not be flipped upside-down

Reported by: neteler Owned by: hamish
Priority: normal Milestone: 7.0.0
Component: Display Version: svn-releasebranch70
Keywords: d.legend Cc: grass-dev@…
CPU: Unspecified Platform: All

Description

Legend of integer (CELL) maps are shown upside-down with the lowest value on top. This enforces the user to always activate the -f flag:

# NC location
g.region rast=basin_50K
d.mon wx0
d.rast basin_50K
d.legend basin_50K

# other example

d.legend basin_50K
r.mapcalc "elev_int = round(elevation)"
r.colors elev_int color=srtm
d.erase
d.rast elev_int
d.legend elev_int -s
## --> upside-down, see screenshot

Expected: the legend should be with the lowest value down and the highest up as it is for floating point maps.

Maybe trivial to fix but I am not sure where to add a "flipit" in the main.c

Attachments (2)

flipped_integer_rast_legend_bug.jpg (44.1 KB) - added by neteler 6 years ago.
Flipped integer map legend
nc08_towns_legend.png (2.1 KB) - added by hamish 6 years ago.
demo of categorical legend

Download all attachments as: .zip

Change History (10)

Changed 6 years ago by neteler

Flipped integer map legend

comment:1 Changed 6 years ago by hamish

Cc: grass-dev@… added

It is like that for CELL maps on purpose and working as designed; it's favouring categorical CELL maps over continuous value CELL maps.

In the NC08 dataset consider: d.legend towns

(see attached screenshot)

I think we can all agree that counting from category 1 (smallest value) at the top is how we would like that to be.

However, if there are more categories in the map than will fit on the display frame d.legend automatically switches to a smoothed gradient legend to avoid the user having to use the thin=, lines=, range=, or use= options to cut down the number of boxes it tries to draw.

So it comes down to the question of is the data categorical (in which case smallest value is at the top) or continuous gradient which happens to be stored as integers (in which case smallest values is at the bottom). Since CELL maps can be used for both there is no single correct answer to that, and so the module goes with the logic that if the range of available cats or the frame size happens to change by a little bit, pushing it over the threshold, it will change the boxes into thin lines, but the overall view will remain the same, it has just gone into "compressed mode".

note I built in two handy tricks to get the flip to happen without the -f flag: in GRASS 6 (and with at= in G7) when drawing the box with the mouse draw from bottom up instead of top down, and another way is to reverse the order of values in the range= option.

regards, Hamish

Changed 6 years ago by hamish

Attachment: nc08_towns_legend.png added

demo of categorical legend

comment:2 Changed 6 years ago by hamish

Owner: changed from grass-dev@… to hamish
Status: newassigned

comment:3 Changed 6 years ago by cmbarton

With a background in archaeology and earth sciences, I normally expect the smaller (i.e., older or lower) value to be at the bottom. But Hamish makes a good case for why others would want it at the top for categorical maps. The -f flag is not much of a pain. So I'm not sure it is worth changing a very long-standing default. I suppose it could break a few scripts to do so (but probably not many).

Michael

comment:4 in reply to:  1 Changed 6 years ago by annakrat

Replying to hamish:

So it comes down to the question of is the data categorical (in which case smallest value is at the top) or continuous gradient which happens to be stored as integers (in which case smallest values is at the bottom). Since CELL maps can be used for both there is no single correct answer to that, and so the module goes with the logic that if the range of available cats or the frame size happens to change by a little bit, pushing it over the threshold, it will change the boxes into thin lines, but the overall view will remain the same, it has just gone into "compressed mode".

In my view, the order should be defined by the gradient/box legend, not by the type of the map since it is not reliable. Gradient would have low values in the bottom, and boxes would be ordered in the opposite direction. This behavior could create less confusion and would be expected in most cases, in my opinion.

comment:5 in reply to:  1 Changed 6 years ago by wenzeslaus

Replying to hamish:

In the NC08 dataset consider: d.legend towns

(see attached screenshot)

I think we can all agree that counting from category 1 (smallest value) at the top is how we would like that to be.

Sorry, I cannot agree entirely. I don't see the reason to have numbers there when labels are the only important thing in case of of towns. Then of course the order (order according category) is not important. Although I agree that we might suppose some ordering imprinted in categories, e.g. in case of labels for slope.

note I built in two handy tricks to get the flip to happen without the -f flag: in GRASS 6 (and with at= in G7) when drawing the box with the mouse draw from bottom up instead of top down, and another way is to reverse the order of values in the range= option.

I generally agree with introducing these tricks (clever decision making, heuristics). However, in this case it is questionable if it creates more confusion then convenient/handy behavior. Perhaps option order=ascending, order=descending and order=auto would improve the situation by making things explicit. order=auto can be the default. order=ascending and order=descending would disable any handy tricks.

comment:6 Changed 6 years ago by hamish

Resolution: wontfix
Status: assignedclosed

annakrat wrote:

In my view, the order should be defined by the gradient/box legend, not by the type of the map since it is not reliable. Gradient would have low values in the bottom, and boxes would be ordered in the opposite direction. This behavior could create less confusion and would be expected in most cases, in my opinion.

"smoothed" legend != "gradient" legend

One is a visual change, the other a conceptual change. Visual adjustments are easier to follow than conceptual ones. As the determining factor here in rendering style is the height of the display frame -- a visual change as well -- that's the smallest logical jump to make. A good demo of this is if you have a map with the number of categories near to the maximum number of boxes that will fit in the display frame, and tweak the size of the window a bit taller and shorter to watch it jump back and forth between rendering styles. For categorical maps it is not a gradient at all, just a stack of blocks, often with random color transitions.

Again, there is no one right answer here for all use cases, and no way for the software to know ahead of time. So we pick one way and hope it is the right choice 51% of the time. Another way to make the choice is by how far from the too-many-boxes threshold you are. That might make it do the right thing more often for an integer elevation map with a range of 100s or 1000s of meters (admittedly a common alternative and the one which inspired this ticket), but IMO the logic and arbitrary choice of threshold value becomes too muddy to explain and it moves into the horrible realm of software "auto correct"s.

wenzeslaus wrote:

Sorry, I cannot agree entirely. I don't see the reason to have numbers there when labels are the only important thing in case of of towns. Then of course the order (order according category) is not important.

The towns map was just an example of a purely categorical, as opposed to continuous gradient, CELL map with a useful number of categories. Of course the category numbers are not very meaningful in that example, but their order may very well be. Depends on the map! In practice for the towns map the -c flag would be used to suppress the numbers.

I generally agree with introducing these tricks (clever decision making, heuristics). However, in this case it is questionable if it creates more confusion then convenient/handy behavior.

I don't think the two flipping triggers I mentioned cause any confusion. Certainly the rules= way logically flows from the way you type it in, and the flipped at= order only happens if you know about it.

Perhaps option order=ascending, order=descending and order=auto would improve the situation by making things explicit. order=auto can be the default. order=ascending and order=descending would disable any handy tricks.

It's over-engineering the problem. Just use the -f flag if you need to.

Claiming author's prerogative and closing as wontfix. I spent many many hours thinking through these problems and experimenting with this on a wide range of maps & display sizes, and for better or worse, depending on your point of view, the current way came out on top.

regards, Hamish

comment:7 Changed 6 years ago by hamish

"smoothed" legend != "gradient" legend

Hi,

I was thinking a bit more about this, maybe a way around the ambiguity of what kind of data a CELL map contains is for d.legend to test if the r.support units= has been set and has a string length > 0, and if it contains a value assume it is a continuous gradient map, and so smallest value on the bottom.

I fear it moves a bit into 'too tricky for its own good' territory, the existing help text is nicely concise, but apparently what to expect is not obvious if you haven't read that. I guess since it talks about "categorical" and not CELL maps, the text wouldn't have to change for a continuous gradient CELL map? Seems a bit of a stretch & I don't want to introduce more confusion..

       Raster maps based on  floating  point  values  will
       display  smoothed, from greatest to smallest value,
       while categorical raster maps will display in order,
       from  top to bottom. Horizontal legends will always
       be smoothed. If the box is defined with inverted y-
       values  or an inverted range, the legend will auto-
       matically flip. If this is not the desired  result,
       the -f flag may be used to flip it back.

messy!

Hamish

comment:8 in reply to:  7 Changed 6 years ago by wenzeslaus

Replying to hamish:

"smoothed" legend != "gradient" legend

Hi,

I was thinking a bit more about this, maybe a way around the ambiguity of what kind of data a CELL map contains is for d.legend to test if the r.support units= has been set and has a string length > 0, and if it contains a value assume it is a continuous gradient map, and so smallest value on the bottom.

This is using map metadata to decide what map means. I quite like it.

I fear it moves a bit into 'too tricky for its own good' territory, the existing help text is nicely concise, but apparently what to expect is not obvious if you haven't read that. I guess since it talks about "categorical" and not CELL maps, the text wouldn't have to change for a continuous gradient CELL map? Seems a bit of a stretch & I don't want to introduce more confusion..

Raster maps based on floating point values will display smoothed, from greatest to smallest value, while categorical raster maps will display in order, from top to bottom. Horizontal legends will always be smoothed. If the box is defined with inverted y- values or an inverted range, the legend will auto- matically flip. If this is not the desired result, the -f flag may be used to flip it back.

I think that the requirement is that that the default behavior must be the most expected thing. Getting smoothed from bottom to top legend for floating point maps and for maps which have units and the opposite for categorical is the expected thing. It think that it is clear for us and it seems also that there is a way to implement it.

However, there should always be a clear way to set what I want if I know what I want and I'm not sure if the mechanism behind giving expected behavior will work for me. I'm not sure if the interface is clear enough for this case. I'm thinking what if I have to program something which would be using d.legend how I will deal with change of legend just because of slight change of the size of the window.

I never know if -f means "flip back if flipped", "flip from bottom-to-top to top-to-bottom" or "flip to the opposite of what the automatic mechanism would do". Again, I'm scared of having to program something which is using the inverted coordinates approach. Only the flipped range looks quite clear but why then I'm confused we need the other two?

Note: See TracTickets for help on using tickets.