Published
Edited
Dec 9, 2020
Insert cell
Insert cell
Insert cell
uniq_countries = _.uniqBy(price, d => d["Country"]).map(d => d["Country"])
Insert cell
colorScale = d3.scaleOrdinal(uniq_countries, d3.schemePaired)
Insert cell
extent_cost = d3.extent(price, d => +d["CostForTwo"])
Insert cell
extent_production = d3.extent(price, d => +d["Production"])
Insert cell
xScale = d3.scaleLinear()
.domain(extent_production)
.range([margin.left, width - margin.right])
Insert cell
yScale = d3.scaleLinear()
.domain(extent_cost)
.range([height - margin.bottom, margin.top])
Insert cell
xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(xScale))
Insert cell
yAxis = g => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(yScale))
Insert cell
price_production_plot = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.style("overflow", "display");
const circles = svg
.selectAll("circle")
.data(price)
.join("circle")
.attr("r", 7)
.attr("cx", d => xScale(d.Production))
.attr("cy", d => yScale(d.CostForTwo))
.attr("fill", d => colorScale(d.Country))
.attr("opacity", 1);
const tip = svg
.append("g")
.style("pointer-events", "none")
.style("text-anchor", "middle");
circles.on("mouseenter", event => {
const value = event.target.__data__;
const pointer = d3.pointer(event, this);
tip.call(hover, pointer, value);
});

circles.on("mouseout", event => {
tip.selectAll("*").remove();
});
svg.append("text")
.style("text-anchor", "middle")
.attr("x", 500)
.attr("y", -20)
.text("Total Production vs Average Cost for Two")
const xlabel = svg
.append("text")
.attr("class", "x label")
.style("text-anchor", "middle")
.attr("x", width / 2)
.attr("y", height - 10)
.text("Total Crop Production (Tonnes)")
const ylabel = svg
.append("text")
.attr("class", "y label")
.style("text-anchor", "middle")
.attr("x", -250)
.attr("y", margin.left / 2 - 25)
.attr("transform", "rotate(-90)")
.text("Average Meal Cost For Two (USD)")
svg.append("g").call(xAxis)
svg.append("g").call(yAxis)
return svg.node()
}
Insert cell
hover = (tip, pos, value) => {
const side_padding = 5;

const text = ["Country: " + [value.Country],
"Avg. Cost for Two: " + [value.CostForTwo],
"Total Production (Tonnes): " + [value.Production],
"Avg. Rating: " + [value.Rating],
"Avg. Price Range Rating: " + [value.PriceRange]]
// Add the text
tip
.style("text-anchor", "start")
.style("pointer-events", "none")
.attr("transform", `translate(${pos[0]}, ${pos[1]})`)
.selectAll("text")
.data(text)
.join('text')
.style("dominant-baseline", "ideographic")
.text(d => d)
.attr("y", (d, i) => (i - (text.length - 1)) * 15);

const bbox = tip.node().getBBox();

// Add background rectangle
tip
.append("rect")
.attr("y", bbox.y)
.attr("x", bbox.x - side_padding)
.attr("width", bbox.width + side_padding * 2)
.attr("height", bbox.height)
.style("fill", "white")
.style("stroke", "#d3d3d3")
.lower();

// Reposition the full g element to make sure it doesn't go offscreen
let x = pos[0];
let y = pos[1];

// Make sure it doesn't go beyond the left of the chart
if (x + bbox.x < margin.left) {
x = margin.left + bbox.width / 2 + side_padding;
}
// Make sure it doesn't go beyond the right of the chart
else if (x - bbox.x > width - margin.right) {
x = width - margin.right - bbox.width / 2;
}

// Make sure it doesn't go over the top of the chart
if (y + bbox.y < 0) {
y = margin.top + bbox.height + 10;
}
tip.attr("transform", `translate(${x}, ${y})`);
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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