mirror of
https://github.com/SqrtMinusOne/dotfiles.git
synced 2025-12-11 11:43:03 +03:00
history: i3 -> EXWM
This commit is contained in:
parent
9b0bee3ddd
commit
df2f07f949
2 changed files with 11 additions and 273 deletions
|
|
@ -78,7 +78,17 @@
|
||||||
"color": "b",
|
"color": "b",
|
||||||
"states": [
|
"states": [
|
||||||
{
|
{
|
||||||
"startDate": "2020-05-08"
|
"startDate": "2020-05-08",
|
||||||
|
"endDate": "2021-11-14"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "EXWM",
|
||||||
|
"color": "m",
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"startDate": "2021-11-14"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -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]]
|
|
||||||
Loading…
Add table
Reference in a new issue