diff --git a/dot-stats/history.json b/dot-stats/history.json index 1e2ec22..e08d236 100644 --- a/dot-stats/history.json +++ b/dot-stats/history.json @@ -78,7 +78,17 @@ "color": "b", "states": [ { - "startDate": "2020-05-08" + "startDate": "2020-05-08", + "endDate": "2021-11-14" + } + ] + }, + { + "name": "EXWM", + "color": "m", + "states": [ + { + "startDate": "2021-11-14" } ] }, diff --git a/dot-stats/history.org b/dot-stats/history.org deleted file mode 100644 index 6a7b899..0000000 --- a/dot-stats/history.org +++ /dev/null @@ -1,272 +0,0 @@ -#+TITLE: Program Usage History -#+PROPERTY: header-args:python :session *history* -#+PROPERTY: header-args:python+ :exports both -#+PROPERTY: header-args:python+ :tangle yes -#+PROPERTY: header-args:python+ :async yes -#+PROPERTY: header-args:python+ :kernel python3 - -#+begin_src elisp :exports none -(setq-local org-image-actual-width '(1024)) -#+end_src - -#+RESULTS: -| 1024 | - -* Init -#+begin_src python -from matplotlib import pyplot as plt -from matplotlib import dates as mdates -from pprint import pprint -from datetime import date, datetime - -import copy -import json -import matplotlib as mpl -import numpy as np -import pandas as pd - -mpl.rcParams['figure.dpi'] = 125 -mpl.rcParams['figure.facecolor'] = '0.1' -mpl.rcParams['hatch.linewidth'] = 4.0 -#+end_src - -#+RESULTS: - -#+begin_src python -plt.style.use('./palenight.mplstyle') -#+end_src - -#+RESULTS: - -** Colors -#+begin_src python -COLORS = { - 'k': '#292d3e', - 'r': '#f07178', - 'g': '#c3e88d', - 'y': '#ffcb6b', - 'b': '#82aaff', - 'm': '#c792ea', - 'c': '#89ddff', - 'w': '#d0d0d0', - 'k-l': '#434758', - 'r-l': '#ff8b92', - 'g-l': '#ddffa7', - 'y-l': '#ffe585', - 'b-l': '#9cc4ff', - 'm-l': '#e1acff', - 'c-l': '#a3f7ff', - 'w-l': '#ffffff' -} -#+end_src - -#+RESULTS: - -* General history -** Load data -*** Read file -#+begin_src python -DATA = './history.json' - -with open(DATA, 'r') as f: - data_o = json.load(f) - -# pprint(data) -#+end_src - -#+RESULTS: -*** Some preprocessing -#+begin_src python -def preprocess_data(data): - data = copy.deepcopy(data) - for category in data: - for elem in category['elements']: - for state in elem['states']: - if 'TODO' in state['startDate']: - print(f'TODO in {elem["name"]} (startDate)') - state['startDate'] = state['startDate'].replace('TODO', '').strip() - state['startDate'] = datetime.strptime(state['startDate'], '%Y-%m-%d') - try: - if 'TODO' in state['endDate']: - print(f'TODO in {elem["name"]} (endDate)') - state['endDate'] = state['endDate'].replace('TODO', '').strip() - state['endDate'] = datetime.strptime(state['endDate'], '%Y-%m-%d') - except KeyError: - state['endDate'] = datetime.today() - try: - state['hatchColor'] = COLORS.get(state['hatchColor'], state['hatchColor']) - except KeyError: - pass - elem['states'].sort(key=lambda k: k['startDate']) - try: - elem['color'] = COLORS.get(elem['color'], elem['color']) - except KeyError: - pass - category['elements'].sort(key=lambda k: k['states'][0]['startDate']) - - return data - -data = preprocess_data(data_o) -#+end_src - -#+RESULTS: -: TODO in Linux Mint (startDate) -: TODO in Windows (startDate) -: TODO in Windows (endDate) -: TODO in bash (startDate) -: TODO in Mailspring (startDate) -*** Crop data -#+begin_src python -def crop_data(data, start_date): - data = copy.deepcopy(data) - for category in data: - for elem in category['elements']: - elem['states'] = [ - state for state in elem['states'] - if state['endDate'] >= start_date - ] - for state in elem['states']: - if state['startDate'] <= start_date: - state['startDate'] = start_date - - category['elements'] = [ - element for element in category['elements'] - if len(element['states']) > 0 - ] - - data = [ - category for category in data - if len(category['elements']) > 0 - ] - return data - -data = crop_data(data, datetime(2017, 1, 1)) -#+end_src - -#+RESULTS: - -** Plot one category -#+begin_src python -CAT_W = 0.3 - -def process_category(category, ax, is_last=True, notes=None): - ticks = list(range(0, -len(category['elements']), -1)) - if notes is None: - notes = [] - min_start_date = 10**9 - for elem, k in zip(category['elements'], ticks): - for state in elem['states']: - start_date, end_date = mdates.date2num(state['startDate']), mdates.date2num(state['endDate']) - min_start_date = min(min_start_date, start_date) - kwargs = {} - kwargs['color'] = elem.get('color', None) - - if state.get('state', None) == 'dashed': - kwargs['hatch'] = '//' - kwargs['edgecolor'] = state.get('hatchColor', 'y') - kwargs['lw'] = 0 - - note = state.get('note', None) - if note is not None: - notes.append(note) - stars = '*' * len(notes) - ax.text(end_date, k + CAT_W * 0.7, stars, size=15) - - bars = ax.broken_barh( - [(start_date, end_date - start_date)], - (k - CAT_W, CAT_W * 2), - ,**kwargs - ) - - ax.set_yticks(ticks) - ax.set_yticklabels([elem['name'] for elem in category['elements']]) - ax.set_axisbelow(True) - ax.grid(True, alpha=0.25) - if not is_last: - ax.tick_params(axis='x', which='both', labelbottom=False, length=0) - else: - ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m')) - - return notes - -def plot_notes(fig, ax, notes, x=0.9, y = 0.03): - if len(notes) > 0: - notes_text = '' - for i, note in enumerate(notes): - notes_text += '*' * (i + 1) + ' ' + note + '\n' - ax.text(x, y, notes_text, transform=fig.transFigure, va='top', ha='right') - -fig, ax = plt.subplots(figsize=(12, 3)) -notes = process_category(data[0], ax) -ax.set_title(data[0]['title']) -plot_notes(fig, ax, notes) -notes -#+end_src - -#+RESULTS: -:RESULTS: -| Dual boot, rarely used | -[[file:./.ob-jupyter/3c6983044abfb21ba631ed1538a98a15c91d50aa.png]] -:END: - -** Plot all separately -#+begin_src python :display plain -def plot_category(category): - fig, ax = plt.subplots(figsize=(12, len(category['elements']) * 0.7 + 1)) - notes = process_category(category, ax) - ax.set_title(category['title']) - plot_notes(fig, ax, notes) - return fig - -def plot_separate(data): - for category in data: - fig = plot_category(category) - # fig.tight_layout() - fig.savefig(f'./img/{category["title"].replace("/", "-")}.png') - -# plot_separate(data) -#+end_src - -#+RESULTS: - -** Plot all in one chart -#+begin_src python :file img/all.png -def plot_all(data): - fig, axes = plt.subplots( - len(data), - gridspec_kw={ - 'height_ratios': [len(datum['elements']) for datum in data] - }, - figsize=(14, 11), - sharex=True - ) - notes = [] - for i, [datum, ax] in enumerate(zip(data, axes)): - is_last = i == len(data) - 1 - notes = process_category(datum, ax, is_last=is_last, notes=notes) - ax.yaxis.set_label_position("right") - ax.set_ylabel(datum['title'], labelpad=16, rotation=270) - plot_notes(fig, ax, notes, y=0.09) - # fig.tight_layout() - fig.subplots_adjust(hspace=0.15) - ax.text(0.075, 0.08, f'upd. {datetime.now().strftime("%Y-%m-%d")}', transform=fig.transFigure, va='top', ha='left') - -plot_all(data) -#+end_src - -#+RESULTS: -[[file:img/all.png]] - -* Emacs history -#+begin_src python :file img/emacs.png -EMACS_DATA = './emacs-history.json' - -with open(EMACS_DATA, 'r') as f: - data_e = json.load(f) - -data_e = preprocess_data(data_e) -plot_all(data_e) -#+end_src - -#+RESULTS: -[[file:img/emacs.png]]