Reputation: 141
I'm trying to create a graph with plotly and cufflinks that has dates on the xaxis, some amounts on the primary y, and time on the secondary y.
The data looks like this:
automatic manual time
2019-02-25 206.0 1206.0 2019-02-26 16:58:09
2019-02-26 225.0 136.0 2019-02-27 08:33:49
2019-02-27 213.0 554.0 2019-02-28 07:25:19
2019-02-28 244.0 103.0 2019-03-01 07:32:37
2019-03-01 102.0 119.0 2019-03-04 12:06:37
The setup for the figure is as follows:
fig = go.Figure(**cf.tools.merge_figures([
df.figure(columns=["automatic", "manual"], kind="bar", barmode="stack"),
df.figure(columns=["time"])
])).set_axis(["time"], side="right")
The only way I've gotten the graph I want is by setting the date part of each date in the df.time
column to the same arbitrary date, like so:
df.loc[:, "time"] = df.time.apply(lambda d: d.replace(year=1967, month=1, day=1))
However, this way I get the wrong hover text and that arbitrary date is displayed at the bottom of the secondary y.
I've tried to set the range on yaxis2
manually like so:
sotimes = [d for d in df.time.tolist() if not pd.isnull(d)]
fig["layout"].update({"yaxis2": {"range": [f"{min(sotimes):%H:%M:%S}", f"{max(sotimes):%H:%M:%S}"]}})
Strangely, this results in yaxis2
being a date range as well.
I've also tried to convert df.time
to time only, either as a string or as datetime.time like so:
df.loc[:, "time"] = df.time.apply(
lambda d: d.time() if not pd.isnull(d) else pd.NaT)
df.loc[:, "time"] = df.time.apply(
lambda d: f"{d:%H:%M:%S}" if not pd.isnull(d) else "")
Both of these result in yaxis2
not being ordered at all, the times are displayed in the order in which they appear in df.time
.
EDIT 1 - add complete code
import cufflinks as cf
import plotly.graph_objs as go
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
import pandas as pd
# plotly stuff
cf.go_offline()
dct = {
"date": ["2019-02-25", "2019-02-26", "2019-02-27", "2019-02-28", "2019-03-01"],
"auto": [206, 225, 213, 244, 102],
"manual": [1206, 136, 554, 103, 119],
'time': [pd.Timestamp(2019, 2, 26, 16, 58, 9), pd.Timestamp(2019, 2, 27, 8, 33, 49),
pd.Timestamp(2019, 2, 28, 7, 25, 19), pd.Timestamp(2019, 3, 1, 7, 32, 37),
pd.Timestamp(2019, 3, 4, 12, 6, 37)]
}
df = pd.DataFrame(dct).set_index("date")
df.loc[:, "time"] = df.time.apply(lambda d: d.replace(year=1967, month=1, day=1))
fig = go.Figure(**cf.tools.merge_figures([
df.figure(columns=["auto", "manual"], kind="bar", barmode="stack"),
df.figure(columns=["time"])
])).set_axis(["time"], side="right")
# sotimes = [d for d in df.time.tolist() if not pd.isnull(d)]
# fig["layout"].update({"yaxis2": {"range": [f"{min(sotimes):%H:%M:%S}", f"{max(sotimes):%H:%M:%S}"]}})
plot(fig)
Upvotes: 0
Views: 1212
Reputation: 11
This isn't an answer to the whole question, but creates a working graph the way you would want it to. Using the approach of setting every datetime instance to the same date, you could adapt the tick labels using:
fig["layout"].update({"yaxis2": {"tickformat": "%H:%M"}})
Upvotes: 1