Plotly.py is an open-source Python library for creating interactive browser-based visualizations. Because it wraps Plotly.js, users can build high-quality charts in Python without needing to touch JavaScript directly.
My contribution focused on a bug and refactor path around labeled autoshapes, especially add_vline() on datetime axes.
The Issue
Historically, Plotly.py created two separate objects whenever a user added a labeled line or rectangle:
- a shape
- an annotation
That worked until users plotted datetime data and called add_vline(x="2020-09-24", annotation_text="Test"). The old code tried to compute the mean of x-coordinates to decide where to place the annotation, but dates cannot be averaged with integers, which caused a hard crash.
The real issue was architectural. Plotly.py was duplicating annotation behavior that Plotly.js already supports natively through shape.label.
Why I Started With add_vline()
I intentionally started with add_vline() because the datetime-axis crash was easiest to reproduce there. That made it the best entry point for validating whether the move to shape.label actually fixed the real user-facing failure mode.
What I Learned from Debugging
The old approach:
- computed averages and min/max values over user coordinates
- built annotations manually
- did not account cleanly for datetimes or mixed data types
- duplicated logic that Plotly.js already handled correctly
By shifting toward shape.label, that fragile arithmetic disappears. The label becomes part of the shape, and Plotly.js handles placement more consistently across axis types.
Progress
- Built
_coerceshape_label_from_legacy_annotation_kwargsto map legacy annotation args into label fields. - Updated
_process_multiple_axis_spanning_shapes()soadd_vline()can produce a single labeled shape. - Validated that the datetime-axis crash no longer occurs.
- Pushed the work to a shared branch and opened a draft PR.
- Outlined the next test and refactor targets for
add_hline(),add_vrect(), andadd_hrect().
Why it mattered
This contribution helped me understand how architectural decisions inside large libraries can create subtle but real failures for users. It also reinforced the importance of aligning abstractions across language boundaries when working on wrapper libraries like Plotly.py.
Related project · Plotly.py repository · Original LinkedIn article