How to create a heatmap with fixed color limits in Plotly (with Code)
The Short Answer (TL;DR)
Pass range_color=(lower, upper) to px.imshow for a numeric two-dimensional heatmap. Reusing the same limits and color scale across charts makes a given numeric value use the same color.
import plotly.express as px
fig = px.imshow([[0, 2, 5], [3, 7, 10]], range_color=(0, 10), color_continuous_scale="Viridis", text_auto=True)
fig.write_html("fixed-color-heatmap.html", include_plotlyjs=True, auto_open=False)
Detailed Implementation
This example uses synthetic data and does not need a network connection. Install the recorded package versions in a separate Python environment before running it.
python -m pip install pandas==3.0.6 plotly==7.1.0 numpy==2.5.4
import numpy as np
import plotly.express as px
values = np.array([[0.0, 2.0, 5.0], [3.0, 7.0, 10.0]])
fig = px.imshow(values, x=["Sample A", "Sample B", "Sample C"],
y=["Run 1", "Run 2"], origin="upper", aspect="auto",
range_color=(0, 10), color_continuous_scale="Viridis",
text_auto=".1f", binary_string=False,
labels={"x": "Sample", "y": "Run", "color": "Measurement"},
title="Measurements on a fixed 0 to 10 color scale")
fig.update_layout(template="plotly_white", height=420)
fig.write_html("fixed-color-heatmap.html", include_plotlyjs=True, full_html=True,
auto_open=False, div_id="fixed-color-heatmap")
The HTML contains six labelled cells with their original values and a colorbar fixed from 0 to 10. The value 5 lies halfway through the specified color scale.
How do fixed limits help comparisons?
With limits of 0 and 10, a value of 5 has the same normalized position in every chart that uses this scale. Autoscaling each chart independently can assign the same color to different values. Keep the units, color scale and limits consistent when comparing panels.
What happens outside the specified range?
Values outside the limits use the end colors. The underlying measurements remain available in the numeric trace and its hover information. Check the data range and state any clipping so saturated colors are not mistaken for identical measurements.
Why use a numeric heatmap rather than a binary image?
binary_string=False retains scalar values in a Heatmap trace, and text_auto formats the cell labels. Plotly Express also accepts RGB images, but those have different color handling. range_color here applies to a scalar two-dimensional array, not a general rule for RGB channels.
Mathematical Context
A linear color normalization maps a value z to u=(z-L)/(U-L), for limits L smaller than U. In this example, z=5 maps to 0.5 because L=0 and U=10. The display uses endpoint colors beyond the selected range. This transformation chooses color positions; it does not standardize the observations statistically or change the stored values.
\[ u=\frac{z-L}{U-L},\qquad L<U \]
Reproducibility
Executed with Python 3.12.14; pandas 3.0.6, plotly 7.1.0, numpy 2.5.4. Automated checks confirm the stated output properties.