Public
Edited
Feb 12, 2024
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
makeChart1(data)
Insert cell
makeChart1 = (dataset) => {
const w = 600;
const h = dataset.length * 28; // I increased the height to give everything more space

// We'll return chart1Svg.node() from this function
const chart1Svg = d3.create("svg").attr("width", w).attr("height", h);

// sort the data by downloads
// uses built-in Array.sort() with comparator function
dataset.sort((a, b) => b.downloads - a.downloads);

// our range is limited from 0 to width - 100,
// which is for the 80 pixels on left for axis and
// 20 pixels on right for padding
const xScale = d3
.scaleLinear()
.domain([0, d3.max(dataset, (d) => d.downloads)])
.rangeRound([0, w - 100]);

// using scale band to work with nominal values
// the Array.map() call allows us to get a new array
// by calling a function on each item of the source array
// here it pulls out the app_name
const yScale = d3
.scaleBand()
.domain(dataset.map((d) => d.app_name))
.rangeRound([20, h - 20]);

// d3 allows scaling between colors
// This is here for demonstrating that you *can* do this, though
// in this instance, it's not a particularly good use of color.
// In your assignment, I'd question using a color scale here to
// visualize a third data variable and instead replace this with
// either static values, or change the domain/range to apply to
// a data variable already in use in the chart to reinforce a
// a data variable visually.
const colorScale = d3.scaleLinear().domain([74369, 990365]).range(["#f00", "#00f"]); // I changed the colors to be from red to blue, and changed the range to be from the lowest number of downloads to the highest to correspond better with the actual data being presented

chart1Svg
.selectAll("rect")
.data(dataset)
.join("rect")
.attr("x", 80)
.attr("y", (d) => yScale(d.app_name))
.attr("width", (d) => xScale(d.downloads))
.attr("height", 20)
.attr("fill", (d) => colorScale(d.downloads));

// AXES
chart1Svg
.append("g")
.attr("class", "axis")
.attr("transform", `translate(80, ${h - 18})`) // Here i reduced the distance from the bottom
.call(d3.axisBottom(xScale));

chart1Svg
.append("g")
.attr("class", "axis")
.attr("transform", `translate(70,0)`)
.call(d3.axisLeft(yScale).tickSize(0)); // right here is where I fixed the ticks

return chart1Svg.node();
}
Insert cell
Insert cell
makeChart2 = (dataset) => {
const w = 600;
const h = dataset.length * 28;
const chart2Svg = d3.create("svg")
.attr('width', w)
.attr('height', h);

// FILL IN HERE, and observe changes below
dataset.sort((a, b) => b.average_rating - a.average_rating);

const xScale = d3
.scaleLinear()
.domain([4.5, d3.max(dataset, (d) => d.average_rating)])
.rangeRound([0, w-100]);

const yScale = d3
.scaleBand()
.domain(dataset.map((d) => d.app_name))
.rangeRound([20, h - 20]);

const colorScale = d3.scaleLinear().domain([4.55, 5]).range(["#0f0", "#f0f"]);

chart2Svg
.selectAll("rect")
.data(dataset)
.join("rect")
.attr("x", 80)
.attr("y", (d) => yScale(d.app_name))
.attr("width", (d) => xScale(d.average_rating))
.attr("height", 20)
.attr("fill", (d) => colorScale(d.average_rating));

chart2Svg
.append("g")
.attr("class", "axis")
.attr("transform", `translate(80, ${h - 18})`)
.call(d3.axisBottom(xScale));

chart2Svg
.append("g")
.attr("class", "axis")
.attr("transform", `translate(70,0)`)
.call(d3.axisLeft(yScale).tickSize(0));

return chart2Svg.node();
}
Insert cell
makeChart2(data)
Insert cell
Insert cell
makeChart3 = (dataset) => {
const w = 600;
const h = dataset.length * 24;
const chart3Svg = d3.create("svg")
.attr('width', w)
.attr('height', h);

// FILL IN HERE, and observe changes below
dataset.sort((a, b) => b.thirty_day_keep - a.thirty_day_keep);

const xScale = d3
.scaleLinear()
.domain([50, d3.max(dataset, (d) => d.thirty_day_keep)])
.rangeRound([0, w-100]);

const yScale = d3
.scaleBand()
.domain(dataset.map((d) => d.app_name))
.rangeRound([20, h - 20]);

const colorScale = d3.scaleLinear().domain([70, 100]).range(["#33FFAD", "#FF9C33"]);

chart3Svg
.selectAll("rect")
.data(dataset)
.join("rect")
.attr("x", 80)
.attr("y", (d) => yScale(d.app_name))
.attr("width", (d) => xScale(d.thirty_day_keep))
.attr("height", 20)
.attr("fill", (d) => colorScale(d.thirty_day_keep));

chart3Svg
.append("g")
.attr("class", "axis")
.attr("transform", `translate(80, ${h - 18})`)
.call(d3.axisBottom(xScale));

chart3Svg
.append("g")
.attr("class", "axis")
.attr("transform", `translate(70,0)`)
.call(d3.axisLeft(yScale).tickSize(0));
return chart3Svg.node();
}
Insert cell
makeChart3(data)
Insert cell
Insert cell
makeChart4 = (dataset) => {
const w = 600;
const h = dataset.length * 24;
const chart4Svg = d3.create("svg")
.attr('width', w)
.attr('height', h);

// FILL IN HERE, and observe changes below\
const minDownloads = d3.min(dataset, (d) => d.downloads);
const maxDownloads = d3.max(dataset, (d) => d.downloads);
const minRatings = d3.min(dataset, (d) => d.average_rating);
const maxRatings = d3.max(dataset, (d) => d.average_rating);

const xScale = d3
.scaleLinear()
.domain([0, maxDownloads])
.range([0, w - 100]);

const yScale = d3
.scaleLinear()
.domain([4.5, maxRatings])
.range([h - 20, 20]);

const rScale = d3
.scaleSqrt()
.domain([4.5, maxRatings])
.range([5,15]);
chart4Svg
.selectAll("circle")
.data(dataset)
.join("circle")
.attr("cx", (d) => xScale(d.downloads))
.attr("cy", (d) => yScale(d.average_rating))
.attr("r", (d) => rScale(d.average_rating))
.attr("transform", `translate(70,0)`)
.attr("fill", "orange"); // .style() also works
chart4Svg
.selectAll("text")
.data(dataset)
.join("text")
.attr("x", (d) => xScale(d.downloads))
.attr("y", (d) => yScale(d.average_rating) - 10)
.text((d) => `${d.app_name}`)
.attr("transform", `translate(70,0)`)
.style("text-anchor", "middle")
.style("font-size", "8px");

chart4Svg
.append("g")
.attr("class", "axis")
.attr("transform", `translate(80, ${h - 18})`)
.call(d3.axisBottom(xScale));

chart4Svg
.append("g")
.attr("class", "axis")
.attr("transform", `translate(70,0)`)
.call(d3.axisLeft(yScale).tickSize(0));
return chart4Svg.node();
}
Insert cell
makeChart4(data)
Insert cell
Insert cell
makeChart5 = (dataset) => {
const w = 600;
const h = dataset.length * 24;
const chart5Svg = d3.create("svg")
.attr('width', w)
.attr('height', h);

// FILL IN HERE, and observe changes below
const minDownloads = d3.min(dataset, (d) => d.downloads);
const maxDownloads = d3.max(dataset, (d) => d.downloads);
const minDay = d3.min(dataset, (d) => d.thirty_day_keep);
const maxDay = d3.max(dataset, (d) => d.thirty_day_keep);

const xScale = d3
.scaleLinear()
.domain([0, maxDownloads])
.range([0, w - 100]);

const yScale = d3
.scaleLinear()
.domain([70, 100])
.range([h - 20, 20]);

const rScale = d3
.scaleSqrt()
.domain([70, maxDay])
.range([5,15]);
chart5Svg
.selectAll("circle")
.data(dataset)
.join("circle")
.attr("cx", (d) => xScale(d.downloads))
.attr("cy", (d) => yScale(d.thirty_day_keep))
.attr("r", (d) => rScale(d.thirty_day_keep))
.attr("transform", `translate(70,0)`)
.attr("fill", "orange"); // .style() also works
chart5Svg
.selectAll("text")
.data(dataset)
.join("text")
.attr("x", (d) => xScale(d.downloads))
.attr("y", (d) => yScale(d.thirty_day_keep) - 10)
.text((d) => `${d.app_name}`)
.attr("transform", `translate(70,0)`)
.style("text-anchor", "middle")
.style("font-size", "8px");

chart5Svg
.append("g")
.attr("class", "axis")
.attr("transform", `translate(80, ${h - 18})`)
.call(d3.axisBottom(xScale));

chart5Svg
.append("g")
.attr("class", "axis")
.attr("transform", `translate(70,0)`)
.call(d3.axisLeft(yScale).tickFormat(d => (d + '%')));
return chart5Svg.node();
}
Insert cell
makeChart5(data)
Insert cell
Insert cell
theStory = md`
---
## Conclusions

A cool story might go here...
Shocking turn of events tonight as we go over the app industry today. Hit game DoubleyDo seems to have soared past the competition in terms of downloads, but struggles to keep their players longer than thirty days. What about the game causes people to lose interest so quickly? In stark contrast, Cardify maintains its small playerbase with an iron grip--maybe I should give the game a try! These players truly seem to love their game. Transcof, an up-and-coming in the industry, seems to be destroying the competition with its high downloads and high player retention rate! (If only it could get its ratings up...) In other news, Prodder seems to be struggling to hold its head above water--time to sell!

`
Insert cell
Insert cell
Insert cell
data = d3.csvParse(dataCsv)
Insert cell
Insert cell
d3 = require("d3@7")
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