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

d.legend: handle 0 for log (-l) #1507

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open

Conversation

HuidaeCho
Copy link
Member

Attempt to address #1482

@HuidaeCho
Copy link
Member Author

TODO: This module needs indent after this PR is merged.

@HuidaeCho
Copy link
Member Author

HuidaeCho commented Apr 7, 2021

@neteler Please test it with negative, non-positive, negative to positive, and 0 to positive rasters. It shouldn't affect positive rasters, but just in case test them too. It still doesn't support absolute logarithm.

Noticed that the flag name (-l) is different from -g from r.colors, but -l makes more sense and is reserved for r.colors.

@HuidaeCho HuidaeCho requested a review from neteler April 7, 2021 00:37
@HuidaeCho HuidaeCho added enhancement New feature or request raster Related to raster data processing labels Apr 7, 2021
@neteler
Copy link
Member

neteler commented Apr 11, 2021

Thanks a lot!
For testing, I applied the PR to G78 and got this compilation warning (just FYI):

grass78_git/display/d.legend]$ make
gcc  -O3 -march=native -fdiagnostics-color   -I/home/mundialis/software/grass78_git/dist.x86_64-pc-linux-gnu/include -I/home/mundialis/software/grass78_git/dist.x86_64-pc-linux-gnu/include    -DPACKAGE=\""grassmods"\"   -I/home/mundialis/software/grass78_git/dist.x86_64-pc-linux-gnu/include -I/home/mundialis/software/grass78_git/dist.x86_64-pc-linux-gnu/include -DRELDIR=\"display/d.legend\" -o OBJ.x86_64-pc-linux-gnu/draw.o -c draw.c
draw.c: In function ‘draw’:
draw.c:273:40: warning: ‘%d’ directive writing between 1 and 11 bytes into a region of size 4 [-Wformat-overflow=]
  273 |                 sprintf(DispFormat, "%%%dd", (int)(log10(fabs(maxCat))) + 1);
      |                                        ^~
draw.c:273:37: note: directive argument in the range [-2147483647, 2147483647]
  273 |                 sprintf(DispFormat, "%%%dd", (int)(log10(fabs(maxCat))) + 1);
      |                                     ^~~~~~~
In file included from /usr/include/stdio.h:866,
                 from /home/mundialis/software/grass78_git/dist.x86_64-pc-linux-gnu/include/grass/gis.h:24,
                 from draw.c:14:
/usr/include/x86_64-linux-gnu/bits/stdio2.h:38:10: note: ‘__builtin___sprintf_chk’ output between 4 and 14 bytes into a destination of size 5
   38 |   return __builtin___sprintf_chk (__s, __USE_FORTIFY_LEVEL - 1,
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   39 |       __bos (__s), __fmt, __va_arg_pack ());
      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Here my user test:

  • not more min=0 related error, great
  • the maximum shown is not that reported thru stats (see below, but I didn't manage to reproduce it!):
GRASS 7.8.6dev (latlong_wgs84):~ > r.info -r worldpop_2020_1km_aggregated_UNadj
min=0
max=52820.77
GRASS 7.8.6dev (latlong_wgs84):~ > r.univar worldpop_2020_1km_aggregated_UNadj -g | grep min
min=0

d.legend -s -d -l raster=worldpop_2020_1km_aggregated_UNadj@worldpop_south_america title=worldpop_2020_1km_aggregated_UNadj font=Vera

image

@HuidaeCho
Copy link
Member Author

* the maximum shown is not that reported thru stats (see below, but I didn't manage to reproduce it!):

@neteler I couldn't reproduce it. Can you share your data (worldpop_2000_1km_aggregated_UNadj)?

@HuidaeCho
Copy link
Member Author

draw.c:273:40: warning: ‘%d’ directive writing between 1 and 11 bytes into a region of size 4 [-Wformat-overflow=]
273 | sprintf(DispFormat, "%%%dd", (int)(log10(fabs(maxCat))) + 1);
| ^~
draw.c:273:37: note: directive argument in the range [-2147483647, 2147483647]
273 | sprintf(DispFormat, "%%%dd", (int)(log10(fabs(maxCat))) + 1);
| ^~~~~~~

I think you use GCC >= 7 (https://gcc.gnu.org/gcc-7/changes.html). I'm stuck with GCC 5 :-(. The warning is because DispFormat is not big enough. Buffer overflow can actually happen if maxCat is very large such that log10(maxCat)+1 >= 100. That is, maxCat >= 10^99, which looks pretty safe... One solution would be DispFormat[7] (two more bytes) and

sprintf(DispFormat, "%%%dd", (char)(log10(fabs(maxCat))) + 1);

char ranges from -128 to 127 so it can take up four bytes max plus %, d, and \0.

Now, if maxCat is very small and log10(fabs(maxCat)) becomes < -1, text will be left-aligned unintentionally.

In general, I think this module needs a major refactoring including the above warnings, uninitialized variables, indentation, breaking long code, etc.

@neteler
Copy link
Member

neteler commented Apr 19, 2021

* the maximum shown is not that reported thru stats (see below, but I didn't manage to reproduce it!):

@neteler I couldn't reproduce it. Can you share your data (worldpop_2000_1km_aggregated_UNadj)?

(btw: gcc version 10.2.1 here)

My use case is this one:

#1482 (comment)

but I'll test again to see if it happens again + (try to) provide synthetic test data generated with r.random.* etc.

@neteler
Copy link
Member

neteler commented Apr 19, 2021

@neteler Please test it with negative, non-positive, negative to positive, and 0 to positive rasters. It shouldn't affect positive rasters, but just in case test them too. It still doesn't support absolute logarithm.

OK, I have set up some test cases (see below). Hope they are somehow meaningful...

# NC sample dataset
g.region -p n=228500 s=215000 w=630000 e=645000 res=100 -p
d.mon wx0

Negative values

# negative, DCELL
r.surf.random out=random_negative min=-100 max=-1
r.univar random_negative
r.info -r random_negative
min=-99.9995498657227
max=-1.01180768013

d.rast random_negative
d.legend raster=random_negative@user1 title=random_negative
d.legend -l raster=random_negative@user1 title="Log random_negative"

image

Negative to positive

# negative to positive, DCELL
r.surf.random out=random_negative_positive min=-100 max=100
r.univar random_negative_positive
r.info -r random_negative_positive
min=-99.9983367919922
max=99.9910354614258

d.rast random_negative_positive
d.legend raster=random_negative_positive@user1 title=random_negative_positive
d.legend -l raster=random_negative_positive@user1 title="Log random_negative_positive"

image

0 to positive

# 0 to positive rasters, DCELL
r.surf.random out=tmp min=0 max=100
r.mapcalc "random_positive = if( tmp < 1.0, 0.0, tmp)"
g.remove raster name=tmp -f
r.univar random_positive
r.info -r random_positive
min=0
max=99.9885711669922

d.rast random_positive
d.legend raster=random_positive@user1 title=random_positive
d.legend -l raster=random_positive@user1 title="Log random_positive"

image

@veroandreo
Copy link
Contributor

These are my tests with and without this PR:

  • Without the PR:
  1. positive values starting from 0.something (lots of small values some pretty high)
    2021-04-22_18-54

  2. negative and positive values - only legend without -l can be drawn, for -l, I get the reported error

Failed to run command 'd.legend -b -l raster=prueba_grib@pruebas title="With -l flag" at=5,50,47,50'. Details:
GRASS_INFO_ERROR(207604,1): Range [-69.550, 42.850] out of the logarithm domain.
GRASS_INFO_END(207604,1)     
  • With this PR:
  1. looks good - same as before the PR
    2021-04-22_19-10

  2. legend with -l does not look good, only positive values shown, though I no longer get the error
    2021-04-22_19-16

I wonder if it really make sense to try to plot a logarithmic scale with negative data... For the case of value zero, can't we just add 1 to get 0 as a result?

Also, while no error is reported for negative data, I believe it's worthy to raise a warning at least

@veroandreo
Copy link
Contributor

veroandreo commented Apr 22, 2021

@neteler Please test it with negative, non-positive, negative to positive, and 0 to positive rasters. It shouldn't affect positive rasters, but just in case test them too. It still doesn't support absolute logarithm.

OK, I have set up some test cases (see below). Hope they are somehow meaningful...

I find the legends pretty odd, tbh, even the one for all positive numbers... I would expect colors to be more equally distributed as in my case 1 examples. Maybe the distribution of values plays a role?

@HuidaeCho
Copy link
Member Author

HuidaeCho commented Apr 23, 2021

Let me summarize what this PR does:

  • For a positive raster, everything is good. Output should be exactly the same as without this PR.
  • For a 0-to-positive or negative-to-positive raster, use 1 as the min color
    • It can be a problem when the raster's max is smaller than 1. This is why it would be great to know the true positive min value.
    • We also skip all raster colors between the min and 1.
  • For a negative raster, use the max color only.

@HuidaeCho
Copy link
Member Author

@neteler Please test it with negative, non-positive, negative to positive, and 0 to positive rasters. It shouldn't affect positive rasters, but just in case test them too. It still doesn't support absolute logarithm.

OK, I have set up some test cases (see below). Hope they are somehow meaningful...

I find the legends pretty odd, tbh, even the one for all positive numbers... I would expect colors to be more equally distributed as in my case 1 examples. Maybe the distribution of values plays a role?

I think your example 1 is a good case for a logarithmic legend. Data looks logarithmically distributed than linearly. The log legend looks good to me.

@HuidaeCho
Copy link
Member Author

Now, fatal error on a non-positive raster and warnings on min <= 0.

@nilason nilason added the C Related code is in C label Feb 15, 2023
@neteler
Copy link
Member

neteler commented Feb 18, 2023

This PR looks good, i.e., it improves the current situation. Merge it?

Copy link
Contributor

@petrasovaa petrasovaa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this implementation is improvement, but the PR needs to be cleaned up, see my other comments.

"discarding colors for cells <= %g and "
"assuming a positive min cell value of %g"),
eps, eps);
eps_min = eps;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if you couldn't just use dmin = eps_min here, which would avoid all the changes below.

Comment on lines +405 to +414
/* XXX: for log scale, if the entire raster is not
* positive, use the max color only; actually, this is
* incorrect because negative values can have different
* colors on the monitor; maybe, we should throw a fatal
* error in this case because using the max color only for
* displaying a raster and its legend is different and the
* legend must always match the display; well... unless the
* raster is colorized using r.colors -g, but how do we
* know that? */
val = dmax <= 0 ? dmax : eps_min * pow(dmax / eps_min, num);
Copy link
Contributor

@petrasovaa petrasovaa Feb 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All these comments are somewhat confusing and perhaps not updated after introducing the fatal error for rasters with all negative values. I would suggest to summarize the reasoning and perhaps move it somewhere close to the fatal error call.

Given the fatal error in the beginning, these expressions don't need to test for the negative cases and can be simplified. This applies to all/most of the changes below.

@wenzeslaus wenzeslaus modified the milestones: 8.3.0, 8.4.0 Mar 17, 2023
@HuidaeCho HuidaeCho self-assigned this Mar 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C Related code is in C display enhancement New feature or request module raster Related to raster data processing
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants