Skip to content

Commit 1b18844

Browse files
committed
feat: add treemap visualization and extract chart functions
- implement treemap charts using ggplot2 and treemapify packages - extract pie chart generation into separate R/pie.R file - update CI workflow to include required R packages - add code formatting script R/fmt.R - generate charts in SVG and PNG formats for both types Signed-off-by: mingcheng <mingcheng@apache.org>
1 parent 2c9227b commit 1b18844

5 files changed

Lines changed: 270 additions & 67 deletions

File tree

.github/workflows/r.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
# File Created: 2025-10-25 17:30:24
1010
#
1111
# Modified By: mingcheng <mingcheng@apache.org>
12-
# Last Modified: 2025-10-25 20:04:04
12+
# Last Modified: 2025-10-25 23:56:06
1313
##
1414

1515
name: GitHub Repository Language Statistics
@@ -78,7 +78,7 @@ jobs:
7878
- name: Install R dependencies
7979
run: |
8080
Rscript -e '
81-
packages <- c("httr", "jsonlite", "dplyr", "magrittr", "showtext")
81+
packages <- c("httr", "jsonlite", "dplyr", "magrittr", "showtext", "ggplot2", "treemapify", "svglite")
8282
new_packages <- packages[!(packages %in% installed.packages()[,"Package"])]
8383
if(length(new_packages)) {
8484
install.packages(new_packages, repos="https://cloud.r-project.org", dependencies=TRUE)

R/fmt.R

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!#
2+
# Copyright (c) 2025 Hangzhou Guanwaii Technology Co., Ltd.
3+
#
4+
# This source code is licensed under the MIT License,
5+
# which is located in the LICENSE file in the source tree's root directory.
6+
#
7+
# File: fmt.R
8+
# Author: mingcheng <mingcheng@apache.org>
9+
# File Created: 2025-10-25 23:57:18
10+
#
11+
# Modified By: mingcheng <mingcheng@apache.org>
12+
# Last Modified: 2025-10-25 23:57:46
13+
##
14+
15+
if (!require("styler", quietly = TRUE)) {
16+
install.packages("styler")
17+
library(styler)
18+
}
19+
20+
#' Format R Code Files
21+
styler::style_dir("R", recursive = TRUE)

R/main.R

Lines changed: 13 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,6 @@ if (!require("jsonlite", quietly = TRUE)) {
2020
library(jsonlite)
2121
}
2222

23-
if (!require("showtext", quietly = TRUE)) {
24-
install.packages("showtext")
25-
library(showtext)
26-
}
2723

2824
# Source helper functions
2925
tryCatch(
@@ -78,73 +74,25 @@ message("Successfully processed repository data")
7874
write.csv(repos, plotted_file_name, row.names = FALSE)
7975
message("Statistical data saved to ", plotted_file_name)
8076

81-
# Setup font for visualization
77+
# Generate visualizations
78+
79+
# Generate pie chart
8280
tryCatch(
83-
font_add("MapleMono", regular = "./assets/MapleMono-NF-CN-Regular.ttf"),
84-
error = function(e) {
85-
warning("Failed to load custom font, using default: ", e$message)
86-
}
81+
suppressMessages(source("R/pie.R")),
82+
error = function(e) stop("Failed to source R/pie.R: ", e$message)
8783
)
8884

89-
# Enable showtext before opening graphics device
90-
showtext_auto()
91-
92-
# Define function to generate chart
93-
generate_chart <- function(username, repos, colors, total_repos, date_str) {
94-
par(
95-
bg = "white",
96-
mai = c(0.5, 0.5, 0.8, 0.5),
97-
lwd = 1,
98-
family = "MapleMono"
99-
)
100-
101-
pie(
102-
repos$final_score,
103-
labels = repos$label,
104-
col = colors,
105-
main = paste0(
106-
"Repository Distribution by Language\n",
107-
"GitHub User: ", username, " | Total Repositories: ", total_repos, "\n",
108-
"Updated on ", date_str
109-
),
110-
cex = 1,
111-
cex.main = 0.8,
112-
col.main = "#777777",
113-
radius = 1
114-
)
115-
}
85+
generate_pie_chart(username, repos, dir_name, json_data)
11686

117-
# Generate pie charts in multiple formats
118-
colors <- rainbow(nrow(repos))
119-
total_repos <- nrow(json_data)
120-
date_str <- format(Sys.Date(), "%Y-%m-%d")
121-
122-
# Define chart files
123-
chart_files <- list(
124-
svg = c(
125-
file.path(dir_name, paste0("chart_", today, ".svg")),
126-
file.path(dir_name, "latest.svg")
127-
),
128-
png = c(
129-
file.path(dir_name, paste0("chart_", today, ".png")),
130-
file.path(dir_name, "latest.png")
131-
)
87+
# Generate treemap
88+
tryCatch(
89+
suppressMessages(source("R/treemap.R")),
90+
error = function(e) stop("Failed to source R/treemap.R: ", e$message)
13291
)
13392

134-
# Generate SVG charts
135-
for (svg_file in chart_files$svg) {
136-
svg(svg_file, width = 10, height = 6)
137-
generate_chart(username, repos, colors, total_repos, date_str)
138-
dev.off()
139-
message("SVG chart saved to ", svg_file)
140-
}
93+
generate_treemap(username, repos, dir_name, json_data)
94+
95+
14196

142-
# Generate PNG charts
143-
for (png_file in chart_files$png) {
144-
png(png_file, width = 1200, height = 720, res = 120, bg = "white")
145-
generate_chart(username, repos, colors, total_repos, date_str)
146-
dev.off()
147-
message("PNG chart saved to ", png_file)
148-
}
14997

15098
message("Analysis complete!")

R/pie.R

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#!#
2+
# Copyright (c) 2025 Hangzhou Guanwaii Technology Co., Ltd.
3+
#
4+
# This source code is licensed under the MIT License,
5+
# which is located in the LICENSE file in the source tree's root directory.
6+
#
7+
# File: pie.R
8+
# Author: mingcheng <mingcheng@apache.org>
9+
# File Created: 2025-10-25 23:36:10
10+
#
11+
# Modified By: mingcheng <mingcheng@apache.org>
12+
# Last Modified: 2025-10-25 23:58:45
13+
##
14+
15+
if (!require("showtext", quietly = TRUE)) {
16+
install.packages("showtext")
17+
library(showtext)
18+
}
19+
20+
generate_pie_chart <- function(username, repos, dir_name, json_data) {
21+
# Setup font for visualization
22+
tryCatch(
23+
font_add("MapleMono", regular = "../assets/MapleMono-NF-CN-Regular.ttf"),
24+
error = function(e) {
25+
warning("Failed to load custom font, using default: ", e$message)
26+
}
27+
)
28+
29+
# Enable showtext before opening graphics device
30+
showtext_auto()
31+
32+
# Define function to generate chart
33+
generate_chart <- function(username, repos, colors, total_repos, date_str) {
34+
par(
35+
bg = "white",
36+
mai = c(0.5, 0.5, 0.8, 0.5),
37+
lwd = 1,
38+
family = "MapleMono"
39+
)
40+
41+
pie(
42+
repos$final_score,
43+
labels = repos$label,
44+
col = colors,
45+
main = paste0(
46+
"Repository Distribution by Language\n",
47+
"GitHub User: ", username, " | Total Repositories: ", total_repos, "\n",
48+
"Updated on ", date_str
49+
),
50+
cex = 1,
51+
cex.main = 0.8,
52+
col.main = "#777777",
53+
radius = 1
54+
)
55+
}
56+
57+
# Generate pie charts in multiple formats
58+
colors <- rainbow(nrow(repos))
59+
total_repos <- nrow(json_data)
60+
date_str <- format(Sys.Date(), "%Y-%m-%d")
61+
62+
# Define chart files
63+
chart_files <- list(
64+
svg = c(
65+
file.path(dir_name, paste0("chart_", today, ".svg")),
66+
file.path(dir_name, "latest.svg")
67+
),
68+
png = c(
69+
file.path(dir_name, paste0("chart_", today, ".png")),
70+
file.path(dir_name, "latest.png")
71+
)
72+
)
73+
74+
# Generate SVG charts
75+
for (svg_file in chart_files$svg) {
76+
svg(svg_file, width = 10, height = 6)
77+
generate_chart(username, repos, colors, total_repos, date_str)
78+
dev.off()
79+
message("SVG chart saved to ", svg_file)
80+
}
81+
82+
# Generate PNG charts
83+
for (png_file in chart_files$png) {
84+
png(png_file, width = 1200, height = 720, res = 120, bg = "white")
85+
generate_chart(username, repos, colors, total_repos, date_str)
86+
dev.off()
87+
message("PNG chart saved to ", png_file)
88+
}
89+
}

R/treemap.R

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
#!#
2+
# Copyright (c) 2025 Hangzhou Guanwaii Technology Co., Ltd.
3+
#
4+
# This source code is licensed under the MIT License,
5+
# which is located in the LICENSE file in the source tree's root directory.
6+
#
7+
# File: treemap.R
8+
# Author: mingcheng <mingcheng@apache.org>
9+
# File Created: 2025-10-25 23:41:07
10+
#
11+
# Modified By: mingcheng <mingcheng@apache.org>
12+
# Last Modified: 2025-10-25 23:59:44
13+
##
14+
15+
# Load required packages
16+
if (!require("ggplot2", quietly = TRUE)) {
17+
install.packages("ggplot2")
18+
library(ggplot2)
19+
}
20+
21+
if (!require("treemapify", quietly = TRUE)) {
22+
install.packages("treemapify")
23+
library(treemapify)
24+
}
25+
26+
if (!require("showtext", quietly = TRUE)) {
27+
install.packages("showtext")
28+
library(showtext)
29+
}
30+
31+
if (!require("svglite", quietly = TRUE)) {
32+
install.packages("svglite")
33+
library(svglite)
34+
}
35+
36+
#' Generate Treemap Visualization
37+
#'
38+
#' Creates a treemap visualization of repository language distribution
39+
#' using ggplot2 and treemapify packages.
40+
#'
41+
#' @param username GitHub username
42+
#' @param repos Data frame with language statistics
43+
#' @param dir_name Output directory path
44+
#' @param json_data Raw repository data
45+
#' @export
46+
generate_treemap <- function(username, repos, dir_name, json_data) {
47+
# Setup font for visualization
48+
tryCatch(
49+
font_add("MapleMono", regular = "./assets/MapleMono-NF-CN-Regular.ttf"),
50+
error = function(e) {
51+
warning("Failed to load custom font, using default: ", e$message)
52+
}
53+
)
54+
55+
# Enable showtext
56+
showtext_auto()
57+
58+
# Prepare data for treemap
59+
total_repos <- nrow(json_data)
60+
date_str <- format(Sys.Date(), "%Y-%m-%d")
61+
today <- format(Sys.Date(), "%Y%m%d")
62+
63+
# Filter data: only keep languages with percentage >= 1%
64+
repos_filtered <- repos[repos$percentage >= 1, ]
65+
66+
# If too many languages remain, keep only top 12
67+
if (nrow(repos_filtered) > 12) {
68+
repos_filtered <- head(repos_filtered, 12)
69+
}
70+
71+
message("Displaying ", nrow(repos_filtered), " languages in treemap (filtered >= 1%)")
72+
73+
# Create the treemap plot
74+
p <- ggplot(repos_filtered, aes(
75+
area = final_score,
76+
fill = language,
77+
# label = paste0(language, "\n", percentage, "%\n(", repo_count, " repos)")
78+
label = paste0(language, "\n", percentage, "%")
79+
)) +
80+
geom_treemap(colour = "white", size = 2) +
81+
geom_treemap_text(
82+
aes(size = percentage),
83+
place = "centre",
84+
family = "MapleMono",
85+
min.size = 12
86+
) +
87+
scale_size_continuous(range = c(12, 36)) +
88+
labs(
89+
title = "Repository Distribution by Language",
90+
subtitle = sprintf(
91+
"GitHub User: %s | Total Repositories: %d | Updated on %s",
92+
username, total_repos, date_str
93+
)
94+
) +
95+
theme_minimal(base_family = "MapleMono") +
96+
theme(
97+
plot.title = element_text(
98+
hjust = 0.5,
99+
size = 24
100+
),
101+
plot.subtitle = element_text(
102+
hjust = 0.5,
103+
size = 10,
104+
colour = "#777777"
105+
),
106+
legend.position = "none"
107+
)
108+
109+
# Define treemap file paths
110+
treemap_files <- list(
111+
svg = c(
112+
file.path(dir_name, paste0("treemap_", today, ".svg")),
113+
file.path(dir_name, "treemap_latest.svg")
114+
),
115+
png = c(
116+
file.path(dir_name, paste0("treemap_", today, ".png")),
117+
file.path(dir_name, "treemap_latest.png")
118+
)
119+
)
120+
121+
# Save SVG versions
122+
for (svg_file in treemap_files$svg) {
123+
ggsave(
124+
svg_file,
125+
plot = p,
126+
width = 10,
127+
height = 6,
128+
bg = "white"
129+
)
130+
message("Treemap SVG saved to ", svg_file)
131+
}
132+
133+
# Save PNG versions
134+
for (png_file in treemap_files$png) {
135+
ggsave(
136+
png_file,
137+
plot = p,
138+
width = 10,
139+
height = 6,
140+
dpi = 120,
141+
bg = "white"
142+
)
143+
message("Treemap PNG saved to ", png_file)
144+
}
145+
}

0 commit comments

Comments
 (0)