plotly / plotly/plotly.py

add_vline/hline annotation text location fixed to first shape if using a pre-instantiated dict for the "annotation" input parameter

Open
#3,547 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug P3
Dominant language
Python
Stars
18.8k
Forks
2.8k
Avg merge
16h 26m
Merged PRs (30d)
21

Description

Hi

When I instantiate a dict once with some constant formatting that I want to pass to the "annotation" argument for several calls of .add_vline() (or .add_hline()), all annotations for shapes created with this dict are placed with the shape created by the initial .add_vline() call.

e.g.:

import plotly.graph_objects as go

fig = go.Figure()

y_1 = [3000, 3500, 4000, 3500, 3000, 3500]
x_1 = list(range(len(y_1)))
fig.add_trace(go.Scatter(x=x_1, y=y_1))


annotation = dict(font_color="#000000")

fig.add_vline(x=2, annotation_text="vline 1", annotation=annotation)

print(f"annotation after first .add_vline():\n{annotation}")

fig.add_vline(x=3, annotation_text="vline 2", annotation=annotation)

print(f"annotation after second .add_vline():\n{annotation}")


fig.write_html("graph.html")

produces graph and output (similar result if .add_hline() used instead) - expected graph can be seen at the end of this post:
image

annotation after first .add_vline():
{'font_color': '#000000', 'text': 'vline 1', 'xanchor': 'left', 'yanchor': 'top', 'x': 2, 'y': 1, 'showarrow': False}
annotation after second .add_vline():
{'font_color': '#000000', 'text': 'vline 2', 'xanchor': 'left', 'yanchor': 'top', 'x': 2, 'y': 1, 'showarrow': False}

Is this expected behaviour? As the x coordinate is explicitly given in the method I would expect that the annotation defined would be placed at that x, as happens with the different annotation_text values.

As we can see from the output, it is because the original annotation dictionary instance is being mutated in the process of adding the annotation. Then if an x value is present in the annotation dictionary, it is not overwritten, but the text value is if a new annotation_text value is passed.

Looking at the package code, I can achieve the behaviour I expected by implementing an else here:
https://github.com/plotly/plotly.py/blob/cfad7862594b35965c0e000813bd7805e8494a5b/packages/python/plotly/plotly/shapeannotation.py#L203-L204
Suggestion:

    if annotation is None:
        annotation = dict()
    else:
        annotation = annotation.copy()

I have made this change locally and run fine and as I expect.

If the current behaviour is not the expected behaviour, and if the suggested change above is acceptable, I would be glad to implement and test it appropriately then submit a pull request.

Cheers!


Graph I expect:
image

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in plotly/shapeannotation.py at lines 203-204 and reproduce the issue with repeated add_vline() calls using one annotation dictionary, then compare add_hline(). Done means the supplied dictionary is not mutated and each shape's annotation uses its own coordinate; add or update tests for both methods as appropriate.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
data-visualization
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.