In [ ]:
from bokeh.io import show, output_notebook
output_notebook()
In [ ]:
from app.utils import timelog_path
In [ ]:
import pandas as pd
import numpy as np
import datetime
raw = pd.read_table(timelog_path, quotechar=' ', sep=': ', names=['timestamp', 'activity'], engine='python',)
# Set the column types
raw.timestamp = pd.to_datetime(raw.timestamp)
raw = raw.drop_duplicates()
### Build the times
raw['formatted_time'] = raw.timestamp.apply(lambda x: x.strftime("%I %p")) # Used for hover tools
raw['end'] = raw.timestamp
raw['start'] = raw['end'].shift(1)
raw['start'] = np.where(
raw['activity'] == 'start', # If the activity is start
raw['timestamp'], # Set the start to timestamp
raw['start'], # Else leave it as start
)
raw['delta'] = raw.end - raw.start
# Remove the non-work activities which all have ***
raw = raw[~raw.activity.str.contains('\*\*\*')]
# Boil down the categories to the main work categories
raw.activity = raw.activity.str.split(' ').str[0]
raw.head()
In [ ]:
# Build a dictionary of frames - one for each category
activities = list(raw.activity.unique())
activities.remove('start')
start_df = raw[raw.activity == 'start']
nan_df = start_df.copy()
nan_df['delta'] = np.NaN
nan_df['activity'] = '_'
dfs = {}
for activity in activities:
activity_df = raw[raw.activity == activity]
# Add in the start rows with 0 deltas and do cumsum
activity_df = activity_df.append(start_df)
activity_df.sort('timestamp', inplace=True)
activity_df['cumsum'] = np.cumsum(activity_df.groupby(activity_df.timestamp.dt.date)['delta'])
activity_df['cumsum_hrs'] = activity_df['cumsum'].dt.seconds / (60 * 60)
# Add in the nan rows so bokeh can plobt
activity_df = activity_df.append(nan_df)
activity_df.sort(['timestamp', 'activity'], inplace=True)
dfs[activity] = activity_df
terra = dfs['terra']
terra.head()
In [ ]:
from bokeh.models import (
Plot, Line, ColumnDataSource, DataRange1d,
LinearAxis, BasicTicker,
DatetimeAxis, DatetimeTicker, DatetimeTickFormatter,
BoxZoomTool, PanTool, ResetTool, WheelZoomTool,
HoverTool, Grid
)
from bokeh import palettes
In [ ]:
plot = Plot(
x_range=DataRange1d(),
y_range=DataRange1d(),
background_fill='black',
border_fill='black',
outline_line_color=None,
plot_width=900,
plot_height=300
)
yticker = BasicTicker(min_interval=4)
close_ticker = DatetimeTicker(desired_num_ticks=8)
year_ticker = DatetimeTicker(desired_num_ticks=4)
year_ticks = DatetimeTickFormatter(
formats={
'years': ["%Y"],
'months': ["%Y"],
'days': ["%Y"],
'hours': ["%Y"]
}
)
close_ticks = DatetimeTickFormatter(
formats={
'years': ["%b"],
'months': ["%b"],
'days': ["%a %d %b"],
'hours': ["%I%p %d %b"]
}
)
axis_properties = dict(
major_label_text_color='white',
)
plot.add_layout(LinearAxis(ticker=yticker, **axis_properties), 'left')
plot.add_layout(DatetimeAxis(formatter=close_ticks, ticker=close_ticker, **axis_properties), 'below')
plot.add_layout(DatetimeAxis(formatter=year_ticks, ticker=year_ticker, **axis_properties), 'below')
plot.add_layout(Grid(dimension=1, ticker=yticker, grid_line_alpha=0.3))
tool_opts = dict(dimensions=['width'])
plot.add_tools(
BoxZoomTool(**tool_opts),
WheelZoomTool(**tool_opts),
PanTool(**tool_opts),
ResetTool(),
)
palette = getattr(palettes, 'Spectral%s' % len(activities))
for i, activity in enumerate(activities):
frame = dfs[activity][['cumsum_hrs', 'timestamp', 'formatted_time']]
source = ColumnDataSource(frame)
line = Line(
line_color=palette[i],
line_join='round', line_cap='round', line_width=5, line_alpha=0.75,
x='timestamp', y='cumsum_hrs'
)
plot.add_glyph(source, line)
show(plot)
In [ ]: