Published
Edited
Feb 15, 2020
Insert cell
md`# Species map`
Insert cell
taxon_id = 123168
Insert cell
md`I happen to know there are just under 1000 of them. I'm going to manually load 5 pages 200 at a time`
Insert cell
observations = {
let a = (await fetch("https://api.inaturalist.org/v1/observations?order_by=observed_on&taxon_id=123168&per_page=200&page=1&quality_grade=research").then(r => r.json())).results.concat(
(await fetch("https://api.inaturalist.org/v1/observations?order_by=observed_on&taxon_id=123168&per_page=200&page=2&quality_grade=research").then(r => r.json())).results
).concat(
(await fetch("https://api.inaturalist.org/v1/observations?order_by=observed_on&taxon_id=123168&per_page=200&page=3&quality_grade=research").then(r => r.json())).results
).concat(
(await fetch("https://api.inaturalist.org/v1/observations?order_by=observed_on&taxon_id=123168&per_page=200&page=4&quality_grade=research").then(r => r.json())).results
).concat(
(await fetch("https://api.inaturalist.org/v1/observations?order_by=observed_on&taxon_id=123168&per_page=200&page=5&quality_grade=research").then(r => r.json())).results
);
return a;
}
Insert cell
L = {
const L = window.L = await require('leaflet@1.2.0');
return L;
}

Insert cell
html`This cell loads the CSS needed by Leaflet and its plugin<link href='${resolve('leaflet@1.6.0/dist/leaflet.css')}' rel='stylesheet' />`
Insert cell
url = "https://san-francisco.datasettes.com/sf-trees-ebc2ad9.json?sql=select+Latitude%2C+Longitude%2C+qSpecies.value+as+qSpecies%2C%0D%0A++qAddress%0D%0Afrom+Street_Tree_List+%0D%0A++join+qSpecies+on+Street_Tree_List.qSpecies+%3D+qSpecies.id%0D%0Awhere+Street_Tree_List.rowid+in+%28select+rowid+from+%5BStreet_Tree_List_fts%5D+where+%5BStreet_Tree_List_fts%5D+match+%3Asearch%29&search=cherry"
Insert cell
trees = {
let response = await fetch(url);
let json = await response.json();
return json.rows;
}
Insert cell
map = {
let container = DOM.element("div", {
style: `width:${width}px;height:${width / 1.6}px`
});
yield container;

let map = L.map(container).setView([37.7881014522033, -122.420267712778], 13);
let osmLayer = L.tileLayer(
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
{
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}
).addTo(map);
if (observations.length) {
observations.forEach(observation => {
let markerHtmlStyles = `
background-color: ${rgbForDate(observation.observed_on)};
width: 7px;
height: 7px;
display: block;
border-radius: 50%;
border: 1px solid #FFFFFF`;
let title = JSON.stringify(observation);
let icon = L.divIcon({
className: "my-custom-pin",
/* iconAnchor: [0, 24],
labelAnchor: [-6, 0],
popupAnchor: [0, -36], */
html: `<span style="${markerHtmlStyles}" />`
});
if (observation.geojson) {
let marker = L.marker(
L.latLng(observation.geojson.coordinates[1], observation.geojson.coordinates[0]),
{
title: title,
icon: icon
}
).addTo(map);
marker.bindPopup(rgbForDate(observation.observed_on) + ' ' + observation.observed_on);
}
});
}
}

Insert cell
observed_at = "2020-02-14T11:54:00-08:00"
Insert cell
ms_since = Date.now() - Date.parse(observed_at)
Insert cell
ms_since / ( 24 * 60 * 60 * 1000)
Insert cell
md`Shades of red. If it was recent, bright red. If it was 365 days ago, white.`
Insert cell
function rgbForDate(date) {
let ms_since = Date.now() - Date.parse(date);
let days = ms_since / ( 24 * 60 * 60 * 1000);
if (days > 365) {
days = 365;
}
let r = (days / 365) * 255;
return `rgb(${r}, 0, 0)`;
}
Insert cell
rgbForDate(observed_at)
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