You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
add_hline not working for make_subplots if not populated #5136
Whenever you add a hline/vline to a plot it should display it at the given position. However, when the figure is made with make_subplots and is not yet populated with data, it never shows the line.
importplotly.graph_objectsasgofromplotly.subplotsimportmake_subplotsforname, figin {
"go.Figure": go.Figure(),
"make_subplots": make_subplots(rows=1, cols=1)
}.items():
fig.add_hline(y=0.5)
# Add a trace after the linefig.add_trace(go.Scatter(x=[1, 2], y=[0, 1]))
fig.update_layout(title=name)
fig.show()
In Figure.add_hline() and �dd_vline(), �xclude_empty_subplots defaults to True.
When a figure is initialized via make_subplots(), _has_subplots() is True. During _add_annotation_like() in plotly/basedatatypes.py: python if exclude_empty_subplots and ( not self._subplot_not_empty( xref, yref, selector=bool(exclude_empty_subplots) ) ): return self
Since self.data is empty at that point, _subplot_not_empty() evaluates to False for all subplots. The shape is silently dropped (
eturn self) instead of being appended to layout.shapes. When ig.add_trace(...) is called afterwards, the shape is already lost.
In contrast, on a bare go.Figure(), _has_subplots() is False, which resets
ow and col to None. This bypasses the subplot grid check entirely and allows �dd_hline() to succeed before data is added.
Proposed Fix
We can adjust the check in _add_annotation_like() so that �xclude_empty_subplots only filters subplots when the figure actually contains plotted data (i.e. �ool(self.data)), preserving reference lines configured prior to populating traces.
Happy to open a PR with regression unit tests covering �dd_hline/�dd_vline on unpopulated subplots if this direction sounds good to the maintainers!
Thanks for sharing your perspective @camdecoster! That is a really interesting point — when specific
ow and col arguments are passed, the intent to target that exact cell is very clear.
At the same time, we completely understand the maintainers' rationale discussed earlier in #5254 regarding how �xclude_empty_subplots was designed to avoid cluttering empty grids. The tricky part from a user standpoint is just the subtle order-of-operations effect: calling �dd_hline() before versus after �dd_trace() behaves differently because the shape gets dropped if traces aren't present yet.
@emilykl@gvwilson Whenever you have a chance to take a look, we would love to hear your thoughts on what you feel is the best direction for plotly.py:
Keeping the current behavior as-is and recommending �xclude_empty_subplots=False (perhaps adding a small note in the docstring to help users who run into this).
Or allowing a small tweak so that explicit
ow/col targets aren't dropped before data is populated.
No rush at all, and happy to help with either a docs clarification or a small PR depending on what the team prefers!
I think it's okay to make the small changes that I described to make the library more user friendly. If you want to do that, we can review a PR. FYI, those users that you tagged aren't maintainers here (while I am), so they wouldn't be able to make a decision on this.
Activity
gvwilson commentedon Apr 9, 2025
thanks for the bug report @NoniosTheMad
leavor commentedon Nov 14, 2025
plotly.py verson 6.4.0, has same issue
ioseba commentedon Oct 13, 2026
Hi @NoniosTheMad @gvwilson, I investigated the root cause of this behavior in plotly.py.
Root Cause
In Figure.add_hline() and �dd_vline(), �xclude_empty_subplots defaults to True.
When a figure is initialized via make_subplots(), _has_subplots() is True. During _add_annotation_like() in plotly/basedatatypes.py:
python if exclude_empty_subplots and ( not self._subplot_not_empty( xref, yref, selector=bool(exclude_empty_subplots) ) ): return selfSince self.data is empty at that point, _subplot_not_empty() evaluates to False for all subplots. The shape is silently dropped (
eturn self) instead of being appended to layout.shapes. When ig.add_trace(...) is called afterwards, the shape is already lost.
In contrast, on a bare go.Figure(), _has_subplots() is False, which resets
ow and col to None. This bypasses the subplot grid check entirely and allows �dd_hline() to succeed before data is added.
Proposed Fix
We can adjust the check in _add_annotation_like() so that �xclude_empty_subplots only filters subplots when the figure actually contains plotted data (i.e. �ool(self.data)), preserving reference lines configured prior to populating traces.
Happy to open a PR with regression unit tests covering �dd_hline/�dd_vline on unpopulated subplots if this direction sounds good to the maintainers!
camdecoster commentedon Oct 15, 2026
I think a better idea would be to skip
exclude_empty_subplotswhen it's obvious that the user wants the line such as:row/colioseba commentedon Oct 18, 2026
Thanks for sharing your perspective @camdecoster! That is a really interesting point — when specific
ow and col arguments are passed, the intent to target that exact cell is very clear.
At the same time, we completely understand the maintainers' rationale discussed earlier in #5254 regarding how �xclude_empty_subplots was designed to avoid cluttering empty grids. The tricky part from a user standpoint is just the subtle order-of-operations effect: calling �dd_hline() before versus after �dd_trace() behaves differently because the shape gets dropped if traces aren't present yet.
@emilykl @gvwilson Whenever you have a chance to take a look, we would love to hear your thoughts on what you feel is the best direction for plotly.py:
ow/col targets aren't dropped before data is populated.
No rush at all, and happy to help with either a docs clarification or a small PR depending on what the team prefers!
camdecoster commentedon Oct 19, 2026
I think it's okay to make the small changes that I described to make the library more user friendly. If you want to do that, we can review a PR. FYI, those users that you tagged aren't maintainers here (while I am), so they wouldn't be able to make a decision on this.