From 40c947234b16a301a65b50477836882f048687db Mon Sep 17 00:00:00 2001 From: NF-coder Date: Sat, 15 Nov 2025 20:31:42 +0300 Subject: [PATCH 1/2] add github-like languages coloring --- settings.yaml | 9 ++-- src/main.py | 66 +++++++++++++++++--------- src/settings/Coloring.py | 14 ++++++ src/settings/GeneralSettings.py | 4 +- src/settings/Settings.py | 20 +++++--- src/settings/coloring/OKLCHColoring.py | 7 --- 6 files changed, 80 insertions(+), 40 deletions(-) create mode 100644 src/settings/Coloring.py delete mode 100644 src/settings/coloring/OKLCHColoring.py diff --git a/settings.yaml b/settings.yaml index d7b230e..f58a57c 100644 --- a/settings.yaml +++ b/settings.yaml @@ -4,9 +4,12 @@ general: height: 140 width: 250 coloring: - type: "oklch" - chroma: 0.099 - lightness: 0.636 + type: "github" + other_color: "#666666" + # coloring: + # type: "oklch" + # chroma: 0.099 + # lightness: 0.636 excluded_languages: - Jupyter Notebook diff --git a/src/main.py b/src/main.py index 60d4b85..aa2aaea 100644 --- a/src/main.py +++ b/src/main.py @@ -1,4 +1,5 @@ import os +from dataclasses import dataclass from renderer.renderer import RenderBuilder from oklchUtils.OKLCHUtils import OKLCHUtils @@ -6,7 +7,7 @@ from settings import Settings from fetcher.fetcher import FetchLangStats -# Fetch info +# Some settinga USERNAME = os.environ['USERNAME'] TOKEN = os.environ['GITHUB_TOKEN'] OUTPUT_FILE: str = "./out.svg" @@ -14,47 +15,68 @@ SETTINGS = Settings.from_yaml(SETTINGS_FILE) + +@dataclass +class LangData: + name: str + size: float + github_color: str + def get_langs_data( token: str, username: str, exclude_langs: list[str] = SETTINGS.GENERAL_SETTINGS.EXCLUDED_LANGUAGES - ) -> dict[str, float]: - info = {} - total_size = 0 + ) -> list[LangData]: + info: dict[str, LangData] = {} + total_size: float = 0 for elem in FetchLangStats(token).fetch_user(username): if elem.name in exclude_langs: continue total_size += elem.size - if elem.name not in info: info[elem.name] = elem.size - else: info[elem.name] += elem.size + if elem.name not in info: info[elem.name] = LangData(elem.name, elem.size, elem.github_color) + else: info[elem.name].size += elem.size - return {k: info[k]/total_size for k in info} + return [LangData( + info[k].name, + info[k].size/total_size, + info[k].github_color + ) for k in info] -def truncate(langs_arr: list[tuple[float, str]], k: int): +def truncate(langs_arr: list[LangData], k: int): if len(langs_arr) <= k: return langs_arr - return langs_arr[:k-1] + [(sum(map(lambda x: x[0], langs_arr[k-1:])), "Other")] + return langs_arr[:k-1] + [LangData("Other", sum(map(lambda x: x.size, langs_arr[k-1:])), SETTINGS.GENERAL_SETTINGS.COLORING.OTHER_COLOR)] -def main(): - languages_stats = get_langs_data(TOKEN, USERNAME) +def coloring(sorted_percents: list[LangData]) -> list[str]: + coloring_cfg = SETTINGS.GENERAL_SETTINGS.COLORING + + if coloring_cfg.TYPE == "oklch": + if hasattr(coloring_cfg, "CHROMA") and hasattr(coloring_cfg, "LIGHTNESS"): + return OKLCHUtils.create_colors_array( + length=len(sorted_percents), + chroma=getattr(coloring_cfg, "CHROMA"), + lightness=getattr(coloring_cfg, "LIGHTNESS") + ) + raise ValueError("Invalid oklch coloring config") + elif coloring_cfg.TYPE == "github": + return [elem.github_color for elem in sorted_percents] + + raise ValueError("No such coloring config") - sorted_percents = sorted( - [(percent, name) for percent,name in zip(languages_stats.values(), languages_stats.keys())], - key=lambda x: x[0], +def main(): + sorted_langs = sorted( + get_langs_data(TOKEN, USERNAME), + key=lambda x: x.size, reverse=True ) - sorted_percents = truncate(sorted_percents, SETTINGS.GENERAL_SETTINGS.TOP_K) + sorted_percents = truncate(sorted_langs, SETTINGS.GENERAL_SETTINGS.TOP_K) _ = Calc( outer_radius=SETTINGS.DIAGRAM_SETTINGS.OUTER_RADIUS, thickness=SETTINGS.DIAGRAM_SETTINGS.THICKNESS, - percent_array=[elem[0] for elem in sorted_percents], - sections_colors_array=OKLCHUtils.create_colors_array( - length=len(sorted_percents), - chroma=SETTINGS.GENERAL_SETTINGS.COLORING.CHROMA, - lightness=SETTINGS.GENERAL_SETTINGS.COLORING.LIGHTNESS - ), + percent_array=[elem.size for elem in sorted_percents], + sections_colors_array=coloring(sorted_percents), renderer=RenderBuilder( height=SETTINGS.GENERAL_SETTINGS.PLANE.HEIGHT, width=SETTINGS.GENERAL_SETTINGS.PLANE.WIDTH, @@ -69,7 +91,7 @@ def main(): ), margin_x=SETTINGS.DIAGRAM_SETTINGS.MARGIN_X, margin_y=SETTINGS.DIAGRAM_SETTINGS.MARGIN_Y, - names_array=[elem[1] for elem in sorted_percents] + names_array=[elem.name for elem in sorted_percents] ) with open(OUTPUT_FILE, "w+", encoding="utf-8-sig") as f: diff --git a/src/settings/Coloring.py b/src/settings/Coloring.py new file mode 100644 index 0000000..e8a576e --- /dev/null +++ b/src/settings/Coloring.py @@ -0,0 +1,14 @@ +from dataclasses import dataclass +from typing import Union + +@dataclass +class OKLCHColoring(): + TYPE = "oklch" + CHROMA: float + LIGHTNESS: float + OTHER_COLOR: str + +@dataclass +class GithubColoring(): + TYPE = "github" + OTHER_COLOR: str \ No newline at end of file diff --git a/src/settings/GeneralSettings.py b/src/settings/GeneralSettings.py index e38934f..ee15298 100644 --- a/src/settings/GeneralSettings.py +++ b/src/settings/GeneralSettings.py @@ -1,11 +1,11 @@ from dataclasses import dataclass -from .coloring.OKLCHColoring import OKLCHColoring +from .Coloring import * @dataclass class GeneralSettings: TOP_K: int PLANE: "PlaneSubsettings" - COLORING: OKLCHColoring + COLORING: OKLCHColoring | GithubColoring EXCLUDED_LANGUAGES: list[str] @dataclass diff --git a/src/settings/Settings.py b/src/settings/Settings.py index b2c7b2a..e3ae0cd 100644 --- a/src/settings/Settings.py +++ b/src/settings/Settings.py @@ -4,7 +4,7 @@ from .GeneralSettings import GeneralSettings, PlaneSubsettings from .LegendSettings import LegendSettings from .DiagramSettings import DiagramSettings -from .coloring.OKLCHColoring import OKLCHColoring +from .Coloring import * class Settings: GENERAL_SETTINGS: GeneralSettings @@ -18,16 +18,15 @@ def from_yaml(cls, path: str) -> Self: inst = cls() + coloring = select_coloring(data["general"]["coloring"]) + inst.GENERAL_SETTINGS = GeneralSettings( data["general"]["top_k"], PlaneSubsettings( data["general"]["plane"]["height"], data["general"]["plane"]["width"] ), - OKLCHColoring( - data["general"]["coloring"]["chroma"], - data["general"]["coloring"]["lightness"] - ), + coloring, data["general"]["excluded_languages"] ) @@ -45,4 +44,13 @@ def from_yaml(cls, path: str) -> Self: data["diagram"]["margin_y"] ) - return inst \ No newline at end of file + return inst + +def select_coloring(data: dict) -> OKLCHColoring | GithubColoring: + t = data.get("type") + if t == "oklch": + return OKLCHColoring(data["chroma"], data["lightness"], data["other_color"]) + elif t == "github": + return GithubColoring(data["other_color"]) + + raise ValueError(f"Unknown coloring type: {t!r}") \ No newline at end of file diff --git a/src/settings/coloring/OKLCHColoring.py b/src/settings/coloring/OKLCHColoring.py deleted file mode 100644 index d155ad8..0000000 --- a/src/settings/coloring/OKLCHColoring.py +++ /dev/null @@ -1,7 +0,0 @@ -from dataclasses import dataclass - -@dataclass -class OKLCHColoring(): - CHROMA: float - LIGHTNESS: float - TYPE = "oklvh" \ No newline at end of file From 121a68681c3a2bbf567cfd586b62d50db810101a Mon Sep 17 00:00:00 2001 From: NOT_FOUND Date: Sat, 15 Nov 2025 20:44:39 +0300 Subject: [PATCH 2/2] Add info about settings.yaml options --- README.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/README.md b/README.md index 2f305c4..e0b9d9d 100644 --- a/README.md +++ b/README.md @@ -9,3 +9,36 @@ Then you can use it with ```html ``` + +## Configuring +Example config u can see in `setting.yaml` +```yaml +general: + top_k: 4 # how many sections will be on donut-chart (including "Other" section) + plane: + height: 140 # height of svg + width: 250 # width of svg + coloring: + type: "github" # type of coloring (github or oklch available) + other_color: "#666666" # color of "Other" section + # coloring: + # type: "oklch" # type of coloring (github or oklch available) + # chroma: 0.099 # coloring oklch chroma + # lightness: 0.636 # coloring oklch lightness + # other_color: "#666666" # color of "Other" section + excluded_languages: # list of languages that should be excluded + - Jupyter Notebook # removed because jupyter files are too large + +legend: + margin_x: 140 # margin of legend (x-axis) + margin_y: 30 # margin of legend (y-axis) + space_between_captions: 22 # space between legend options + font_color: "#c1c1c1" # font color + +diagram: + outer_radius: 55 # outer circle radius + thickness: 12 # size of donut-chart + margin_x: 20 # margin of diagram (x-axis) + margin_y: 15 # margin of diagram (y-axis) +``` +About **oklch** u can read [here](https://oklch.com/)