Skip to content

autocolorscale doesn't seem to pickup on diverging numberlines #3064

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

Closed
mbkupfer opened this issue Oct 1, 2018 · 7 comments
Closed

autocolorscale doesn't seem to pickup on diverging numberlines #3064

mbkupfer opened this issue Oct 1, 2018 · 7 comments
Labels
feature something new

Comments

@mbkupfer
Copy link

mbkupfer commented Oct 1, 2018

I have a data set for employment in the US. When I use autocolorscale with a diverging set (i.e numbers that are negative and positive), many positive numbers get picked up as negative ones.

Below is a Choropleth figure that this can be tested on. Only a few numbers are negative, yet the colorscale makes many of the states appear negative. This could easily be fixed if a zero could be applied to the scale, rather than percentage of zmin/zmax.

Choropleth({
    'autocolorscale': True,
    'hoverinfo': 'location+text',
    'locationmode': 'USA-states',
    'locations': [AL, AK, AZ, AR, CA, CO, CT, DE, DC, FL, GA, HI, ID, IL, IN, IA,
                  KS, KY, LA, ME, MD, MA, MI, MN, MS, MO, MT, NE, NV, NH, NJ, NM,
                  NY, NC, ND, OH, OK, OR, PA, RI, SC, SD, TN, TX, UT, VT, VA, WA,
                  WV, WI, WY, GU, PR, VI],
    'marker': {'line': {'color': '#ffffff', 'width': 1}},
    'text': [9,580, -5,330, 51,060, 8,810, 728,430, 47,620, -11,860, 1,930, 5,840,
             197,000, 89,120, 870, 22,140, 24,040, 27,230, 550, -5,070, 6,780,
             -20,110, 2,790, 23,430, 68,160, 63,950, 27,870, 2,190, 30,830, 6,000,
             2,230, 39,290, 4,900, 52,120, -4,360, 110,220, 67,370, -8,530, 32,750,
             -13,890, 39,850, 34,590, 720, 29,640, 1,950, 22,710, 145,630, 35,770,
             440, 29,360, 119,500, -8,910, 20,160, -8,140, 0, -7,580, 170],
    'z': [9580.0, -5330.0, 51060.0, 8810.0, 728430.0, 47620.0, -11860.0, 1930.0,
          5840.0, 197000.0, 89120.0, 870.0, 22140.0, 24040.0, 27230.0, 550.0,
          -5070.0, 6780.0, -20110.0, 2790.0, 23430.0, 68160.0, 63950.0, 27870.0,
          2190.0, 30830.0, 6000.0, 2230.0, 39290.0, 4900.0, 52120.0, -4360.0,
          110220.0, 67370.0, -8530.0, 32750.0, -13890.0, 39850.0, 34590.0, 720.0,
          29640.0, 1950.0, 22710.0, 145630.0, 35770.0, 440.0, 29360.0, 119500.0,
          -8910.0, 20160.0, -8140.0, 0.0, -7580.0, 170.0]
})
@mbkupfer
Copy link
Author

mbkupfer commented Oct 1, 2018

autocolorscale

@alexcjohnson
Copy link
Collaborator

When you say "the colorscale makes many of the states appear negative" I guess you mean that zero should be grey, positive should be shades of red, and negative should be shades of blue, right? Because as it is the colors seem to match up correctly with the colorbar, it's just that zero isn't any particular color.

So it seems clear what you want from the color scale, and this seems completely reasonable. But as far as the color bar I can think of two possible outcomes, both of which might be useful in different cases but I'm curious what you had in mind:

  1. the colorbar range is symmetric. The full range of colors is displayed, from strong blue to bright red, but its values go beyond the data (in this case, -728k to +728k).
  2. the colorscale itself gets clipped, so that grey is near the bottom and the colors in the colorbar range from very light blue to bright red.

@alexcjohnson alexcjohnson added the feature something new label Oct 2, 2018
@mbkupfer
Copy link
Author

mbkupfer commented Oct 2, 2018

Yes, the colorbar is accurate, and you are correct in that all positives should be red and negatives blue, at least in this coloscale case.

Based on your first suggestion, I added the snippet below and it looks like it gave me the desired effect, that is, positives and negatives have different colors. There are two issues though:

  1. There are no negative values that come close to to what the colorbar shows (but, perhaps this could be fixed by using your second suggestion of clipping the colorbar range)
  2. Non-extreme values are harder to tell apart

autocolorscale-v2

   values = [i for i in df[metric]]
   #set the zmin and zmax using the range of values
   if abs(max(values)) >= abs(min(values)):
       zmax, zmin = max(values), -max(values)
   else:
       zmax, zmin = abs(min(values)), min(values)

@alexcjohnson
Copy link
Collaborator

Ok great. What you're showing here is my solution 1 - which I think we could support by adding an attribute like zrangemode: 'symmetric' that would force zmin = -zmax like you've done manually. Other values there could be 'normal' (current behavior), 'tozero' (like axis rangemode: 'tozero' - would ensure zero is included even if the range is all positive or all negative) and perhaps 'autosymmetric' which, along with autocolorscale: true, would choose 'tozero' if the data are all the same sign (so we pick a sequential red or blue colorscale) or 'symmetric' if the data cross zero.

There are no negative values that come close to to what the colorbar shows (but, perhaps this could be fixed by altering the colorbar)

That's my solution 2, which could be nice as well, but it's a bit more involved (and, as I think about it, probably confusing to use...) as we would need to clip the colorscale itself, which seems like it would require something like a fixed point on the color mapping - like z0: 0, c0: 0.5 to say "make sure z=0 gets put at 0.5, the middle, on the colorscale." Then we'd stretch the colorscale so instead of zmin->0 and zmax->1, zmin (and the bottom of the displayed colorbar) would map to, in this case, something like 0.47 on the colorscale. You could even imagine two fixed points, like you want 0 to always be blue and 1 to be red, but you want the colorbar to only show the actual range of data.

Non-extreme values are harder to tell apart

That you're going to have to solve by changing the colorscale. The default RdBu tries to be perceptually uniform, but you actually want something that varies more near zero. We don't have anything built-in that fits that description, but perhaps something like matplotlib's seismic https://matplotlib.org/tutorials/colors/colormaps.html would be useful for you. I wouldn't mind adding that as a named scale in plotly.js to support cases like this, but unless/until we do, translating their source to our format gives:

[[0, 'rgb(0,0,76)'], [0.25, 'rgb(0,0,255)'],
 [0.5, 'rgb(255,255,255)'], [0.75, 'rgb(255,0,0)'],
 [1, 'rgb(127,0,0)']]

@mbkupfer
Copy link
Author

mbkupfer commented Oct 2, 2018

Thanks. Just to clarify, what is the solution for the colorbar? As of now, it is symmetrical which is not necessary given how small the lowest negative number is. In reality, it should really only go down to -20k.

Non-extreme values are harder to tell apart

That you're going to have to solve by changing the colorscale.

Ok, sounds good. Thanks for that advice. I'll experiment with different scales. For the record though, Seismic still does not differentiate enough between extreme values. Here is what is came out to using the scale you translated:

image

@etpinard
Copy link
Contributor

Essentially closed by #3549

Adding cmd: 0 should do the trick.

@etpinard
Copy link
Contributor

Going to close this thing.

@mbkupfer if the cmid: 0 solution doesn't cut for you and you can think of a better one, please open another issue. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature something new
Projects
None yet
Development

No branches or pull requests

3 participants