Black Lives Matter. Please consider donating to Black Girls Code today.
Dash HoloViews is now available! Check out the docs.

Can plotly.js distinguish between row major and column major order for arrays?

Recently I started plotting plotly plots using PlotlyJS.jl (with PlotlyBase.jl), based on Julia programming language.

When I tried to plot heatmaps I noticed that the plot resulted from Julia code is not the same generated by plotly.py.

Python is a row major language, i.e. its arrays are stored row after row, while Julia is column major, with columns stored column after column.

I give a simple example and asssociate the resulting json file created by plotly.py, respectively by PlotlyBase.jl.

Heatmap with plotly.py:

import plotly.graph_objects as go
import numpy as np
z = [[ 3,  9, 12,  7],
[11,  6,  8, 11],
[ 5,  7, 11, 14]]
fig=go.Figure(go.Heatmap(z=z, colorscale="Viridis"))
fig.update_layout(width=600, height=450)

plotlypy

Heatmap with PlotlyJS.jl and the same data

using PlotlyJS
z = [ 3  9 12  7;
     11  6  8 11; 
     5  7 11 14]
fig = plot(heatmap(z=z, colorscale="Viridis"),
           Layout(width=600, height=400))

plotlyJulia

The last heatmap is not the right one, because by definition, the involved z-array has 3 rows and 4 columns, but the plot iluustrates 4 rows and 3 columns.

Let us print the corresponding json files:

  1. The json resulted from plotly.py:
fig={
  "data": [
    {
      "colorscale": [
        [
          0.0,
          "rgb(12,51,131)"
        ],
        [
          0.25,
          "rgb(10,136,186)"
        ],
        [
          0.5,
          "rgb(242,211,56)"
        ],
        [
          0.75,
          "rgb(242,143,56)"
        ],
        [
          1.0,
          "rgb(217,30,30)"
        ]
      ],
      "type": "heatmap",
      "z": [
        [
          3,
          9,
          12,
          7
        ],
        [
          11,
          6,
          8,
          11
        ],
        [
          5,
          7,
          11,
          14
        ]
      ]
    }
  ],
  "layout": {
    "height": 450,
      "width": 600
  }
}
  1. The json code generated by PlotlyBase.jl:
print(json(fig, 2))

{
  "layout": {
    "height": 400,
    "margin": {
      "l": 50,
      "b": 50,
      "r": 50,
      "t": 60
    },
    "width": 600
  },
  "frames": [],
  "data": [
    {
      "type": "heatmap",
      "colorscale": "Viridis",
      "z": [
        [
          3,
          11,
          5
        ],
        [
          9,
          6,
          7
        ],
        [
          12,
          8,
          11
        ],
        [
          7,
          11,
          14
        ]
      ]
    }
  ]
}

Notice that the same z-array is passed differently to plotly.js, that’s why the two heatmaps do not coincide.

If we define the Julia code for heatmap with the transpose of z, we get the right plot.

My final question: this behaviour is generated by the way the json file is created by PlotlyBase.jl or because plotly.js cannot distinguish between row major order and column major order and only reads the array passed through the json file?

I opened this issue https://github.com/JuliaPlots/PlotlyJS.jl/issues/355 on the PlotlyJS.jl repository two weeks ago and no answer so far.

It’s not only the heatmap and contour plot that work wrong, but also surface and any trace that involves arrays of (m,n)-type. In each case the array is passed naturally to plotly.py trace definition, but it must be transposed when passed to PlotlyJS.jl.

It is much more complicated to define PlotlyJs.jl plots when the customdata for defining hovertemplate is a multi-array of (m, n, p) dimensions.

People working with Dash for Julia, with no experiencce with plotly.py, cannot realize what is wrong with their plots, because all examples given on PlotlyJS.jl use z-arrays, not their transposed arrays as it should be passed, and no docs exist to explain why these arrays must be transposed…

Hi @empet - it certainly looks like PlotlyJS.jl is transposing the data, and I guess if as you say “Julia is column major” at a language level, that would be the reason. Now, as to whether this should be considered a bug, that’s a little less clear. Perhaps this is exactly what experienced Julia users would expect, given the column-major character of the language?

There was a question early on in development of plotly.js about which way heatmaps should behave. We ended up using row-major, on the grounds that it matches better the way a 2D array is displayed in text, either in JS/JSON or in Python. (It’ll be upside down - the top row in your Python code is the bottom row as graphed - but you can always flip the y axis if you want it that way) But there are common contexts in which the data naturally have a column-major structure (the most important for Plotly early on being Chart Studio) so we added the transpose attribute to heatmaps to make it easier to work with such data.

Hi @alexcjohnson,

Thank you for the answer. I did not consider there is a bug within json files, but in the way the heatmaps, contours or surfaces are defined in the examples posted by the author of PlotlyJS.jl. A Julia user following those examples could be confused on why he doesn’t get the right plot. I asked here about how plotly.js interprets the arrays to be able to argue on the PlotlyJS.jl repo why they must transpose the z-arrays.