Published
Edited
Jun 15, 2021
Importers
1 star
Insert cell
Insert cell
Insert cell
function simpleTabularJoin(featureCollection, featureCollectionJoinCol, joinData, joinDataNames, joinDataCol) {
let returnArray = new Array(featureCollection.length)
for (let i=0; i<joinData.length;i++) {
for (let n=0; n<featureCollection.length; n++) {
returnArray[n] = featureCollection[n]
returnArray[n][joinDataNames[i]] = _.find(
joinData[i],
[joinDataCol[i], featureCollection[n].properties[featureCollectionJoinCol]]
)
}
}
return returnArray
}
Insert cell
function tabularJoin(featureCollection, featureCollectionJoinCol, joinData, joinDataNames, joinDataCol){
// declare parent dictionaries
let features = {}
let dataDict = {}
// declare and prep feature collection object
let i = featureCollection.features.length;
let colNumCheck = parseInt(featureCollection.features[0].properties[featureCollectionJoinCol])
if (Number.isInteger(colNumCheck)) {
while (i>0) {
i--;
features[parseInt(featureCollection.features[i].properties[featureCollectionJoinCol])] = featureCollection.features[i];
dataDict[parseInt(featureCollection.features[i].properties[featureCollectionJoinCol])] = {};
}
} else {
while (i>0) {
i--;
features[featureCollection.features[i].properties[featureCollectionJoinCol]] = featureCollection.features[i];
dataDict[featureCollection.features[i].properties[featureCollectionJoinCol]] = {};
}
}
// loop through data and add to dictionaries
let n = joinData.length;
while (n>0) {
n--;
let cols = Object.keys(joinData[n][0]);
i = cols.length;
while (i>0) {
i--;
try {
dataDict[cols[i]][joinDataNames[n]] = joinData[n][0][cols[i]]
} catch {}
}
}
// // use lodash to merge data
let merged = _.merge(features, dataDict)
// clean data
let rtn = [];
let keys = Object.keys(merged)
for (let i = 0; i < keys.length; i++) {
rtn.push(merged[keys[i]])
}

return rtn;
}
Insert cell
Insert cell
async function getParseCSV(url, joinCol, accumulate, dateList){

const tempData = await fetch(url)
.then(response => {
return response.ok ? response.text() : Promise.reject(response.status);
}).then(text => {
let data = d3.csvParse(text, d3.autoType);
let rtn = {};
let n = data.length;
let selectedJoinColumn;
let dateIndices = null;

joinCol.forEach(colOption => {
if (data[0].hasOwnProperty(colOption)) selectedJoinColumn = colOption;
})
if (dateList !== undefined) dateIndices = findDateIndices(dateList, Object.keys(data[0]))

if (accumulate) {
while (n>0){
n--;
let i = 0;
let tempArr = new Array(dateList.length);
while (i < dateList.length){
tempArr[i] = (data[n][dateList[i]]||0)+(tempArr[i-1]||0);
i++;
}
rtn[data[n][selectedJoinColumn]] = tempArr
}
} else if (dateList !== undefined){
while (n>0){
n--;
let i = 0;
let tempArr = new Array(dateList.length);
while (i < dateList.length){
tempArr[i] = (data[n][dateList[i]]||tempArr[i-1])
i++;
}
rtn[data[n][selectedJoinColumn]] = tempArr
}
} else {
while (n>0){
n--;
rtn[data[n][selectedJoinColumn]] = Object.values(data[n])
}
}
return [rtn, Object.keys(data[0]), dateIndices]
});
return tempData;
}

Insert cell
Insert cell
function findDateIndices( dateList, columnList ){
let validIndices = []
for (let i=0; i<dateList.length; i++) {
if (columnList.indexOf(dateList[i]) !== -1) validIndices.push(i)
}
return validIndices
}
Insert cell
Insert cell
function getDateLists(){
const stripLeadingZero = ( str ) => str[0] !== '0' ? str : str.slice(1,)
const isoToUsDate = (date) => stripLeadingZero(date.slice(5,7)) + '/'+ stripLeadingZero(date.slice(8,10)) + '/' + date.slice(2,4)

Date.prototype.addDays = function(days) {
var date = new Date(this.valueOf());
date.setDate(date.getDate() + days);
return date;
}

let todayDate = new Date()
let initialDate = new Date('01/21/2020')
let dateList = []
let isoDateList = []
let usDateList = []

while (initialDate < todayDate) {
dateList.push(initialDate)
let isoDate = initialDate.toISOString().slice(0,10);
isoDateList.push(isoDate)
usDateList.push(isoToUsDate(isoDate))
initialDate = initialDate.addDays(1)
}

return { isoDateList, usDateList }
}
Insert cell
Insert cell
async function getJson(url){
const response = await fetch(url)
const responseFromJson = response.clone();
const abData = await responseFromJson.arrayBuffer();
const geojsonData = await response.json()
return { geojsonData, abData }
}
Insert cell
function getGeoidIndex(features){
let geoidOrder = {};
let indexOrder = {};
let i = 0
while (i<features.length) {
geoidOrder[features[i].properties.GEOID] = i
indexOrder[i] = features[i].properties.GEOID
i++;
}

return {geoidOrder, indexOrder};
}
Insert cell
async function loadJson(url, gdaProxy){
const data = getJson(url).then(values => {
gdaProxy.readGeoJSON(url.split('/').slice(-1,)[0], values.abData);
return {
data: values.geojsonData,
geoidIndex: getGeoidIndex(values.geojsonData.features)
}
})
return data;
}
Insert cell
Insert cell
async function getCSV(url){
const tempData = await fetch(url)
.then(response => {
return response.ok ? response.text() : Promise.reject(response.status);
}).then(text => {
let data = d3.csvParse(text, d3.autoType)
return data
})
return tempData
}
Insert cell
Insert cell
function getCurrentWuuid(gdaProxy, selectedDataset){
var w = gdaProxy.CreateQueenWeights(selectedDataset, 1, 0, 0);

return {
'map_uuid': selectedDataset,
'w': w,
'w_uuid': w.get_uid()
};
}
Insert cell
function getDataForLisa(data, order){
const keys = Object.keys(data)
let returnArray = new Array(keys.length)
for (let i=0; i<keys.length;i++) {
returnArray[order[keys[i]]] = data[keys[i]]
}
return returnArray
}
Insert cell
function getLisaValues(gdaProxy, dataset, data){
let w = getCurrentWuuid(gdaProxy, dataset);
let all_zeros = true;
for (let i=0; i<data.length; ++i) {
if (data[i] !== 0)
all_zeros = false;
}
let clusters = [];
let sig = [];

if (all_zeros) {
for (let i=0; i<data.length; ++i) {
clusters.push(0);
sig.push(0);
}
} else {
var lisa = gdaProxy.local_moran(w.map_uuid, w.w_uuid, data);
clusters = gdaProxy.parseVecDouble(lisa.clusters());
sig = gdaProxy.parseVecDouble(lisa.significances());
}
return clusters;
}
Insert cell
function matchLisaValues(geoids, data){
let returnObject = {}
for (let i=0; i<data.length; i++){
returnObject[geoids[i]] = data[i]
}
return returnObject
}
Insert cell
Insert cell
lisaColors = [
[240,240,240],
[255,0,0],
[0,0,255],
[167, 173, 249],
[244, 173, 168],
]
Insert cell
lisaNames = [
"Not Significant",
"High-high hotspot",
"Low-low coldspot",
"Low-high near hotspot",
"High-low near coldspot"
]
Insert cell
Insert cell
async function getLisaData(params){
const {gdaProxy, geojsonURL, geoJsonJoinCol, csvList, joinCols, names, tableName, columnName} = params;
const geoData = await loadJson(geojsonURL, gdaProxy)
const csvData = await Promise.all(
[
...csvList.map(csv => getCSV(csv)
.then(result => {return result}))
]
)
const joinedData = await simpleTabularJoin(
geoData.data.features.slice(),
geoJsonJoinCol,
csvData,
names,
joinCols
)
let orderedData = {}
joinedData.forEach(f => orderedData[f.properties[geoJsonJoinCol]] = f[tableName][columnName]);
const lisaData = getDataForLisa(orderedData, geoData.geoidIndex.geoidOrder)
const lisaValues = matchLisaValues(geoData.geoidIndex.indexOrder, getLisaValues(gdaProxy, geojsonURL.split('/').slice(-1,)[0], lisaData))
const naturalBreaks = await gdaProxy.custom_breaks(
geojsonURL.split('/').slice(-1,)[0],
'natural_breaks',
8,
null,
Object.values(orderedData)
);
const hingeBreaks = await gdaProxy.custom_breaks(
geojsonURL.split('/').slice(-1,)[0],
'hinge15_breaks',
6,
null,
Object.values(orderedData)
);
for (let i=0;i<geoData.data.features.length; i++){
geoData.data.features[i].lisaValue = lisaValues[geoData.data.features[i].properties.geoJsonJoinCol]
}
return {
geoData,
csvData,
lisaValues,
naturalBreaks,
hingeBreaks
}
}
Insert cell
async function generateBreaks(gdaProxy, numBins, values){
const quantileBreaks = await gdaProxy.quantile_breaks(
'tempGeojson',
numBins,
values,
)
const naturalBreaks = await gdaProxy.custom_breaks(
'tempGeojson',
'natural_breaks',
numBins,
null,
values
);
const hingeBreaks = await gdaProxy.custom_breaks(
'tempGeojson',
'hinge15_breaks',
numBins,
null,
values
);
return {
quantileBreaks,
naturalBreaks,
hingeBreaks
}
}
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