Public
Edited
Mar 13
Insert cell
Insert cell
map = {
const accName =
"Geographic map of New York City showing likely rent stabilized properties.";

return htl.svg`<svg viewBox="0 0 ${width} ${height}" role="img" aria-label=${accName}>
<clipPath id="clip-path">
<rect x="0" y="0" width="${width}" height="${height}" />
</clipPath/>
${tile().map(
([x, y, z], i, { translate: [tx, ty], scale: k }) =>
svg`
<image
clip-path="url(#clip-path)"
xlink:href="${getBasemapTileUrl(x, y, z)}"
x="${(x + tx) * k}"
y="${(y + ty) * k}"
width="${k}"
height="${k}"
>
`
)}
${geojson?.features?.map(
(d) =>
htl.svg`<path
clip-path="url(#clip-path)"
stroke="#fff"
stroke-width="0.7"
fill="#ff6600"
fill-opacity="0.7"
d="${path(d)}"
/>`
)}
</svg>`;
}
Insert cell
function getBasemapTileUrl(x, y, z) {
return `https://cartodb-basemaps-${
"abc"[Math.abs(x + y) % 3]
}.global.ssl.fastly.net/light_all/${z}/${x}/${y}${
devicePixelRatio > 1 ? "@2x" : ""
}.png`;
}
Insert cell
height = Math.floor((width * 2) / 3)
Insert cell
zoom = 25
Insert cell
path = d3.geoPath(projection)
Insert cell
tile = d3Tile
.tile()
.size([width, height])
.scale(projection.scale() * 2 * Math.PI)
.translate(projection([0, 0]))
Insert cell
projection = d3
.geoMercator()
.center(coordinates)
.scale(Math.pow(2, zoom) / (2 * Math.PI))
.translate([width / 2, height / 2])
.precision(0)
Insert cell
geojson = ({
type: "FeatureCollection",
features: data?.rows?.map((d) => {
// NOTE: BigQuery's ST_AsGeoJSON() seems to return GeoJSON geometries with the incorrect winding order, so we need to fix them for use with d3-geo.
// See: https://stackoverflow.com/a/49311635/2193086
const feature = rewind(
{
type: "Feature",
properties: {},
geometry: JSON.parse(d.geojson)
},
{ reverse: true }
);

return feature;
})
})
Insert cell
data = querySqlApi(query)
Insert cell
querySqlApi = async (query) => {
const encoded = encodeURIComponent(query);
const url = `${endpointUrl}?q=${encoded}`;
const headers = new Headers({ Authorization: `Bearer ${apiKey}` });
const options = { headers };
try {
const res = await fetch(url, options);
if (res.ok) {
const result = await res.json();
return result;
}
} catch (error) {
return error?.message || "couldn't query maps API";
}
}
Insert cell
// using Big Query geography functions, see: https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions
query = `SELECT ST_ASGEOJSON(geom) as geojson FROM ${tableName} WHERE ST_DWithin(geom, ST_GeogFromText('POINT(${coordinates[0]} ${coordinates[1]})'), ${bufferDistance})`
Insert cell
bufferDistance = 500 // meters
Insert cell
coordinates = [-73.95757, 40.658]
Insert cell
tableName = "shared.mappluto_likely_rs_2020_v8"
Insert cell
endpointUrl = `${apiBaseUrl}/v3/sql/carto_dw/query`
Insert cell
import { apiKey, apiBaseUrl } from "@clhenrick/hello-carto-maps-api-v3"
Insert cell
d3Tile = require("d3-tile")
Insert cell
rewind = (await import("@turf/rewind")).rewind
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