Published
Edited
May 27, 2020
1 fork
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
weather2012to2015 = d3.csvParse(await FileAttachment("weather-1.csv").text())
Insert cell
md`## Filter`
Insert cell
weatherByYear = weather2012to2015.filter(
d => timeformat(d.date).getFullYear() == choiceYear
)
Insert cell
// Create a nested data structure that has the min,max, and avg price for each PermitClass
summary_by_year = d3
.nest() // create a nesting function
.key(d => timeformat(d.date)) // Where we nest by the "date" value of each object
.rollup(d => {
// For each _group_, compute the following values
return {
max_temp: d3.max(d, dd => +dd.temp_max),
min_temp: d3.min(d, dd => +dd.temp_min),
wind: d3.max(d, dd => +dd.wind)
};
})
.entries(weatherByYear) // Pass our data in as we create the function!
Insert cell
weatherdate2 = weather2012to2015.map(d => timeformat(d.date).getFullYear())
Insert cell
scaleBand = d3
.scaleBand()
.domain(weatherByYear.map(d => timeformat(d.date)))
.range([50, width])
.padding(0.1)
Insert cell
xScaleAxis = d3
.axisBottom(scaleBand)
.tickFormat(d3.timeFormat("%Y/%m/%d"))
.tickValues(
scaleBand.domain().filter(function(d, i) {
return !(i % 15);
})
)
Insert cell
bar_yScale = d3
.scaleLinear()
.domain([0, d3.max(summary_by_year.map(d => d.value[choice]))])
.range([height - 50, 50])
Insert cell
viewof choiceYear = select([2012, 2013, 2014, 2015])
Insert cell
viewof choice = select(["max_temp", "min_temp", "wind"])
Insert cell
chart1 = {
const svg = d3.create('svg').attr('viewBox', [0, 0, 1000, height]);

// Append x axis

svg
.append('g')
.attr("transform", `translate(0,${height - 50})`)
.call(xScaleAxis)
.selectAll("text")
.attr("y", 5)
.attr("x", 3)
.attr("dy", ".35em")
.attr("transform", "rotate(40)")
.style("text-anchor", "start");

//append y axis
const yAxis = d3.axisLeft().scale(bar_yScale);

svg
.append('g')
.attr('transform', 'translate(' + 50 + ',0)')
.call(yAxis);

//append title
svg
.append("text")
.attr('transform', `translate(${width / 2}, ${50 / 2})`)
.style('text-anchor', 'middle')
.style('font-size', '20px')
.style('font-weight', 'bold')
.text(choice + ' Data in ' + choiceYear);

// Add the data rectangles/bars
svg
.selectAll('rect')
.data(summary_by_year)
.join(enter => enter.append('rect'))
.attr('x', d => scaleBand(d.key))
.attr('y', d => bar_yScale(d.value.avg_price))
.attr('width', scaleBand.bandwidth())
.attr('height', 0)
.attr('fill', '#F34F1C');

//add animation
svg
.selectAll("rect")
.transition()
.duration(2000)
.attr('y', d => bar_yScale(d.value[choice]))
.attr('height', d => bar_yScale(0) - bar_yScale(d.value[choice]))
.delay(function(d, i) {
//console.log(i);
return i * 10;
});

return svg.node();
}
Insert cell
md`## Abstract/Elaborate`
Insert cell
SeattleLiving = d3.csvParse(await FileAttachment("Airbnb_Cleaned.csv").text())
Insert cell
// Nest your data by type 1, then type 2
nested_data = d3
.nest()
.key(d => d['address'])
.key(a => a['room_type'])
.entries(SeattleLiving)
Insert cell
nested_data.map(d => {
d.name = d.key;
d.children = d.values.map(dd => {
dd.name = dd.key;
return dd;
});
return d;
})
Insert cell
my_pack = data =>
d3
.pack()
.size([width, height])
.padding(3)(
d3
.hierarchy(
{ key: "Greater Seattle Area", values: nested_data },
d => d.values
)
.sum(d => +d.bedrooms)
.sort((a, b) => b.value - a.value)
)
Insert cell
chart = {
const root = my_pack(nested_data);
let focus = root;
let view;

const svg = d3
.create("svg")
.attr("viewBox", `-${width / 2} -${height / 2} ${width} ${height}`)
.style("display", "block")
.style("margin", "0 -14px")
.style("background", color(0))
.style("cursor", "pointer")
.on("click", () => zoom(root));

const node = svg
.append("g")
.selectAll("circle")
.data(root.descendants().slice(1))
.join("circle")
.attr("fill", d => (d.children ? color(d.depth) : "white"))
.attr("pointer-events", d => (!d.children ? "none" : null))
.on("mouseover", function() {
d3.select(this).attr("stroke", "#000");
})
.on("mouseout", function() {
d3.select(this).attr("stroke", null);
})
.on("click", d => focus !== d && (zoom(d), d3.event.stopPropagation()));

const label = svg
.append("g")
.style("font", "10px sans-serif")
.attr("pointer-events", "none")
.attr("text-anchor", "middle")
.selectAll("text")
.data(root.descendants())
.join("text")
.style("fill-opacity", d => (d.parent === root ? 1 : 0))
.style("display", d => (d.parent === root ? "inline" : "none"))
.text(d => d.data.name);

zoomTo([root.x, root.y, root.r * 2]);

function zoomTo(v) {
const k = width / v[2];

view = v;

label.attr(
"transform",
d => `translate(${(d.x - v[0]) * k},${(d.y - v[1]) * k})`
);
node.attr(
"transform",
d => `translate(${(d.x - v[0]) * k},${(d.y - v[1]) * k})`
);
node.attr("r", d => d.r * k);
}

function zoom(d) {
const focus0 = focus;

focus = d;

const transition = svg
.transition()
.duration(d3.event.altKey ? 7500 : 750)
.tween("zoom", d => {
const i = d3.interpolateZoom(view, [focus.x, focus.y, focus.r * 2]);
return t => zoomTo(i(t));
});

label
.filter(function(d) {
return d.parent === focus || this.style.display === "inline";
})
.transition(transition)
.style("fill-opacity", d => (d.parent === focus ? 1 : 0))
.on("start", function(d) {
if (d.parent === focus) this.style.display = "inline";
})
.on("end", function(d) {
if (d.parent !== focus) this.style.display = "none";
});
}

return svg.node();
}
Insert cell
md`## Select`
Insert cell
data = d3.csv(
"https://raw.githubusercontent.com/nytimes/covid-19-data/master/us-states.csv"
)
Insert cell
state_data1 = data.filter(d => d.date === "2020-05-25")
Insert cell
state_data = state_data1
.map(function(d) {
return {
x: d.state,
y: +d.cases,
color: "blue"
};
})
Insert cell
margin = ({
top: 30,
right: 10,
bottom: 80,
left: 80
})
Insert cell
x = d3
.scaleBand()
.domain(state_data.map(d => d.x))
.range([margin.left, width - margin.right])
.padding(0.1)
Insert cell
y = d3
.scaleLinear()
.domain([0, d3.max(state_data, d => d.y)])
.range([height - margin.bottom, margin.top])
Insert cell
yAxis = g =>
g.attr("transform", `translate(${margin.left},0)`).call(d3.axisLeft(y))
Insert cell
xAxis = g =>
g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x))
Insert cell
chart2 = {
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);
const tip = svg.append('g');
const tipRect = tip.append("rect");
const tipText = tip.append('text').style("text-anchor", "middle");

svg
.append("g")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("transform", "rotate(-40)");
svg.append("g").call(yAxis);

svg
.append("text")
.text("# of Cases in Each State")
.style("font-weight", "bold")
.style("font-size", "15px")
.attr("transform", "translate(400, 20)");

svg
.append("text")
.text("States")
.style("font-size", "12px")
.attr("transform", "translate(450, 480)");

svg
.append("text")
.text("# of Cases")
.style("font-size", "12px")
.attr("transform", "translate(15, 200) rotate(-90)");

svg
.selectAll("rect")
.data(state_data)
.join(enter => enter.append("rect"))
.attr("x", d => x(d.x))
.attr("y", d => y(d.y))
.attr("width", x.bandwidth())
.attr("fill", "blue")
.attr("opacity", "0.90")
.on('mouseenter', function(d) {
const position = d3.mouse(this);
d3.select(this).style("fill", "red");
tip.attr('transform', `translate(${position[0]}, ${position[1]})`);
const { x, y, width: w, height: h } = tipText.node().getBBox();
tipRect
.attr("width", w)
.attr("height", h)
.attr("x", x)
.attr("y", y)
.attr("fill", "none");
tipText.text(d.x + ": " + d.y + " cases");
})
.on("mousemove", function(d) {
const position = d3.mouse(this);
tip.attr("transform", `translate(${position[0]}, ${position[1] - 10})`);
})
.on("mouseout", function(d) {
d3.select(this).style("fill", "blue");
tipRect.attr('stroke', 'none').attr('fill', 'none');
tipText.text("");
});

svg
.selectAll("rect")
.transition()
.duration(2000)
.attr("y", d => y(d.y))
.attr("height", d => y(0) - y(d.y));

return svg.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
import { select } from "@jashkenas/inputs"
Insert cell
d3 = require("d3@5", "d3-array@2")
Insert cell
_ = require("lodash")
Insert cell
timeformat = d3.timeParse("%Y/%m/%d")
Insert cell
height = 932
Insert cell
pack_width = 932
Insert cell
format = d3.format(",d")
Insert cell
color = d3
.scaleLinear()
.domain([0, 5])
.range(["hsl(152,80%,80%)", "hsl(228,30%,40%)"])
.interpolate(d3.interpolateHcl)
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