Public
Edited
Sep 18, 2024
Latest
3 forks
3 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
graph
Insert cell
style = html`
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Oswald:wght@300&display=swap" rel="stylesheet">
<style>
h2 {
font-family: "Oswald", sans-serif;
font-weight: bold;
margin: 0px 20px ;
}
${
useShadowsNodes
? `svg circle.shadow {
-webkit-filter: drop-shadow( 2px 2px 1px rgba(0, 0, 0, .7));
filter: drop-shadow( 2px 2px 1px rgba(0, 0, 0, .7));
}
`
: ""
}

${
useShadowsText
? `
svg text.shadow {
font-family: 'Oswald', sans-serif;
-webkit-filter: drop-shadow( 2px 2px 1px rgba(255, 255, 255, .7));
filter: drop-shadow( 2px 2px 1px rgba(255, 255, 255, .7));
}`
: ""
}

<style>
`
Insert cell
// Let's keep here a reference of the targets
dConnections = new Map()
Insert cell
graph = {
for (let n of dData.values()) {
n.degree = 0;
}

const linksArray = links.objects();
for (let l of linksArray) {
const source = dData.get(l.source);
// target = dNodes.get(l.target);

source.cluster = l.target;
// target.cluster = l.target;
source.degree += 1;
// target.degree += 1;
}

const getOrCreateNode = (name) => {
let node = dConnections.get(name);

if (!node) {
node = {
name,
type: "Connection",
cluster: name,
x: width / 2 + (Math.random() * width) / 10,
y: height / 2 + (Math.random() * height) / 10
};
dConnections.set(name, node);
}
return node;
};

// --------- Filter Links and Nodes --------------
const filteredLinks = linksArray.map((l) => {
return {
source: dData.get(l.source),
target: getOrCreateNode(l.target)
};
});

const filteredNodesObject = filteredLinks.reduce(
(p, l) => {
if (!p.set.has(l.source.name)) {
p.set.add(l.source.name);
p.list.push(l.source);
}
if (!p.set.has(l.target.name)) {
p.set.add(l.target.name);
p.list.push(l.target);
}

return p;
},
{ set: new Set(), list: [] }
);

// Clusters is used for the hulls
const clusters = d3.rollups(
filteredLinks,
(v) => v.map((l) => l.source).concat([v[0].target]),
(d) => d.target.name
);

return {
nodes: filteredNodesObject.list,
links: linksArray,
clusters: clusters
};
}
Insert cell
dateFmt = d3.timeParse("%m/%d/%Y")
Insert cell
hullColor = d3.scaleOrdinal(
d3.quantize(
colorInterpolator,
tidyData.groupby(groupBy).count().objects().length
)
)
Insert cell
data[0]
Insert cell
// Transform the data into tidyFormat
viewof tidyData = aq
.from(data)
.fold(
[
"Interdisciplinary College 1",
"Interdisciplinary College 2",
"Interdisciplinary College 3",
"Interdisciplinary College 4"
],
{
as: ["IC", "Appointment"]
}
)
.derive({
"Research Areas": (d) =>
!d["Research Areas"] ? [null] : op.split(d["Research Areas"], "/"),
"Campus": (d) =>
!d["Campus"] ? [null] : op.split(d["Campus"], ",")
})
.unroll("Research Areas")
.derive({
"Academic Track Type": (d) =>
d["Academic Track Type"] === null
? [null]
: op.split(d["Academic Track Type"], "&")
})
.unroll("Academic Track Type")
.derive({ "Academic Track Type": (d) => op.trim(d["Academic Track Type"]) })
.unroll("Campus")
.derive({ "Campus": (d) => op.trim(d["Campus"]) })
// .filter(aq.escape((d) => showKhoury ? true: d.Appointment !== "Khoury College of Computer Sciences" ))
.view()
Insert cell
tidyData.filter(d => d.Campus == "Oakland").view()
Insert cell
data.filter(d => d.Campus == "Oakland")
Insert cell
Insert cell
links.filter(d => d.target=="Oakland").view()
Insert cell
selectedTargets
Insert cell
viewof targets = links
.groupby("target")
.count()
.rename({ target: "name" })
.view()
Insert cell
viewof sources = links
.groupby("source")
.count()
.rename({ source: "name" })
.derive({ type: () => "Faculty" })
.view()
Insert cell
// Inputs.table(data)
Insert cell
// navio(data)
Insert cell
Insert cell
dataScrapped = FileAttachment("khouryFacultyScrapped_2024_09Sep_18.csv").csv({
typed: true
})
Insert cell
facultyFromScrape = dataScrapped.filter(d => d.position.search(/(teach|prof)/gi)!==-1)
Insert cell
data = d3
.csv(
"https://docs.google.com/spreadsheets/d/e/2PACX-1vTX-fbHzk70bzNUMJxwNKsMnkEbtXJ0SPh9Fa8HZy-NRbn2gg721RIWD-wvFZv5xZta7uZLVJOgKgN2/pub?gid=0&single=true&output=csv"
)
// FileAttachment("Faculty_May_2023@1.csv")
// .csv({ typed: true })
.then((res) => {
for (let d of res) {
d.name = `${d["First Name"]} ${d["Last Name"]}`;
d.nameArray = d.name.split(" ");
d.date = dateFmt(d["Year Highest Degree Received"]);
d.type = "Faculty";

d["Interdisciplinary College 4"] = "Khoury College of Computer Sciences";
d["Job Title"] = d["Job Profile"];

if (dDataScrapped.has(d.name)) {
const s = dDataScrapped.get(d.name);
d.Campus = s.location;
d["Job Title"] = d.position;
}

d.Campus = d.Campus == "NU Boston Campus" ? "Boston": d.Campus;
d.photo = photosMap.get(d.name);
}

const dData = new Map(res.map(d => [d.name, d]));

for (let d of facultyFromScrape.filter(d => !dData.has(d.name))) {
res.push({
...d,
name: d.name,
"First Name": d.name.split(" ")[0],
"Last Name": d.name.split(" ").slice(1).join(" "),
"Job Profile": d.position,
"Title": d.position,
"Job Title": d.position,
Campus: d.location,
"Interdisciplinary Dept 1": "Khoury",
"Interdisciplinary College 1": "Khoury College of Computer Sciences",
"Interdisciplinary College 4": "Khoury College of Computer Sciences",
"Interdisciplinary College 3": "",
"Interdisciplinary College 2": "",
"Research Areas": "AI",
"Academic Track Type": "",
date: new Date(),
type: "Faculty",
})
}

return res;
})
Insert cell
navio(data)
Insert cell
Inputs.table(facultyFromScrape)
Insert cell
// A map for the faculty nodes
dData = new Map(data.map(d => [d.name, d]))
Insert cell
dDataScrapped = new Map(facultyFromScrape.map(d => [d.name, d]))
Insert cell
photosMap = new Map(
dataScrapped
.filter((d) => d["Picture URL-src"] && d["Picture URL-src"].indexOf("inline-default") === -1)
.map((d) => [d.name, d["Picture URL-src"]])
)
Insert cell
import { navio } from "@john-guerra/navio"
Insert cell
import { aq, op } from "@uwdata/arquero"
Insert cell
import {Scrubber} from "@mbostock/scrubber"
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more