Plotly JavaScript's Colorscale Feature - How to set colors based on specific data value ranges?

88 Views Asked by At

I am working on developing a function that produces a heatmap in JavaScript's plotly.js library and I am running into an issue that I can't seem to find the answer for from Plotly's documentation. More specifically, what is going on is that I am plotting data with values that mostly fall between -3 and 3. I want to define specific colors of red to correspond to data points between 0.1 and 3.0 (or anything greater than 3) and specifics colors of blue to correspond to data between -0.1 and -3.0 (or anything less than -3). I want values between -0.1 and 0.1 to be white. I wrote the following code:

// Create heatmap data
                let heatmap_data = [{
                    z: total_L2FC,
                    x: indiv_name_list,
                    y: gene_list,
                    type: 'heatmap',
                    hovertemplate: 'Gene: %{y}<br>Individual: %{x}<br>log2FoldChange: %{z}<br>p-adj: %{customdata}<extra></extra>',
                    customdata: total_padj,
                    colorscale: [
                        // defines colorscale gradient in painstaking fashion...        
                        [100, '#970300'],
                        [3, '#970300'],
                        [3, '#AF0300'],
                        [2.67, '#AF0300'],
                        [2.67, '#B81F1C'],
                        [2.33, '#B81F1C'],
                        [2.33, '#C13B39'],
                        [2,0, '#C13B39'],
                        [2.0, '#CA5755'],
                        [1.67, '#CA5755'],
                        [1.67, '#D37371'],
                        [1.33, '#D37371'],
                        [1.33, '#DB8F8E'],
                        [1.0, '#DB8F8E'],
                        [1.0, '#E4ABAA'],
                        [0.67, '#E4ABAA'],
                        [0.67, '#EDC7C6'],
                        [0.33, '#EDC7C6'],
                        [0.33, '#F6E3E3'],
                        [0.10, '#F6E3E3'],
                        [0.10, '#FFFFFF'],
                        [-0.10, '#FFFFFF'],
                        [-0.10, '#E3E4F1'],
                        [-0.33, '#E3E4F1'],
                        [-0.33, '#C6C9E4'],
                        [-0.67, '#C6C9E4'],
                        [-0.67, '#AAAED6'],
                        [-1.0, '#AAAED6'],
                        [-1.0, '#8E93C8'],
                        [-1.33, '#8E93C8'],
                        [-1.33, '#7179BB'],
                        [-1.67, '#7179BB'],
                        [-1.67, '#555EAD'],
                        [-2.0, '#555EAD'],
                        [-2.0, '#39439F'],
                        [-2.33, '#39439F'],
                        [-2.33, '#1C2892'],
                        [-2.67, '#1C2892'],
                        [-2.67, '#000D84'],
                        [-3.0, '#000D84'],
                        [-3.0, '#000A63'],
                        [-100, '#000A63']
                    ],
                    hoverongaps: false,
                    xaxis: {
                        tickangle: 45
                    },
                    yaxis: {
                        autorange: true
                    },
                    colorbar: {
                        title: {
                            text: 'log<sub>2</sub>FC',
                            font: {
                                size: 14
                            }
                        }
                    },
                    // Use a function to set the color for each log2FoldChange value
                    colors: total_L2FC.map(log2FoldChange => {
                        // Assuming log2FoldChange values are within the range of -3.0 to 3.0
                        if (log2FoldChange >= -3.0 && log2FoldChange <= 3.0) {
                            const normalizedValue = (log2FoldChange + 3.0) / 6.0; // Normalize to the range [0, 1]
                            return d3.interpolateTurbo(normalizedValue); // Use a color scale (e.g., turbo) to map the normalized value to a color
                        } else {
                            return 'gray'; // Default color for values outside the specified range
                        }
                    }),
                    showscale: true,
                }];

Expecting that it would function as I described above, only to realize that what I was copying from the documentation shows that the 100, 3, 2.67, 2.33, etc. values that I expected to correspond to breaks in the z value of the data. I then realized that these correspond to percentages of the min and max value of the z data points. In other words, the minimum value gets assigned a blue color and the max a red color.

How can I go about fixing this so that it behaves as I want? I tried creating a linearscale using the d3 library and I found that the colors nearest 0 were turned to gray, so I went with this approach instead.

Thanks a ton StackOverflow community!

0

There are 0 best solutions below