plot-stars.py
Rama master · réplica de lectura del repositorio original.
import os
import tempfile
import xml.etree.ElementTree as ET
os.environ.setdefault('MPLBACKEND', 'Agg')
os.environ.setdefault('MPLCONFIGDIR', tempfile.gettempdir())
import matplotlib.dates as mdates
from matplotlib import rc, rcParams
import matplotlib.pyplot as plt
import datetime
from history_store import field_on_or_before, load_history
'''
Plot stars vs time for top competitors except Discourse.
'''
fs=15
rc('axes', linewidth=2)
rc('text', usetex=False)
rc('legend', fontsize=fs)
rc('font', size=fs)
rc('xtick.major', size=10, width=2)
rc('ytick.major', size=10, width=2)
rc('xtick.minor', size=5, width=1.3)
rc('ytick.minor', size=5, width=1.3)
rcParams['font.family'] = 'sans-serif'
rcParams['font.sans-serif'] = ['DejaVu Sans', 'Arial', 'Lucida Grande']
rcParams['svg.hashsalt'] = 'open-source-comments'
fig = plt.figure('figure', figsize=(10,8))
fig.subplots_adjust(top=.80)
ax = plt.subplot(111)
series = {
'isso': {'label': 'Isso', 'color': 'tab:blue', 'ls': '-'},
'commento': {'label': 'Commento', 'color': 'tab:orange', 'ls': '-'},
'Waline': {'label': 'Waline', 'color': 'tab:green', 'ls': ':'},
'staticman': {'label': 'Staticman', 'color': 'tab:red', 'ls': '--'},
'Artalk': {'label': 'Artalk', 'color': 'tab:gray', 'ls': '-'},
'remark': {'label': 'Remark42', 'color': 'tab:pink', 'ls': '-'},
'valine': {'label': 'Valine', 'color': 'tab:purple', 'ls': '-.'},
}
stars_by_project = {project: [] for project in series}
dates_by_project = {project: [] for project in series}
history = load_history()
for date_str in history['dates']:
date_obj = datetime.datetime.strptime(date_str, '%Y-%m-%d').date()
for project in series:
stars = field_on_or_before(history, project, 'stars', date_str)
if stars is None:
continue
if isinstance(stars, bool) or not isinstance(stars, int):
raise RuntimeError(
'Invalid star history value for {} on {}: {!r}'.format(
project,
date_str,
stars,
)
)
if stars <= 0:
if dates_by_project[project]:
dates_by_project[project].append(date_obj)
stars_by_project[project].append(float('nan'))
continue
if project == 'isso' and datetime.date(2024, 3, 6) <= date_obj <= datetime.date(2024, 3, 12):
continue
stars_by_project[project].append(stars)
dates_by_project[project].append(date_obj)
lw=2.85
all_dates = []
for project, style in series.items():
dates = dates_by_project[project]
stars = stars_by_project[project]
if not dates:
raise RuntimeError('No data points for {}'.format(project))
all_dates.extend(dates)
ax.plot(dates, stars, label=style['label'], lw=lw, ls=style['ls'], color=style['color'])
ax2 = ax.twiny()
years = mdates.YearLocator() # every year
months = mdates.MonthLocator() # every month
yearsFmt = mdates.DateFormatter('%Y')
dateFmt = mdates.DateFormatter('%d %B, %Y')
ax2.xaxis.set_major_locator(years)
ax2.xaxis.set_major_formatter(dateFmt)
ax2.xaxis.set_minor_locator(months)
ax.xaxis.set_major_locator(years)
ax.xaxis.set_major_formatter(yearsFmt)
ax.xaxis.set_minor_locator(months)
ax.set_xlabel('Date')
ax.set_ylabel('Github stars')
ax.legend(ncol=3, loc='center', bbox_to_anchor=(0.4, 1.15))
ax.grid(ls=':', lw=1)
last = max(all_dates)
ax.axvline(x=last, ls=':', color='tab:gray', lw=1)
ax2.set_xlim(ax.get_xlim())
ax2.set_xticks([last])
output = 'stars-v-date.svg'
mode = os.stat(output).st_mode if os.path.exists(output) else 0o644
with tempfile.NamedTemporaryFile(dir='.', suffix='.svg', delete=False) as tmp:
tmp_name = tmp.name
try:
plt.savefig(tmp_name, dpi=300, bbox_inches='tight', metadata={'Date': None})
with open(tmp_name, 'r', encoding='utf-8') as svg_file:
svg = svg_file.read()
with open(tmp_name, 'w', encoding='utf-8') as svg_file:
svg_file.write('\n'.join(line.rstrip() for line in svg.splitlines()))
svg_file.write('\n')
svg_file.flush()
os.fsync(svg_file.fileno())
if len(svg) < 10000:
raise RuntimeError('Generated SVG is unexpectedly small')
ET.parse(tmp_name)
missing_labels = [
style['label']
for style in series.values()
if '<!-- {} -->'.format(style['label']) not in svg
]
if missing_labels:
raise RuntimeError(
'Generated SVG is missing series labels: {}'.format(', '.join(missing_labels))
)
os.chmod(tmp_name, mode)
os.replace(tmp_name, output)
tmp_name = None
finally:
plt.close(fig)
if tmp_name and os.path.exists(tmp_name):
os.unlink(tmp_name)
print('stars-v-date.svg is updated through {}'.format(last))
#plt.show()