Define RGB values for heatmap

Hi,

I would like to specify RGB values per each data point in a heatmap. Any hints on how this could be done?

The normal behaviour is that value of z (real numbers) is used to colour the pixel according to the specified colormap. What I’d ideally want is to be able to use 3-tuple (instead of a single number) to define the colour channels (i.e. override any colormap).

Use case: I have high dimensional data set on which I run Principal Component Analysis to get 3 primary components. These components will form my RGB values.

Hi @tracek, you can use the image trace for this, either with go.Image or with the plotly express function px.imshow. Please see the tutorial on image data, and if your values come from a home-made computation rather than an image file don’t forget to set the zmin and zmax parameters.

Hi @tracek

For me it’s not clear how do you intend to associate a heatmap to a 3d-space or an image following Emmanuelle’s suggestion.
You can associate r, g, b, values to each point, but how do you specify its position in a 2d array to define the image?

I can suggest the following path to using r,g, b for each projected point:
If u1, u2, u3 are the principal directions, represented by three unit vectors,
and each point p in your high dimensional space is projected orthogonally onto
the subspace generated by these vectors, then its projection is
p' = x u1 +y u2 +z u3.

Define the intervals:

[a, b]=[min(x), max(x)], [c, e]=[min(y), max(y)], [e, f]=[min(z), max(z)]
where x,y, respectively z run over all x, y, z coordinates of the projected points.
Then map each such interval onto the interval [0, 255], by:

def mapping_interval(v, a, b):
    if a >= b:
        raise ValueError(f'a={a} must be less than b={b}')
    if  v < a or v > b:
        raise VallueError('...')
    return int(255*(v-a)/(b-a)+0.5)

In this way you can associate r, g, b values to each projected point, i.e. a color code.
Denoting by prx, pry, prz the lists of p' - point coordinates,
you can test this method with this example:

import numpy as np
import plotly.graph_objects as go

a, b = -20, 31
c, d = -16, 27
e, f = -24, 35

def mapping_interval(v, a, b):
    if a >= b:
        raise ValueError(f'a={a} must be less than b={b}')
    if  v < a or v > b:
        raise VallueError('...')
    return int(255*(v-a)/(b-a)+0.5)

prx = np.random.randint(a, b, 25)
pry = np.random.randint(c, d, 25)
prz = np.random.randint(e, f, 25)
color = [f'rgb({mapping_interval(x, a, b)}, {mapping_interval(y, c, d)}, {mapping_interval(z, e, f)})'
for x,y,z in zip(prx, pry,prz)]
fig= go.Figure(go.Scatter3d(x=prx,
                            y=pry,
                            z=prz,
                            mode = 'markers',
                            marker_color =color,
                            marker_size=5,
                            hovertemplate ='x: %{x}<br>y: %{y}<br>z: %{z}<br>color: %{marker.color}'))
fig.update_layout(width=600, height=600)

Here the position is given by the three coordinates with respect to u1, u2, u3. How do associate to each point a position in an image? Only the color is already assigned.

Thanks @Emmanuelle and @empet for the suggestions!

First, to answer your question: I know the position on the graph thanks to the ordering in the sequence. Essentially, each data point is a point in time. On the heatmap, I’d like to to display time of the day on the x axis and date on y axis. The 3 principal components calculated per point are then my RGB values.

Why heatmap specifically? It solves a lot of problems for me out of the box. I am grateful for suggesting how it could work on a scatter plot, but in my case it’d be rather meaningless. Going with imshow absolutely works, it’s just I need to spend much more time to make it behave like heatmap.

Thanks!
Lukasz