Published
Edited
Jun 7, 2020
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
render_data_table(table_info)
Insert cell
Insert cell
md`## Visualization 1: Filter`
Insert cell
viewof movie_or_series = select(["Movie", "Series"])
Insert cell
chart1 = {
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);

if (movie_or_series == "Movie") {
//title
svg
.append("text")
.attr("class", "text")
.attr("transform", "translate(500,50)")
.style("text-anchor", "middle")
.style("font-size", "25px")
.style("font-weight", "bold")
.text("Count of ratings by genre for Disney movies");

//set x
const x_movie = d3
.scaleBand()
.domain(genre_movie.map(d => d.genre))
.range([margin.left, width - margin.right]);

//set y
const y_movie = d3
.scaleLinear()
.domain([d3.max(genre_movie, d => d.rating), 0])
.range([margin.bottom, height - margin.top]);

//setxAxis
const xAxis_movies = g =>
g
.call(d3.axisBottom(x_movie))
.attr('transform', `translate(0, ${height - margin.bottom + 10})`);

const yAxis_movie = g =>
g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y_movie));

x_movie.padding(0.2);

svg
.append('g')
.call(xAxis_movies)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)");
svg.append('g').call(yAxis_movie);

svg
.selectAll('.bar')
.data(genre_movie)
.join(enter => enter.append("rect"))
.attr('x', d => x_movie(d.genre))
.attr('y', d => y_movie(d.rating))
.attr('width', x_movie.bandwidth())
.attr('height', d => y_movie(0) - y_movie(d.rating))
.attr('fill', "purple")
.attr('opacity', 0.7);
} else {
//title
svg
.append("text")
.attr("class", "text")
.attr("transform", "translate(500,50)")
.style("text-anchor", "middle")
.style("font-size", "25px")
.style("font-weight", "bold")
.text("Count of ratings by genre for Disney series");

//set x
const x_series = d3
.scaleBand()
.domain(genre_series.map(d => d.genre))
.range([margin.left, width - margin.right]);

//set y
const y_series = d3
.scaleLinear()
.domain([d3.max(genre_series, d => d.rating), 0])
.range([margin.bottom, height - margin.top]);

//setxAxis
const xAxis_series = g =>
g
.call(d3.axisBottom(x_series))
.attr('transform', `translate(0, ${height - margin.bottom + 10})`);

const yAxis_series = g =>
g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y_series));
x_series.padding(0.2);

svg
.append('g')
.call(xAxis_series)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)");
svg.append('g').call(yAxis_series);

svg
.selectAll('.bar')
.data(genre_movie)
.join(enter => enter.append("rect"))
.attr('x', d => x_series(d.genre))
.attr('y', d => y_series(d.rating))
.attr('width', x_series.bandwidth())
.attr('height', d => y_series(0) - y_series(d.rating))
.attr('fill', "red")
.attr('opacity', 0.7);
}

svg
.append("text")
.attr("class", "text")
.attr("transform", `translate(500, ${height - margin.bottom + 45})`)
.style("text-anchor", "middle")
.style("font-size", "14px")
.text("Genre");
svg
.append("text")
.attr("class", "text")
.attr("transform", `translate(10, ${height / 2})rotate(-90)`)
.style("text-anchor", "middle")
.style("font-size", "14px")
.text("Count");

return svg.node();
}
Insert cell
md`## Visualization 2: Encode (by color)`
Insert cell
x_encode = d3
.scaleLinear()
.domain(d3.extent(disney, d => +d.imdb_rating))
.range([margin.left, width - margin.right])
Insert cell
y_encode = d3
.scaleLinear()
.domain(d3.extent(disney, d => +d.imdb_votes))
.range([height - margin.bottom, margin.top])
Insert cell
viewof color = select(["Purple", "Pink", "Blue"])
Insert cell
chart_encode = {
const svg = d3.create('svg').attr('viewBox', [0, 0, width, height]);
const margin = { top: 50, right: 50, bottom: 50, left: 60 };

const xAxis = g =>
g
.call(d3.axisBottom(x_encode).ticks(50))
.attr('transform', `translate(0, ${height - margin.bottom - 7})`);

svg.append('g').call(xAxis);

const yAxis = g =>
g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y_encode));
svg.append('g').call(yAxis);

svg
.append('g')
.attr('transform', `translate(0, ${height - margin.bottom})`)
.call(xAxis);
svg
.append('g')
.attr('transform', `translate(${margin.left}, 0)`)
.call(yAxis);

if (color == "Purple") {
svg
.append("g")
.attr("stroke", "#000")
.attr("stroke-opacity", 0.2)
.selectAll("circle")
.data(disney)
.enter()
.append("circle")
.attr("cx", d => x_encode(d.imdb_rating))
.attr("cy", d => y_encode(d.imdb_votes))
.attr('fill', "purple")
.attr("r", 1.5);

svg
.append("circle")
.attr("transform", "translate(600,-30)")
.attr("cx", 200)
.attr("cy", 160)
.attr("r", 6)
.style("fill", "purple");
} else if (color == "Pink") {
svg
.append("g")
.attr("stroke", "#000")
.attr("stroke-opacity", 0.2)
.selectAll("circle")
.data(disney)
.enter()
.append("circle")
.attr("cx", d => x_encode(d.imdb_rating))
.attr("cy", d => y_encode(d.imdb_votes))
.attr('fill', "pink")
.attr("r", 1.5);

svg
.append("circle")
.attr("transform", "translate(600,-30)")
.attr("cx", 200)
.attr("cy", 160)
.attr("r", 6)
.style("fill", "pink");
} else {
svg
.append("g")
.attr("stroke", "#000")
.attr("stroke-opacity", 0.2)
.selectAll("circle")
.data(disney)
.enter()
.append("circle")
.attr("cx", d => x_encode(d.imdb_rating))
.attr("cy", d => y_encode(d.imdb_votes))
.attr('fill', "blue")
.attr("r", 1.5);

svg
.append("circle")
.attr("transform", "translate(600,-30)")
.attr("cx", 200)
.attr("cy", 160)
.attr("r", 6)
.style("fill", "blue");
}

svg
.append("text")
.attr("class", "text")
.attr("transform", `translate(500, ${height - margin.bottom + 45})`)
.style("text-anchor", "middle")
.style("font-size", "14px")
.text("Rating");
svg
.append("text")
.attr("class", "text")
.attr("transform", `translate(10, ${height / 2})rotate(-90)`)
.style("text-anchor", "middle")
.style("font-size", "14px")
.text("Vote");

svg
.append("text")
.attr("class", "text")
.attr("transform", "translate(500,50)")
.style("text-anchor", "middle")
.style("font-size", "25px")
.style("font-weight", "bold")
.text("Rating VS Vote: Disney+ ");

svg
.append("text")
.attr("transform", "translate(600,-30)")
.attr("x", 220)
.attr("y", 160)
.text("Disney")
.style("font-size", "15px")
.attr("alignment-baseline", "middle");

return svg.node();
}
Insert cell
md`## Visualization 3: Hover`
Insert cell
x_hover = d3
.scaleLinear()
.domain(d3.extent(disney, d => +d.imdb_rating))
.range([margin.left, width - margin.right])
Insert cell
y_hover = d3
.scaleLinear()
.domain(d3.extent(disney, d => +d.imdb_votes))
.range([height - margin.bottom, margin.top])
Insert cell
tooltip = {
chart_hover;

const tooltip = d3
.select("body")
.append("div")
.attr("class", "svg-tooltip")
.style("position", "absolute")
.style("visibility", "hidden");

d3.selectAll("#select")
.on("mouseover", function(d) {
d3.select(this)
.attr('stroke-width', '1')
.style('fill', 'steelblue')
.attr("stroke", "black");
tooltip
.style("visibility", "visible")
.style("font", "9px")
.text(`Total Votes: ${d.imdb_votes}`);
})
.on("mousemove", function() {
tooltip
.style("top", d3.event.pageY - 10 + "px")
.style("left", d3.event.pageX + 10 + "px");
})
.on("mouseout", function() {
d3.select(this)
.attr('stroke-width', '1')
.style('fill', '#f28e2c');

tooltip.style("visibility", "hidden");
});
}
Insert cell
chart_hover = {
const svg = d3.create('svg').attr('viewBox', [0, 0, width, height]);
const margin = { top: 50, right: 50, bottom: 50, left: 60 };

const xAxis = g =>
g
.call(d3.axisBottom(x_hover).ticks(50))
.attr('transform', `translate(0, ${height - margin.bottom - 7})`);

svg.append('g').call(xAxis);

const yAxis = g =>
g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y_hover));
svg.append('g').call(yAxis);

svg
.append('g')
.attr('transform', `translate(0, ${height - margin.bottom})`)
.call(xAxis);
svg
.append('g')
.attr('transform', `translate(${margin.left}, 0)`)
.call(yAxis);

svg
.append("g")
.attr("stroke", "#000")
.attr("stroke-opacity", 0.2)
.selectAll("circle")
.data(disney)
.enter()
.append("circle")
.attr("cx", d => x_hover(d.imdb_rating))
.attr("cy", d => y_hover(d.imdb_votes))
.attr('fill', "purple")
.attr("r", 1.5)
.attr("id", "select");

svg
.append("text")
.attr("class", "text")
.attr("transform", `translate(500, ${height - margin.bottom + 45})`)
.style("text-anchor", "middle")
.style("font-size", "14px")
.text("Rating");
svg
.append("text")
.attr("class", "text")
.attr("transform", `translate(10, ${height / 2})rotate(-90)`)
.style("text-anchor", "middle")
.style("font-size", "14px")
.text("Vote");

svg
.append("text")
.attr("class", "text")
.attr("transform", "translate(500,50)")
.style("text-anchor", "middle")
.style("font-size", "25px")
.style("font-weight", "bold")
.text("Rating VS Vote: Disney+");

return svg.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
import { select } from "@jashkenas/inputs"
Insert cell
d3 = require('d3')
Insert cell
disney = d3.csvParse(
await FileAttachment("disney_plus_shows.csv").text(),
({ imdb_id, title, type, genre, imdb_rating, imdb_votes, year }) => ({
imdb_id: imdb_id,
type: type,
title: title,
genre: genre,
imdb_rating: imdb_rating,
imdb_votes: imdb_votes.split(",").join(""),
year: year
})
)
Insert cell
disney_movie = disney.filter(d => d.type == 'movie')
Insert cell
disney_series = disney.filter(d => d.type == 'series')
Insert cell
genre_movie = {
let genre_count = [];
disney_movie.forEach(row => {
let genres = row.genre.split(",");
let rating = row.imdb_rating;

for (let i = 0; i < genres.length; i++) {
let this_genre = genres[i].trim();
if (this_genre != "N/A") {
let find_genre = genre_count.find(d => d.genre === this_genre);

// if not in
if (find_genre === undefined) {
let rating_arr = [];
rating_arr.push(rating);
genre_count.push({
genre: this_genre,
count: 1,
rating: rating,
rating_all: rating_arr
});
} else {
find_genre.rating_all.push(rating);
find_genre.count++;
if (rating != "N/A" && rating != "" && rating != undefined) {
find_genre.rating += +rating;
}
}
}
}
});
genre_count.forEach(row => {
row.rating = d3.sum(row.rating_all) / row.count;
});
return genre_count;
}
Insert cell
genre_series = {
let genre_count = [];
disney_series.forEach(row => {
let genres = row.genre.split(",");
let rating = row.imdb_rating;

for (let i = 0; i < genres.length; i++) {
let this_genre = genres[i].trim();
if (this_genre != "N/A") {
let find_genre = genre_count.find(d => d.genre === this_genre);

// if not in
if (find_genre === undefined) {
let rating_arr = [];
rating_arr.push(rating);
genre_count.push({
genre: this_genre,
count: 1,
rating: rating,
rating_all: rating_arr
});
} else {
find_genre.rating_all.push(rating);
find_genre.count++;
if (rating != "N/A" && rating != "" && rating != undefined) {
find_genre.rating += +rating;
}
}
}
}
});
genre_count.forEach(row => {
row.rating = d3.sum(row.rating_all) / row.count;
});
return genre_count;
}
Insert cell
disney_rating = disney
.filter(d => d.imdb_rating != "N/A")
.map(d => d.imdb_rating)
Insert cell
height = 500
Insert cell
margin = ({ top: 50, right: 10, bottom: 60, left: 60 })
Insert cell
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