多类别Plotly箱线图优化:默认颜色获取、单图例设置及箱线顺序控制
Hey there! Let's tackle your three Plotly box plot customization questions one by one, with a polished code solution that addresses all your needs:
1. Use Plotly's Default Color Cycle
Instead of hardcoding colors, you can access Plotly's built-in qualitative color palette via plotly.colors.qualitative.Plotly — this is the exact palette used by default for traces, so your charts will match other Plotly visualizations seamlessly. Just pick the first n colors you need (in this case, 2 for categories "a" and "b"). You can also adjust transparency for fill colors by modifying the color string to use rgba instead of rgb.
2. More Flexible Legend Control
Instead of checking if you're on the first value column, use legend groups to link traces of the same category across subplots. Then, only enable the legend for the first occurrence of each category. This approach is far more robust if you ever add more subplots or reorder your value columns, and it also ensures clicking a legend item toggles all traces of that category across both subplots.
3. Control Category Display Order
To specify the exact order of categories ("a" vs "b") in your box plots, define a custom order list and set categoryorder='array' + categoryarray=your_order in each Box trace. This forces Plotly to render categories in your desired sequence instead of relying on default alphabetical ordering.
Full Modified Code
import pandas as pd import numpy as np from plotly import graph_objects as go from plotly.subplots import make_subplots import plotly.colors # Import to access default color palette np.random.seed(42) df = pd.DataFrame( { "val1": np.random.normal(0, 1, size=100), "val2": np.random.normal(5, 2, size=100), "cat": np.random.choice(["a", "b"], size=100), } ) # --- Customization Settings --- # 1. Grab first 2 colors from Plotly's default qualitative palette default_colors = plotly.colors.qualitative.Plotly # Optional: Add transparency to fill colors fill_colors = { "a": default_colors[0].replace("rgb", "rgba").replace(")", ", 0.5)"), "b": default_colors[1].replace("rgb", "rgba").replace(")", ", 0.5)") } # Use this if you don't want transparency: # fill_colors = {"a": default_colors[0], "b": default_colors[1]} # 2. Define your preferred category display order cat_order = ["a", "b"] # Swap to ["b", "a"] to reverse the order # 3. Track which categories already have a legend entry legend_added = set() # Create subplots fig = make_subplots(rows=2, cols=1, subplot_titles=["Value 1 dist", "Value 2 dist"]) for i, val in enumerate(["val1", "val2"]): # Iterate through categories in your custom order for c in cat_order: dff = df[df["cat"] == c] # Show legend only if this category hasn't been added yet show_legend = c not in legend_added fig.add_trace( go.Box( y=dff[val], x=dff["cat"], boxmean="sd", name=c, showlegend=show_legend, legendgroup=c, # Link same-category traces across subplots fillcolor=fill_colors[c], line={"color": fill_colors[c].split(", 0.5)")[0] + ")"}, # Opaque border # Enforce custom category order on the x-axis categoryorder='array', categoryarray=cat_order ), row=i + 1, col=1, ) # Mark category as having its legend entry added if show_legend: legend_added.add(c) # Optional: Tweak layout for better readability fig.update_layout( height=600, title_text="Customized Box Plots", legend_title_text="Categories" ) fig.show()
Key Details
- Default Colors: The
plotly.colors.qualitative.Plotlylist includes 10 distinct colors, so you can easily expand this for more categories. - Legend Groups: This feature creates a unified legend experience — clicking "a" hides both "a" boxes in the top and bottom subplots.
- Category Order: Simply modify the
cat_orderlist to reposition categories instantly, no need to rearrange your data.
内容的提问来源于stack exchange,提问作者Dror

