Plotting GitHub stats
Mix.install([
{:kino, "~> 0.6.1"},
{:kino_vega_lite, "~> 0.1.1"},
{:req, "~> 0.2.0"}
])
alias VegaLite, as: Vl
Configuration
First, let’s configure the repository we are going to work with.
repo_input = Kino.Input.text("Repository")
repo = Kino.Input.read(repo_input)
Code frequency
We are going to reproduce the code frequency plot. GitHub API exposes weekly commit activity, which includes additions/deletions per week.
%{body: code_frequency} = Req.get!("https://api.github.com/repos/#{repo}/stats/code_frequency")
code_frequency
We need to convert this data to a more plotting-friendly structure, like this:
code_frequency_values =
for [timestamp, additions, deletions] <- code_frequency do
%{
"week" => timestamp |> DateTime.from_unix!() |> DateTime.to_date() |> Date.to_iso8601(),
"additions" => additions,
"deletions" => deletions
}
end
Having the data normalized we can build our plot. In this case we use two layers, one for additions and one for deletions, each with its own color. Both layers share the X axis.
Vl.new(width: 700, height: 300, title: "#{repo} code frequency")
|> Vl.data_from_values(code_frequency_values)
|> Vl.encode_field(:x, "week",
type: :temporal,
axis: [grid: false, format: "%m/%Y"],
title: "month / year"
)
|> Vl.layers([
Vl.new()
|> Vl.mark(:area)
|> Vl.encode_field(:y, "additions", type: :quantitative, title: nil)
|> Vl.encode(:color, value: "#2cbe4e"),
Vl.new()
|> Vl.mark(:area)
|> Vl.encode_field(:y, "deletions", type: :quantitative, title: nil)
|> Vl.encode(:color, value: "#da3633")
])
Commit activity
Next, let’s try mirroring the commit activity plot. GitHub API exposes last year of commit activity, which includes weekly commit count over the past year.
%{body: commit_activity} = Req.get!("https://api.github.com/repos/#{repo}/stats/commit_activity")
commit_activity
This time the data is more structured, but let’s normalize it:
commit_activity_values =
for %{"week" => timestamp, "total" => commits} <- commit_activity do
%{
"week" => timestamp |> DateTime.from_unix!() |> DateTime.to_date() |> Date.to_iso8601(),
"commits" => commits
}
end
To match the GitHub plot, we’re going to dynamically compute a tooltip for each bar, which represents a single week.
Vl.new(width: 800, height: 200, title: "#{repo} commit activity")
|> Vl.data_from_values(commit_activity_values)
|> Vl.transform(
calculate: "datum.commits + ' commits the week of ' + utcFormat(datum.week, '%b %d')",
as: "tooltip"
)
|> Vl.mark(:bar)
|> Vl.encode_field(:x, "week",
type: :temporal,
time_unit: :yearweek,
axis: [grid: false, format: "%m/%d"],
title: "month / day"
)
|> Vl.encode_field(:y, "commits", type: :quantitative, title: nil)
|> Vl.encode_field(:tooltip, "tooltip")
|> Vl.encode(:color, value: "black")