0

I want to represent time_spent as combination of hours and minutes instead of bare seconds. I tried making HoursAndMinutes column and then adding it as y axis into graph, but that ruined scalling of bars. I want to be able to see time in format of (example) 5h 15min and also be able to scale bars properly. Maybe is it possible to sort by different column (time_spent) and display formatted version?

My code:

main.py

import pandas as pd
import plotly.express as px
from utils import TimeHandler


example_data = {"date": ["29/07/2022", "30/07/2022", "31/07/2022"], 
                "time_spent" : [15840, 21720, 40020]}
df = pd.DataFrame(example_data)
df["date"] = pd.to_datetime(df["date"], dayfirst=True)

for i, time_scale in enumerate(["hours", "minutes"]):
    df[time_scale] = df.apply(lambda row: TimeHandler.unpack_seconds(row.time_spent)[i], axis=1)

df["HoursAndMinutes"] = df.apply(lambda row: f'{row.hours}h {row.minutes}min', axis=1)

fig = px.bar(df, x='date', y='HoursAndMinutes',
             labels={'date':'Date'},
             height=900)

config = {'displayModeBar': False}

fig.update_layout(
    title='Time spent over days',
    font={'size': 18})

fig.show(config=config)

utils.py

class TimeHandler:

    @staticmethod
    def unpack_seconds(seconds):
        seconds = int(seconds)
        hours, seconds = divmod(seconds, 3600)
        minutes, seconds = divmod(seconds, 60)
        return hours, minutes, seconds

Current result chart:

figure

Wanna get like this:

figure

Vitalizzare
  • 4,496
  • 7
  • 13
  • 32
batreska
  • 53
  • 5

1 Answers1

0

In this case, the time series is treated as a string and is equally spaced, so it must be treated as a time series. The time series is converted from a time lapse value to a date/time format. That is specified on the y-axis. The graph is modified by using the interval value of the scale on the y-axis as the time. The x-axis is set to 1-day intervals. The horizontal line is the y-axis, and the date of the data and the time of the average time must be specified for the code. Let's say 8 o'clock.

import pandas as pd
import plotly.express as px

example_data = {"date": ["29/07/2022", "30/07/2022", "31/07/2022"], 
                "time_spent" : [15840, 21720, 40020]}
df = pd.DataFrame(example_data)
df["date"] = pd.to_datetime(df["date"], dayfirst=True)

import datetime
df['HoursAndMinutes'] = df['time_spent'].apply(lambda x:str(datetime.timedelta(seconds=x)))
df['HoursAndMinutes'] = pd.to_datetime(df['HoursAndMinutes'])


import plotly.graph_objects as go

fig = go.Figure([go.Bar(x=df['date'], y=df['HoursAndMinutes'])])

fig.update_yaxes(range=[datetime.datetime(2022,8,1,0,0,0), datetime.datetime(2022,8,1,11,0,0)], dtick=60*60*1000, tickformat='%H h')
#fig.update_traces(hovertemplate=None)
#fig.update_layout(hovermode="y unified")
fig.update_xaxes(type='date', dtick='D1')
fig.add_hline(y=datetime.datetime(2022,8,1,8,0,0), line_width=3, line_dash="dash", line_color="green")
fig.add_annotation(x=1.03, y=0.8, xref='paper', yref='paper', text='avg', showarrow=False, font=dict(color='green',size=12))
fig.show()

enter image description here

r-beginners
  • 31,170
  • 3
  • 14
  • 32
  • Is there a way to make time not (ex.) 07:00, but rather 7h 0min or just 7h? Also can't way to scale it from 0 time instead of lowest amount. – batreska Aug 01 '22 at 08:56
  • Y-axis notation was changed to time display, and the range of the Y-axis was changed to start at 0:00. – r-beginners Aug 01 '22 at 12:49
  • is there a way to add text to the line? When i add `annotation_text="test"` into `fig.add_hline` it raises `"TypeError: Addition/subtraction of integers and integer-arrays with Timestamp is no longer supported. Instead of adding/subtracting "n", use "n * obj.freq"` which I don't understand how to solve. Thanks for help in advance! – batreska Aug 01 '22 at 13:38
  • Annotations are set with add_annotation(). You want to add 'avg' on the right side? – r-beginners Aug 01 '22 at 13:53
  • Yes, pretty much as in example shown in post – batreska Aug 01 '22 at 17:24
  • If you set it based on the xy axis of the graph in the text annotation, the graph will collapse, so it is specified based on the graph area. The y-axis values are manually set. – r-beginners Aug 02 '22 at 01:05