Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error on using add_vline with text annotation for data with date-time x axis #3065

Open
MR0205 opened this issue Feb 5, 2021 · 22 comments · May be fixed by #3731
Open

Error on using add_vline with text annotation for data with date-time x axis #3065

MR0205 opened this issue Feb 5, 2021 · 22 comments · May be fixed by #3731
Assignees
Labels
bug something broken P3 backlog sev-2 serious problem
Milestone

Comments

@MR0205
Copy link

MR0205 commented Feb 5, 2021

Hi, I am trying to use the library for a simple visualisation for the first time, and I stumbled upon supposedly a bug trying to draw a vertical line with text annotation on a graph with a date-time x axis.

import plotly.express as px
df = px.data.stocks(indexed=True)
fig = px.line(df)
fig.add_vline(x="2018-09-24", annotation_text="test" )
fig.show()

I get the following error message:

TypeError: unsupported operand type(s) for +: 'int' and 'str'

Could anyone please help me confirm that it is indeed a bug, my version is '4.14.1' ? Thank you.

@nicolaskruchten nicolaskruchten added this to the upcoming milestone Feb 5, 2021
@nicolaskruchten nicolaskruchten added the bug something broken label Feb 5, 2021
@nicolaskruchten
Copy link
Contributor

Yep, definitely a bug! Thanks for the clear and reproducible report :)

I'm not immediately clear why we need to compute the midpoint of anything here

but this is the problem. Ideally we would need to rework this to use the (x|y)anchor attribute instead of trying to do math on the coordinates in the Python layer.

@awrobel1
Copy link

Hi @MR0205,

If you're looking for a temporary workaround, you can get the annotation to work by converting your x value into milliseconds since epoch as follows:

import plotly.express as px
import datetime
df = px.data.stocks(indexed=True)
fig = px.line(df)
fig.add_vline(x=datetime.datetime.strptime("2018-09-24", "%Y-%m-%d").timestamp() * 1000, annotation_text="test" )
fig.show()

@MR0205
Copy link
Author

MR0205 commented Feb 18, 2021

@awrobel1 Thanks for your idea, I thought on using a rectangle as a replacement, where you would make both edges start at the limit of a single day. Not sure though that will completely imitate the vertical line, due to possible problem when zooming.

@YukunYangNPF
Copy link

Following this too!

@tomshaffner
Copy link

The above suggestion from @awrobel1 was great for me. In my case I simplified a tad with x=datetime.datetime(2021,5,27).timestamp() * 1000. No need to convert from a string first in this case.

@nicholas-esterer
Copy link
Contributor

Yes, after looking into this a bit more, the implementation assumes the data are types that can have arithmetic performed on them. It needs to do this in order to compute where to put the annotation. This bug probably got through because to compute where an annotation is placed, it only needs to find the minimum, maximum or mean of the extreme coordinate values. min and max are defined for strings, so dates don't break it for positions like 'left', 'right', etc., but I think the fact that it works is just luck: the strings often sort the same as the dates.
This points to 2 things that could be fixed at the higher level:

  • when doing arithmetic on data, operators should be chosen corresponding to the type of the axis: e.g., if the axis type is 'date' then the values should be converted to milliseconds before arithmetic is performed
  • rather than having anchored annotations only available when using add_hline and the like, maybe have them available when using add_shape? Then add_hline, etc. are just special cases of add_shape.

@ClaudiaBehnke86
Copy link

Hi all,

I have a rather weird problem that might be connected to this issue.

I deployed an app using streamlit (V'1.2.0')

I use Plotly (V'5.3.1') to create a plot in the app.

The plot is a timeline, and there is a vertical line in it.
Based on this bug, i caluclate the postion of the of the line the following:
end_time_prelim = datetime.strptime(df['end_time'].max(), "%Y-%m-%d %H:%M:%S").timestamp() * 1000

And then use this in
fig.add_vline(x=end_time_prelim)
This works fine when I run the code locally.
However, in the online version, the line is at a shifted different position and slightly shifted.

Is this known?
Thanks a lot :-)

Not sure if helpful, but this would be the app:
https://share.streamlit.io/claudiabehnke86/tournamentcalculator/tourcalc/theapp.py

@awrobel1
Copy link

awrobel1 commented Jan 5, 2022

Hi @ClaudiaBehnke86,

Not sure, but you might be having trouble with time zones? When you run time timestamp calculation I believe that its looking for the timestamp based on your current timezone. So locally, everything works intuitively, but when you host your code in the cloud you start running on a UTC server and the times all seem to jump.

If this is the problem you just need to make sure to adjust your line based on the difference between your current time and UTC, by adding/subtracting milliseconds or using timezone aware times.

Also, make sure your code can handle time shifts for daylight savings time if relevant!

@ClaudiaBehnke86
Copy link

Yes, this makes a lot of sense :-D. Thanks for the hint!

@alexrblohm
Copy link

Hi @MR0205,

If you're looking for a temporary workaround, you can get the annotation to work by converting your x value into milliseconds since epoch as follows:

import plotly.express as px
import datetime
df = px.data.stocks(indexed=True)
fig = px.line(df)
fig.add_vline(x=datetime.datetime.strptime("2018-09-24", "%Y-%m-%d").timestamp() * 1000, annotation_text="test" )
fig.show()

Thanks for this! I had the same issue and it worked for me!

@jjrob13 jjrob13 linked a pull request May 14, 2022 that will close this issue
5 tasks
@fzyzcjy
Copy link

fzyzcjy commented Jun 15, 2022

Hi, how can I do similar things when x are strings (labels) instead of dates or numbers?

@mateomontero01
Copy link
Contributor

This is still a problem for all categorial data on the x axis. Is there any solution for when x are strings?

@jasonsross
Copy link

Yup this is still a very real and weird problem because if you try to do the annotation within the add_vline arguments you'll get the exception:

fig = px.line(df, x="string_category", y="some_values")
fig.add_vline(
    x="string_value",
    line_dash="dot",
    annotation_text="some_annotation"
)

but if you do it with an add_annotation function it works fine

fig = px.line(df, x="string_category", y="some_values")
fig.add_vline(
    x="string_value",
    line_dash="dot"
)
fig.add_annotation(x="string_value",text="some_annotation")

@BremondThomas
Copy link

Just got this exact error today, removing the annotation_text parameter works

@NikOcaml
Copy link

NikOcaml commented Jul 10, 2023

Same error! For both, annotation_text="..." and label=dict(text="...") inside add_vline(...)

@ChristopherRabotin
Copy link

Another solution is to add a box with a specific width:

from datetime import timedelta

fig.add_vrect(
        x0=epoch,
        x1=epoch + timedelta(minutes=1),
        annotation_text="Text laebel",
        fillcolor=color,
        line_width=2,
        line_color=color,
    )

@Dario-Mantegazza
Copy link

Got the same problem today as the one before using add_vline with the annotation_text parameter and I used this workaround.

Yup this is still a very real and weird problem because if you try to do the annotation within the add_vline arguments you'll get the exception:

fig = px.line(df, x="string_category", y="some_values")
fig.add_vline(
    x="string_value",
    line_dash="dot",
    annotation_text="some_annotation"
)

but if you do it with an add_annotation function it works fine

fig = px.line(df, x="string_category", y="some_values")
fig.add_vline(
    x="string_value",
    line_dash="dot"
)
fig.add_annotation(x="string_value",text="some_annotation")

@jtwild
Copy link

jtwild commented Feb 23, 2024

Can confirm this problem. Is it planned to be fixed in any upcoming release? It's been around for a while ;)

@archmoj
Copy link
Contributor

archmoj commented Feb 23, 2024

What happens if you convert the dates to UNIX timestamps?

@alexcjohnson
Copy link
Collaborator

Oh gosh, I don’t think we want to recommend Unix timestamps… we’d need them to be in milliseconds, and quite likely this will give time zone problems due to our weird backward-compatibility hacks on the plotlyjs side

@Dario-Mantegazza
Copy link

What happens if you convert the dates to UNIX timestamps?

I will try to test it on the week of the 11th of March as before I don't have time. I hope I will remember XD

@PainOchoco
Copy link

Oh gosh, I don’t think we want to recommend Unix timestamps… we’d need them to be in milliseconds, and quite likely this will give time zone problems due to our weird backward-compatibility hacks on the plotlyjs side

You're right, I've tried changing the datetime to a unix timestamp but the time zone is not kept, resulting in an offset on the vertical lines.
Please look into this, it's been a bug for 3 years!

@Coding-with-Adam Coding-with-Adam added the sev-2 serious problem label Jun 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug something broken P3 backlog sev-2 serious problem
Projects
None yet
Development

Successfully merging a pull request may close this issue.