Public
Edited
Mar 14, 2024
Insert cell
Insert cell
Insert cell
makeChart(dataset);
Insert cell
Insert cell
Insert cell
makeChart = (dataset) => {
dataset = [...dataset]; // Copy dataset array so we don't modify the original
dataset.sort((a,b) => b.downloads - a.downloads);

// Specify the chart’s dimensions.
const width = 1000;
const height = 600;
const marginTop = 25;
const marginRight = 20;
const marginBottom = 200;
const marginLeft = 60;

// Define the horizontal scale.
let x = d3.scaleBand()
.domain(dataset.map((d) => d.title))
.range([marginLeft, width - marginRight]);

// Define the vertical scale.
const y = d3.scaleLinear()
.domain(d3.extent(dataset, d => d.copies_sold)).nice()
.range([height - marginBottom, marginTop]);

const r = d3.scaleRadial()
.domain(d3.extent(dataset, d => d.copies_sold)).nice()
.range([0, 25]);

let c = d3.scaleLinear()
.domain(d3.extent(dataset, d => d.copies_sold)).nice()
.range(['#ff0000', '#00f0ff']);

// Create the container SVG.
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height])
.attr("style", "max-width: 100%; height: auto;");

// Add the axes.
let xAxisGroup = svg.append("g")
.attr("transform", `translate(0,${height - marginBottom})`)
.call(d3.axisBottom().scale(x))

let yAxisGroup = svg.append("g")
.attr("transform", `translate(${marginLeft},0)`)
.call(d3.axisLeft(y));

// Append a rect for each data point.
/*svg.append("g")
.selectAll("rect")
.data(dataset)
.join("rect")
.filter(d => d.copies_sold)
.attr("x", (d) => x(new Date(d.release_date)))
.attr("y", (d) => y(d.copies_sold))
.attr("width", (d) => x(new Date(d.release_date)) - marginRight)
.attr("height", (d) => height - y(d.copies_sold) - marginBottom)
.style("fill", (d) => c(d.copies_sold))
.style("stroke", "black"); */

const updateChartType = (newType) => {
console.log(newType);

switch(newType) {
default:
x = d3.scaleBand()
.domain(dataset.map((d) => d.title))
.range([marginLeft, width - marginRight]);
break;
case 'release_date':
x = d3.scaleTime()
.domain(d3.extent(dataset, d => new Date(d.release_date))).nice()
.range([marginLeft, width - marginRight]);
break;
case 'developer':
x = d3.scaleBand()
.domain(dataset.map((d) => d.developer))
.range([marginLeft, width - marginRight]);
break;
case 'publisher':
x = d3.scaleBand()
.domain(dataset.map((d) => d.publisher))
.range([marginLeft, width - marginRight]);
break;
};

svg
.selectAll('circle')
.data(dataset)
.join(
enter => enter.append('circle')
.filter(d => d.copies_sold)
.attr("cx", (d) => x(d.title))
.attr("cy", (d) => y(d.copies_sold))
.attr("r", (d) => r(d.copies_sold))
.style("fill", (d) => c(d.copies_sold)),
update => update.transition()
.duration(2000)
.filter(d => d.copies_sold)
.attr("cx", (d) => {
let result;
switch(newType){
default:
result = x(d.title);
break;
case 'release_date':
result = x(new Date(d.release_date));
break;
case 'developer':
result = x(d.developer);
break;
case 'publisher':
result = x(d.publisher);
break;
};
return result;
}
)
.attr("cy", (d) => y(d.copies_sold))
.attr("r", (d) => r(d.copies_sold))
.style("fill", (d) => c(d.copies_sold))
);
xAxisGroup.transition().duration(2000).call(d3.axisBottom(x)).selectAll('text').attr('transform', 'rotate(-65)').style('text-anchor', 'end');
yAxisGroup.transition().duration(2000).call(d3.axisLeft(y));
/*.join("circle")
.filter(d => d.copies_sold)
.attr("cx", (d) => x(new Date(d.release_date)))
.attr("cy", (d) => y(d.copies_sold))
.attr("r", (d) => r(d.copies_sold))
.style("fill", (d) => c(d.copies_sold)); */
};

updateChartType('downloads');

const typeSelector = html`
<select id='chartType'>
<option value="title">Title</option>
<option value="publisher">Publisher</option>
<option value="developer">Developer</option>
<option value="release_date">Release Date</option>
</select>
`;
d3.select(typeSelector).on('change', () => {
updateChartType(typeSelector.value);
});
return html`
<div class='chart-div'>
<h3>Nintendo Switch Game Sales</h3>
<label>Sort By:</label>
${typeSelector}
${svg.node()}
</div>
`;
}
Insert cell
dataset = d3.csvParse(dataFile, (row) => ({
title: row.title,
copies_sold: parseFloat(row.copies_sold),
genre: row.genre,
developer: row.developer,
publisher: row.publisher,
as_of: row.as_of,
release_date: row.release_date
}));
Insert cell
html`<style>


.chart-div {
text-align: center;
margin:auto;
padding:10px;
}

.chart-div svg {
display: block;
margin: auto;
padding: 20px;
}

.axis-left1 line,
.axis-left1 path {
stroke: none;
}

.axis-left1 text {
font-weight: bold;
font-size: 7pt;
text-transform: uppercase;
}

.dot-label {
font-size: 8pt;
}

</style>`
Insert cell
Insert cell
clean_best_selling_switch_games.csv
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
Insert cell
best_selling_switch_games@1.csv
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
dataFile = await FileAttachment("clean_best_selling_switch_games.csv").text();
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