Skip to content

Commit c387842

Browse files
committed
feat(frequency): init code frequency chart
1 parent 1d8fc0e commit c387842

File tree

3 files changed

+122
-0
lines changed

3 files changed

+122
-0
lines changed

web/data/demo.csv

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
type,value
2+
variable 1,-1.77631469016691
3+
variable 2,3.38791781876974

web/index.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@
7171
</head>
7272
<body>
7373
<h1>Coco Reporter</h1>
74+
75+
<h2>Code Frequency</h2>
76+
<div id="code-frequency"></div>
77+
7478
<h2>Commit Calendar</h2>
7579
<div id="commit-calendar"></div>
7680
<h2>Branches History</h2>
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,116 @@
11
// such as: https://github.com/inherd/coco/graphs/code-frequency
2+
// set the dimensions and margins of the graph
3+
let margin = {top: 30, right: 30, bottom: 30, left: 60},
4+
width = 460 - margin.left - margin.right,
5+
height = 400 - margin.top - margin.bottom;
6+
7+
// append the svg object to the body of the page
8+
let svg = d3.select("#code-frequency")
9+
.append("svg")
10+
.attr("width", width + margin.left + margin.right)
11+
.attr("height", height + margin.top + margin.bottom)
12+
.append("g")
13+
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
14+
15+
// get the data
16+
d3.csv("data/demo.csv", {typed: true}).then(function (data) {
17+
// add the x Axis
18+
let x = d3.scaleLinear()
19+
.domain([-10, 15])
20+
.range([0, width]);
21+
svg.append("g")
22+
.attr("transform", "translate(0," + height + ")")
23+
.call(d3.axisBottom(x));
24+
25+
// add the first y Axis
26+
let y1 = d3.scaleLinear()
27+
.range([height / 2, 0])
28+
.domain([0, 0.12]);
29+
svg.append("g")
30+
.attr("transform", "translate(-20,0)")
31+
.call(d3.axisLeft(y1).tickValues([0.05, 0.1]));
32+
33+
// add the first y Axis
34+
let y2 = d3.scaleLinear()
35+
.range([height / 2, height])
36+
.domain([0, 0.12]);
37+
svg.append("g")
38+
.attr("transform", "translate(-20,0)")
39+
.call(d3.axisLeft(y2).ticks(2).tickSizeOuter(0));
40+
41+
// Compute kernel density estimation
42+
let kde = kernelDensityEstimator(kernelEpanechnikov(7), x.ticks(60))
43+
let density1 = kde(data.filter(function (d) {
44+
return d.type === "variable 1"
45+
}).map(function (d) {
46+
return d.value;
47+
}));
48+
49+
let density2 = kde(data.filter(function (d) {
50+
return d.type === "variable 2"
51+
}).map(function (d) {
52+
return d.value;
53+
}))
54+
55+
// Plot the area
56+
svg.append("path")
57+
.attr("class", "mypath")
58+
.datum(density1)
59+
.attr("fill", "#69b3a2")
60+
.attr("opacity", ".6")
61+
.attr("stroke", "#000")
62+
.attr("stroke-width", 1)
63+
.attr("stroke-linejoin", "round")
64+
.attr("d", d3.line()
65+
.curve(d3.curveBasis)
66+
.x(function (d) {
67+
return x(d[0]);
68+
})
69+
.y(function (d) {
70+
return y1(d[1]);
71+
})
72+
);
73+
74+
// Plot the area
75+
svg.append("path")
76+
.attr("class", "mypath")
77+
.datum(density2)
78+
.attr("fill", "#404080")
79+
.attr("opacity", ".6")
80+
.attr("stroke", "#000")
81+
.attr("stroke-width", 1)
82+
.attr("stroke-linejoin", "round")
83+
.attr("d", d3.line()
84+
.curve(d3.curveBasis)
85+
.x(function (d) {
86+
return x(d[0]);
87+
})
88+
.y(function (d) {
89+
return y2(d[1]);
90+
})
91+
);
92+
93+
});
94+
95+
// Handmade legend
96+
svg.append("circle").attr("cx", 290).attr("cy", 30).attr("r", 6).style("fill", "#69b3a2")
97+
svg.append("circle").attr("cx", 290).attr("cy", 60).attr("r", 6).style("fill", "#404080")
98+
svg.append("text").attr("x", 310).attr("y", 30).text("variable A").style("font-size", "15px").attr("alignment-baseline", "middle")
99+
svg.append("text").attr("x", 310).attr("y", 60).text("variable B").style("font-size", "15px").attr("alignment-baseline", "middle")
100+
101+
// Function to compute density
102+
function kernelDensityEstimator(kernel, X) {
103+
return function (V) {
104+
return X.map(function (x) {
105+
return [x, d3.mean(V, function (v) {
106+
return kernel(x - v);
107+
})];
108+
});
109+
};
110+
}
111+
112+
function kernelEpanechnikov(k) {
113+
return function (v) {
114+
return Math.abs(v /= k) <= 1 ? 0.75 * (1 - v * v) / k : 0;
115+
};
116+
}

0 commit comments

Comments
 (0)