plotly / plotly.js

Open-source JavaScript charting library behind Plotly and Dash
https://plotly.com/javascript/
MIT License
17.05k stars 1.86k forks source link

Shapes are misplaced when using numbers as categoryarray values #5767

Open perdodi opened 3 years ago

perdodi commented 3 years ago

If X axis type is category, and categoryarray contains (string type) numbers, then shapes are horizontally misplaced, as x0 and x1 values in the shape are not considered as items, but as indices of the categoryarray.

Eg.

This one works perfectly:

<div id="tester"></div>
<script>
    var layout = {
      "xaxis": {
        "type": "category",
        "categoryarray": [
          "red", "green", "blue", "purple", "cyan", "yellow", "magenta"
        ],
      },
      "shapes": [
        {
          "type": "rect",
          "xref": "x",
          "yref": "y",
          "x0": "purple",
          "x1": "yellow",
          "y0": 10,
          "y1": 20,
          "fillcolor": "rgba(45,180,135,0.3)",
        }
      ]
    };

    var data = [
      {
        "x": [ "red", "blue", "cyan", "magenta" ],
        "y": [ 10, 20, 30, 40],
      },
    ];

    TESTER = document.getElementById('tester');
    Plotly.newPlot( TESTER, data, layout );
</script>

image

But if I replace the color names to numbers:

  // in "categoryarray":
      "10", "20", "30", "40", "50", "60", "70"
...
  // in "shapes" this won't work:
      "x0": "40",
      "x1": "60",
...
 // in data:
    "x": [ "10", "30", "50", "70" ],

image

It will work only if I replace the category values to their indices in the shapes:

      "x0": 3,
      "x1": 5,

image

Note: if this is not intended to be a bug, but an undocumented feature, please document it, so I can rely on it later. 😃

nicholas-esterer commented 3 years ago

This seems to be due to the behaviour of the package fast-isnumeric, which is used in https://github.com/plotly/plotly.js/blob/2f17e117648e56ff3eebb5f55e57db522f4d9200/src/plots/cartesian/set_convert.js#L182 Indeed, in a nodejs console:

> var isNumeric = require('fast-isnumeric');
> isNumeric(40)
true
> isNumeric("40")
true

This makes it so that getCategoryIndex is not called even when the value is a string that looks like a number (e.g., "40"). @alexcjohnson is this behaviour desired?

nicholas-esterer commented 3 years ago

also related: https://github.com/plotly/plotly.js/issues/5741

alexcjohnson commented 3 years ago

See also autotypenumbers: 'strict' https://github.com/plotly/plotly.js/pull/5240

alexcjohnson commented 3 years ago

(which is now the default for graphs made with plotly.py)

nicholas-esterer commented 3 years ago

Ok I see. Setting autotypenumbers: "strict" in layout or layout.xaxis (relevant to this use case) doesn't fix the bug, but to be fair the docs just mention "trace data" and not the coordinates of shapes (or images or annotations for that matter). But the expected behaviour is most likely to follow what the axis' autotypesnumbers setting says to do for shapes as well.

alexcjohnson commented 3 years ago

Yep, that sounds right - if an axis is in strict mode, that should apply to shapes, annotations, and images as well as traces. So that part of this issue can be considered a bug.