Public
Edited
Sep 18
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

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more