My data comes as a Pandas DataFrame with a datetime index, that is generated from UNIX timestamps. I would like to display the data in a Plotly chart in the browser's timezone, but haven't figured out how.
What I've tried so far:
float
s): Displays timestamps as numeric values (as expected)I know that there are still open bugs/feature requests regarding timezone handling (central one probably https://github.com/plotly/plotly.js/issues/3870), but given that JavaScript itself also uses a variant of UNIX timestamps to represent dates/times internally, I would guess that just passing the numeric timestamps to Plotly and letting it convert them to the browser's date/time representation in its own timezone would seem quite easy and efficient. However, I haven't found a way of how to do this. Any ideas? Or is what I'm trying to achieve just not possible with Plotly and the timezone needs to be explicitly set on the server side?
Here's a working example displaying what I've tried so far, with the last one being what I'm trying to achieve, but without having to manually specify the timezone:
import calendar
import time
import numpy as np
import pandas as pd
import plotly.graph_objects as go
def ptime(ts: str) -> float:
return calendar.timegm(time.strptime(ts, '%Y-%m-%dT%H:%M:%SZ'))
columns = [
'timestamp',
'value',
]
data = np.array([
[ptime('2024-01-01T00:00:00Z'), 0.0],
[ptime('2024-01-01T01:00:00Z'), 1.0],
[ptime('2024-01-01T02:00:00Z'), 2.0],
[ptime('2024-01-01T03:00:00Z'), 3.0],
[ptime('2024-01-01T04:00:00Z'), 4.0],
[ptime('2024-01-01T05:00:00Z'), 5.0],
])
df = pd.DataFrame(data, columns=columns, index=pd.to_datetime(data[:, 0], unit='s'), dtype=float)
fig = go.Figure()
fig.add_trace(go.Scatter(
x=df['timestamp'],
y=df['value'],
))
fig.update_layout(
title='UNIX timestamps',
margin=dict(l=10, r=10, t=40, b=10),
)
fig.show(renderer='browser')
fig = go.Figure()
fig.add_trace(go.Scatter(
x=df.index,
y=df['value'],
))
fig.update_layout(
title='Naive Pandas DateTimeIndex',
margin=dict(l=10, r=10, t=40, b=10),
)
fig.show(renderer='browser')
fig = go.Figure()
fig.add_trace(go.Scatter(
x=df.index.tz_localize('UTC'),
y=df['value'],
))
fig.update_layout(
title='Localized (UTC) Pandas DateTimeIndex',
margin=dict(l=10, r=10, t=40, b=10),
)
fig.show(renderer='browser')
fig = go.Figure()
fig.add_trace(go.Scatter(
x=df.index.tz_localize('UTC').tz_convert('US/Pacific'),
y=df['value'],
))
fig.update_layout(
title='Localized (UTC) Pandas DateTimeIndex with converted timezone',
margin=dict(l=10, r=10, t=40, b=10),
)
fig.show(renderer='browser')
I've obviously searched in the wrong places, what I wanted to achieve is actually indeed very simple by giving JavaScript timestamps (UNIX timestamp * 1000) and explicitly setting the axis type
to 'date'. No need for Pandas anymore:
import calendar
import time
import numpy as np
import plotly.graph_objects as go
def ptime(ts: str) -> float:
return calendar.timegm(time.strptime(ts, '%Y-%m-%dT%H:%M:%SZ'))
columns = [
'timestamp',
'value',
]
data = np.array([
[ptime('2024-01-01T00:00:00Z'), 0.0],
[ptime('2024-01-01T01:00:00Z'), 1.0],
[ptime('2024-01-01T02:00:00Z'), 2.0],
[ptime('2024-01-01T03:00:00Z'), 3.0],
[ptime('2024-01-01T04:00:00Z'), 4.0],
[ptime('2024-01-01T05:00:00Z'), 5.0],
])
fig = go.Figure()
fig.add_trace(go.Scatter(
x=data[:, 0]*1000, # Timestamp in ms for JavaScript.
y=data[:, 1],
))
fig.update_layout(
title='JavaScript timestamps with axis type "date"',
margin=dict(l=10, r=10, t=40, b=10),
xaxis=dict(
type='date', # Tell Plotly to treat data as timestamps.
),
)
fig.show(renderer='browser')