Public
Edited
Aug 23, 2024
Insert cell
Insert cell
snlCast = FileAttachment("cast (1).json").json()
Insert cell
snlCast
SELECT *, CAST(lastYearActual as int)-CAST(firstYearActual as int)+1 as yearsInCast FROM "snlCast"
Insert cell
snlCast
select names,
years,
firstYearActual,
lastYearActual,
CAST(lastYearActual as int)-CAST(firstYearActual as int)+1 as yearsInCast
FROM "snlCast"
order by yearsInCast desc
-- offset 15 rows
limit 30
Insert cell
tenureChart = {
const dimensions = {
width: 1050,
height: 800,
mt: 50,
mb: 50,
ml: 50,
mr: 50
}
const svg = d3.create('svg').attr('width', dimensions.width).attr('height', dimensions.height);

const x = d3.scaleBand()
.domain(castByTenure.map(c => c.names))
.range([dimensions.ml, dimensions.width-dimensions.mr])
.padding(0.1)
const y = d3.scaleLinear()
.domain([0, d3.max(castByTenure, (d) => d.yearsInCast)])
.range([dimensions.height-dimensions.mb, dimensions.mt])
svg.append("g").attr("fill", "steelblue")
.selectAll()
.data(castByTenure)
.join("rect")
.attr("x", (d) => x(d.names))
.attr("y", (d) => y(d.yearsInCast))
.attr("height", (d) => dimensions.height-dimensions.mb-y(d.yearsInCast))
.attr("width", x.bandwidth())
svg.append("g")
.attr("transform", `translate(0, ${dimensions.height-dimensions.mb})`)
.call(
d3.axisBottom(x)
.tickFormat(x => x)
);
svg.append("g")
.attr("transform", `translate(${dimensions.ml},0)`)
.call(d3.axisLeft(y))
.call(g => g.append("text")
.attr("x", -dimensions.ml)
.attr("y", 10)
.attr("fill", "currentColor"))

return svg.node();
}
Insert cell
snlCast
WITH RECURSIVE years(year) AS (
SELECT 1975
UNION ALL
SELECT year + 1
FROM years
WHERE year < (SELECT MAX(lastYearActual) FROM snlCast)
),
cast_years AS (
SELECT names, firstYearActual, lastYearActual
FROM snlCast
WHERE lastYearActual >= 1975
)
SELECT
y.year,
GROUP_CONCAT(c.names ORDER BY c.names ASC) AS cast_members
FROM
years y
LEFT JOIN
cast_years c ON y.year BETWEEN c.firstYearActual AND c.lastYearActual
GROUP BY
y.year
ORDER BY
y.year ASC;
Insert cell
Insert cell
cohortChart = {
const height = 500;
const width = 1100;
const m = {
t: 50,
b: 50,
r: 20,
l: 30,
};

const svg = d3.create('svg')
.attr('height', height)
.attr('width', width);

const x = d3.scaleBand()
.domain(castByYear[1].map(d => Object.keys(d)[0]))
.range([m.l, width - m.r]);

const y = d3.scaleLinear()
.domain([0, d3.max(castByYear[1], d => Object.values(d)[0])])
.range([height - m.b, m.t]);

const line = d3.line()
.x(d => x(Object.keys(d)[0]) + x.bandwidth() / 2)
.y(d => y(Object.values(d)[0]));

// Add the x-axis
svg.append("g")
.attr("transform", `translate(0,${height - m.b})`)
.call(d3.axisBottom(x).ticks(width / 80).tickSizeOuter(0)
.tickFormat(d => d.substr(2))
);

// Add the y-axis
svg.append("g")
.attr("transform", `translate(${m.l}, 0)`)
.call(d3.axisLeft(y));

// Add the path
svg.append("path")
.datum(castByYear[1])
.attr("fill", "none")
.attr("stroke", "black")
.attr("stroke-width", 1.5)
.attr("d", line);

return svg.node();
}
Insert cell
tenureScatterChart = {
const dimensions = {
width: 1050,
height: 800,
mt: 50,
mb: 50,
ml: 50,
mr: 50
}
const svg = d3.create('svg').attr('width', dimensions.width).attr('height', dimensions.height);

const x = d3.scaleLinear()
.domain([1975, 2024])
.range([dimensions.ml, dimensions.width-dimensions.mr])
// .padding(0.1)
const y = d3.scaleLinear()
.domain([0, d3.max(castByTenure, (d) => d.yearsInCast)])
.range([dimensions.height-dimensions.mb, dimensions.mt])
// svg.append("g")
// .attr("stroke", "steelblue")
// .attr("stroke-width", 1.5)
// .attr("fill", "none")
// .selectAll("circle")
// .data(castByTenure)
// .join("circle")
// .attr("cx", d => x(d.firstYearActual))
// .attr("cy", d => y(d.yearsInCast))
// .attr("r", d => d.yearsInCast);

// Add a layer of labels.
svg.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.selectAll("text")
.data(castByTenure)
.join("text")
.attr("dy", "0.35em")
.attr("x", d => x(d.firstYearActual))
.attr("y", d => Math.random()*10+y(d.yearsInCast))
.text(d => d.names.split(" ")[1]);
svg.append("g")
.attr("transform", `translate(0, ${dimensions.height-dimensions.mb})`)
.call(
d3.axisBottom(x)
.tickSizeOuter(dimensions.height/40)
.tickFormat(x => x)
);
svg.append("g")
.attr("transform", `translate(${dimensions.ml},0)`)
.call(d3.axisLeft(y))
.call(g => g.append("text")
.attr("x", -dimensions.ml)
.attr("y", 10)
.attr("fill", "currentColor"))

return svg.node();
}
Insert cell
imdb_data.db
select * from name_basics
where primaryProfession like '%act%'
Insert cell
selectedActorValue = imdbActors.filter(a => a.primaryName.toLowerCase() === selectedActor.names.toLowerCase())[0]
Insert cell
imdb_data.db
select distinct * from title_basics tb
join title_ratings tr
where tr.tconst = tb.tconst
and tb.genres like '%Comedy%'
and tb.titleType = 'movie'
Insert cell
// viewof selectedActor = Inputs.select(actors, {multiple: false, label: "Select actors", keyof: d => d.primaryName})
viewof selectedActor = Inputs.select(snlCast, {multiple: false, label: "Select actors", keyof: d => d.names})
Insert cell
selectedTitles = imdbComedyTitles.filter(t => selectedActorValue.knownForTitles.split(",").includes(t.tconst))
Insert cell
castComedyMoviesByYear = castsByYear.map(cast => {
const isAllowed = (id) => id !== "\\N";
const titleIdList = Array.from(
new Set(
imdbActors.filter(i => cast.cast_members.split(",")
.includes(i.primaryName))
.flatMap(i => i.knownForTitles.split(","))
)
).filter(id => isAllowed(id));
const titleNames = imdbComedyTitles.filter(t => titleIdList.includes(t.tconst))
return {
...cast,
titles: titleNames
}
})
Insert cell
Insert cell
Plot.plot({
width: 1500,
title: "avg imdb rating for comedy movies by snl cast year",
marks: [
Plot.barY(castComedyMoviesByYear, {
x: d => d.year,
y: d => d3.sum(d.titles.map(t => t.averageRating))/(d.titles.length),
fill: "orange",
}),
Plot.tip(castComedyMoviesByYear, Plot.pointerX({
x: d => d.year,
y: d => d3.sum(d.titles.map(t => t.averageRating))/(d.titles.length)
})),
Plot.ruleY([0])
],
})
Insert cell
Plot.plot({
width: 1000,
marks: [
Plot.cell(castComedyMoviesByYear, {
x: d => d.titles.length,
y: d => d.year,
// fill: "temp_max"
})
]
})
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