Public
Edited
Mar 12, 2023
Insert cell
md`# CS 448B A3 - Amber Patrick and Maxwell Fite (18Feb23)`
Insert cell
Insert cell
restaurant_data = FileAttachment("asst3_google.csv").csv()
Insert cell
Insert cell
function formatData(restaurant_data) {
let restaurant_locations = [];
let full_location = [];
let location_JSON = [];
let ALL_LAT_LONG = [];
let data = [];
for (let i = 0; i < restaurant_data.length; i++) {
full_location = restaurant_data[i]["geometry"];
location_JSON = full_location.replace(/[']+/g, '"');
restaurant_locations = JSON.parse(location_JSON);
ALL_LAT_LONG.push(restaurant_locations.location);
data.push([ALL_LAT_LONG[i].lat,ALL_LAT_LONG[i].lng]);
restaurant_data[i]["geometry"] = data[i]
}
return restaurant_data
}
Insert cell
Insert cell
formattedData = formatData(restaurant_data)
Insert cell
Insert cell
Insert cell
Insert cell
<div id='map' style='width: 100%; height: 30rem;'></div>
Insert cell
Insert cell
filteredData = _.filter(formattedData, d => {
// either the genre is in the filtered genres
return ((_.includes(filteredAspects, "Takeout")) && d.takeout == "True" || !_.includes(filteredAspects, "Takeout"))
&&
((_.includes(filteredAspects, "Serves Breakfast") && d.serves_breakfast == "True" || !_.includes(filteredAspects, "Serves Breakfast")))
&&
((_.includes(filteredAspects, "Serves Lunch") && d.serves_lunch == "True" || !_.includes(filteredAspects, "Serves Lunch")))
&&
((_.includes(filteredAspects, "Serves Dinner") && d.serves_dinner == "True" || !_.includes(filteredAspects, "Serves Dinner")))
})
Insert cell
Insert cell
viewof radius = Inputs.range([1, 10], {value: 3, step: 1, label: "Zone Radius 1 (in Miles)"});
Insert cell
viewof radius1 = Inputs.range([1, 10], {value: 3, step: 1, label: "Zone Radius 2 (in Miles)"});
Insert cell
updateZones = function (radius, radius1) {
d3.select("#intersectionCircles0").attr("r", radius * 11.22)
d3.select("#intersectionCircles1").attr("r", radius1 * 11.22)
update_intersection();
}
Insert cell
updateZones(radius, radius1)
Insert cell
// determine pixel to mile conversion
// formattedData[0]
// formattedData[1]
// get distance by plugging lat/long into https://www.nhc.noaa.gov/gccalc.shtml
// check cx and cy for pixel locations and use distance formula
// convert
Insert cell
Insert cell
maplibregl = {
const gl = await require("maplibre-gl@2.4.0");
const href = await require.resolve("maplibre-gl@2.4.0/dist/maplibre-gl.css");
document.head.appendChild(html`<link href=${href} rel=stylesheet>`);
return gl;
}
Insert cell
Insert cell
// reference: https://observablehq.com/@tmcw/using-mapbox-gl-js
map = {
var map = new maplibregl.Map({
container: 'map',
style: 'https://api.maptiler.com/maps/streets/style.json?key=get_your_own_OpIi9ZULNHzrESv6T2vL',
center: [-122.169961, 37.596235],
zoom: 8.5,
interactive: false
});
//map.addControl(new maplibregl.NavigationControl(), 'bottom-left'); // adds the controls
map.scrollZoom.disable();
return map
}
Insert cell
Insert cell
Insert cell
svg = {
var container = map.getCanvasContainer();
var svg = d3
.select(container)
.append("svg")
.attr("width", "100%")
.attr("height", "100%")
.style("position", "absolute")
.style("z-index", 2); // make this appear above the mapbox backing layer
return svg
}
Insert cell
Insert cell
function update_intersection() {
update_dots.attr("fill", function(d) {
var locX = d3.select(this).attr("cx");
var locY = d3.select(this).attr("cy");
return withinIntersection(locX, locY) ? "purple" : "gray";
})
}
Insert cell
function withinIntersection (xdot, ydot) {
let first_x = d3.select("#intersectionCircles0").attr("cx");
let first_y = d3.select("#intersectionCircles0").attr("cy");
let first_r = d3.select("#intersectionCircles0").attr("r");
let second_x = d3.select("#intersectionCircles1").attr("cx");
let second_y = d3.select("#intersectionCircles1").attr("cy");
let second_r = d3.select("#intersectionCircles1").attr("r");
let withinFirst = (Math.abs(first_x - xdot) <= first_r) && (Math.abs(first_y - ydot) <= first_r);
let withinSecond = (Math.abs(second_x - xdot) <= second_r) && (Math.abs(second_y - ydot) <= second_r);
return withinFirst && withinSecond;
}
Insert cell
Insert cell
circles = {
const circles = d3.range(2).map(i => ({
x: 100,
y: 100,
id: i,
}));

let locators = svg
.selectAll("circle.zone")
.data(circles)
.join("circle")
.attr("id", d => "intersectionCircles" + d.id)
.attr("class", "zone")
.attr("cx", d => d.x)
.attr("cy", d => d.y)
.attr("r", 11.22)
.style("opacity", .3)
.attr("fill", (d, i) => d3.schemeCategory10[i % 10])
.call(drag);

return svg.node();
}
Insert cell
Insert cell
dots = {
let dots = svg.selectAll("circle")
.data(filteredData)
.join("circle")
.attr("id","dot")
.attr("r", 4)
.attr("fill", "gray")
.attr("stroke", "black")
.attr("stroke-width", "0.5")
//.attr("r", Math.max(map.getZoom()**2/25, 3))
return dots;
}
Insert cell
update_dots = {
let update_dots = svg.selectAll("#dot")
.data(filteredData)
.join("circle")
.attr("id","dot")
.attr("r", 4)
.attr("fill", "gray")
.attr("stroke", "black")
.attr("stroke-width", "0.5")
return update_dots
}
Insert cell
Insert cell
drag = {
function dragstarted(event, d) {
d3.select(this).raise().attr("stroke", "black");
}

function dragged(event, d) {
d3.select(this).attr("cx", d.x = event.x).attr("cy", d.y = event.y);
update_intersection();
}

function dragended(event, d) {
d3.select(this).attr("stroke", "black");
d3.selectAll("#dot").raise()
}

return d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended);
}
Insert cell
Insert cell
function project(lng,lat) {
return map.project(new maplibregl.LngLat(lng, lat));
}
Insert cell
function unproject(x,y) {
return map.unproject([x,y]);
}
Insert cell
Insert cell
function render() {
update_dots
.attr("cx", function (d) {
return project(d.geometry[1], d.geometry[0]).x;
})
.attr("cy", function (d) {
return project(d.geometry[1], d.geometry[0]).y;
})
.on('mouseover', function(event, d) {
d3.select('#tooltip').html(d.name + "<br>Rating: "
+ d.rating).transition().duration(200).style('opacity', 1);
d3.select(this)
.style("fill", "black")
.style("opacity", 1);
if (d.rating >= 4.8) {
d3.select(this)
.style("fill","green");
}
if (d.rating < 4) {
d3.select(this)
.style("fill","red");
}
})
.on('mouseout', function(event, d) {
map.getCanvasContainer().style.cursor = '';
d3.select('#tooltip').style('opacity', 0);
d3.select(this)
.style("stroke", "black")
.style("stroke-width", "0.5")
.style("opacity", 1)
.style("fill", update_intersection());
})
.on('mousemove', function(event, d) {
map.getCanvasContainer().style.cursor = 'pointer';
d3.select('#tooltip').style("top", (event.pageY+25)+"px").style("left", (event.pageX)+"px");
});
d3.selectAll("#dot").raise()
}
Insert cell
{
map.on("viewreset", render);
map.on("move", render);
map.on("moveend", render);
render();
}
Insert cell
Insert cell
theToolTip = {
d3.select("body")
.append("div")
.attr('id', 'tooltip')
.attr('style', 'position: absolute; opacity: 0;')
.attr("class", "tooltip")
.style("background-color", "white")
.style("border", "solid")
.style("border-width", "2px")
.style("border-radius", "5px")
.style("padding", "5px")
.style('font-size', '10px')
.style("z-index", 2);
}
Insert cell
Insert cell
import {checkbox} from "@jashkenas/inputs"
Insert cell
Insert cell
_ = require('lodash')
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