Published
Edited
Feb 2, 2021
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
md`The experimenters tested the perpetual accuracy of the different encodings by testing a theory.
The theory they were testing was that the encodings would be ranked based on how easy they were to differentiation.
The test subjects were asked to determine values for the different visualizations and the difference percentages. The experimenters were looking to see how effective the visuals were. They asked a mix of people these questions i.e people who were technically adept and those who were not.`
Insert cell
Insert cell
md`They did not create an entirely unbiased experiment for testing the perpetual accuracy (so there are some concerns here) and then they also did not test all of the visual encodings so it would be difficult for me to use the results of this study for my own visuals. `
Insert cell
Insert cell
md`With scatter plots we can see also the relationship between the x and y values by looking at slopes
or creating a line of best fit. This is done by looking at the direction that this line/relationship is going in.`
Insert cell
Insert cell
data = d3.csvParse(await FileAttachment("SeattleWeather2017.csv").text(), d3.autoType)
Insert cell
height = 500
Insert cell
width = 1000
Insert cell
margin = ({ top: 20, right: 30, bottom: 30, left: 40 })
Insert cell
function colorConvert(boolean) {
if (boolean == 'TRUE') {
return 'yellow';
}
return 'blue';
}
Insert cell
data_array = data.map(function(day) {
return {
x: day.Date,
y: day.TempMax,
color: colorConvert(day.Rain)
};
})
Insert cell
date_range = [d3.min(data_array, d => d.x), d3.max(data_array, d => d.x)]
Insert cell
temp_range = [d3.min(data_array, d => d.y), d3.max(data_array, d => d.y)]
Insert cell
x_scale = d3.scaleTime()
.domain(date_range)
.range([margin.left, width - margin.right])
Insert cell
y_scale = d3
.scaleLinear()
.domain(temp_range)
.range([height - margin.bottom, margin.top])
Insert cell
xAxis = g =>
g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x_scale))
Insert cell
yAxis = g =>
g.attr("transform", `translate(${margin.left},0)`).call(d3.axisLeft(y_scale))
Insert cell
barX = d3
.scaleBand()
.domain(data.map(d => d.drink))
.range([margin.left, width - margin.right])
.padding(0.1)
Insert cell
barxAxis = g =>
g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(barX).tickSizeOuter(0))
Insert cell
md`### POSITION`
Insert cell
position_chart = {
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);
svg.append("g").call(xAxis);
svg.append("g").call(yAxis);

svg
.append("text")
.attr("x", width / 2)
.attr("y", height)
.text("Month")
.style("font-size", "15px");

svg
.append("text")
.attr("transform", "translate(10, 300) rotate(-90)")
.text("Rain")
.style("font-size", "15px");

svg
.append("text")
.attr("x", width / 3)
.attr("y", 20)
.attr("text-anchor", "middle")
.text("Seattle Rain by Month")
.style("font-size", "18px");

svg
.selectAll('circle')
.data(data_array)
.join(enter => enter.append("circle"))
.attr('cx', d => x_scale(d.x))
.attr('cy', d => y_scale(d.y))
.attr('r', 5);

return svg.node();
}
Insert cell
md`### COLOR`
Insert cell
color_chart = {
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);
svg.append("g").call(xAxis);
svg.append("g").call(yAxis);
svg
.append("text")
.attr("x", width / 2)
.attr("y", height)
.text("Month")
.style("font-size", "15px");

svg
.append("text")
.attr("transform", "translate(10, 300) rotate(-90)")
.text("Rain")
.style("font-size", "15px");

svg
.append("text")
.attr("x", width / 2.5)
.attr("y", 14)
.attr("text-anchor", "middle")
.text("Seattle Rain by Month")
.style("font-size", "18px");

svg
.selectAll('circle')
.data(data_array)
.join(enter => enter.append("circle"))
.attr('cx', d => x_scale(d.x))
.attr('cy', d => y_scale(d.y))
.attr('r', 5)
.attr('fill', d => d.color);

return svg.node();
}
Insert cell
md`### LENGTH`
Insert cell
length_chart = {
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);
svg.append("g").call(xAxis);
svg.append("g").call(yAxis);
svg.append('text', 'label');

svg
.append("text")
.attr("x", width / 2)
.attr("y", height)
.text("Month")
.style("font-size", "15px");

svg
.append("text")
.attr("transform", "translate(10, 300) rotate(-90)")
.text("Temperature")
.style("font-size", "15px");

svg
.append("text")
.attr("x", width / 3)
.attr("y", 15)
.attr("text-anchor", "middle")
.text("Seattle Rain by Month")
.style("font-size", "18px");

svg
.selectAll('.rect')
.data(data_array)
.join(enter => enter.append("rect"))
.attr("x", d => x_scale(d.x))
.attr("y", d => y_scale(d.y))
.attr("transform", "translate(10, -margin.bottom)")
.attr('width', 3)
.attr("height", d => y_scale(0) - y_scale(d.y) - 235)
.attr('fill', "yellow")
.attr("stroke-width", "0.5px")
.attr("stroke", "blue");

return svg.node();
}
Insert cell
arc = {
const radius = Math.min(width, height) / 2;
return d3
.arc()
.innerRadius(radius * 0.67)
.outerRadius(radius - 1);
}
Insert cell
pie = d3
.pie()
.padAngle(0.005)
.sort(null)
.value(d => d.value)
Insert cell
arcLabel = {
const radius = (Math.min(width, height) / 2) * 0.8;
return d3
.arc()
.innerRadius(radius)
.outerRadius(radius);
}
Insert cell
Num_days_rain = data.map(function(day) {
if (day.Rain == 'TRUE') {
return 1;
}
return 0;
})
Insert cell
Rain_days = {
let runningTotal = 0;
for (let i = 0; i < Num_days_rain.length; i++) {
runningTotal = runningTotal + Num_days_rain[i];
}

return [
{
key: 'Rain',
value: runningTotal
},
{
key: 'No Rain',
value: data.length - runningTotal
}
];
}
Insert cell
d3 = require("d3@6")
Insert cell
color = d3
.scaleOrdinal()
.domain(Rain_days.map(d => d.key[(0, 1)]))
.range(["blue", "yellow"])
Insert cell
md`### ANGLE`
Insert cell
pie_chart = {
const arcs = pie(Rain_days);
const svg = d3
.create("svg")
.attr("viewBox", [-width / 2, -height / 2, width, height]);

svg
.append("text")
.attr("x", width / 4)
.attr("y", 10)
.text("Seattle Rain vs No Rain Days")
.style("font-size", "16px");

svg
.append('g')
.attr('stroke', 'black')
.selectAll("path")
.data(arcs)
.join("path")
.attr("fill", d => color(d.data.key))
.attr("d", arc);

svg
.selectAll('mySlices')
.data(arcs)
.enter()
.append('text')
.text(function(d) {
return d.data.key;
})
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.style("text-anchor", "middle")
.style("font-size", 12);

return svg.node();
}
Insert cell
Insert cell
newData = d3.csvParse(await FileAttachment("seattle-weather.csv").text())
Insert cell
curveData = newData.map(d => {
return {
date: new Date(d.date),
max: Number(d.temp_max * 1.8 + 32),
min: Number(d.temp_min * 1.8 + 32),
difference: Number(d.temp_max * 1.8 + 32) - Number(d.temp_min * 1.8 + 32)
};
})
Insert cell
curveYDomain = [d3.min(curveData, d => d.min), d3.max(curveData, d => d.max)]
Insert cell
curveY = d3
.scaleLinear()
.domain(curveYDomain)
.range([height - margin.bottom, margin.top])
.nice()
Insert cell
curveYAxis = g =>
g.attr("transform", `translate(${margin.left},0)`).call(d3.axisLeft(curveY))
Insert cell
positionX = d3
.scaleTime()
.domain(positionXDomain)
.range([margin.left, width - margin.right])
.nice()
Insert cell
positionY = d3
.scaleLinear()
.domain(positionYDomain)
.range([height - margin.bottom, margin.top])
.nice()
Insert cell
lineGeneratorMin = d3
.line()
.x(d => positionX(d.date))
.y(d => positionY(d.temp_min))
Insert cell
lineGeneratorMax = d3
.line()
.x(d => positionX(d.date))
.y(d => positionY(d.temp_max))
Insert cell
positionXDomain = [d3.min(curveData, d => d.date), d3.max(curveData, d => d.date)]
Insert cell
positionYDomain = [
d3.min(curveData, d => d.temp_min),
d3.max(curveData, d => d.temp_max)
]
Insert cell
positionXAxis = g =>
g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(positionX))
Insert cell
positionYAxis = g =>
g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(positionY))
Insert cell
md`## Curve Difference Chart`
Insert cell
md` These types of charts compare two or more curves to each other from a given data. The limitation
here is that the user has to see for themselves the amount of space between the two curves. This is difficult to do especially if the space at a certain point between the two is too small to see.`
Insert cell
curve_chart = {
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);
svg.append("g").call(positionXAxis);
svg.append("g").call(curveYAxis);

svg
.append("text")
.attr("x", width / 2)
.attr("y", 30)
.attr("text-anchor", "middle")
.style("font-size", "18px")
.text("Temp and Months Range (Seattle 2012)");

svg
.append("text")
.attr("x", width / 2)
.attr("y", height)
.style("font-size", "15px")
.style("text-anchor", "middle")
.text("Month");

svg
.append("text")
.attr("x", (height / 2) * -1)
.attr("y", margin.left - 27)
.style("text-anchor", "middle")
.style("font-size", "15px")
.attr("transform", "rotate(-90)")
.text("Temperature");

// Show two lines for min and max temp.
svg
.append('path')
.datum(newData)
.attr('d', lineGeneratorMin(curveData))
.attr('stroke', 'blue')
.attr('fill', 'none');

svg
.append('path')
.datum(newData)
.attr('d', lineGeneratorMax(curveData))
.attr('stroke', 'red')
.attr('fill', 'none');

return svg.node();
}
Insert cell
md`## Alternative Curve`
Insert cell
curveYDomainAlt = [d3.min(curveData, d => d.difference), d3.max(curveData, d => d.difference)]
Insert cell
curveYAxisAlt = g =>
g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(curveYAlt))
Insert cell
curveYAlt = d3
.scaleLinear()
.domain(curveYDomainAlt)
.range([height - margin.bottom, margin.top])
.nice()
Insert cell
lineGeneratorAlt = d3
.line()
.x(d => positionX(d.date))
.y(d => curveYAlt(d.difference))
Insert cell
alt_curve_chart = {
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);
svg.append("g").call(positionXAxis);
svg.append("g").call(curveYAxisAlt);

svg
.append("text")
.attr("x", width / 2)
.attr("y", 30)
.attr("text-anchor", "middle")
.style("font-size", "18px")
.text("Temp and Months Range (Seattle 2012)");

svg
.append("text")
.attr("x", width / 2)
.attr("y", height)
.style("font-size", "15px")
.style("text-anchor", "middle")
.text("Month");

svg
.append("text")
.attr("x", (height / 2) * -1)
.attr("y", margin.left - 27)
.style("text-anchor", "middle")
.style("font-size", "15px")
.attr("transform", "rotate(-90)")
.text("Temperature");

svg
.append('path')
.datum(newData)
.attr('d', lineGeneratorAlt(curveData))
.attr('stroke', 'black')
.attr('fill', 'none');

return svg.node();
}
Insert cell
Insert cell
md`The lines for my curve chart won't show up but my alternative chart works fine. `
Insert cell
Insert cell
import {
displayCaution,
assignment_instructions,
observable_challenges
} from "@uw-info474/utilities"
Insert cell
import { render_data_table, table_styles } from "@info474/utilities"
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