Published
Edited
May 28, 2021
Fork of Star map
2 stars
Insert cell
Insert cell
map = {
const cx = width / 2;
const cy = height / 2;

const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.attr("text-anchor", "middle")
.attr("fill", "currentColor")
.style("margin", "0 -14px")
.style("color", "white")
.style("background", "radial-gradient(#081f2b 0%, #061616 100%)")
.style("display", "block");//#081f2b 0%, #061616 100%

svg.append("path")
.attr("d", path(graticule))
.attr("fill", "none")
.attr("stroke", "currentColor")
.attr("stroke-opacity", 0.2);

svg.append("path")
.attr("d", path(outline))
.attr("fill", "none")
.attr("stroke", "currentColor");

svg.append("g")
.call(xAxis);

svg.append("g")
.call(yAxis);

const focusDeclination = svg.append("circle")
.attr("cx", cx)
.attr("cy", cy)
.attr("fill", "none")
.attr("stroke", "yellow");

const focusRightAscension = svg.append("line")
.attr("x1", cx)
.attr("y1", cy)
.attr("x2", cx)
.attr("y2", cy)
.attr("stroke", "yellow");

svg.append("g")
.attr("stroke", "black")
.selectAll("circle")
.data(data)
.join("circle")
.attr("r", d => radius(Math.sqrt(d.Floor)/150))
.attr("fill", d => color(d.Type))
.attr("transform", d => `translate(${projection(d)})`);

svg.append("g")
.attr("pointer-events", "all")
.attr("fill", "none")
.selectAll("path")
.data(data)
.join("path")
.on("mouseover", mouseovered)
.on("mouseout", mouseouted)
.attr("d", (d, i) => voronoi.renderCell(i))
.append("title")
.text(formatTitle);

function mouseovered(event, d) {
const [px, py] = projection(d);
const dx = px - cx;
const dy = py - cy;
const a = Math.atan2(dy, dx);
focusDeclination.attr("r", Math.hypot(dx, dy));
focusRightAscension.attr("x2", cx + 1e3 * Math.cos(a)).attr("y2", cy + 1e3 * Math.sin(a));
}

function mouseouted(event, d) {
focusDeclination.attr("r", null);
focusRightAscension.attr("x2", cx).attr("y2", cy);
}

return svg.node();
}
Insert cell
function formatTitle({ID, Type, City,Floor}){
return `ID${ID}FL${Floor}${Type === null ? ``
: City === null ? `
${nominative[Type]}` : `
${City
.replace( w => letters[w])
.replace(c => superscript[c])} ${genitive[Type]}`}`;
}
Insert cell
superscript = "⁰¹²³⁴⁵⁶⁷⁸⁹"
Insert cell
letters = ({Boston: "Boston", Cambridge: "Cambridge", Chicago: "Chicago", Philadelphia: "Philadelphia", Washington: "Washington"})
Insert cell
nominative = ({Education: "Education", Food: "Food", Lodging: "Lodging", Office: "Office",HealthCare:"HealthCare",Residential: "Residential", PublicAssembly:"PublicAssembly",PublicSafety:"PublicSafety",Residential:"Residential",Retail: "Retail", Warehouse: "Warehouse"})
Insert cell
genitive = ({Education: "Education", Food: "Food", Lodging: "Lodging", Office: "Office",HealthCare:"HealthCare",Residential: "Residential", PublicAssembly:"PublicAssembly",PublicSafety:"PublicSafety",Residential:"Residential",Retail: "Retail", Warehouse: "Warehouse"})
Insert cell
xAxis = g => g
.call(g => g.append("g")
.attr("stroke", "currentColor")
.selectAll("line")
.data(d3.range(0,1440,6)) // every 5 minutes
.join("line")
.datum(d => [
projection([d / 4, 0]),
projection([d / 4, d % 60 ? -1 : -2])
])
.attr("x1", ([[x1]]) => x1)
.attr("x2", ([, [x2]]) => x2)
.attr("y1", ([[, y1]]) => y1)
.attr("y2", ([, [, y2]]) => y2))
.call(g => g.append("g")
.selectAll("text")
.data(d3.range(0,1440,60)) // every hour
.join("text")
.attr("dy", "0.35em")
.text(d => `${1790+d*240/1440}`)
.attr("font-size", d => d % 360 ? null : 14)
.attr("font-weight", d => d % 360 ? null : "bold")
.datum(d => projection([d / 4, -4]))
.attr("x", ([x]) => x)
.attr("y", ([, y]) => y))
Insert cell
yAxis = g => g
.call(g => g.append("g")
.selectAll("text")
.data(d3.range(0,90,9)) // every 9°
.join("text")
.attr("dy", "0.35em")
.text(d => `${100-d*10/9}`)
.datum(d => projection([0, d]))
.attr("x", ([x]) => x)
.attr("y", ([, y]) => y))
Insert cell
voronoi = d3.Delaunay.from(data.map(projection)).voronoi([0, 0, width, height])
Insert cell
radius = d3.scaleLinear([0,6], [0,6])
Insert cell
//color = d3.scaleOrdinal(data.map(d => d.Type), d3.interpolateBrBG())

//color = d3.scaleSequential([0, 360], d3.interpolateRainbow)
//color=d3.scaleOrdinal(data.map(d => d.Type) /* YOUR DOMAIN */).interpolator(d3.interpolateRainbow)
//color = d3.scaleDiverging(d3.interpolateBrBG).domain([d3.min(data.map(d => d.Type)), 0, d3.max(data.map(d => d.Type))])
color = d3
.scaleOrdinal().domain(data.map(d => d.Type)).range(["#f0704a",
"#7bfe5f",
"#efe9ef",
"#fedd8d",
"#de4d4a","#4575b1",
"#e0f3a1",
"#631d70",
"#f2a549",
"#39988f",
"#15776e",
"#94d4a4"])
Insert cell
path = d3.geoPath(projection)
Insert cell
projection = d3.geoStereographic()
.reflectY(true)
.scale(scale)
.clipExtent([[0, 0], [width, height]])
.rotate([0, -90])
.translate([width / 2, height / 2])
.precision(0.1)
Insert cell
outline = d3.geoCircle().radius(90).center([0, 90])()
Insert cell
graticule = d3.geoGraticule().stepMinor([15, 10])()
Insert cell
data = (d3.csvParse(await FileAttachment("D3starnew.csv").text(), d => {
d3.autoType(d);
d[0] = (d.YearBuilt-1790)/240*24*15; // longitude
d[1] = 90-d.Rate*9/10; // latitude
return d;
})).sort((a, b) => d3.ascending(a.Floor, b.Floor))
Insert cell
scale = (width - 120) * 0.5
Insert cell
width = 954 + 28
Insert cell
height = width
Insert cell
import {ramp} from "@mbostock/color-ramp"
Insert cell
import {legend} from "@d3/color-legend"
Insert cell
d3 = require("d3@6")
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