Merge pull request #363 from anmol098/feat/new_graph_drawing_backend

New graph drawing backend
This commit is contained in:
Alexander Sergeev
2023-02-16 22:58:27 +01:00
committed by GitHub
4 changed files with 56 additions and 98 deletions

View File

@@ -1,4 +1,4 @@
FROM nikolaik/python-nodejs:python3.9-nodejs16 FROM python:3.9-alpine
ENV PYTHONUNBUFFERED 1 ENV PYTHONUNBUFFERED 1
ENV PYTHONDONTWRITEBYTECODE 1 ENV PYTHONDONTWRITEBYTECODE 1
@@ -6,9 +6,7 @@ ENV PYTHONDONTWRITEBYTECODE 1
WORKDIR /waka-readme-stats WORKDIR /waka-readme-stats
ADD requirements.txt ./requirements.txt ADD requirements.txt ./requirements.txt
RUN pip install --upgrade pip && pip install -r requirements.txt RUN apk add --no-cache g++ jpeg-dev zlib-dev libjpeg make && pip3 install -r requirements.txt
RUN npm i npm@next-8 && npm i vega vega-lite vega-cli canvas
ADD sources/* ./ ADD sources/* ./
ENTRYPOINT python3 /waka-readme-stats/main.py ENTRYPOINT python3 /waka-readme-stats/main.py

View File

@@ -1,10 +1,7 @@
PyGithub==1.54.1 PyGithub==1.54.1
matplotlib==3.4.1 matplotlib==3.6.3
numpy==1.24.2
python-dotenv==0.17.0 python-dotenv==0.17.0
numpy==1.24.1
pandas==1.2.3
altair==4.1.0
altair-saver==0.5.0
pytz==2021.1 pytz==2021.1
humanize==3.3.0 humanize==3.3.0
httpx==0.23.3 httpx==0.23.3

View File

@@ -5,7 +5,7 @@ from github import Github, InputGitAuthor, AuthenticatedUser
import datetime import datetime
from download_manager import DownloadManager from download_manager import DownloadManager
from make_bar_graph import BarGraph from make_bar_graph import build_graph
class LinesOfCode: class LinesOfCode:
@@ -28,8 +28,7 @@ class LinesOfCode:
return yearly_data return yearly_data
async def plotLoc(self, yearly_data): async def plotLoc(self, yearly_data):
graph = BarGraph(yearly_data) await build_graph(yearly_data)
await graph.build_graph()
self.pushChart() self.pushChart()
def getQuarter(self, timeStamp): def getQuarter(self, timeStamp):

View File

@@ -1,105 +1,69 @@
import pandas as pd from typing import Dict
import altair as alt from os.path import join, dirname
from json import load
import numpy as np
import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
from download_manager import DownloadManager from download_manager import DownloadManager
# npm install vega-lite vega-cli canvas MAX_LANGUAGES = 5
class BarGraph: async def build_graph(yearly_data: Dict) -> str:
"""
Draws graph of lines of code written by user by quarters of years.
Picks top `MAX_LANGUAGES` languages from each quarter only.
def __init__(self, yearly_data): :param yearly_data: GitHub user yearly data.
self.yearly_data = yearly_data :return: String, path to graph file.
"""
colors = await DownloadManager.get_remote_yaml("linguist")
async def build_graph(self): languages_all_loc = dict()
years = len(yearly_data.keys())
year_indexes = np.arange(years)
colors = await DownloadManager.get_remote_yaml("linguist") for i, y in enumerate(sorted(yearly_data.keys())):
allColorsValues = [] for q in yearly_data[y].keys():
langs = sorted(yearly_data[y][q].keys(), key=lambda l: yearly_data[y][q][l], reverse=True)[0:MAX_LANGUAGES]
# filter data for lang in langs:
max_languages = 5 if lang not in languages_all_loc:
top_languages = {} languages_all_loc[lang] = np.array([[0] * years] * 4)
for year in self.yearly_data.keys(): languages_all_loc[lang][q - 1][i] = yearly_data[y][q][lang]
for quarter in self.yearly_data[year].keys():
for language in sorted(list(self.yearly_data[year][quarter].keys()),
key=lambda lang: self.yearly_data[year][quarter][lang], reverse=True)[
0:max_languages]:
if 'top' not in self.yearly_data[year][quarter]:
self.yearly_data[year][quarter]['top'] = {}
if self.yearly_data[year][quarter][language] != 0:
self.yearly_data[year][quarter]['top'][language] = self.yearly_data[year][quarter][language]
if language not in top_languages: fig = plt.figure()
top_languages[language] = 1 ax = fig.add_axes([0, 0, 1.5, 1])
top_languages[language] += 1
# print(self.yearly_data) language_handles = []
cumulative = np.array([[0] * years] * 4)
all_languages = list(top_languages.keys()) for key, value in languages_all_loc.items():
color = colors[key]["color"] if colors[key]["color"] is not None else "w"
language_handles += [mpatches.Patch(color=color, label=key)]
for language in all_languages: for quarter in range(4):
if colors[language]['color'] is not None: ax.bar(year_indexes + quarter * 0.21, value[quarter], 0.2, bottom=cumulative[quarter], color=color)
allColorsValues.append(colors[language]['color']) cumulative[quarter] = np.add(cumulative[quarter], value[quarter])
languages_all_loc = {} ax.set_ylabel("LOC added", fontdict=dict(weight="bold"))
ax.set_xticks(np.array([np.arange(i, i + 0.84, step=0.21) for i in year_indexes]).flatten(), labels=["Q1", "Q2", "Q3", "Q4"] * years)
for language in all_languages: sax = ax.secondary_xaxis("top")
language_year = [] sax.set_xticks(year_indexes + 0.42, labels=sorted(yearly_data.keys()))
for year in self.yearly_data.keys(): sax.spines["top"].set_visible(False)
language_quarter = [0, 0, 0, 0]
for quarter in self.yearly_data[year].keys():
if language in self.yearly_data[year][quarter]['top']:
language_quarter[quarter - 1] = self.yearly_data[year][quarter]['top'][language]
else:
language_quarter[quarter - 1] = 0
language_year.append(language_quarter)
languages_all_loc[language] = language_year
# print(languages_all_loc) ax.legend(title="Language", handles=language_handles, loc="upper left", bbox_to_anchor=(1, 1), framealpha=0, title_fontproperties=dict(weight="bold"))
language_df = {} sax.tick_params(axis="both", length=0)
sax.spines["top"].set_visible(False)
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
def prep_df(df, name): plt.ylim(0, 1.05 * np.amax(cumulative))
df = df.stack().reset_index() plt.savefig("bar_graph.png", bbox_inches="tight")
df.columns = ['c1', 'c2', 'values'] plt.close(fig)
df['Language'] = name return "bar_graph.png"
return df
for language in languages_all_loc.keys():
language_df[language] = pd.DataFrame(languages_all_loc[language], index=list(self.yearly_data.keys()),
columns=["Q1", "Q2", "Q3", "Q4"])
for language in language_df.keys():
language_df[language] = prep_df(language_df[language], language)
df = pd.concat(language_df.values())
chart = alt.Chart(df).mark_bar().encode(
# tell Altair which field to group columns on
x=alt.X('c2:N', title=None),
# tell Altair which field to use as Y values and how to calculate
y=alt.Y('sum(values):Q',
axis=alt.Axis(
grid=False,
title='LOC added')),
# tell Altair which field to use to use as the set of columns to be represented in each group
column=alt.Column('c1:N', title=None),
# tell Altair which field to use for color segmentation
color=alt.Color('Language:N',
scale=alt.Scale(
domain=all_languages,
# make it look pretty with an enjoyable color pallet
range=allColorsValues,
),
)) \
.configure_view(
# remove grid lines around column clusters
strokeOpacity=0
)
chart.save('bar_graph.png')
return 'bar_graph.png'