Published
Edited
Mar 11, 2019
6 stars
Insert cell
Insert cell
Insert cell
Insert cell
scale = d3.scaleLinear()
Insert cell
Insert cell
{
scale.domain([100, 500]);
scale.range([10, 350]);
}
Insert cell
Insert cell
scale(300)
Insert cell
Insert cell
Insert cell
{
const width = 500;
const height = 100;
const graph = d3.select(DOM.svg(width, height));
const data = scatterData;
graph.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", d => d[0])
.attr("cy", d => d[1])
.attr("r", d => Math.sqrt(height - d[1]));
graph.selectAll("text")
.data(data)
.enter()
.append("text")
.text(d => d[0] + "," + d[1])
.attr("x", d => d[0])
.attr("y", d => d[1])
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "hotpink");
return graph.node();
}
Insert cell
Insert cell
{
const width = 500;
const height = 100;
const graph = d3.select(DOM.svg(width, height));
const data = scatterData;
const xScale = d3.scaleLinear() // define a new x scale
.domain([0, d3.max(data, d => d[0])]) // mapping values between 0 and the max x-value
.range([0, width]); // to values between 0 and the width
const yScale = d3.scaleLinear() // define a new y scale
.domain([0, d3.max(data, d => d[1])]) // mapping values between 0 and the max y-value
.range([0, height]); // to values between 0 and the height
graph.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", d => xScale(d[0])) // instead of using d[0] directly, use the scale
.attr("cy", d => yScale(d[1])) // instead of using d[1] directly, use the scale
.attr("r", d => Math.sqrt(height - d[1]));
graph.selectAll("text")
.data(data)
.enter()
.append("text")
.text(d => d[0] + "," + d[1])
.attr("x", d => xScale(d[0])) // instead of using d[0] directly, use the scale
.attr("y", d => yScale(d[1])) // instead of using d[1] directly, use the scale
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "hotpink");
return graph.node();
}
Insert cell
Insert cell
{
const width = 500;
const height = 100;
const padding = {top: 20, left: 20, right: 40, bottom: 20}; // introduce some padding
const graph = d3.select(DOM.svg(width, height));
const data = scatterData;
const xScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d[0])])
.range([padding.left, width - padding.right]); // add padding to the range
const yScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d[1])])
.range([height - padding.bottom, padding.top]); // swap values + padding
graph.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", d => xScale(d[0]))
.attr("cy", d => yScale(d[1]))
.attr("r", d => Math.sqrt(height - d[1]));
graph.selectAll("text")
.data(data)
.enter()
.append("text")
.text(d => d[0] + "," + d[1])
.attr("x", d => xScale(d[0]))
.attr("y", d => yScale(d[1]))
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "hotpink");
return graph.node();
}
Insert cell
Insert cell
{
const width = 500;
const height = 100;
const padding = {top: 20, left: 20, right: 40, bottom: 20};
const graph = d3.select(DOM.svg(width, height));
let data = scatterData;
// if you uncomment the line below, you can see how the graph automatically adapts
//data = [...scatterData, [600, 150]];
const xScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d[0])])
.range([padding.left, width - padding.right]);
const yScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d[1])])
.range([height - padding.bottom, padding.top]);
const rScale = d3.scaleSqrt() // new sqrt scale
.domain([0, d3.max(data, d => d[1])]) // map values between 0 and max y-value
.range([0, 10]); // to values between 0 and 10
graph.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", d => xScale(d[0]))
.attr("cy", d => yScale(d[1]))
.attr("r", d => rScale(d[1])); // use our new scale
graph.selectAll("text")
.data(data)
.enter()
.append("text")
.text(d => d[0] + "," + d[1])
.attr("x", d => xScale(d[0]))
.attr("y", d => yScale(d[1]))
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "hotpink");
return graph.node();
}
Insert cell
Insert cell
Insert cell
{
const width = 500;
const height = 100;
const padding = {top: 20, left: 20, right: 40, bottom: 20};
const graph = d3.select(DOM.svg(width, height));
let data = scatterData;
//data = [...scatterData, [600, 150]]; // uncomment if you want to see the effect of outliers
const xScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d[0])])
.range([padding.left, width - padding.right]);
const yScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d[1])])
.range([height - padding.bottom, padding.top]);
const rScale = d3.scaleSqrt()
.domain([0, d3.max(data, d => d[1])])
.range([0, 10]);
const xAxis = d3.axisBottom() // create a new bottom axis
.scale(xScale); // that uses the domain of the xScale
graph.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", d => xScale(d[0]))
.attr("cy", d => yScale(d[1]))
.attr("r", d => rScale(d[1]));
graph.selectAll("text")
.data(data)
.enter()
.append("text")
.text(d => d[0] + "," + d[1])
.attr("x", d => xScale(d[0]))
.attr("y", d => yScale(d[1]))
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "hotpink");
graph.append("g") // create a "container" to put our axis in
.attr("class", "axis") // add a class to be able to reference it
.attr("transform", `translate(0, ${height - padding.bottom})`) // place it at the bottom of the chart
.call(xAxis); // add the axis to the chart
return graph.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
const width = 500;
const height = 100;
const padding = {top: 20, left: 20, right: 40, bottom: 20};
const graph = d3.select(DOM.svg(width, height));
let data = scatterData;
//data = [...scatterData, [600, 150]];
const xScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d[0])])
.range([padding.left, width - padding.right]);
const yScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d[1])])
.range([height - padding.bottom, padding.top]);
const rScale = d3.scaleSqrt()
.domain([0, d3.max(data, d => d[1])])
.range([0, 10]);
const xAxis = d3.axisBottom()
.scale(xScale)
.ticks(numberOfTicks); // use a custom number of ticks
graph.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", d => xScale(d[0]))
.attr("cy", d => yScale(d[1]))
.attr("r", d => rScale(d[1]));
graph.selectAll("text")
.data(data)
.enter()
.append("text")
.text(d => d[0] + "," + d[1])
.attr("x", d => xScale(d[0]))
.attr("y", d => yScale(d[1]))
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "hotpink");
graph.append("g")
.attr("class", "axis")
.attr("transform", `translate(0, ${height - padding.bottom})`)
.call(xAxis);
return graph.node();
}
Insert cell
Insert cell
{
const width = 500;
const height = 300;
const padding = {top: 20, left: 50, right: 40, bottom: 20};
const graph = d3.select(DOM.svg(width, height));
let data = scatterData;
//data = [...scatterData, [600, 150]];
const xScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d[0])])
.range([padding.left, width - padding.right]);
const yScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d[1])])
.range([height - padding.bottom, padding.top]);
const rScale = d3.scaleSqrt()
.domain([0, d3.max(data, d => d[1])])
.range([0, 10]);
const xAxis = d3.axisBottom()
.scale(xScale)
.ticks(numberOfTicks);
const yAxis = d3.axisLeft() // create a y axis
.scale(yScale) // based on the y scale
.tickFormat(d3.format("$.2f")); // and format the marks as currency
graph.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", d => xScale(d[0]))
.attr("cy", d => yScale(d[1]))
.attr("r", d => rScale(d[1]));
graph.selectAll("text")
.data(data)
.enter()
.append("text")
.text(d => d[0] + "," + d[1])
.attr("x", d => xScale(d[0]))
.attr("y", d => yScale(d[1]))
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "hotpink");
graph.append("g")
.attr("class", "x axis")
.attr("transform", `translate(0, ${height - padding.bottom})`)
.call(xAxis);
graph.append("g") // add the y axis to the graph
.attr("class", "y axis")
.attr("transform", `translate(${padding.left}, 0)`) // slight transform to position it correctly
.call(yAxis);
return graph.node();
}
Insert cell
Insert cell
timeData = d3.csv("https://raw.githubusercontent.com/alignedleft/d3-book/master/chapter_08/time_scale_data.csv", d => {
return {
date: d3.timeParse("%m/%d/%y")(d.Date), // convert from string to date
amount: parseInt(d.Amount) // convert from string to int
}})
Insert cell
Insert cell
{
const width = 600;
const height = 300;
const padding = {top: 20, left: 40, right: 40, bottom: 20};
const graph = d3.select(DOM.svg(width, height));
const data = timeData;
const xScale = d3.scaleTime() // use a time scale
.domain(d3.extent(data, d => d.date)) // extent returns an array containing min and max
.range([padding.left, width - padding.right]);
const yScale = d3.scaleLinear()
.domain(d3.extent(data, d => d.amount))
.range([height - padding.bottom, padding.top]);
const xAxis = d3.axisBottom()
.scale(xScale)
.ticks(5);
const yAxis = d3.axisLeft()
.scale(yScale)
.ticks(5);
const formatTime = d3.timeFormat("%b %e"); // we will use this formatter to format our labels
graph.selectAll("text")
.data(data)
.enter()
.append("text")
.text(d => formatTime(d.date)) // format the labels using our custom formatter
.attr("x", d => xScale(d.date) + 4) // move the labels a bit from the center of the dots
.attr("y", d => yScale(d.amount) + 4)
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "hotpink");
graph.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", d => xScale(d.date)) // because we have objects instead of arrays, call property
.attr("cy", d => yScale(d.amount))
.attr("r", 2);
graph.append("g")
.attr("class", "x axis")
.attr("transform", `translate(0, ${height - padding.bottom})`)
.call(xAxis);
graph.append("g")
.attr("class", "y axis")
.attr("transform", `translate(${padding.left}, 0)`)
.call(yAxis);
return graph.node();
}
Insert cell
Insert cell
{
const width = 600;
const height = 300;
const padding = {top: 20, left: 40, right: 40, bottom: 50};
const graph = d3.select(DOM.svg(width, height));
const formatTime = d3.timeFormat("%b %e");
const data = timeData;
const [startDate, endDate] = d3.extent(data, d => d.date);
const xScale = d3.scaleTime()
// extend the domain with 1 day at each side
.domain([d3.timeDay.offset(startDate, -1), d3.timeDay.offset(endDate, 1)])
.range([padding.left, width - padding.right]);
const yScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d.amount)]) // start the domain at 0 instead of min
.range([height - padding.bottom, padding.top]);
const xAxis = d3.axisBottom()
.scale(xScale)
.ticks(9)
.tickFormat(formatTime); // use our custom formatter to also format the axis labels
const yAxis = d3.axisLeft()
.scale(yScale)
.ticks(10);
// add a thin line for each data point
graph.selectAll("line")
.data(data)
.enter()
.append("line")
.attr("x1", d => xScale(d.date))
.attr("y1", height - padding.bottom)
.attr("x2", d => xScale(d.date))
.attr("y2", d => yScale(d.amount))
.attr("stroke", "#ddd")
.attr("stroke-width", 1);
graph.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", d => xScale(d.date))
.attr("cy", d => yScale(d.amount))
.attr("r", 2);
graph.append("g")
.attr("class", "x axis")
.attr("transform", `translate(0, ${height - padding.bottom})`)
.call(xAxis)
.selectAll("text") // slant the axis labels
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-45)");
graph.append("g")
.attr("class", "y axis")
.attr("transform", `translate(${padding.left}, 0)`)
.call(yAxis);
// add an extra axis label
graph.select(".y.axis")
.append("text")
.text("Unicorn sightings")
.style("text-anchor", "end")
.attr("dx", -padding.top)
.attr("dy", "1em")
.attr("transform", "rotate(-90)")
.attr("fill", "black");
return graph.node();
}
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