Description
A Plotly Express sunburst chart changes color assignment when marker.colors is
reassigned to its current value.
The chart structure and labels stay the same, but the segment colors differ. This
looks like marker.colors is not idempotent for sunburst traces: explicitly assigning
the existing color tuple changes the color resolution path.
Screenshots/Video
Steps to reproduce
import io
import json
import plotly
import plotly.express as px
import plotly.io as pio
from PIL import Image, ImageChops
from playwright.sync_api import sync_playwright
print(f"Plotly version: {plotly.__version__}")
def make_fig():
df = px.data.tips()
return px.sunburst(
df,
path=["sex", "day", "time"],
values="total_bill",
color="time",
)
colors = tuple(make_fig().data[0].marker.colors)
# Case 1: reassign marker.colors before the initial render.
fig1 = make_fig()
fig1.data[0].marker.colors = colors
assert tuple(fig1.data[0].marker.colors) == colors
html1 = pio.to_html(fig1, full_html=True, include_plotlyjs=True)
# Case 2: render first, then reassign the same value with Plotly.restyle.
fig2 = make_fig()
html2 = pio.to_html(fig2, full_html=True, include_plotlyjs=True)
html2 = html2.replace(
"</body>",
f"""
<script>
window.addEventListener("DOMContentLoaded", () => {{
const plotEl = document.getElementsByClassName("plotly-graph-div")[0];
setTimeout(() => {{
Plotly.restyle(plotEl, {{"marker.colors": {json.dumps(colors)}}}, [0]);
}}, 1000);
}});
</script>
</body>""",
)
with sync_playwright() as playwright:
browser = playwright.chromium.launch(
headless=True,
args=["--no-sandbox", "--disable-dev-shm-usage", "--disable-gpu"],
)
page = browser.new_page(viewport={"width": 1200, "height": 800})
page.set_content(html1, wait_until="domcontentloaded")
page.wait_for_timeout(1500)
img1 = page.screenshot(path="plot1.png")
page.set_content(html2, wait_until="domcontentloaded")
page.wait_for_timeout(2000)
img2 = page.screenshot(path="plot2.png")
browser.close()
diff = ImageChops.difference(
Image.open(io.BytesIO(img1)).convert("RGB"),
Image.open(io.BytesIO(img2)).convert("RGB"),
)
print("Saved plot1.png (Python-side reassignment before render)")
print("Saved plot2.png (JS-side restyle after render)")
assert diff.getbbox() is not None, "Reproducer did not reproduce: images are identical."
print("Bug reproduced: the two renderings differ.")
Notes
Add info here that doesn't fit in the other sections.
Description
A Plotly Express sunburst chart changes color assignment when
marker.colorsisreassigned to its current value.
The chart structure and labels stay the same, but the segment colors differ. This
looks like
marker.colorsis not idempotent for sunburst traces: explicitly assigningthe existing color tuple changes the color resolution path.
Screenshots/Video
Steps to reproduce
Notes
Add info here that doesn't fit in the other sections.