Published
Edited
Jul 10, 2022
2 forks
1 star
Insert cell
Insert cell
Insert cell
Insert cell
L = require('leaflet@1.8.0') // mise à jour de leaflet en 1.8.0
Insert cell
<link href='${resolve('leaflet@1.8.0/dist/leaflet.css')}' rel='stylesheet' /> // mise à jour de leaflet en 1.8.0
Insert cell
Insert cell
FileAttachment("geojson.png").image()
Insert cell
Insert cell
Insert cell
//Our function is in map

map = {
// You'll often see Leaflet examples initializing a map like L.map('map'),
// which tells the library to look for a div with the id 'map' on the page.
// In Observable, we instead create a div from scratch in this cell called 'container', so it's
// completely self-contained.
let container = DOM.element('div', { style: `width:${width}px;height:${width/1.6}px` });
// This component utilizes "yield", which pauses the execution of this code block
// Yield returns the value of container back to the notebook, which allows the div to be placed on the page.
//This is important, because Leaflet uses the div's .offsetWidth and .offsetHeight (to get current size of the div) and size the map. If I were to only return the container at the end of this method, Leaflet might get the wrong idea about the map's size.
yield container;
// Now we create a map object and add a layer to it.
let map = L.map(container).setView([49.2527, -123.1207], 10.5); // initializes the map, sets zoom & coordinates

//This adds the tile layer to the map. The map dynamically loads tiles based on current view the experience smooth and seamless. Make sure to add attribution to your map.
let baseLayer = 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);

}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
grandCentral = {
let response = await fetch('https://nominatim.openstreetmap.org/search.php?q=grand+central+station%2C+new+york&polygon_geojson=1&format=json');
let json = await response.json();
return json[0].geojson
}
Insert cell
grandCentralMap = {
// You'll often see Leaflet examples initializing a map like L.map('map'),
// which tells the library to look for a div with the id 'map' on the page.
// In Observable, we instead create a div from scratch in this cell, so it's
// completely self-contained.

//Here, I changed the width and height of the map since I got tired of accidentally scrolling in and out while navigating through the page
let container = DOM.element('div', { style: `width:${600}px;height:${width/2}px` });
// Note that I'm yielding the container pretty early here: this allows the
// div to be placed on the page. This is important, because Leaflet uses
// the div's .offsetWidth and .offsetHeight to size the map. If I were
// to only return the container at the end of this method, Leaflet might
// get the wrong idea about the map's size.
yield container;
// Now we create a map object and add a layer to it.
//Notice the basemap tile layer below
let map = L.map(container);
let baseLayer = L.tileLayer(cartoLight, {
attribution: cartoAttr
}).addTo(map);

//instantiates a new geoJson layer using built in geoJson handling
let grandCentralLayer = L.geoJson(grandCentral,
{
weight: 5, //We can set the attributes of the polygons (like CSS), including line weight and colors
color: '#432'
})
.addTo(map);

//finds bounds of polygon and automatically gets map view to fit (useful for interaction and not having to 'cook' the map zoom and coordinates as in map instantiation
grandCentralLayer.bindPopup('Grand Central Terminal'); //tooltip
map.fitBounds(grandCentralLayer.getBounds());
}
Insert cell
Insert cell
Insert cell
VanAreas = FileAttachment("VancouverAreaSize.json").json()
Insert cell
lille_iris_txactif = FileAttachment("Lille_IRIS_txactif.geojson").json()
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
vanOneWays
Insert cell
vanStreets
Insert cell
streetUses //I defined a helper function that fetches me the types of street uses listed in the JSON
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
vanFoodGardens
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
LilleIrisCarte2 = {

// Limitation de la fenêtre de la carte à une certaine taille
let width = 700
let height = 500
let container = DOM.element('div', { style: `width:${width}px;height:${height}px` });

yield container;
//Ici définition du zoom pour visualisation lIlle 12 après essai + légende
let map = L.map(container, {maxZoom: 12, minZoom: 12});

//add base layer
let baseLayer = L.tileLayer(cartoLight, {
attribution: cartoAttr,
subdomains: 'abcd',
maxZoom: 20,
minZoom: 0
}).addTo(map);

// make a lookup table indexed by GEOID10, so we can go from that ID to the total housing count
// let IrisByCode = new Map(lille_iris_datapopm.map(row => [row['cartodb_id'], row]))
// this is a *dynamic* style generator, where the fill color is based on the total housing count
/* let styleGenerator = feature => {
let style = {
"color": "rgb(100, 100, 100)",
"fillColor": colorScale(housingByGeoId.get(feature.properties.GEOID10).HD01_VD01),
"opacity": 1,
"weight": 2,
"fillOpacity": 0.7,
}
return style;
};
*/
// var poptot =
/* var taille = resultat => {
IrisByCode.get(resultat.properties.cartodb_id).size_pop_tot} */
//geoMarker obj
/*let geojsonMarkerOptions = {
radius: taille,
fillColor: "#ff7800",
color: "#ff7800",
weight: 1,
opacity: 1,
fillOpacity: 0.6
};*/
let styleGenerator = feature => {
let style = {
radius: 5,
fillColor: "#ff7800",
color: "#ff7800",
weight: 1,
opacity: 1,
fillOpacity: 0.6
}
return style;
}
//passing a pointToLayer function in a GeoJSON options object when creating the GeoJSON layer.
//This function is passed a LatLng and should return an instance of ILayer, in this case likely a Marker or CircleMarker.
//we use arrow notation here, but this essentially is the same as using an anonymous function like so: function (feature, latlng){...return stuff}
let LillePointLayer = L.geoJSON(lille_irisc_pop, {
pointToLayer: (feature, latlng) => {
return L.circleMarker(latlng, {style: styleGenerator});
}})
.bindTooltip(function (Layer) {
return 'Iris: '+ Layer.feature.properties.nom_iris + '<br> Population tot. = ' + Layer.feature.properties.pop_tot_15_64;
})
.addTo(map);


//finds bounds of polygon and automatically gets map view to fit
map.fitBounds(LillePointLayer.getBounds());
}

Insert cell
// fichier des centroïdes des iris de Lille
lille_irisc_pop = FileAttachment("Lille_IrisC_Pop.geojson").json()
Insert cell
Insert cell
Insert cell
// vérification contenu de la table
{//return lille_iris_datapop.length
return (lille_iris_datapopm[0].sqrt_pop_tot)
}
Insert cell
Insert cell
Insert cell
// vérification contenu de la table
{//return lille_iris_datapop.length
return (lille_iris_datapop[0].size_pop_tot)
}

Insert cell
Insert cell
Insert cell
vanCrime
Insert cell
crimePoints
Insert cell
FilteredGeoCrimes
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{return "Neighbourhood selected: " + (nHood == null ? 'none' : nHood)}
Insert cell
<div style="
background: #fff;
display: grid;
height: ${screen.height / screen.width * 100}vw;
grid-template-areas:
'a'
'b';
grid-gap: 10px;
">
<div name="a" style="grid-area:a;border:solid 1px #ccc;text-align: center">${viewof crimeChart}</div>
<div name="b" style="grid-area:b;border:solid 1px #ccc;text-align: center">${viewof crimeMap}</div>
</div>`
Insert cell
brush = vl.selectInterval().encodings('x').resolve('global');
Insert cell
click = vl.selectPoint().encodings('color');
Insert cell
//OUR HEATMAP SHOWING CRIMES IN VANCOUVER
viewof crimeMap = {

let width = 900;
let container = DOM.element('div', { style: `width:${width}px;height:${width/1.6}px` });
yield container;

//Use setview when making heatmaps, because heatLayer doesn't have a getBounds() method
let map = L.map(container).setView([49.2527, -123.1207], 10.5);

//add base layer
let baseLayer = L.tileLayer(cartoLight, {
attribution: cartoAttr,
subdomains: 'abcd',
maxZoom: 12,
minZoom: 12
}).addTo(map);

//heatmap Style
let heatStyle = {
radius: 10,
blur: 15,
// maxZoom: 12,
// minZoom: 12,
max: 4.0,
scaleRadius: true
}


//layer for our neighborhoods
//*********THIS IS VERY IMPORTANT: onEachFeature ADDS A LISTENER TO THE LAYER with a callback function called featureEvents**********************
let VanAreasLayer = L.geoJson(vanAreas, {style: neighbourhoodStyle, onEachFeature: featureEvents})
.bindPopup(d => d.feature.properties.NAME)
.addTo(map);
//our heatmap layer
let crimeLayer = heatLayer(crimePoints, heatStyle).addTo(map);

//another mouse listener that resets the state of nHood when we click on a blank part of the map
map.on('click', () =>
mutable nHood = null
);

map.fitBounds(VanAreasLayer.getBounds());
}
Insert cell
//OUR CONCATENATED BAR CHART / LINE CHART THAT DOES BRUSHING AND LINKING
//Interactions are defined very similarly to the brushing & linking we did in Tutorial 6, except now we use the filter function to combine the selection returned internally by our bar/line brush, and the global selection of neighbourhoods from our map (mapSelection)

viewof crimeChart = {
//our filter function is telling us: we will use the 'and' operator while filtering, to only show the selection returned by 1) `brush`, and 2) our predicate of mapSelection (which returns neighbourhood names selected from the map) that are in the field NEIGHBOURHOOD
const crimeBar = vl.markBar()
.data(vanCrime2)
.transform(vl.filter({'and':
[brush, {'field': 'NEIGHBOURHOOD', 'oneOf': mapSelection}]}))
.select(click)
.encode(
vl.x().count(),
vl.y().fieldN('Offense'),
vl.color().value('lightgray').if(click, vl.color().fieldN('Offense Category'))
)
.width(200)
.height(200)

//Interactions are defined very similarly to the brushing & linking we did in Tutorial 6, except now we use the filter function
//our filter function is telling us: we will use the 'and' operator while filtering, to only show the selection returned by 1) `brclickush`, and 2) our predicate of mapSelection (which returns neighbourhood names selected from the map) that are in the field NEIGHBOURHOOD
const crimeLine = vl.markLine()
.data(vanCrime2)
.transform(vl.filter({'and':
[click, {'field': 'NEIGHBOURHOOD', 'oneOf': mapSelection}]}))
.encode(
vl.x().fieldT('Date').timeUnit('utcdatemonth'),
vl.y().count(),
vl.color().fieldN('Offense Category')
)
.params(brush)
.width(400)
.height(200)

//concat the bars together
// const concatMaps = vl.hconcat(crimeBar, crimeLine)
// .transform(vl.filter(mapSelection))
return vl.hconcat(crimeBar, crimeLine).render()

}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
vl.markCircle({size: 30})
.data(crimeDensityTotal)
.transform(
vl.filter({'and':
[{'field': 'NEIGHBOURHOOD', 'oneOf': mapSelection}]})
)
.encode(
vl.x().fieldN('Offense').count().axis('Number of crimes').scale({type: 'log'}),
vl.y().fieldQ('sqm').axis({title: 'Square meters/person'}).scale({'domain': [0, 500]}),
vl.column().fieldN('Offense Type'),
vl.color().fieldN('Offense Category')
)
.width(250)
.title(selectedNeighbourhoods)
.render()

Insert cell
Insert cell
viewof popMap = {
let width = 400
let height = 350
let container = DOM.element('div', { style: `width:${width}px;height:${width/2}px` });
yield container
let map = L.map(container,
{ maxZoom: 11,
minZoom: 11
});
let osmLayer = L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}@2x.png', {
attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
let VanAreasLayer = L.geoJson(vanAreas, {style: style0})
.bindTooltip(function (Layer) { //binds a tooltip when clicking on each polygon
return Layer.feature.properties.NAME;}).addTo(map); //Adds the layer to the map.
map.fitBounds(VanAreasLayer.getBounds());
}
Insert cell
viewof densityMap = {
let width = 400
let height = 350
let container = DOM.element('div', { style: `width:${width}px;height:${width/2}px` });
yield container
let map = L.map(container,
{ maxZoom: 11,
minZoom: 11
});
let osmLayer = L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}@2x.png', {
attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
let VanAreasLayer = L.geoJson(vanAreas, {style: style})
.bindTooltip(function (Layer) { //binds a tooltip when clicking on each polygon
return Layer.feature.properties.NAME;})
.addTo(map); //Adds the layer to the map.
//add the crime points
let crimePoints = FilteredGeoCrimes.features.map(feature =>
feature.geometry.coordinates.slice().reverse().concat([0.1]));
map.fitBounds(VanAreasLayer.getBounds());
}
Insert cell
Insert cell
Insert cell
vanAreas
Insert cell
Insert cell
html`<link href='${resolve(
'leaflet@1.2.0/dist/leaflet.css'
)}' rel='stylesheet' /><style>

.legend {
line-height: 18px;
color: #555;
border: 1px solid #000000;
border-radius: 4px;
padding: 8px;
background: rgba(255,255,255,0.8);
}
.legend i {
width: 18px;
height: 18px;
float: left;
margin-right: 8px;
opacity: 0.7;
}</style>`
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
//We are writing the event listener function for each feature in our geojson layer
//when each of these events are fired, a callback function is triggered
//more interaction (such as hover) is covered here: https://leafletjs.com/SlavaUkraini/examples/choropleth/

function featureEvents(feature, layer) {
layer.on({
click: whenClicked, //callback functions
});
}
Insert cell
//We update our data in the function using mutable. This overrides observables defaults so we can push data from within //function scope globally
whenClicked = (event) => {
mutable nHood = event.target.feature.properties.NAME
}
Insert cell
//Mutable overrides Observable's defaults state, so we can push data from within function scope globally
mutable nHood = null
Insert cell
mapSelection = {
if(nHood == null ){
return Array.from(new Set(vanCrime2.map(d => d.NEIGHBOURHOOD))) //Set is a new datastructure in ES6 -> only unique values
} else {
return [nHood]
}
}
Insert cell
selectedNeighbourhoods = selectedNames(mapSelection);
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
VegaLite = require('vega-lite@2.0.0-beta.2/build/vega-lite.min.js')
//Vegalite = require("@observablehq/vega-lite@0.2")
Insert cell
vegalite = require("@observablehq/vega-lite@0.1")
Insert cell
Insert cell
heatLayer = L, require('leaflet.heat').catch(() => L.heatLayer)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function style0(feature) {
return {
fillColor: getPopColor(feature.properties.population),
weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7
};
}
Insert cell
function neighbourhoodStyle(){
return {
fillColor: '#999999',
weight: 2,
opacity: .5,
color: 'white',
dashArray: '3',
fillOpacity: 0.2,
}};
Insert cell
Insert cell
Insert cell
vanFoodGardens = FileAttachment("community-gardens-and-food-trees.geojson").json()
Insert cell
vanAreas = FileAttachment("VanAreas.json").json()
Insert cell
vanAreaValues2 = d3.json("https://www.sfu.ca/~lyn/data/Urban/VancouverAreaSizeTopo.json")
Insert cell
vanStreets = FileAttachment("public-streets.geojson").json()
Insert cell
vanOneWays = FileAttachment("one-way-streets.geojson").json()
Insert cell
Insert cell
vanCrime2 = {
let i=vanCrime.features.length;
let j=0;
let k=0;
let temp ={};
let newCrime=[];
for(k=0;k<i; k++)
{
newCrime[k]= vanCrime.features[k].properties;
}
return (newCrime);
}
Insert cell
Insert cell
Insert cell
crimePoints = FilteredGeoCrimes.features.map(feature =>
feature.geometry.coordinates.slice().reverse().concat([0.1]))
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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