Spaces:
Running
Running
Saba Noorassa
commited on
Commit
·
1e8f76d
1
Parent(s):
dc0b857
sunburst chart
Browse files- .gitignore +1 -0
- data/sunburst_data.min.json +0 -0
- index.html +27 -17
- style.css +24 -14
- sunburst.js +128 -0
.gitignore
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
.DS_STORE
|
data/sunburst_data.min.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
index.html
CHANGED
@@ -1,19 +1,29 @@
|
|
1 |
-
<!
|
2 |
<html>
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
</html>
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
<html>
|
3 |
+
<head>
|
4 |
+
<meta charset="utf-8" />
|
5 |
+
<meta name="viewport" content="width=device-width" />
|
6 |
+
<title>Xet Storage Sunburst</title>
|
7 |
+
<link rel="stylesheet" href="style.css" />
|
8 |
+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/d3.min.js"></script>
|
9 |
+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/d3-scale.min.js"></script>
|
10 |
+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/d3-hierarchy.min.js"></script>
|
11 |
+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/d3-shape.min.js"></script>
|
12 |
+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/d3-format.min.js"></script>
|
13 |
+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/d3-scale-chromatic.min.js"></script>
|
14 |
+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/d3-interpolate.min.js"></script>
|
15 |
+
<script defer src="sunburst.js"></script>
|
16 |
+
</head>
|
17 |
+
<body>
|
18 |
+
<div id="content">
|
19 |
+
<h1>☀️ Xet Storage Sunburst ☀️</h1>
|
20 |
+
<p>
|
21 |
+
This sunburst diagram represents all public data stored using Xet. The
|
22 |
+
diagram presents this information hierarchically first by repo type
|
23 |
+
(model, dataset, or space) then owner (user or org), repo name, and
|
24 |
+
finally individual files within the repo backed by Xet.
|
25 |
+
</p>
|
26 |
+
<svg id="sunburst"></svg>
|
27 |
+
</div>
|
28 |
+
</body>
|
29 |
</html>
|
style.css
CHANGED
@@ -1,28 +1,38 @@
|
|
1 |
body {
|
2 |
-
|
3 |
-
|
4 |
}
|
5 |
|
6 |
h1 {
|
7 |
-
|
8 |
-
|
9 |
}
|
10 |
|
11 |
p {
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
}
|
17 |
|
18 |
.card {
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
}
|
25 |
|
26 |
.card p:last-child {
|
27 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
}
|
|
|
1 |
body {
|
2 |
+
padding: 2rem;
|
3 |
+
font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
|
4 |
}
|
5 |
|
6 |
h1 {
|
7 |
+
font-size: 36px;
|
8 |
+
margin-top: 0;
|
9 |
}
|
10 |
|
11 |
p {
|
12 |
+
color: rgb(107, 114, 128);
|
13 |
+
font-size: 15px;
|
14 |
+
margin-bottom: 10px;
|
15 |
+
margin-top: 5px;
|
16 |
}
|
17 |
|
18 |
.card {
|
19 |
+
max-width: 620px;
|
20 |
+
margin: 0 auto;
|
21 |
+
padding: 16px;
|
22 |
+
border: 1px solid lightgray;
|
23 |
+
border-radius: 16px;
|
24 |
}
|
25 |
|
26 |
.card p:last-child {
|
27 |
+
margin-bottom: 0;
|
28 |
+
}
|
29 |
+
|
30 |
+
#content {
|
31 |
+
max-width: 1024px;
|
32 |
+
margin: 0 auto;
|
33 |
+
}
|
34 |
+
|
35 |
+
#sunburst {
|
36 |
+
margin-top: 2rem;
|
37 |
+
max-width: 928px;
|
38 |
}
|
sunburst.js
ADDED
@@ -0,0 +1,128 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
(async () => {
|
2 |
+
// Fetch graph data.
|
3 |
+
const response = await fetch("/data/sunburst_data.min.json");
|
4 |
+
if (!response.ok) throw new Error(response.statusText);
|
5 |
+
const data = await response.json();
|
6 |
+
|
7 |
+
// Specify the chart’s dimensions.
|
8 |
+
const width = 928;
|
9 |
+
const height = width;
|
10 |
+
const radius = width / 6;
|
11 |
+
|
12 |
+
// Create the color scale.
|
13 |
+
const color = d3.scaleOrdinal(d3.quantize(d3.interpolateRainbow, data.children.length + 1));
|
14 |
+
|
15 |
+
// Compute the layout.
|
16 |
+
const hierarchy = d3.hierarchy(data)
|
17 |
+
.sum(d => d.value)
|
18 |
+
.sort((a, b) => b.value - a.value);
|
19 |
+
const root = d3.partition()
|
20 |
+
.size([2 * Math.PI, hierarchy.height + 1])
|
21 |
+
(hierarchy);
|
22 |
+
root.each(d => d.current = d);
|
23 |
+
|
24 |
+
// Create the arc generator.
|
25 |
+
const arc = d3.arc()
|
26 |
+
.startAngle(d => d.x0)
|
27 |
+
.endAngle(d => d.x1)
|
28 |
+
.padAngle(d => Math.min((d.x1 - d.x0) / 2, 0.005))
|
29 |
+
.padRadius(radius * 1.5)
|
30 |
+
.innerRadius(d => d.y0 * radius)
|
31 |
+
.outerRadius(d => Math.max(d.y0 * radius, d.y1 * radius - 1))
|
32 |
+
|
33 |
+
// Select the SVG container.
|
34 |
+
const svg = d3.select("#sunburst")
|
35 |
+
.attr("viewBox", [-width / 2, -height / 2, width, width])
|
36 |
+
.style("font", "10px sans-serif");
|
37 |
+
|
38 |
+
// Append the arcs.
|
39 |
+
const path = svg.append("g")
|
40 |
+
.selectAll("path")
|
41 |
+
.data(root.descendants().slice(1))
|
42 |
+
.join("path")
|
43 |
+
.attr("fill", d => { while (d.depth > 1) d = d.parent; return color(d.data.name); })
|
44 |
+
.attr("fill-opacity", d => arcVisible(d.current) ? (d.children ? 0.6 : 0.4) : 0)
|
45 |
+
.attr("pointer-events", d => arcVisible(d.current) ? "auto" : "none")
|
46 |
+
|
47 |
+
.attr("d", d => arc(d.current));
|
48 |
+
|
49 |
+
// Make them clickable if they have children.
|
50 |
+
path.filter(d => d.children)
|
51 |
+
.style("cursor", "pointer")
|
52 |
+
.on("click", clicked);
|
53 |
+
|
54 |
+
const format = d3.format(",d");
|
55 |
+
path.append("title")
|
56 |
+
.text(d => `${d.ancestors().map(d => d.data.name).reverse().join("/")}\n${format(d.value)}`);
|
57 |
+
|
58 |
+
const label = svg.append("g")
|
59 |
+
.attr("pointer-events", "none")
|
60 |
+
.attr("text-anchor", "middle")
|
61 |
+
.style("user-select", "none")
|
62 |
+
.selectAll("text")
|
63 |
+
.data(root.descendants().slice(1))
|
64 |
+
.join("text")
|
65 |
+
.attr("dy", "0.35em")
|
66 |
+
.attr("fill-opacity", d => +labelVisible(d.current))
|
67 |
+
.attr("transform", d => labelTransform(d.current))
|
68 |
+
.text(d => d.data.name);
|
69 |
+
|
70 |
+
const parent = svg.append("circle")
|
71 |
+
.datum(root)
|
72 |
+
.attr("r", radius)
|
73 |
+
.attr("fill", "none")
|
74 |
+
.attr("pointer-events", "all")
|
75 |
+
.on("click", clicked);
|
76 |
+
|
77 |
+
// Handle zoom on click.
|
78 |
+
function clicked(event, p) {
|
79 |
+
parent.datum(p.parent || root);
|
80 |
+
|
81 |
+
root.each(d => d.target = {
|
82 |
+
x0: Math.max(0, Math.min(1, (d.x0 - p.x0) / (p.x1 - p.x0))) * 2 * Math.PI,
|
83 |
+
x1: Math.max(0, Math.min(1, (d.x1 - p.x0) / (p.x1 - p.x0))) * 2 * Math.PI,
|
84 |
+
y0: Math.max(0, d.y0 - p.depth),
|
85 |
+
y1: Math.max(0, d.y1 - p.depth)
|
86 |
+
});
|
87 |
+
|
88 |
+
const t = svg.transition().duration(event.altKey ? 7500 : 750);
|
89 |
+
|
90 |
+
// Transition the data on all arcs, even the ones that aren’t visible,
|
91 |
+
// so that if this transition is interrupted, entering arcs will start
|
92 |
+
// the next transition from the desired position.
|
93 |
+
path.transition(t)
|
94 |
+
.tween("data", d => {
|
95 |
+
const i = d3.interpolate(d.current, d.target);
|
96 |
+
return t => d.current = i(t);
|
97 |
+
})
|
98 |
+
.filter(function(d) {
|
99 |
+
return +this.getAttribute("fill-opacity") || arcVisible(d.target);
|
100 |
+
})
|
101 |
+
.attr("fill-opacity", d => arcVisible(d.target) ? (d.children ? 0.6 : 0.4) : 0)
|
102 |
+
.attr("pointer-events", d => arcVisible(d.target) ? "auto" : "none")
|
103 |
+
|
104 |
+
.attrTween("d", d => () => arc(d.current));
|
105 |
+
|
106 |
+
label.filter(function(d) {
|
107 |
+
return +this.getAttribute("fill-opacity") || labelVisible(d.target);
|
108 |
+
}).transition(t)
|
109 |
+
.attr("fill-opacity", d => +labelVisible(d.target))
|
110 |
+
.attrTween("transform", d => () => labelTransform(d.current));
|
111 |
+
}
|
112 |
+
|
113 |
+
function arcVisible(d) {
|
114 |
+
return d.y1 <= 3 && d.y0 >= 1 && d.x1 > d.x0;
|
115 |
+
}
|
116 |
+
|
117 |
+
function labelVisible(d) {
|
118 |
+
return d.y1 <= 3 && d.y0 >= 1 && (d.y1 - d.y0) * (d.x1 - d.x0) > 0.03;
|
119 |
+
}
|
120 |
+
|
121 |
+
function labelTransform(d) {
|
122 |
+
const x = (d.x0 + d.x1) / 2 * 180 / Math.PI;
|
123 |
+
const y = (d.y0 + d.y1) / 2 * radius;
|
124 |
+
return `rotate(${x - 90}) translate(${y},0) rotate(${x < 180 ? 0 : 180})`;
|
125 |
+
}
|
126 |
+
|
127 |
+
// return svg.node();
|
128 |
+
})();
|