dimwit 0.2.8__tar.gz → 0.2.9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dimwit
3
- Version: 0.2.8
3
+ Version: 0.2.9
4
4
  Summary: A package containing various functions and classes for fetching, transforming, and visualising data for personal metrics.
5
5
  Home-page: https://github.com/danielsoutar/dimwit
6
6
  Author: Daniel Soutar
@@ -1,4 +1,6 @@
1
1
  from dimwit.main import *
2
2
  import dimwit.airflow
3
3
  import dimwit.legacy
4
+ import dimwit.pomodoro
5
+ import dimwit.weight
4
6
  import dimwit.air_pollution as ap
@@ -0,0 +1,168 @@
1
+ import pandas as pd
2
+ from typing_extensions import NamedTuple
3
+
4
+
5
+ def is_business_day(date):
6
+ return bool(len(pd.bdate_range(date, date)))
7
+
8
+
9
+ def generate_cumulative_df(df, ref_policy, from_date=None, until_date=None):
10
+ from_date = df.index[0] if from_date is None else from_date
11
+ until_date = df.index[-1] if until_date is None else until_date
12
+ time_range_df = df.copy(deep=True).loc[from_date:until_date]
13
+
14
+ exclude_dates = []
15
+
16
+ resolution = ref_policy.pomodoro_length + ref_policy.break_length
17
+ current_time = pd.Timestamp.today().time().replace(second=0, microsecond=0)
18
+ start_of_business = current_time.replace(hour=9, minute=0)
19
+ close_of_business = current_time.replace(hour=17, minute=0)
20
+ ref_entries = get_reference_entries(
21
+ time_range_df.index,
22
+ resolution,
23
+ start_of_business,
24
+ close_of_business,
25
+ exclude_dates,
26
+ )
27
+
28
+ target_entries = get_target_entries(time_range_df.index, exclude_dates)
29
+
30
+ ref_pom_col = "Reference Pomodoro Lengths " + ref_policy.description
31
+ ref_break_col = "Reference Break Lengths " + ref_policy.description
32
+ target_pom_col = "Target Pomodoro Lengths (3x 45+15)"
33
+ target_break_col = "Target Break Lengths (3x 45+15)"
34
+
35
+ time_range_df[ref_pom_col] = 0.0
36
+ time_range_df[ref_break_col] = 0.0
37
+ time_range_df[target_pom_col] = 0.0
38
+ time_range_df[target_break_col] = 0.0
39
+
40
+ time_range_df.loc[ref_entries, ref_pom_col] = ref_policy.pomodoro_length
41
+ time_range_df.loc[ref_entries, ref_break_col] = ref_policy.break_length
42
+ time_range_df.loc[target_entries, target_pom_col] = 45.0
43
+ time_range_df.loc[target_entries, target_break_col] = 15.0
44
+
45
+ cumulative_df = time_range_df.cumsum()
46
+
47
+ return cumulative_df
48
+
49
+
50
+ def get_target_entries(index, exclude_dates):
51
+ valid_entries_for_target = []
52
+
53
+ set_times = set([9, 10, 11])
54
+
55
+ for i, timestamp in enumerate(index):
56
+ if timestamp in exclude_dates or not is_business_day(timestamp):
57
+ continue
58
+ ts: pd.Timestamp = timestamp
59
+ if ts.time().hour in set_times and ts.time().minute == 0:
60
+ valid_entries_for_target.append(ts)
61
+
62
+ return valid_entries_for_target
63
+
64
+
65
+ def get_reference_entries(
66
+ index,
67
+ resolution,
68
+ start_time,
69
+ end_time,
70
+ exclude_dates,
71
+ ):
72
+ valid_entries_for_reference = []
73
+
74
+ for i, timestamp in enumerate(index):
75
+ if timestamp in exclude_dates:
76
+ continue
77
+ if is_business_day(timestamp):
78
+ time = timestamp.time()
79
+ start_of_day, end_of_day = start_time, end_time
80
+ if time >= start_of_day and time < end_of_day and time.hour != 13:
81
+ # Way to fix this would be to check if the latest valid entry
82
+ # has the delta. Skip this step until len(valid_entries) > 0.
83
+ if len(valid_entries_for_reference) > 0:
84
+ delta = timestamp - valid_entries_for_reference[-1]
85
+ if delta < pd.Timedelta(minutes=resolution):
86
+ continue
87
+ valid_entries_for_reference.append(timestamp)
88
+
89
+ return valid_entries_for_reference
90
+
91
+
92
+ class ReferencePolicy(NamedTuple):
93
+ pomodoro_length: float
94
+ break_length: float
95
+ description: str
96
+
97
+
98
+ def get_kth_latest_monday(k=0):
99
+ today = pd.to_datetime("today", utc=True)
100
+ latest_monday = today - pd.Timedelta(days=today.weekday(), weeks=k)
101
+ latest_monday_start_of_day = latest_monday.replace(hour=8, minute=0)
102
+ return latest_monday_start_of_day
103
+
104
+
105
+ def get_kth_latest_sunday(k=0):
106
+ today = pd.to_datetime("today", utc=True)
107
+ today_k_weeks_ago = today - pd.Timedelta(weeks=k)
108
+ latest_sunday = today_k_weeks_ago + pd.Timedelta(
109
+ days=7 - today.weekday() - 1,
110
+ )
111
+ latest_sunday_end_of_day = latest_sunday.replace(hour=18, minute=0)
112
+ return latest_sunday_end_of_day
113
+
114
+
115
+ def generate_cumulative_df_for_kth_latest_week(df, k):
116
+ pomodoro_date_range = pd.date_range(
117
+ start=get_kth_latest_monday(k), freq="d", end=get_kth_latest_sunday(k)
118
+ )
119
+ start, end = pomodoro_date_range[0], pomodoro_date_range[-1]
120
+
121
+ # If end later than latest available entry in df (i.e. start of the week),
122
+ # then pad out df to generate zero entries.
123
+ # if end > df.index[-1]:
124
+ # num_entries = 0
125
+ # latest_val = df.index[-1]
126
+ # while end > latest_val:
127
+ # latest_val += df.index.freq
128
+ # num_entries += 1
129
+ # df = dimwit.pad_out_table(
130
+ # df, num_entries, df.index.freq, pad_before=False
131
+ # )
132
+
133
+ ref_policy = ReferencePolicy(45.0, 15.0, "(45+15)")
134
+ cum_df = generate_cumulative_df(df, ref_policy, start, end)
135
+
136
+ return cum_df, ref_policy, start, end
137
+
138
+
139
+ def plot_burn_up_plot_for_kth_latest_week(df, k):
140
+ result = generate_cumulative_df_for_kth_latest_week(df, k)
141
+ cum_df, ref_policy, start, end = result
142
+
143
+ ref_col = "Reference Pomodoro Lengths " + ref_policy.description
144
+ target_col = "Target Pomodoro Lengths (3x 45+15)"
145
+
146
+ ax = cum_df.plot(y=["pomodoro_lengths", ref_col, target_col])
147
+
148
+ total_pomodoro_length = cum_df["pomodoro_lengths"].iloc[-1]
149
+ total_ref_pomodoro_length = cum_df[ref_col].iloc[-1]
150
+ total_target_pomodoro_length = cum_df[target_col].iloc[-1]
151
+
152
+ ax.legend(
153
+ labels=[
154
+ f"Pomodoro Lengths (Mixed), total={total_pomodoro_length}",
155
+ target_col + f", total={total_target_pomodoro_length}",
156
+ ref_col + f", total={total_ref_pomodoro_length}",
157
+ ],
158
+ loc="upper right",
159
+ )
160
+ ax.set_ylabel("Cumulative time (minutes)")
161
+
162
+ start_str = start.to_pydatetime().strftime("%d/%m")
163
+ end_str = end.to_pydatetime().strftime("%d/%m")
164
+
165
+ ax.set_title(f"Work Pomodoros for week ({start_str}-{end_str})")
166
+ ax.set_ylim(0, 2100)
167
+
168
+ return ax
@@ -0,0 +1,65 @@
1
+ from dimwit import get_moving_average_trend, populate_with_events
2
+
3
+ from datetime import datetime, timedelta
4
+
5
+ import datetime as dat
6
+ import matplotlib.pyplot as plt
7
+ import numpy as np
8
+
9
+
10
+ def beginning_of_data():
11
+ dst = dat.timezone(dat.timedelta(seconds=3600))
12
+ return datetime(2023, 5, 20, 0, 0, tzinfo=dst)
13
+
14
+
15
+ def daterange(start_date, end_date, unit, step=1):
16
+ N = int((end_date - start_date) / timedelta(**{unit: 1}))
17
+ for n in range(0, N, step):
18
+ yield start_date + timedelta(**{unit: n})
19
+
20
+
21
+ def data_over_period(df, from_date, moving_average_window_size, events, title):
22
+ fig, ax = plt.subplots(1, 1, figsize=(12, 6))
23
+ current_target = 68.0
24
+
25
+ latest_df = df.loc[from_date:]
26
+ xs = latest_df.index
27
+ ys = np.array(latest_df["weight_kg"])
28
+
29
+ category_names = ["active-era-ref-scale", "external-scale", "historical"]
30
+ category_labels = ["Reference", "External", "Historical"]
31
+
32
+ for category, label in zip(category_names, category_labels):
33
+ category_df = latest_df.loc[latest_df["category"] == category]
34
+ category_xs = category_df.index
35
+ ax.scatter(category_xs, category_df["weight_kg"], label=label)
36
+
37
+ current_target_ys = [current_target] * len(xs)
38
+ ax.plot(
39
+ xs,
40
+ current_target_ys,
41
+ label=f"Current Target ({current_target}kg)",
42
+ )
43
+
44
+ window_size = moving_average_window_size
45
+
46
+ # Calculate the rolling average over the max values array
47
+ # TODO: Figure out whether to use actual data rather than repeating first
48
+ # point (k - 1) / 2 times, where possible.
49
+ rolling_average = get_moving_average_trend(ys, window_size)
50
+ ax.plot(
51
+ xs,
52
+ rolling_average,
53
+ label=f"Rolling Avg ({window_size})",
54
+ color="green",
55
+ )
56
+
57
+ ax = populate_with_events(ax, events, xs[0])
58
+
59
+ ax.set_ylabel("Weight (kg)")
60
+ plt.legend()
61
+ plt.grid()
62
+ # Add a title to the entire figure
63
+ fig.suptitle(title, fontsize=16)
64
+
65
+ return fig, ax
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "dimwit"
3
- version = "0.2.8"
3
+ version = "0.2.9"
4
4
  description = "A package containing various functions and classes for fetching, transforming, and visualising data for personal metrics."
5
5
  authors = ["Daniel Soutar <danielsoutar144@gmail.com>"]
6
6
  readme = "README.md"
File without changes
File without changes
File without changes
File without changes
File without changes