3
$\begingroup$

I used unscaled coordinates with a custom color function to visualize data for life expectancy in African countries (see code below). Five intervals for five colors. But it seems tha WM choses the boundaries of the intervals somehow different. What's the problem? Thanks!

GeoRegionValuePlot[ EntityClass["Country", "Africa"] -> "LifeExpectancy", ColorFunctionScaling -> False, ColorFunction -> (Which[70 < #, Pink, 65 < # <= 70, Blue, 60 < # <= 65, Green, 55 < # <= 60, Gray, 50 < # <= 55, Orange] &), ImageSize -> 350, GeoLabels -> ((Tooltip[#1, Row[{#2, Spacer[5], #4}]] &))]
$\endgroup$
2
$\begingroup$

OP's color function:

ClearAll[cF]
cF = Which[70 < #, Pink, 65 < # <= 70, Blue, 60 < # <= 65, Green, 
    55 < # <= 60, Gray, 50 < # <= 55, Orange] &;

grvp = GeoRegionValuePlot[ 
  EntityClass["Country", "Africa"] -> "LifeExpectancy",  
  ColorFunctionScaling -> False, ColorFunction -> cF, 
  ImageSize -> 350, 
  GeoLabels -> ((Tooltip[#1, Row[{#2, Spacer[5], #4}]] &))]

enter image description here

As a work-around, you can create a BarLegend using your color function cF or the list of colors and specifying the list of contours in the second argument:

range = Range[50, 75, 5];
legend = BarLegend[{cF, {50, 75}}, range];
legend2 = BarLegend[{{Orange, Gray, Green, Blue, Pink}, {50, 75}}, range];
Row[{legend, legend2}]

enter image description here

and replace the legend in grvp with legend:

grvp /. _BarLegend -> legend

enter image description here

You can also use legend with Legended after extracting the plot from grvp (its firt Part):

Legended[grvp[[1]], Placed[legend, Right]]

same picture

Note: I would have expected that using the option PlotLegends -> legend in GeoRegionValuePlot would have fixed the issue; it doesn't.

| improve this answer | |
$\endgroup$
  • $\begingroup$ Thank you very much! But I'm afraid it's not all tha simple.As a result you get 2 different pictures, that is Africa and legend and they are not connected. Just have a look at South Sudan in the center of the continent, Life expectancy is 56.811 yr. The initial legend that produced by GeoRegionValuePlot is correct but one cannot control it. $\endgroup$ – Gregory Fridman Sep 2 '19 at 14:51
  • $\begingroup$ @GregoryFridman, not sure I follow. How come " initial legend that produced by GeoRegionValuePlot is correct"? Your color function says a country with life expectancy in $(55,60]$ (so South Sudan with LE 56.811) should be colored Gray (initial legend colors it Green), and the interval $(60, 65]$ should be mapped to Green (initial legend has Pink for that interval of values) $\endgroup$ – kglr Sep 2 '19 at 15:29
  • $\begingroup$ GeoRegionValuePlot generated the legend that corresponds to LE for countries (for instance, South Sudan is colored Blue and legend indicates "blue interval" for such values), But this legend does not correspond to my color function and this is the problem. On your picture the legend is okay (Blue color is from 65 to 70, etc.) but you may see that Sudan should be Gray, exactly as you mentioned. $\endgroup$ – Gregory Fridman Sep 2 '19 at 18:10
2
$\begingroup$

Seems to be a bug in GeoRegionValuePlot. You can fix it by executing the following code:

DownValues@System`GeoPlotsDump`iGeoRegionValuePlot = 
  DownValues@System`GeoPlotsDump`iGeoRegionValuePlot /. 
   HoldPattern@
     Rescale[
      #, 
      minMax : {0, 1} | PatternSequence[],
      {#2[[1]], Plus @@ #2}
     ] :> 
      Rescale[#, minMax, #2];

Now the code from the question works as expected:

GeoRegionValuePlot[
 EntityClass["Country", "Africa"] -> "LifeExpectancy",
 ColorFunctionScaling -> False,
 ColorFunction -> (Which[70 < #, Pink, 65 < # <= 70, Blue, 
     60 < # <= 65, Green, 55 < # <= 60, Gray, 50 < # <= 55, Orange] &),
 ImageSize -> 350,
 GeoLabels -> ((Tooltip[#1, Row[{#2, Spacer[5], #4}]] &))
 ]

enter image description here

Why?

It seems the creator of GeoRegionValuePlot stumbled over the behavior of Rescale. The following is an excerpt of the code used to preprocess the given ColorFunction (in System`GeoPlotsDump`iGeoRegionValuePlot):

cf = (* some wrapper code… *) cfunc[
  If[
    TrueQ[cscaleQ],
    Rescale[#, {#2[[1]], Plus@@#2}],
    Rescale[#, {0, 1}, {#2[[1]], Plus@@#2}]
  ]
] (* some wrapper code… *)&;

Where cf is the processes ColorFunction, cfunc the ColorFunction specified in the options, and cscaleQ is ColorFunctionScaling. cf is called like this:

cf[#, {Min @ values, Max @ values}]& /@ {(* list of values between 0 and 1 *)}

So the second argument gives the range of the original data, which can directly be supplied as last argument to Rescale, without the need to add anything together…

| improve this answer | |
$\endgroup$
  • $\begingroup$ Lukas, thank you very much. It is exactly what I was looking for. $\endgroup$ – Gregory Fridman Sep 15 '19 at 19:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.