Skip to content

Commit cb7acfa

Browse files
Merge pull request #611 from M-L-D-H/jsb
Update Projects
2 parents b9f047a + 4b87b0e commit cb7acfa

1 file changed

Lines changed: 173 additions & 0 deletions

File tree

sustainability_chart2.html

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<title>Sustainability Visualization</title>
6+
<link href="https://fonts.googleapis.com/css2?family=Inter&display=swap" rel="stylesheet">
7+
<script src="https://cdn.jsdelivr.net/npm/vega@5"></script>
8+
<script src="https://cdn.jsdelivr.net/npm/vega-lite@5.20.1"></script>
9+
<script src="https://cdn.jsdelivr.net/npm/vega-embed@6"></script>
10+
<style>
11+
body {
12+
font-family: 'Inter', sans-serif;
13+
margin: 0;
14+
padding: 0;
15+
background-color: #fff;
16+
color: #2F4A60;
17+
}
18+
19+
#vis.vega-embed {
20+
width: 90%;
21+
max-width: 1000px;
22+
margin: 2rem auto;
23+
padding: 1rem;
24+
background-color: #fafafa;
25+
border-radius: 10px;
26+
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
27+
}
28+
29+
h1 {
30+
text-align: center;
31+
font-weight: 600;
32+
font-size: 1.8rem;
33+
margin-top: 2rem;
34+
}
35+
</style>
36+
</head>
37+
<body>
38+
<h1>Sustainability Metadata Overview</h1>
39+
<div id="vis">Loading chart...</div>
40+
41+
<script>
42+
async function getSustainabilityData() {
43+
const res = await fetch('/Projects.json');
44+
const allProjects = await res.json();
45+
46+
const rawProjects = await Promise.all(
47+
Object.entries(allProjects).map(async ([uuid, project]) => {
48+
const folderPath = project.path;
49+
const filePath = folderPath.endsWith('/')
50+
? folderPath + uuid + '.json'
51+
: folderPath + '/' + uuid + '.json';
52+
53+
try {
54+
const res = await fetch(filePath);
55+
const data = await res.json();
56+
const sustainability = data.project?.research_data?.sustainability_plan ?? {};
57+
58+
return {
59+
website: sustainability.project_website ?? 'N/A',
60+
github: sustainability.Github ?? 'N/A',
61+
data_accessibility: sustainability.data_accessibility ?? 'N/A',
62+
publications: sustainability.publications ?? 'N/A',
63+
publication_count: sustainability.publication_count ?? 0,
64+
open_access_count: sustainability.open_access_count ?? 0,
65+
webhosting: sustainability.webhosting ?? 'N/A'
66+
};
67+
} catch (err) {
68+
console.warn(`Skipping project ${uuid} at ${filePath}:`, err);
69+
return null;
70+
}
71+
})
72+
);
73+
74+
return rawProjects.filter(p => p !== null);
75+
}
76+
77+
function groupData(projects) {
78+
const total = projects.length;
79+
const countBy = (key, val) => projects.filter(p => p[key] === val).length;
80+
81+
const bar = (cat, label, count) => ({
82+
Category: cat,
83+
"Score Label": label,
84+
Count: count,
85+
Tooltip: `From ${total} total projects, ${count} projects are in category "${label}".`
86+
});
87+
88+
return [
89+
bar("Website", "Full / Yes", countBy("website", 1.0)),
90+
bar("Website", "No / None", countBy("website", 0.0)),
91+
92+
bar("Github", "Full / Yes", countBy("github", 1.0)),
93+
bar("Github", "No / None", countBy("github", 0.0)),
94+
95+
bar("Data Accessibility", "Full / Yes", countBy("data_accessibility", 1.0)),
96+
bar("Data Accessibility", "Partial / Mentioned", countBy("data_accessibility", 0.5)),
97+
bar("Data Accessibility", "No / None", countBy("data_accessibility", 0.0)),
98+
99+
bar("Publications", "Full / Yes", countBy("publications", 1.0)),
100+
bar("Publications", "No / None", countBy("publications", 0.0)),
101+
102+
bar("Open Access Publications", "Full / Yes", projects.filter(p => p.publication_count > 0 && p.publication_count === p.open_access_count).length),
103+
bar("Open Access Publications", "Partial / Mentioned", projects.filter(p => p.open_access_count > 0 && p.open_access_count < p.publication_count).length),
104+
bar("Open Access Publications", "No / None", projects.filter(p => p.publication_count > 0 && p.open_access_count === 0).length),
105+
106+
bar("Webhosting", "Full / Yes", countBy("webhosting", 1.0)),
107+
bar("Webhosting", "Partial / Mentioned", countBy("webhosting", 0.5)),
108+
bar("Webhosting", "No / None", countBy("webhosting", 0.0))
109+
];
110+
}
111+
112+
async function renderChart() {
113+
const projects = await getSustainabilityData();
114+
const values = groupData(projects);
115+
116+
const spec = {
117+
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
118+
"title": "Sustainability Metadata Overview (" + projects.length + " Projects)",
119+
"selection": {
120+
"highlight": {
121+
"type": "single",
122+
"on": "mouseover",
123+
"empty": "all",
124+
"clear": "mouseout"
125+
}
126+
},
127+
"data": { "values": values },
128+
"mark": "bar",
129+
"encoding": {
130+
"x": {
131+
"field": "Category",
132+
"type": "nominal",
133+
"title": "Category",
134+
"axis": { "labelAngle": 30 }
135+
},
136+
"xOffset": { "field": "Score Label", "type": "nominal" },
137+
"y": {
138+
"field": "Count",
139+
"type": "quantitative",
140+
"title": "Number of Projects"
141+
},
142+
"color": {
143+
"field": "Score Label",
144+
"type": "nominal",
145+
"legend": { "title": "Sustainability Score" },
146+
"scale": {
147+
"domain": ["Full / Yes", "Partial / Mentioned", "No / None"],
148+
"range": ["#2F4A60", "#F29559", "#B8B18F"]
149+
}
150+
},
151+
"opacity": {
152+
"condition": {
153+
"selection": "highlight",
154+
"value": 1
155+
},
156+
"value": 0.2
157+
},
158+
"tooltip": { "field": "Tooltip", "type": "nominal" }
159+
},
160+
"width": 700,
161+
"height": 400
162+
};
163+
164+
vegaEmbed("#vis", spec, {}).catch(err => {
165+
document.getElementById("vis").innerHTML = `<pre style="color:red;">Error: ${err.message}</pre>`;
166+
console.error(err);
167+
});
168+
}
169+
170+
renderChart();
171+
</script>
172+
</body>
173+
</html>

0 commit comments

Comments
 (0)