Plotly(Python)自定义色阶重置为默认值的问题及需求
Hey there! I’ve dealt with this exact challenge before—getting a RdBu color scale anchored at z=1 (your mean value) while preserving full dynamic range and keeping sharp color detail in population-dense regions. Here’s a step-by-step solution that works:
Core Approach
The main trick is to build a custom color scale that locks yellow (the RdBu midpoint) exactly to z=1, while adding extra color stops in data-dense areas to avoid washing out subtle differences. We’ll calculate normalized positions for each color stop based on your actual z-value min/max, so the scale adapts to your dataset.
Full Code Example
Let’s assume you have your state data ready, with z_values being each state’s value divided by the overall mean (so z=1 is the average):
import plotly.express as px import numpy as np # Replace with your actual state codes and z-values state_codes = ['AL', 'AK', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'FL', 'GA', 'HI', 'ID', 'IL', 'IN', 'IA', 'KS', 'KY', 'LA', 'ME', 'MD', 'MA', 'MI', 'MN', 'MS', 'MO', 'MT', 'NE', 'NV', 'NH', 'NJ', 'NM', 'NY', 'NC', 'ND', 'OH', 'OK', 'OR', 'PA', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VT', 'VA', 'WA', 'WV', 'WI', 'WY'] z_values = np.random.uniform(0.4, 2.8, size=len(state_codes)) # Example z-scores relative to mean=1 # Calculate min/max of your z-values to normalize color stops z_min = z_values.min() z_max = z_values.max() # Build custom color scale: anchor yellow at z=1, add stops for dense regions # Format: [normalized_position, hex_color] color_stops = [ # Lower range (z < 1): blue → yellow [(z_min - z_min)/(z_max - z_min), '#003399'], # Dark blue for lowest z [(0.7 - z_min)/(z_max - z_min), '#6699FF'], [(0.9 - z_min)/(z_max - z_min), '#CCDDFF'], [(1 - z_min)/(z_max - z_min), '#FFFF00'], # Exact midpoint at z=1 (yellow) # Upper range (z > 1): yellow → red [(1.1 - z_min)/(z_max - z_min), '#FFDDCC'], [(1.3 - z_min)/(z_max - z_min), '#FF9966'], [(1.6 - z_min)/(z_max - z_min), '#FF6633'], [(z_max - z_min)/(z_max - z_min), '#990000'] # Dark red for highest z ] # Create the choropleth fig = px.choropleth( locations=state_codes, locationmode='USA-states', color=z_values, scope='usa', color_continuous_scale=color_stops, color_continuous_midpoint=None, # Disable auto midpoint to use our custom scale range_color=[z_min, z_max] # Lock to full z-value range (no clipping) ) # Add clear colorbar labeling to highlight the mean fig.update_layout( coloraxis_colorbar=dict( title='Value / Mean', tickvals=[z_min, 1, z_max], ticktext=[f'{z_min:.2f}', '1 (Mean)', f'{z_max:.2f}'], ticks='outside', thickness=20 ) ) fig.show()
Key Details Explained
- Custom Color Stops: Each stop uses a normalized position calculated as
(z_value - z_min)/(z_max - z_min). This ensures z=1 maps to a fixed position on the color bar, regardless of how asymmetric your min/max values are. - Extra Stops for Dense Areas: By adding stops at z=0.7, 0.9, 1.1, etc., we increase color resolution in regions where population-dense states are likely to cluster (near the mean or high z-values). This makes small differences easier to spot without losing full dynamic range.
- Locking the Range:
range_color=[z_min, z_max]guarantees the scale covers every value in your dataset—no clipping at either end. - Disabling Auto Midpoint: Setting
color_continuous_midpoint=Noneprevents Plotly from overriding your custom scale with its default midpoint calculation.
Adjustments for Your Data
If your dense regions are concentrated in high z-values (e.g., populous states have z > 1), shift extra stops to the upper range:
# Modified stops for high-value dense regions color_stops = [ [(z_min - z_min)/(z_max - z_min), '#003399'], [(1 - z_min)/(z_max - z_min), '#FFFF00'], [(1.2 - z_min)/(z_max - z_min), '#FFDDCC'], [(1.4 - z_min)/(z_max - z_min), '#FFBB99'], [(1.7 - z_min)/(z_max - z_min), '#FF8866'], [(2.0 - z_min)/(z_max - z_min), '#FF5533'], [(z_max - z_min)/(z_max - z_min), '#990000'] ]
内容的提问来源于stack exchange,提问作者NauticalN

