mirror of
https://github.com/SqrtMinusOne/dotfiles.git
synced 2025-12-10 19:23:03 +03:00
feat(stats): add stats
This commit is contained in:
parent
6ebf968c01
commit
2b4935ba77
5 changed files with 666 additions and 2 deletions
13
README.org
13
README.org
|
|
@ -1,4 +1,6 @@
|
|||
* My dotfiles
|
||||
#+TITLE: My dotfiles
|
||||
|
||||
* Programs used
|
||||
Deployed with [[https://yadm.io/][yadm]]
|
||||
|
||||
| Group | Program | Purpose | Status | Documented? | Notes |
|
||||
|
|
@ -43,10 +45,17 @@ Deployed with [[https://yadm.io/][yadm]]
|
|||
| misc | [[https://github.com/risacher/sunwait][sunwait]] | sunrise calculator | *active* | - | |
|
||||
| misc | [[https://github.com/vergoh/vnstat][vnstat]] | traffic stats | *active* | - | |
|
||||
|
||||
* Some statistics
|
||||
Run the following to show the pictures with reasonable width:
|
||||
#+begin_src elisp :results none
|
||||
(setq-local org-image-actual-width '(1024))
|
||||
#+end_src
|
||||
|
||||
** History
|
||||
[[./dot-stats/img/all.png]]
|
||||
|
||||
* Notes
|
||||
- =M-u C-c C-v t= to tangle a particular block
|
||||
- =M-u M-u C-c C-v t= to tangle a particular file
|
||||
|
||||
Uses yadm's =post_alt= hook to create symlinks
|
||||
|
||||
|
|
|
|||
377
dot-stats/history.json
Normal file
377
dot-stats/history.json
Normal file
|
|
@ -0,0 +1,377 @@
|
|||
[
|
||||
{
|
||||
"title": "OS/Distro",
|
||||
"elements": [
|
||||
{
|
||||
"name": "Manjaro",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2020-08-24"
|
||||
}
|
||||
],
|
||||
"color": "g"
|
||||
},
|
||||
{
|
||||
"name": "Linux Mint",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "TODO 2018-03-12",
|
||||
"endDate": "2020-08-24"
|
||||
}
|
||||
],
|
||||
"color": "m"
|
||||
},
|
||||
{
|
||||
"name": "Windows",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "TODO 2018-11-25",
|
||||
"endDate": "2019-10-07",
|
||||
"state": "dashed",
|
||||
"hatchColor": "y",
|
||||
"note": "Dual boot, rarely used"
|
||||
},
|
||||
{
|
||||
"startDate": "2016-09-01",
|
||||
"endDate": "TODO 2018-11-25"
|
||||
}
|
||||
],
|
||||
"color": "b"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "DE stuff",
|
||||
"elements": [
|
||||
{
|
||||
"name": "KDE",
|
||||
"color": "y",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2018-03-12",
|
||||
"endDate": "2018-08-01"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Cinnamon",
|
||||
"color": "g",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2018-08-01",
|
||||
"endDate": "2020-05-08"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "i3(-gaps)",
|
||||
"color": "b",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2020-05-08"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "i3blocks",
|
||||
"color": "b-l",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2020-05-08",
|
||||
"endDate": "2020-12-11"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "polybar",
|
||||
"color": "m",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2020-12-11"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "shell",
|
||||
"elements": [
|
||||
{
|
||||
"name": "bash",
|
||||
"color": "w",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "TODO 2018-03-12",
|
||||
"endDate": "2020-09-09"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fish",
|
||||
"color": "c",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2020-09-09"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "CLI tools",
|
||||
"elements": [
|
||||
{
|
||||
"name": "ranger",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2019-04-03",
|
||||
"endDate": "2020-02-17"
|
||||
}
|
||||
],
|
||||
"color": "y"
|
||||
},
|
||||
{
|
||||
"name": "vifm",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2020-02-17",
|
||||
"endDate": "2020-11-11"
|
||||
}
|
||||
],
|
||||
"color": "g"
|
||||
},
|
||||
{
|
||||
"name": "tmux",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2020-01-22"
|
||||
}
|
||||
],
|
||||
"color": "b"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Office",
|
||||
"elements": [
|
||||
{
|
||||
"name": "LaTeX",
|
||||
"color": "b",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2019-04-12"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Zathura",
|
||||
"color": "c",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2019-04-12"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "OneNote",
|
||||
"color": "m",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2016-09-01",
|
||||
"endDate": "2019-03-21"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Editor/IDE",
|
||||
"elements": [
|
||||
{
|
||||
"name": "Emacs",
|
||||
"color": "m",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2020-10-12"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "NeoVim",
|
||||
"color": "g",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2019-03-30",
|
||||
"endDate": "2020-10-12"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Qt Creator",
|
||||
"color": "y",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2017-09-01",
|
||||
"endDate": "2018-07-17"
|
||||
},
|
||||
{
|
||||
"startDate": "2019-09-11",
|
||||
"endDate": "2019-12-04"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Notepad++",
|
||||
"color": "w",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2017-09-01",
|
||||
"endDate": "2018-05-25"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Various JetBrains",
|
||||
"color": "c",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2018-09-01",
|
||||
"endDate": "2019-03-30"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "DataGrip",
|
||||
"color": "b",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2020-02-01"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Jupyter (Notebook|Lab)",
|
||||
"color": "r",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2018-10-24",
|
||||
"endDate": "2020-11-01"
|
||||
},
|
||||
{
|
||||
"startDate": "2020-11-01",
|
||||
"state": "dashed",
|
||||
"note": "Mostly replaced by Org Mode",
|
||||
"hatchColor": "w"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Browser",
|
||||
"elements": [
|
||||
{
|
||||
"name": "Opera",
|
||||
"color": "r",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2018-09-01",
|
||||
"endDate": "2019-02-01"
|
||||
},
|
||||
{
|
||||
"startDate": "2019-09-01",
|
||||
"endDate": "2020-02-11"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Chromium",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2018-04-01",
|
||||
"endDate": "2018-09-01"
|
||||
}
|
||||
],
|
||||
"color": "c"
|
||||
},
|
||||
{
|
||||
"name": "qutebrowser",
|
||||
"color": "b",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2020-02-11",
|
||||
"endDate": "2020-12-20"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Vivaldi",
|
||||
"color": "r-l",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2019-02-01",
|
||||
"endDate": "2019-09-01"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Firefox",
|
||||
"color": "y",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2017-05-14",
|
||||
"endDate": "2018-04-01"
|
||||
},
|
||||
{
|
||||
"startDate": "2020-12-20",
|
||||
"state": "dashed",
|
||||
"note": "+ Tridactyl",
|
||||
"hatchColor": "k-l"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Misc",
|
||||
"elements": [
|
||||
{
|
||||
"name": "ncmpcpp & mpd",
|
||||
"color": "c",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2020-07-26"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "newsboat",
|
||||
"color": "r",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2021-01-22"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Mailspring",
|
||||
"color": "g",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "TODO 2019-01-28",
|
||||
"endDate": "2021-01-29"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "notmuch",
|
||||
"color": "b",
|
||||
"states": [
|
||||
{
|
||||
"startDate": "2021-01-29"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
255
dot-stats/history.org
Normal file
255
dot-stats/history.org
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
#+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
|
||||
|
||||
#+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'] = 200
|
||||
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:
|
||||
|
||||
* 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/755e058676d772859fe9f7ed207011006268ac2b.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)
|
||||
|
||||
plot_all(data)
|
||||
#+end_src
|
||||
|
||||
#+RESULTS:
|
||||
[[file:img/all.png]]
|
||||
BIN
dot-stats/img/all.png
Normal file
BIN
dot-stats/img/all.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 195 KiB |
23
dot-stats/palenight.mplstyle
Normal file
23
dot-stats/palenight.mplstyle
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
### FONT
|
||||
text.color: D0D0D0
|
||||
|
||||
### AXES
|
||||
axes.facecolor: 363B52
|
||||
axes.edgecolor: FFFFFF
|
||||
axes.labelcolor: FFFFFF
|
||||
|
||||
### TICKS
|
||||
xtick.color: FFFFFF
|
||||
ytick.color: FFFFFF
|
||||
|
||||
### GRIDS
|
||||
grid.color: FFFFFF
|
||||
|
||||
### Legend
|
||||
legend.facecolor: inherit
|
||||
legend.edgecolor: C792EA
|
||||
|
||||
### FIGURE
|
||||
|
||||
figure.facecolor: 292D3E
|
||||
savefig.facecolor: 292D3E
|
||||
Loading…
Add table
Reference in a new issue