- {scenarioDescription}
+
+ {/*TODO: This subscript is a note to self, related to
+ https://github.com/natcap/urban-online-workflow/issues/124*/}
+
{singleLULC}
{
(jobID)
?
diff --git a/frontend/src/edit/scenarioTable.jsx b/frontend/src/edit/scenarioTable.jsx
index 4c75ed2..d04693c 100644
--- a/frontend/src/edit/scenarioTable.jsx
+++ b/frontend/src/edit/scenarioTable.jsx
@@ -1,32 +1,55 @@
import React, { useState, useEffect } from 'react';
import {
+ HTMLSelect,
HTMLTable,
Button,
} from '@blueprintjs/core';
-import landuseCodes from '../../../appdata/NLCD_2016.lulcdata.json';
+import { toAcres } from '../utils';
+import nlcdLookup from '../../../appdata/nlcd_colormap.json';
+import nludLookup from '../../../appdata/nlud_colormap.json';
+import treeLookup from '../../../appdata/tree_colormap.json';
-function acres(count) {
- if (!parseInt(count)) {
- return '';
- }
- const acres = (count * 30 * 30) / 4047; // square-meters to acres
- return acres.toFixed(1);
-}
+const LULC_LOOKUP = {
+ nlcd: nlcdLookup,
+ nlud: nludLookup,
+ tree: treeLookup,
+};
+
+const LULC_TYPES = {
+ nlcd: 'landcover',
+ nlud: 'landuse',
+ tree: 'tree cover',
+};
export default function ScenarioTable(props) {
const { scenarios } = props;
const [scenarioTable, setScenarioTable] = useState(null);
+ const [landcoverTypes, setLandcoverTypes] = useState([]);
+ const [landuseTypes, setLanduseTypes] = useState([]);
+ const [treeTypes, setTreeTypes] = useState([]);
+ const [lulcType, setLulcType] = useState('nlcd');
useEffect(() => {
+ const landcover = [];
+ const landuse = [];
+ const tree = [];
(async () => {
const table = {};
scenarios.forEach((scene) => {
table[scene.name] = JSON.parse(scene.lulc_stats);
});
setScenarioTable(table);
+ Object.values(table).forEach((obj) => {
+ landcover.push(...Object.keys(obj['nlcd']));
+ landuse.push(...Object.keys(obj['nlud']));
+ tree.push(...Object.keys(obj['tree']));
+ });
+ setLandcoverTypes(new Set(landcover));
+ setLanduseTypes(new Set(landuse));
+ setTreeTypes(new Set(tree));
})();
}, [scenarios]);
@@ -34,7 +57,16 @@ export default function ScenarioTable(props) {
const scenarioHeader = (
- Landcover composition by scenario |
+
+ setLulcType(event.target.value)}
+ value={lulcType}
+ >
+ {Object.entries(LULC_TYPES).map(
+ ([type, label]) =>
+ )}
+
+ |
{Object.keys(scenarioTable).map(
(name) => {name} |
)}
@@ -43,26 +75,44 @@ export default function ScenarioTable(props) {
const rows = [];
rows.push(scenarioHeader);
- Object.keys(landuseCodes).forEach((code) => {
+
+ let codes;
+ switch (lulcType) {
+ case 'nlcd':
+ codes = landcoverTypes;
+ break;
+ case 'nlud':
+ codes = landuseTypes;
+ break;
+ case 'tree':
+ codes = treeTypes;
+ break;
+ default:
+ codes = [];
+ }
+ codes.forEach((code) => {
const counts = [];
- Object.entries(scenarioTable).forEach(([name, table]) => {
- const count = scenarioTable[name][code] || '';
+ Object.entries(scenarioTable).forEach(([x, table]) => {
+ const count = table[lulcType][code] || '';
counts.push(count);
});
if (counts.reduce((x, y) => (x || 0) + (y || 0), 0)) { // skip rows of all 0s
const cells = [];
cells.push(
-
- {landuseCodes[code].name}
+ {LULC_LOOKUP[lulcType][code].name}
|
);
cells.push(...counts.map((c, idx) => {
let content = '';
if (c) {
- content = {acres(c)} acres;
+ content = {toAcres(c)} acres;
}
return {content} | ;
}));
diff --git a/frontend/src/edit/studyAreaTable.jsx b/frontend/src/edit/studyAreaTable.jsx
index a715b95..6d45bb7 100644
--- a/frontend/src/edit/studyAreaTable.jsx
+++ b/frontend/src/edit/studyAreaTable.jsx
@@ -2,11 +2,27 @@ import React, { useState } from 'react';
import {
Button,
+ HTMLSelect,
HTMLTable,
} from '@blueprintjs/core';
import { removeParcel } from '../requests';
-import landuseCodes from '../../../appdata/NLCD_2016.lulcdata.json';
+import { toAcres } from '../utils';
+import nlcdLookup from '../../../appdata/nlcd_colormap.json';
+import nludLookup from '../../../appdata/nlud_colormap.json';
+import treeLookup from '../../../appdata/tree_colormap.json';
+
+const LULC_LOOKUP = {
+ nlcd: nlcdLookup,
+ nlud: nludLookup,
+ tree: treeLookup,
+};
+
+const LULC_TYPES = {
+ nlcd: 'landcover',
+ nlud: 'landuse',
+ tree: 'tree cover'
+};
export default function StudyAreaTable(props) {
const {
@@ -16,8 +32,8 @@ export default function StudyAreaTable(props) {
immutableStudyArea,
setHoveredParcel,
} = props;
- const [highlightedCode, setHighlightedCode] = useState(null);
const [hiddenRowClass, setHiddenRowClass] = useState('');
+ const [lulcType, setLulcType] = useState('nlcd');
const deleteParcel = async (parcelID) => {
await removeParcel(parcelID, studyAreaID);
@@ -32,31 +48,12 @@ export default function StudyAreaTable(props) {
}
};
- function plot(table) {
- const blocks = [];
- Object.entries(table).forEach(([code, count]) => {
- let n = 0;
- while (n < count) {
- blocks.push(
- setHighlightedCode(code)}
- onMouseOut={() => setHighlightedCode(null)}
- />,
- );
- n++;
- }
- });
- return blocks;
+ function sortCounts(countsMap) {
+ return Object.entries(countsMap)
+ .sort(([, a], [, b]) => b - a);
}
- const rows = [];
- rows.push(
+ const headerRow = (
|
address |
- landuse composition |
-
,
+
+ setLulcType(event.target.value)}
+ value={lulcType}
+ >
+ {Object.entries(LULC_TYPES).map(
+ ([type, label]) =>
+ )}
+
+ |
+ acres |
+
);
+ const rows = [];
+ rows.push(headerRow);
+
parcelArray.forEach((parcel) => {
- const lulcData = JSON.parse(parcel.parcel_stats.lulc_stats);
- rows.push(
-
setHoveredParcel(parcel.parcel_id)}
- onFocus={() => setHoveredParcel(parcel.parcel_id)}
- onMouseOut={() => setHoveredParcel(null)}
- onBlur={() => setHoveredParcel(null)}
- >
-
- |
- {parcel.address} |
-
- {
- (lulcData)
- ? (
-
- {plot(lulcData.base)}
-
- )
- :
- }
- |
-
,
- );
+ const data = JSON.parse(parcel.parcel_stats.lulc_stats);
+ if (!data) { return; }
+ const sorted = sortCounts(data[lulcType]);
+ rows.push(sorted.map(([code, count], i) => {
+ const label = LULC_LOOKUP[lulcType][code].name;
+ let header =
| ;
+ let address =
| ;
+ let rowClass = '';
+ if (i === 0) {
+ header = (
+
+ |
+ );
+ address =
{parcel.address} | ;
+ rowClass = 'address-row';
+ }
+ return (
+
setHoveredParcel(parcel.parcel_id)}
+ onFocus={() => setHoveredParcel(parcel.parcel_id)}
+ onMouseOut={() => setHoveredParcel(null)}
+ onBlur={() => setHoveredParcel(null)}
+ >
+ {header}
+ {address}
+ {label} |
+ {toAcres(count)} |
+
+ );
+ }));
});
return (
@@ -111,26 +127,6 @@ export default function StudyAreaTable(props) {
{rows}
-
- {
- (highlightedCode)
- ? (
- <>
-
-
{landuseCodes[highlightedCode].name}
- >
- )
- :
- }
-
);
}
diff --git a/frontend/src/index.css b/frontend/src/index.css
index a183452..c8fd7f3 100644
--- a/frontend/src/index.css
+++ b/frontend/src/index.css
@@ -81,7 +81,7 @@ html, body, #root, .App {
display: flex;
/*height: 1rem;/*
/*padding-bottom: 2rem;*/
- width: 250px;
+ width: 350px;
position: absolute;
bottom: 1rem;
right: 1rem;
@@ -114,7 +114,7 @@ html, body, #root, .App {
.panel {
background-color: rgba(240, 240, 240, 1.0);
- filter: drop-shadow(1px 1px 1px grey);
+ filter: drop-shadow(0px 0px 3px grey);
padding: 0.5rem;
}
@@ -122,6 +122,32 @@ html, body, #root, .App {
padding-top: 0.5rem;
}
+#landuse-select-form {
+ display: flex;
+ flex-direction: column;
+}
+
+.lulc-select {
+ margin-top: 0.5rem;
+ margin-bottom: 0.5rem;
+}
+
+.lulc-select p {
+ display: inline-block;
+ white-space: nowrap;
+ width: 16%;
+}
+
+.lulc-select #nlud-subtype {
+ display:inline-block;
+ font-style: italic;
+}
+
+.lulc-select .bp4-html-select {
+ margin-left: 1rem;
+ margin-right: 1rem;
+}
+
.wallpaper-options {
display: inline-block;
vertical-align: top;
@@ -188,36 +214,46 @@ html, body, #root, .App {
.study-area-table {
margin-top: 0.5rem;
border-collapse: collapse;
+ width: 100%;
+ margin-bottom: 0.75rem;
}
-.study-area-table tr {
+.study-area-table .address-row {
border: solid;
border-color: lightgray;
border-width: 0.5px 0;
+ border-bottom: none;
}
.study-area-table tr:first-child {
border-top: none;
}
+.study-area-table tr:last-child {
+ border: solid;
+ border-color: lightgray;
+ border-width: 0.5px 0;
+ border-top: none;
+}
+
.study-area-table .parcel-address {
- width: 200px;
+ width: 120px;
}
-.study-area-table .parcel-block {
+/*.study-area-table .parcel-block {
display: flex;
flex-wrap: wrap;
-}
+}*/
.study-area-table .hidden-row {
display: none;
}
-.study-area-table-legend {
+/*.study-area-table-legend {
display: flex;
height: 1rem;
padding-bottom: 2rem;
-}
+}*/
#scenario-table {
padding-top: 1rem;
diff --git a/frontend/src/map/legendControl.jsx b/frontend/src/map/legendControl.jsx
index f79e144..2106a76 100644
--- a/frontend/src/map/legendControl.jsx
+++ b/frontend/src/map/legendControl.jsx
@@ -1,33 +1,71 @@
import React, { useState } from 'react';
-import landuseCodes from '../../../appdata/NLCD_2016.lulcdata.json';
+import { HTMLSelect } from '@blueprintjs/core';
+import landuseCodes from '../../../appdata/lulc_crosswalk.json';
+import nlcdLookup from '../../../appdata/nlcd_colormap.json';
+import nludLookup from '../../../appdata/nlud_colormap.json';
+import treeLookup from '../../../appdata/tree_colormap.json';
+
+const LULC_LOOKUP = {
+ nlcd: nlcdLookup,
+ nlud: nludLookup,
+ tree: treeLookup,
+};
+
+const LULC_TYPES = {
+ nlcd: 'landcover',
+ nlud: 'landuse',
+ tree: 'tree cover',
+};
export default function LegendControl(props) {
const {
lulcCode,
+ setLulcStyle,
+ show,
} = props;
+ const [lulcType, setLulcType] = useState('nlcd');
+
+ const changeLulc = (event) => {
+ setLulcType(event.target.value);
+ setLulcStyle(event.target.value);
+ };
return (
{
- (lulcCode)
+ (show)
? (
- <>
-
-
-
{landuseCodes[lulcCode].name}
-
- >
+
+
+ {Object.entries(LULC_TYPES).map(
+ ([type, label]) =>
+ )}
+
+ {
+ (lulcCode)
+ ? (
+ <>
+
+
{LULC_LOOKUP[lulcType][landuseCodes[lulcCode][lulcType]].name}
+ >
+ )
+ :
+ }
+
)
:
}
diff --git a/frontend/src/map/lulcLayer.js b/frontend/src/map/lulcLayer.js
index 10946a3..4ec1b7b 100644
--- a/frontend/src/map/lulcLayer.js
+++ b/frontend/src/map/lulcLayer.js
@@ -1,72 +1,70 @@
import GeoTIFF from 'ol/source/GeoTIFF';
import TileLayer from 'ol/layer/WebGLTile';
-import ImageLayer from 'ol/layer/Image';
-import landuseCodes from '../../../appdata/NLCD_2016.lulcdata.json';
import { publicUrl } from '../utils';
+import landuseCodes from '../../../appdata/lulc_crosswalk.json';
+import nlcdLookup from '../../../appdata/nlcd_colormap.json';
+import nludLookup from '../../../appdata/nlud_colormap.json';
+import treeLookup from '../../../appdata/tree_colormap.json';
-const colors = Array(256).fill('#000000');
+// landuseCodes range from 0 to 2400, allow 3000 indices.
+const nlcdColors = Array(3000).fill('#000000');
+const nludColors = Array(3000).fill('#000000');
+const treeColors = Array(3000).fill('#000000');
Object.entries(landuseCodes).forEach(([code, data]) => {
- colors[code] = data.color;
+ nlcdColors[code] = nlcdLookup[data.nlcd].color;
+});
+Object.entries(landuseCodes).forEach(([code, data]) => {
+ nludColors[code] = nludLookup[data.nlud].color;
+});
+Object.entries(landuseCodes).forEach(([code, data]) => {
+ treeColors[code] = treeLookup[data.tree].color;
});
-export function lulcTileLayer(url, title, type, sourceOptions) {
- const source = new GeoTIFF({
- sources: [{
- url: publicUrl(url),
- projection: 'EPSG:3857',
- }],
- interpolate: false,
- sourceOptions: sourceOptions,
- });
+const COLORMAPS = {
+ nlcd: nlcdColors,
+ nlud: nludColors,
+ tree: treeColors,
+};
- return new TileLayer({
- source: source,
- title: title,
- type: type,
- visible: false,
- style: {
- // https://openlayers.org/en/latest/apidoc/module-ol_style_expressions.html#~ExpressionValue
- // https://github.com/openlayers/openlayers/blob/main/test/rendering/cases/webgl-palette/main.js
- color: [
+export function getStyle(lulcType) {
+ // https://openlayers.org/en/latest/apidoc/module-ol_style_expressions.html#~ExpressionValue
+ // https://github.com/openlayers/openlayers/blob/main/test/rendering/cases/webgl-palette/main.js
+ return {
+ color: [
+ // the GeoTIFF source reads the nodata value from the file
+ // and creates band 2 for use as alpha values.
+ // https://github.com/openlayers/openlayers/issues/13588#issuecomment-1125317573
+ 'case',
+ ['==', ['band', 2], 0],
+ '#00000000',
+ [
'palette',
- // band values now in rgb-space; *255 to get original values
- ['*', ['band', 1], 255],
- colors,
+ ['band', 1],
+ COLORMAPS[lulcType],
],
- saturation: -0.5,
- contrast: 0.0,
- },
- });
+ ],
+ saturation: -0.5,
+ contrast: 0.0,
+ };
}
-// TODO: unused
-export function lulcImageLayer(url, title) {
+export function lulcTileLayer(url, title, type, sourceOptions) {
const source = new GeoTIFF({
sources: [{
url: publicUrl(url),
projection: 'EPSG:3857',
}],
interpolate: false,
+ normalize: false,
+ sourceOptions: sourceOptions,
});
- return new ImageLayer({
+ return new TileLayer({
source: source,
title: title,
- type: 'base',
+ type: type,
visible: false,
- style: {
- // https://openlayers.org/en/latest/apidoc/module-ol_style_expressions.html#~ExpressionValue
- // https://github.com/openlayers/openlayers/blob/main/test/rendering/cases/webgl-palette/main.js
- color: [
- 'palette',
- // band values now in rgb-space; *255 to get original values
- ['*', ['band', 1], 255],
- colors,
- ],
- saturation: -0.3,
- contrast: -0.4,
- }
+ style: getStyle('nlcd'),
});
}
-
diff --git a/frontend/src/map/map.jsx b/frontend/src/map/map.jsx
index ab92866..8a2cd0d 100644
--- a/frontend/src/map/map.jsx
+++ b/frontend/src/map/map.jsx
@@ -34,7 +34,7 @@ import { Button, Icon } from '@blueprintjs/core';
import ParcelControl from './parcelControl';
import LegendControl from './legendControl';
-import { lulcTileLayer } from './lulcLayer';
+import { lulcTileLayer, getStyle } from './lulcLayer';
import LayerPanel from './LayerPanel';
import {
satelliteLayer,
@@ -53,17 +53,8 @@ import {
import { publicUrl } from '../utils';
-const BASE_LULC_URL = 'https://storage.googleapis.com/natcap-urban-online-datasets-public/NLCD_2016_epsg3857.tif'
-const GEOTIFF_SOURCE_OPTIONS = {
- allowFullFile: true,
- blockSize: 256,
- maxRanges: 1, // doesn't seem to work as advertised
- headers: {
- // 'range' is case-sensitive, despite the fact that browser & docs
- // capitalize 'Range'.
- // 'range': 'bytes=0-3356',
- }
-};
+const GCS_BUCKET = 'https://storage.googleapis.com/natcap-urban-online-datasets-public';
+const BASE_LULC_URL = `${GCS_BUCKET}/lulc_overlay_3857.tif`
const SCENARIO_LAYER_GROUP_NAME = 'Scenarios';
// JSTS utilities
@@ -159,11 +150,13 @@ serviceshedLayer.setZIndex(3);
// Set a default basemap to be visible
satelliteLayer.setVisible(true);
+const lulcLayer = lulcTileLayer(BASE_LULC_URL, 'Landcover', 'base');
+
const map = new Map({
layers: [
satelliteLayer,
streetMapLayer,
- lulcTileLayer(BASE_LULC_URL, 'Landcover', 'base'),
+ lulcLayer,
parcelLayer,
selectionLayer,
hoveredLayer,
@@ -201,6 +194,7 @@ export default function MapComponent(props) {
const [showLayerControl, setShowLayerControl] = useState(false);
const [selectedParcel, setSelectedParcel] = useState(null);
const [hoveredCode, setHoveredCode] = useState(null);
+ const [showLegendControl, setShowLegendControl] = useState(false);
// refs for elements to insert openlayers-controlled nodes into the dom
const mapElementRef = useRef();
@@ -241,6 +235,7 @@ export default function MapComponent(props) {
map.getLayers().forEach(lyr => {
if (lyr.get('title') === title) {
lyr.setVisible(visible);
+ setShowLegendControl(lyr.get('type') === 'scenario-group')
}
});
setMapLayers();
@@ -252,18 +247,27 @@ export default function MapComponent(props) {
layer.setVisible(layer.get('title') === title);
}
});
+ setShowLegendControl(title === 'Landcover');
setMapLayers();
};
const switchScenario = (title) => {
map.getAllLayers().forEach((layer) => {
if (layer.get('type') === 'scenario') {
- layer.setVisible(layer.get('title') === title)
+ layer.setVisible(layer.get('title') === title);
}
});
setMapLayers();
};
+ const setLulcStyle = (lulcType) => {
+ map.getAllLayers().forEach((layer) => {
+ if (layer.get('type') === 'scenario' || layer.get('title') === 'Landcover') {
+ layer.setStyle(getStyle(lulcType));
+ }
+ });
+ };
+
const toggleLayerControl = () => {
if (showLayerControl) {
setShowLayerControl(false);
@@ -379,10 +383,10 @@ export default function MapComponent(props) {
}
}
});
- if (scenarioData) {
+ if (scenarioData && scenarioData[1]) { // check band [1] for nodata
// Get here if a Scenario LULC is visible
setHoveredCode(scenarioData[0].toString());
- } else if (baseData) {
+ } else if (baseData && baseData[1]) {
// Base LULC visible but no Scenario LULC visible
setHoveredCode(baseData[0].toString());
} else {
@@ -445,6 +449,7 @@ export default function MapComponent(props) {
scenarioLayers.push(mostRecentLyr);
scenarioLayerGroup.setLayers(new Collection(scenarioLayers));
map.addLayer(scenarioLayerGroup);
+ setShowLegendControl(true);
}
clearSelection();
}, [scenarios]);
@@ -511,7 +516,9 @@ export default function MapComponent(props) {
immutableStudyArea={Boolean(scenarios.length)}
/>
);
diff --git a/frontend/src/requests.js b/frontend/src/requests.js
index b8b7632..fd46414 100644
--- a/frontend/src/requests.js
+++ b/frontend/src/requests.js
@@ -331,4 +331,61 @@ export async function getInvestResults(scenarioID) {
.then((response) => response.json())
.catch((error) => console.log(error))
);
-}
\ No newline at end of file
+}
+
+export async function getNLUDTier2() {
+ return (
+ window.fetch(`${apiBaseURL}/lucodes/nlud_tier_2`, {
+ method: 'get',
+ headers: { 'Content-Type': 'application/json' },
+ })
+ .then((response) => response.json())
+ .catch((error) => console.log(error))
+ );
+}
+
+export async function getNLUDTier3(tier2) {
+ return (
+ window.fetch(`${apiBaseURL}/lucodes/nlud_tier_3`, {
+ method: 'post',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ nlud_tier_2: tier2,
+ }),
+ })
+ .then((response) => response.json())
+ .catch((error) => console.log(error))
+ );
+}
+
+export async function getNLCD(tier2, tier3) {
+ return (
+ window.fetch(`${apiBaseURL}/lucodes/nlcd`, {
+ method: 'post',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ nlud_tier_2: tier2,
+ nlud_tier_3: tier3,
+ }),
+ })
+ .then((response) => response.json())
+ .catch((error) => console.log(error))
+ );
+}
+
+export async function getLucode(tier2, tier3, nlcd, tree) {
+ return (
+ window.fetch(`${apiBaseURL}/lucodes/lucode`, {
+ method: 'post',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ nlud_tier_2: tier2,
+ nlud_tier_3: tier3,
+ nlcd: nlcd,
+ tree: tree,
+ }),
+ })
+ .then((response) => response.json())
+ .catch((error) => console.log(error))
+ );
+}
diff --git a/frontend/src/utils.js b/frontend/src/utils.js
index 2b9a13a..b99bd85 100644
--- a/frontend/src/utils.js
+++ b/frontend/src/utils.js
@@ -1,13 +1,24 @@
/**
* The vite dev server serves `/opt/appdata/` at the root `/` path.
* So filenames beginning with that path need to be adjusted.
- *
- * @param {string} filepath
+ *
+ * @param {string} filepath
* @return {string}
*/
export function publicUrl(filepath) {
- if (filepath.startsWith('/opt/appdata/')) {
+ if (filepath.startsWith('/opt/appdata/')) {
return filepath.replace('/opt/appdata/', 'http://localhost:9000/')
}
return filepath;
}
+
+/**
+ * convert counts of pixels to acres
+ */
+export function toAcres(count) {
+ if (!parseInt(count)) {
+ return '';
+ }
+ const acres = (count * 30 * 30) / 4047; // square-meters to acres
+ return acres.toFixed(1);
+}
diff --git a/frontend/tests/app.test.jsx b/frontend/tests/app.test.jsx
index 93b38b8..bf3d5a7 100644
--- a/frontend/tests/app.test.jsx
+++ b/frontend/tests/app.test.jsx
@@ -26,6 +26,10 @@ vi.mock('../src/requests', () => {
runInvest: () => JOBS,
getInvestResults: () => INVEST_RESULT,
getPatterns: () => null,
+ getNLUDTier2: () => [],
+ getNLUDTier3: () => [],
+ getNLCD: () => [],
+ getLucode: () => null,
};
});
@@ -82,7 +86,9 @@ test('results panel is linked to map layers', async () => {
expect(radioB).toBeChecked();
});
-test('wallpapering toggle is linked to map layers', async () => {
+// Wallpapering is currently disabled.
+// https://github.com/natcap/urban-online-workflow/issues/125
+test.skip('wallpapering toggle is linked to map layers', async () => {
const user = userEvent.setup();
const screen = renderAppWithResults();
diff --git a/frontend/tests/edit.test.jsx b/frontend/tests/edit.test.jsx
index 80d7739..a16ab4c 100644
--- a/frontend/tests/edit.test.jsx
+++ b/frontend/tests/edit.test.jsx
@@ -12,6 +12,10 @@ import INVEST_RESULT from './fixtures/investResult.json';
vi.mock('../src/requests', () => {
return {
getInvestResults: () => INVEST_RESULT,
+ getNLUDTier2: () => [],
+ getNLUDTier3: () => [],
+ getNLCD: () => [],
+ getLucode: () => null,
};
});
@@ -48,7 +52,7 @@ test('no parcel present in study area', async () => {
const studyAreaTable = await screen.queryByRole('table');
expect(studyAreaTable).toBeNull();
- const scenarioBuilder = await screen.queryByText(/Modify the landuse/);
+ const scenarioBuilder = await screen.queryByText(/choose new landuse/);
expect(scenarioBuilder).toBeNull();
const createScenario = await screen.queryByText(/Create a scenario/);
@@ -61,24 +65,20 @@ test('parcel present in study area, without scenarios', async () => {
const addressCell = await screen.findByText(STUDY_AREA.parcels[0].address);
- const scenarioBuilder = await screen.getByText('Modify the landuse in this study area:');
- expect(scenarioBuilder).toBeInTheDocument();
const createScenario = await screen.getByText(/Create a scenario/);
expect(createScenario).toBeInTheDocument();
});
-test('scenarios exist', async () => {
+test('scenarios & results exist', async () => {
const screen = renderEdit(STUDY_AREA, SCENARIOS);
- const tableText = await screen.findByText(
- /Landcover composition by scenario/
- );
+ const tableText = await screen.findByText(/baseline/);
const table = tableText.closest('table');
const rows = within(table).getAllByRole('row');
const cols = within(rows[1]).getAllByRole('cell');
- expect(rows).toHaveLength(4); // number of diff lulc types represented, + header
+ expect(rows).toHaveLength(2); // number of diff lulc types represented, + header
expect(cols).toHaveLength(SCENARIOS.length + 1);
const investBtn = await screen.getByRole('button', { name: /Evaluate Impacts/ });
- expect(investBtn).toBeEnabled();
+ await waitFor(() => expect(investBtn).not.toBeEnabled());
});
diff --git a/frontend/tests/fixtures/scenarios.json b/frontend/tests/fixtures/scenarios.json
index 3f8e73a..d58a351 100644
--- a/frontend/tests/fixtures/scenarios.json
+++ b/frontend/tests/fixtures/scenarios.json
@@ -6,7 +6,7 @@
"study_area_id": 75,
"lulc_url_result": "/foo/opt/appdata/scenarios/14/14_lulc_crop.tif",
"lulc_url_base": "NLCD_2016_epsg3857.tif",
- "lulc_stats": "{\"21\": 4, \"22\": 4}"
+ "lulc_stats": "{\"nlcd\": {\"11\": 5396}, \"nlud\": {\"1\": 5396}, \"tree\": {\"0\": 5396}}"
},
{
"name": "a1",
@@ -15,7 +15,7 @@
"study_area_id": 75,
"lulc_url_result": "/foo/opt/appdata/scenarios/15/15_lulc_fill.tif",
"lulc_url_base": "NLCD_2016_epsg3857.tif",
- "lulc_stats": "{\"11\": 8}"
+ "lulc_stats": "{\"nlcd\": {\"11\": 5396}, \"nlud\": {\"1\": 5396}, \"tree\": {\"0\": 5396}}"
},
{
"name": "b1",
@@ -24,6 +24,6 @@
"study_area_id": 75,
"lulc_url_result": "/foo/opt/appdata/scenarios/16/16_lulc_fill.tif",
"lulc_url_base": "NLCD_2016_epsg3857.tif",
- "lulc_stats": "{\"21\": 8}"
+ "lulc_stats": "{\"nlcd\": {\"11\": 5396}, \"nlud\": {\"1\": 5396}, \"tree\": {\"0\": 5396}}"
}
]
\ No newline at end of file
diff --git a/frontend/tests/fixtures/studyArea.json b/frontend/tests/fixtures/studyArea.json
index 33c5ee9..7f37bb9 100644
--- a/frontend/tests/fixtures/studyArea.json
+++ b/frontend/tests/fixtures/studyArea.json
@@ -7,8 +7,8 @@
"wkt": "POLYGON ((-10965116.390570192 3426536.1231499603, -10965106.537359515 3426533.286619614, -10965090.26463279 3426528.509305346, -10965072.946868569 3426523.1348267947, -10965070.856793577 3426477.3024680377, -10965069.961047152 3426462.5226520216, -10965106.089486303 3426461.925487738, -10965107.731688082 3426465.8070555804, -10965112.956875563 3426473.868773408, -10965119.227100538 3426482.676946589, -10965125.646616586 3426491.335828699, -10965134.305498697 3426502.084785802, -10965143.56154509 3426512.684451834, -10965153.265464697 3426522.686953582, -10965148.338859359 3426524.3291553613, -10965126.24378087 3426532.5401642593, -10965116.390570192 3426536.1231499603))",
"address": "111 PARKROW",
"parcel_stats": {
- "lulc_stats": "{\"base\": {\"21\": 4, \"22\": 3}}"
+ "lulc_stats": "{\"nlcd\": {\"22\": 18, \"41\": 21}, \"nlud\": {\"14\": 5}, \"tree\": {\"1\": 281}}"
}
}
]
-}
\ No newline at end of file
+}
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index 6a467e5..2b29a9f 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -319,115 +319,115 @@
esquery "^1.4.0"
jsdoc-type-pratt-parser "~3.1.0"
-"@esbuild/android-arm64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz#bafb75234a5d3d1b690e7c2956a599345e84a2fd"
- integrity sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==
-
-"@esbuild/android-arm@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.17.19.tgz#5898f7832c2298bc7d0ab53701c57beb74d78b4d"
- integrity sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==
-
-"@esbuild/android-x64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.17.19.tgz#658368ef92067866d95fb268719f98f363d13ae1"
- integrity sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==
-
-"@esbuild/darwin-arm64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz#584c34c5991b95d4d48d333300b1a4e2ff7be276"
- integrity sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==
-
-"@esbuild/darwin-x64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz#7751d236dfe6ce136cce343dce69f52d76b7f6cb"
- integrity sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==
-
-"@esbuild/freebsd-arm64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz#cacd171665dd1d500f45c167d50c6b7e539d5fd2"
- integrity sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==
-
-"@esbuild/freebsd-x64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz#0769456eee2a08b8d925d7c00b79e861cb3162e4"
- integrity sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==
-
-"@esbuild/linux-arm64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz#38e162ecb723862c6be1c27d6389f48960b68edb"
- integrity sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==
-
-"@esbuild/linux-arm@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz#1a2cd399c50040184a805174a6d89097d9d1559a"
- integrity sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==
-
-"@esbuild/linux-ia32@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz#e28c25266b036ce1cabca3c30155222841dc035a"
- integrity sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==
-
-"@esbuild/linux-loong64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz#0f887b8bb3f90658d1a0117283e55dbd4c9dcf72"
- integrity sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==
-
-"@esbuild/linux-mips64el@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz#f5d2a0b8047ea9a5d9f592a178ea054053a70289"
- integrity sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==
-
-"@esbuild/linux-ppc64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz#876590e3acbd9fa7f57a2c7d86f83717dbbac8c7"
- integrity sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==
-
-"@esbuild/linux-riscv64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz#7f49373df463cd9f41dc34f9b2262d771688bf09"
- integrity sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==
-
-"@esbuild/linux-s390x@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz#e2afd1afcaf63afe2c7d9ceacd28ec57c77f8829"
- integrity sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==
-
-"@esbuild/linux-x64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz#8a0e9738b1635f0c53389e515ae83826dec22aa4"
- integrity sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==
-
-"@esbuild/netbsd-x64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz#c29fb2453c6b7ddef9a35e2c18b37bda1ae5c462"
- integrity sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==
-
-"@esbuild/openbsd-x64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz#95e75a391403cb10297280d524d66ce04c920691"
- integrity sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==
-
-"@esbuild/sunos-x64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz#722eaf057b83c2575937d3ffe5aeb16540da7273"
- integrity sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==
-
-"@esbuild/win32-arm64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz#9aa9dc074399288bdcdd283443e9aeb6b9552b6f"
- integrity sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==
-
-"@esbuild/win32-ia32@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz#95ad43c62ad62485e210f6299c7b2571e48d2b03"
- integrity sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==
-
-"@esbuild/win32-x64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz#8cfaf2ff603e9aabb910e9c0558c26cf32744061"
- integrity sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==
+"@esbuild/android-arm64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622"
+ integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==
+
+"@esbuild/android-arm@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682"
+ integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==
+
+"@esbuild/android-x64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2"
+ integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==
+
+"@esbuild/darwin-arm64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz#08172cbeccf95fbc383399a7f39cfbddaeb0d7c1"
+ integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==
+
+"@esbuild/darwin-x64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d"
+ integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==
+
+"@esbuild/freebsd-arm64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54"
+ integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==
+
+"@esbuild/freebsd-x64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e"
+ integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==
+
+"@esbuild/linux-arm64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0"
+ integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==
+
+"@esbuild/linux-arm@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0"
+ integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==
+
+"@esbuild/linux-ia32@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7"
+ integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==
+
+"@esbuild/linux-loong64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d"
+ integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==
+
+"@esbuild/linux-mips64el@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231"
+ integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==
+
+"@esbuild/linux-ppc64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb"
+ integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==
+
+"@esbuild/linux-riscv64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6"
+ integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==
+
+"@esbuild/linux-s390x@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071"
+ integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==
+
+"@esbuild/linux-x64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338"
+ integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==
+
+"@esbuild/netbsd-x64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1"
+ integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==
+
+"@esbuild/openbsd-x64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae"
+ integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==
+
+"@esbuild/sunos-x64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d"
+ integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==
+
+"@esbuild/win32-arm64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9"
+ integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==
+
+"@esbuild/win32-ia32@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102"
+ integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==
+
+"@esbuild/win32-x64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d"
+ integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==
"@eslint/eslintrc@^1.3.0":
version "1.3.0"
@@ -562,17 +562,17 @@
resolved "https://registry.yarnpkg.com/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz#ce56e539f83552b58d10d672ea4d6fc9adc7b234"
integrity sha1-zlblOfg1UrWNENZy6k1vya3HsjQ=
-"@mapbox/mapbox-gl-style-spec@^13.20.1":
- version "13.23.1"
- resolved "https://registry.yarnpkg.com/@mapbox/mapbox-gl-style-spec/-/mapbox-gl-style-spec-13.23.1.tgz#481f41801517b7b52fea595f07d3633a903a250c"
- integrity sha512-C6wh8A/5EdsgzhL6y6yl464VCQNIxK0yjrpnvCvchcFe3sNK2RbBw/J9u3m+p8Y6S6MsGuSMt3AkGAXOKMYweQ==
+"@mapbox/mapbox-gl-style-spec@^13.23.1":
+ version "13.28.0"
+ resolved "https://registry.yarnpkg.com/@mapbox/mapbox-gl-style-spec/-/mapbox-gl-style-spec-13.28.0.tgz#2ec226320a0f77856046e000df9b419303a56458"
+ integrity sha512-B8xM7Fp1nh5kejfIl4SWeY0gtIeewbuRencqO3cJDrCHZpaPg7uY+V8abuR+esMeuOjRl5cLhVTP40v+1ywxbg==
dependencies:
"@mapbox/jsonlint-lines-primitives" "~2.0.2"
"@mapbox/point-geometry" "^0.1.0"
"@mapbox/unitbezier" "^0.0.0"
csscolorparser "~1.0.2"
json-stringify-pretty-compact "^2.0.0"
- minimist "^1.2.5"
+ minimist "^1.2.6"
rw "^1.3.3"
sort-object "^0.3.2"
@@ -805,44 +805,44 @@
test-exclude "^6.0.0"
v8-to-istanbul "^9.1.0"
-"@vitest/expect@0.33.0":
- version "0.33.0"
- resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-0.33.0.tgz#f48652591f3573ad6c2db828ad358d5c078845d3"
- integrity sha512-sVNf+Gla3mhTCxNJx+wJLDPp/WcstOe0Ksqz4Vec51MmgMth/ia0MGFEkIZmVGeTL5HtjYR4Wl/ZxBxBXZJTzQ==
+"@vitest/expect@0.34.6":
+ version "0.34.6"
+ resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-0.34.6.tgz#608a7b7a9aa3de0919db99b4cc087340a03ea77e"
+ integrity sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==
dependencies:
- "@vitest/spy" "0.33.0"
- "@vitest/utils" "0.33.0"
- chai "^4.3.7"
+ "@vitest/spy" "0.34.6"
+ "@vitest/utils" "0.34.6"
+ chai "^4.3.10"
-"@vitest/runner@0.33.0":
- version "0.33.0"
- resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-0.33.0.tgz#0b1a4d04ff8bc5cdad73920eac019d99550edf9d"
- integrity sha512-UPfACnmCB6HKRHTlcgCoBh6ppl6fDn+J/xR8dTufWiKt/74Y9bHci5CKB8tESSV82zKYtkBJo9whU3mNvfaisg==
+"@vitest/runner@0.34.6":
+ version "0.34.6"
+ resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-0.34.6.tgz#6f43ca241fc96b2edf230db58bcde5b974b8dcaf"
+ integrity sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==
dependencies:
- "@vitest/utils" "0.33.0"
+ "@vitest/utils" "0.34.6"
p-limit "^4.0.0"
pathe "^1.1.1"
-"@vitest/snapshot@0.33.0":
- version "0.33.0"
- resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-0.33.0.tgz#4400a90c48907808122b573053a2112a832b3698"
- integrity sha512-tJjrl//qAHbyHajpFvr8Wsk8DIOODEebTu7pgBrP07iOepR5jYkLFiqLq2Ltxv+r0uptUb4izv1J8XBOwKkVYA==
+"@vitest/snapshot@0.34.6":
+ version "0.34.6"
+ resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-0.34.6.tgz#b4528cf683b60a3e8071cacbcb97d18b9d5e1d8b"
+ integrity sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==
dependencies:
magic-string "^0.30.1"
pathe "^1.1.1"
pretty-format "^29.5.0"
-"@vitest/spy@0.33.0":
- version "0.33.0"
- resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-0.33.0.tgz#366074d3cf9cf1ed8aeaa76e50e78c799fb242eb"
- integrity sha512-Kv+yZ4hnH1WdiAkPUQTpRxW8kGtH8VRTnus7ZTGovFYM1ZezJpvGtb9nPIjPnptHbsyIAxYZsEpVPYgtpjGnrg==
+"@vitest/spy@0.34.6":
+ version "0.34.6"
+ resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-0.34.6.tgz#b5e8642a84aad12896c915bce9b3cc8cdaf821df"
+ integrity sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==
dependencies:
tinyspy "^2.1.1"
-"@vitest/utils@0.33.0":
- version "0.33.0"
- resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-0.33.0.tgz#6b9820cb8f128d649da6f78ecaa9b73d6222b277"
- integrity sha512-pF1w22ic965sv+EN6uoePkAOTkAPWM03Ri/jXNyMIKBb/XHLDPfhLvf/Fa9g0YECevAIz56oVYXhodLvLQ/awA==
+"@vitest/utils@0.34.6":
+ version "0.34.6"
+ resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-0.34.6.tgz#38a0a7eedddb8e7291af09a2409cb8a189516968"
+ integrity sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==
dependencies:
diff-sequences "^29.4.3"
loupe "^2.3.6"
@@ -1145,18 +1145,18 @@ capital-case@^1.0.4:
tslib "^2.0.3"
upper-case-first "^2.0.2"
-chai@^4.3.7:
- version "4.3.7"
- resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.7.tgz#ec63f6df01829088e8bf55fca839bcd464a8ec51"
- integrity sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==
+chai@^4.3.10:
+ version "4.3.10"
+ resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.10.tgz#d784cec635e3b7e2ffb66446a63b4e33bd390384"
+ integrity sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==
dependencies:
assertion-error "^1.1.0"
- check-error "^1.0.2"
- deep-eql "^4.1.2"
- get-func-name "^2.0.0"
- loupe "^2.3.1"
+ check-error "^1.0.3"
+ deep-eql "^4.1.3"
+ get-func-name "^2.0.2"
+ loupe "^2.3.6"
pathval "^1.1.1"
- type-detect "^4.0.5"
+ type-detect "^4.0.8"
chalk@^2.0.0:
version "2.4.2"
@@ -1201,10 +1201,12 @@ change-case@^4.1.2:
snake-case "^3.0.4"
tslib "^2.0.3"
-check-error@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
- integrity sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==
+check-error@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694"
+ integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==
+ dependencies:
+ get-func-name "^2.0.2"
chromium-bidi@0.4.16:
version "0.4.16"
@@ -1408,7 +1410,7 @@ decimal.js@^10.4.3:
resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23"
integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==
-deep-eql@^4.1.2:
+deep-eql@^4.1.3:
version "4.1.3"
resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d"
integrity sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==
@@ -1653,33 +1655,33 @@ es-to-primitive@^1.2.1:
is-date-object "^1.0.1"
is-symbol "^1.0.2"
-esbuild@^0.17.5:
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.17.19.tgz#087a727e98299f0462a3d0bcdd9cd7ff100bd955"
- integrity sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==
+esbuild@^0.18.10:
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.18.20.tgz#4709f5a34801b43b799ab7d6d82f7284a9b7a7a6"
+ integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==
optionalDependencies:
- "@esbuild/android-arm" "0.17.19"
- "@esbuild/android-arm64" "0.17.19"
- "@esbuild/android-x64" "0.17.19"
- "@esbuild/darwin-arm64" "0.17.19"
- "@esbuild/darwin-x64" "0.17.19"
- "@esbuild/freebsd-arm64" "0.17.19"
- "@esbuild/freebsd-x64" "0.17.19"
- "@esbuild/linux-arm" "0.17.19"
- "@esbuild/linux-arm64" "0.17.19"
- "@esbuild/linux-ia32" "0.17.19"
- "@esbuild/linux-loong64" "0.17.19"
- "@esbuild/linux-mips64el" "0.17.19"
- "@esbuild/linux-ppc64" "0.17.19"
- "@esbuild/linux-riscv64" "0.17.19"
- "@esbuild/linux-s390x" "0.17.19"
- "@esbuild/linux-x64" "0.17.19"
- "@esbuild/netbsd-x64" "0.17.19"
- "@esbuild/openbsd-x64" "0.17.19"
- "@esbuild/sunos-x64" "0.17.19"
- "@esbuild/win32-arm64" "0.17.19"
- "@esbuild/win32-ia32" "0.17.19"
- "@esbuild/win32-x64" "0.17.19"
+ "@esbuild/android-arm" "0.18.20"
+ "@esbuild/android-arm64" "0.18.20"
+ "@esbuild/android-x64" "0.18.20"
+ "@esbuild/darwin-arm64" "0.18.20"
+ "@esbuild/darwin-x64" "0.18.20"
+ "@esbuild/freebsd-arm64" "0.18.20"
+ "@esbuild/freebsd-x64" "0.18.20"
+ "@esbuild/linux-arm" "0.18.20"
+ "@esbuild/linux-arm64" "0.18.20"
+ "@esbuild/linux-ia32" "0.18.20"
+ "@esbuild/linux-loong64" "0.18.20"
+ "@esbuild/linux-mips64el" "0.18.20"
+ "@esbuild/linux-ppc64" "0.18.20"
+ "@esbuild/linux-riscv64" "0.18.20"
+ "@esbuild/linux-s390x" "0.18.20"
+ "@esbuild/linux-x64" "0.18.20"
+ "@esbuild/netbsd-x64" "0.18.20"
+ "@esbuild/openbsd-x64" "0.18.20"
+ "@esbuild/sunos-x64" "0.18.20"
+ "@esbuild/win32-arm64" "0.18.20"
+ "@esbuild/win32-ia32" "0.18.20"
+ "@esbuild/win32-x64" "0.18.20"
escalade@^3.1.1:
version "3.1.1"
@@ -2104,16 +2106,16 @@ gensync@^1.0.0-beta.2:
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
-geotiff@^2.0.2:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/geotiff/-/geotiff-2.0.5.tgz#ef94227aba5c1b64167b49c44304b1fea5b01c95"
- integrity sha512-U5kVYm118YAmw2swiLu8rhfrYnDKOFI7VaMjuQwcq6Intuuid9Pyb4jjxYUxxkq8kOu2r7Am0Rmb52PObGp4pQ==
+geotiff@2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/geotiff/-/geotiff-2.0.4.tgz#d6f231fdd76186aba21c61823ed759fcbf5d4f86"
+ integrity sha512-aG8h9bJccGusioPsEWsEqx8qdXpZN71A20WCvRKGxcnHSOWLKmC5ZmsAmodfxb9TRQvs+89KikGuPzxchhA+Uw==
dependencies:
"@petamoriken/float16" "^3.4.7"
lerc "^3.0.0"
+ lru-cache "^6.0.0"
pako "^2.0.4"
parse-headers "^2.0.2"
- quick-lru "^6.1.0"
web-worker "^1.2.0"
xml-utils "^1.0.2"
@@ -2127,6 +2129,11 @@ get-func-name@^2.0.0:
resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41"
integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==
+get-func-name@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41"
+ integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==
+
get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6"
@@ -2878,13 +2885,6 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
-loupe@^2.3.1:
- version "2.3.4"
- resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.4.tgz#7e0b9bffc76f148f9be769cb1321d3dcf3cb25f3"
- integrity sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==
- dependencies:
- get-func-name "^2.0.0"
-
loupe@^2.3.6:
version "2.3.6"
resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.6.tgz#76e4af498103c532d1ecc9be102036a21f787b53"
@@ -2981,7 +2981,7 @@ minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2:
dependencies:
brace-expansion "^1.1.7"
-minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6:
+minimist@^1.2.0, minimist@^1.2.6:
version "1.2.6"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
@@ -3144,22 +3144,21 @@ object.values@^1.1.5:
define-properties "^1.1.3"
es-abstract "^1.19.1"
-ol-mapbox-style@^7.1.1:
- version "7.1.1"
- resolved "https://registry.yarnpkg.com/ol-mapbox-style/-/ol-mapbox-style-7.1.1.tgz#cf33c39badd943c25fc438c689bf678f9aa847a2"
- integrity sha512-GLTEYiH/Ec9Zn1eS4S/zXyR2sierVrUc+OLVP8Ra0FRyqRhoYbXdko0b7OIeSHWdtJfHssWYefDOGxfTRUUZ/A==
+ol-mapbox-style@^8.0.5:
+ version "8.2.1"
+ resolved "https://registry.yarnpkg.com/ol-mapbox-style/-/ol-mapbox-style-8.2.1.tgz#0f0c252b6495853a137d7e4dd3f915fab664b356"
+ integrity sha512-3kBBuZC627vDL8vnUdfVbCbfkhkcZj2kXPHQcuLhC4JJEA+XkEVEtEde8x8+AZctRbHwBkSiubTPaRukgLxIRw==
dependencies:
- "@mapbox/mapbox-gl-style-spec" "^13.20.1"
+ "@mapbox/mapbox-gl-style-spec" "^13.23.1"
mapbox-to-css-font "^2.4.1"
- webfont-matcher "^1.1.0"
-ol@latest:
- version "6.14.1"
- resolved "https://registry.yarnpkg.com/ol/-/ol-6.14.1.tgz#8061bdcf7cd67a665fc8e76545442a702cbc7282"
- integrity sha512-sIcUWkGud3Y2gT3TJubSHlkyMXiPVh1yxfCPHxmY8+qtm79bB9oRnei9xHVIbRRG0Ro6Ldp5E+BMVSvYCxSpaA==
+ol@^6.15.1:
+ version "6.15.1"
+ resolved "https://registry.yarnpkg.com/ol/-/ol-6.15.1.tgz#364f459939ef71f970b2376a821a896529f65e3a"
+ integrity sha512-ZG2CKTpJ8Q+tPywYysVwPk+yevwJzlbwjRKhoCvd7kLVWMbfBl1O/+Kg/yrZZrhG9FNXbFH4GeOZ5yVRqo3P4w==
dependencies:
- geotiff "^2.0.2"
- ol-mapbox-style "^7.1.1"
+ geotiff "2.0.4"
+ ol-mapbox-style "^8.0.5"
pbf "3.2.1"
rbush "^3.0.1"
@@ -3391,10 +3390,10 @@ popper.js@^1.14.4, popper.js@^1.16.1:
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b"
integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==
-postcss@^8.4.23:
- version "8.4.24"
- resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.24.tgz#f714dba9b2284be3cc07dbd2fc57ee4dc972d2df"
- integrity sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==
+postcss@^8.4.27:
+ version "8.4.29"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.29.tgz#33bc121cf3b3688d4ddef50be869b2a54185a1dd"
+ integrity sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw==
dependencies:
nanoid "^3.3.6"
picocolors "^1.0.0"
@@ -3520,11 +3519,6 @@ queue-tick@^1.0.1:
resolved "https://registry.yarnpkg.com/queue-tick/-/queue-tick-1.0.1.tgz#f6f07ac82c1fd60f82e098b417a80e52f1f4c142"
integrity sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==
-quick-lru@^6.1.0:
- version "6.1.1"
- resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-6.1.1.tgz#f8e5bf9010376c126c80c1a62827a526c0e60adf"
- integrity sha512-S27GBT+F0NTRiehtbrgaSE1idUAJ5bX8dPAQTdylEyNlrdcH5X4Lz7Edz3DYzecbsCluD5zO8ZNEe04z3D3u6Q==
-
quickselect@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/quickselect/-/quickselect-2.0.0.tgz#f19680a486a5eefb581303e023e98faaf25dd018"
@@ -3682,10 +3676,10 @@ rimraf@^3.0.2:
dependencies:
glob "^7.1.3"
-rollup@^3.21.0:
- version "3.25.3"
- resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.25.3.tgz#f9a8986f0f244bcfde2208da91ba46b8fd252551"
- integrity sha512-ZT279hx8gszBj9uy5FfhoG4bZx8c+0A1sbqtr7Q3KNWIizpTdDEPZbV2xcbvHsnFp4MavCQYZyzApJ+virB8Yw==
+rollup@^3.27.1:
+ version "3.29.0"
+ resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.0.tgz#1b40e64818afc979c7e5bef93de675829288986b"
+ integrity sha512-nszM8DINnx1vSS+TpbWKMkxem0CDWk3cSit/WWCBVs9/JZ1I/XLwOsiUglYuYReaeWWSsW9kge5zE5NZtf/a4w==
optionalDependencies:
fsevents "~2.3.2"
@@ -4026,10 +4020,10 @@ tinybench@^2.5.0:
resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.5.0.tgz#4711c99bbf6f3e986f67eb722fed9cddb3a68ba5"
integrity sha512-kRwSG8Zx4tjF9ZiyH4bhaebu+EDz1BOx9hOigYHlUW4xxI/wKIUQUqo018UlU4ar6ATPBsaMrdbKZ+tmPdohFA==
-tinypool@^0.6.0:
- version "0.6.0"
- resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-0.6.0.tgz#c3640b851940abe2168497bb6e43b49fafb3ba7b"
- integrity sha512-FdswUUo5SxRizcBc6b1GSuLpLjisa8N8qMyYoP3rl+bym+QauhtJP5bvZY1ytt8krKGmMLYIRl36HBZfeAoqhQ==
+tinypool@^0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-0.7.0.tgz#88053cc99b4a594382af23190c609d93fddf8021"
+ integrity sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==
tinyspy@^2.1.1:
version "2.1.1"
@@ -4109,7 +4103,7 @@ type-check@~0.3.2:
dependencies:
prelude-ls "~1.1.2"
-type-detect@^4.0.0, type-detect@^4.0.5:
+type-detect@^4.0.0, type-detect@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
@@ -4217,46 +4211,57 @@ v8-to-istanbul@^9.1.0:
"@types/istanbul-lib-coverage" "^2.0.1"
convert-source-map "^1.6.0"
-vite-node@0.33.0:
- version "0.33.0"
- resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-0.33.0.tgz#c6a3a527e0b8090da7436241bc875760ae0eef28"
- integrity sha512-19FpHYbwWWxDr73ruNahC+vtEdza52kA90Qb3La98yZ0xULqV8A5JLNPUff0f5zID4984tW7l3DH2przTJUZSw==
+vite-node@0.34.6:
+ version "0.34.6"
+ resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-0.34.6.tgz#34d19795de1498562bf21541a58edcd106328a17"
+ integrity sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==
dependencies:
cac "^6.7.14"
debug "^4.3.4"
mlly "^1.4.0"
pathe "^1.1.1"
picocolors "^1.0.0"
- vite "^3.0.0 || ^4.0.0"
+ vite "^3.0.0 || ^4.0.0 || ^5.0.0-0"
+
+"vite@^3.0.0 || ^4.0.0 || ^5.0.0-0", "vite@^3.1.0 || ^4.0.0 || ^5.0.0-0":
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/vite/-/vite-4.5.0.tgz#ec406295b4167ac3bc23e26f9c8ff559287cff26"
+ integrity sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==
+ dependencies:
+ esbuild "^0.18.10"
+ postcss "^8.4.27"
+ rollup "^3.27.1"
+ optionalDependencies:
+ fsevents "~2.3.2"
-"vite@^3.0.0 || ^4.0.0", vite@^4.3.9:
- version "4.3.9"
- resolved "https://registry.yarnpkg.com/vite/-/vite-4.3.9.tgz#db896200c0b1aa13b37cdc35c9e99ee2fdd5f96d"
- integrity sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==
+vite@^4.4.9:
+ version "4.4.9"
+ resolved "https://registry.yarnpkg.com/vite/-/vite-4.4.9.tgz#1402423f1a2f8d66fd8d15e351127c7236d29d3d"
+ integrity sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==
dependencies:
- esbuild "^0.17.5"
- postcss "^8.4.23"
- rollup "^3.21.0"
+ esbuild "^0.18.10"
+ postcss "^8.4.27"
+ rollup "^3.27.1"
optionalDependencies:
fsevents "~2.3.2"
-vitest@^0.33.0:
- version "0.33.0"
- resolved "https://registry.yarnpkg.com/vitest/-/vitest-0.33.0.tgz#e2be6153aec1d30e3460ac6d64265bf72da2551c"
- integrity sha512-1CxaugJ50xskkQ0e969R/hW47za4YXDUfWJDxip1hwbnhUjYolpfUn2AMOulqG/Dtd9WYAtkHmM/m3yKVrEejQ==
+vitest@^0.34.0:
+ version "0.34.6"
+ resolved "https://registry.yarnpkg.com/vitest/-/vitest-0.34.6.tgz#44880feeeef493c04b7f795ed268f24a543250d7"
+ integrity sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==
dependencies:
"@types/chai" "^4.3.5"
"@types/chai-subset" "^1.3.3"
"@types/node" "*"
- "@vitest/expect" "0.33.0"
- "@vitest/runner" "0.33.0"
- "@vitest/snapshot" "0.33.0"
- "@vitest/spy" "0.33.0"
- "@vitest/utils" "0.33.0"
+ "@vitest/expect" "0.34.6"
+ "@vitest/runner" "0.34.6"
+ "@vitest/snapshot" "0.34.6"
+ "@vitest/spy" "0.34.6"
+ "@vitest/utils" "0.34.6"
acorn "^8.9.0"
acorn-walk "^8.2.0"
cac "^6.7.14"
- chai "^4.3.7"
+ chai "^4.3.10"
debug "^4.3.4"
local-pkg "^0.4.3"
magic-string "^0.30.1"
@@ -4265,9 +4270,9 @@ vitest@^0.33.0:
std-env "^3.3.3"
strip-literal "^1.0.1"
tinybench "^2.5.0"
- tinypool "^0.6.0"
- vite "^3.0.0 || ^4.0.0"
- vite-node "0.33.0"
+ tinypool "^0.7.0"
+ vite "^3.1.0 || ^4.0.0 || ^5.0.0-0"
+ vite-node "0.34.6"
why-is-node-running "^2.2.2"
vm2@^3.9.19:
@@ -4297,11 +4302,6 @@ web-worker@^1.2.0:
resolved "https://registry.yarnpkg.com/web-worker/-/web-worker-1.2.0.tgz#5d85a04a7fbc1e7db58f66595d7a3ac7c9c180da"
integrity sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==
-webfont-matcher@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/webfont-matcher/-/webfont-matcher-1.1.0.tgz#98ce95097b29e31fbe733053e10e571642d1c6c7"
- integrity sha1-mM6VCXsp4x++czBT4Q5XFkLRxsc=
-
webidl-conversions@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
diff --git a/scripts/lucode_explore.ipynb b/scripts/lucode_explore.ipynb
new file mode 100644
index 0000000..870a6d9
--- /dev/null
+++ b/scripts/lucode_explore.ipynb
@@ -0,0 +1,709 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "71a9445c-83fa-4c48-a96d-c33d5e7aa9d9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from collections import Counter\n",
+ "\n",
+ "import numpy\n",
+ "import pygeoprocessing\n",
+ "import pandas\n",
+ "import ipywidgets as widgets\n",
+ "from IPython.display import display"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "87c6dfbb-017f-4164-b9f9-edff36a823d2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# ! mamba install jupyterlab_widgets"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "ac4bf3f9-3543-42da-8afe-56ea96a16262",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "raster_path = 'H:/Shared drives/Online Urban ES Modeling Tool/Data from Chris/Combined NLCD NLUD Tree/overlay.tif'\n",
+ "csv_path = 'H:/Shared drives/Online Urban ES Modeling Tool/Data from Chris/Combined NLCD NLUD Tree/combined_structure.csv'"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "d9b31d02-51dd-4664-a576-828ff2677c91",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "df = pandas.read_csv(csv_path)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "718348a8-bce4-42e8-b356-1c15875232df",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " lucode | \n",
+ " code | \n",
+ " nlud | \n",
+ " nlud tier 1 | \n",
+ " nlud tier 2 | \n",
+ " nlud tier 3 | \n",
+ " nlud colors | \n",
+ " nlcd | \n",
+ " nlcd lulc | \n",
+ " nlcd colors | \n",
+ " tree | \n",
+ " tree canopy cover | \n",
+ " tree colors | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " 0 | \n",
+ " 111110 | \n",
+ " 111 | \n",
+ " Water | \n",
+ " Natural - area | \n",
+ " Lake | \n",
+ " #0070ff | \n",
+ " 11 | \n",
+ " Open Water | \n",
+ " #476BA0 | \n",
+ " 0 | \n",
+ " none | \n",
+ " #ffffff | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " 1 | \n",
+ " 111111 | \n",
+ " 111 | \n",
+ " Water | \n",
+ " Natural - area | \n",
+ " Lake | \n",
+ " #0070ff | \n",
+ " 11 | \n",
+ " Open Water | \n",
+ " #476BA0 | \n",
+ " 1 | \n",
+ " low | \n",
+ " #e5f5e0 | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " 2 | \n",
+ " 111112 | \n",
+ " 111 | \n",
+ " Water | \n",
+ " Natural - area | \n",
+ " Lake | \n",
+ " #0070ff | \n",
+ " 11 | \n",
+ " Open Water | \n",
+ " #476BA0 | \n",
+ " 2 | \n",
+ " medium | \n",
+ " #a1d99b | \n",
+ "
\n",
+ " \n",
+ " 3 | \n",
+ " 3 | \n",
+ " 111113 | \n",
+ " 111 | \n",
+ " Water | \n",
+ " Natural - area | \n",
+ " Lake | \n",
+ " #0070ff | \n",
+ " 11 | \n",
+ " Open Water | \n",
+ " #476BA0 | \n",
+ " 3 | \n",
+ " high | \n",
+ " #31a354 | \n",
+ "
\n",
+ " \n",
+ " 4 | \n",
+ " 4 | \n",
+ " 111120 | \n",
+ " 111 | \n",
+ " Water | \n",
+ " Natural - area | \n",
+ " Lake | \n",
+ " #0070ff | \n",
+ " 12 | \n",
+ " Perennial Ice/Snow | \n",
+ " #D1DDF9 | \n",
+ " 0 | \n",
+ " none | \n",
+ " #ffffff | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " lucode code nlud nlud tier 1 nlud tier 2 nlud tier 3 nlud colors \\\n",
+ "0 0 111110 111 Water Natural - area Lake #0070ff \n",
+ "1 1 111111 111 Water Natural - area Lake #0070ff \n",
+ "2 2 111112 111 Water Natural - area Lake #0070ff \n",
+ "3 3 111113 111 Water Natural - area Lake #0070ff \n",
+ "4 4 111120 111 Water Natural - area Lake #0070ff \n",
+ "\n",
+ " nlcd nlcd lulc nlcd colors tree tree canopy cover tree colors \n",
+ "0 11 Open Water #476BA0 0 none #ffffff \n",
+ "1 11 Open Water #476BA0 1 low #e5f5e0 \n",
+ "2 11 Open Water #476BA0 2 medium #a1d99b \n",
+ "3 11 Open Water #476BA0 3 high #31a354 \n",
+ "4 12 Perennial Ice/Snow #D1DDF9 0 none #ffffff "
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "df.head()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "5c6872dd-7515-48e7-894a-9978d24eb369",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def count(c, block):\n",
+ " return c + Counter(block)\n",
+ "counts = pygeoprocessing.raster_reduce(count, (raster_path, 1), Counter())"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "5517d4f1-d9cd-45e8-8865-3beecc0552c3",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def unique(unique, block):\n",
+ " return unique.union(set(numpy.unique(block)))\n",
+ "value_set = pygeoprocessing.raster_reduce(unique, (raster_path, 1), set())"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "d17adcfc-b070-433c-862d-91dd4fc1f51d",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "1556"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "len(value_set)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "af753d10-29f7-48ff-b719-7f467d7f0350",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "table = df.loc[df.lucode.isin(value_set)]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "11795382-4941-422f-87b0-9bb8195aa3e8",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " lucode | \n",
+ " code | \n",
+ " nlud | \n",
+ " nlud tier 1 | \n",
+ " nlud tier 2 | \n",
+ " nlud tier 3 | \n",
+ " nlud colors | \n",
+ " nlcd | \n",
+ " nlcd lulc | \n",
+ " nlcd colors | \n",
+ " tree | \n",
+ " tree canopy cover | \n",
+ " tree colors | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " 0 | \n",
+ " 111110 | \n",
+ " 111 | \n",
+ " Water | \n",
+ " Natural - area | \n",
+ " Lake | \n",
+ " #0070ff | \n",
+ " 11 | \n",
+ " Open Water | \n",
+ " #476BA0 | \n",
+ " 0 | \n",
+ " none | \n",
+ " #ffffff | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " 1 | \n",
+ " 111111 | \n",
+ " 111 | \n",
+ " Water | \n",
+ " Natural - area | \n",
+ " Lake | \n",
+ " #0070ff | \n",
+ " 11 | \n",
+ " Open Water | \n",
+ " #476BA0 | \n",
+ " 1 | \n",
+ " low | \n",
+ " #e5f5e0 | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " 2 | \n",
+ " 111112 | \n",
+ " 111 | \n",
+ " Water | \n",
+ " Natural - area | \n",
+ " Lake | \n",
+ " #0070ff | \n",
+ " 11 | \n",
+ " Open Water | \n",
+ " #476BA0 | \n",
+ " 2 | \n",
+ " medium | \n",
+ " #a1d99b | \n",
+ "
\n",
+ " \n",
+ " 8 | \n",
+ " 8 | \n",
+ " 111210 | \n",
+ " 111 | \n",
+ " Water | \n",
+ " Natural - area | \n",
+ " Lake | \n",
+ " #0070ff | \n",
+ " 21 | \n",
+ " Developed, Open Space | \n",
+ " #DDC9C9 | \n",
+ " 0 | \n",
+ " none | \n",
+ " #ffffff | \n",
+ "
\n",
+ " \n",
+ " 9 | \n",
+ " 9 | \n",
+ " 111211 | \n",
+ " 111 | \n",
+ " Water | \n",
+ " Natural - area | \n",
+ " Lake | \n",
+ " #0070ff | \n",
+ " 21 | \n",
+ " Developed, Open Space | \n",
+ " #DDC9C9 | \n",
+ " 1 | \n",
+ " low | \n",
+ " #e5f5e0 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " lucode code nlud nlud tier 1 nlud tier 2 nlud tier 3 nlud colors \\\n",
+ "0 0 111110 111 Water Natural - area Lake #0070ff \n",
+ "1 1 111111 111 Water Natural - area Lake #0070ff \n",
+ "2 2 111112 111 Water Natural - area Lake #0070ff \n",
+ "8 8 111210 111 Water Natural - area Lake #0070ff \n",
+ "9 9 111211 111 Water Natural - area Lake #0070ff \n",
+ "\n",
+ " nlcd nlcd lulc nlcd colors tree tree canopy cover tree colors \n",
+ "0 11 Open Water #476BA0 0 none #ffffff \n",
+ "1 11 Open Water #476BA0 1 low #e5f5e0 \n",
+ "2 11 Open Water #476BA0 2 medium #a1d99b \n",
+ "8 21 Developed, Open Space #DDC9C9 0 none #ffffff \n",
+ "9 21 Developed, Open Space #DDC9C9 1 low #e5f5e0 "
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "table.head()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "id": "35041cc5-d2a5-4a51-b417-33138bc5d638",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "table.columns = [col.replace(' ', '_') for col in table.columns]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "id": "bdb0e3c1-7d29-4d94-bd9b-5d55ff06f7e4",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Index(['lucode', 'code', 'nlud', 'nlud_tier_1', 'nlud_tier_2', 'nlud_tier_3',\n",
+ " 'nlud_colors', 'nlcd', 'nlcd_lulc', 'nlcd_colors', 'tree',\n",
+ " 'tree_canopy_cover', 'tree_colors'],\n",
+ " dtype='object')"
+ ]
+ },
+ "execution_count": 15,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "table.columns"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "id": "6bb720a4-4373-4a25-9853-1b9fb7ec68d7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "table.to_csv('H:/Shared drives/Online Urban ES Modeling Tool/Data from Chris/Combined NLCD NLUD Tree/present_in_raster.csv', index=False)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7af7922e-e93d-4a41-9dd5-31e66b539c94",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 36,
+ "id": "b616ef45-22f0-4f9b-a605-e38265c412d8",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "dbd416350a6e4c9381f9155a4f22fc0d",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "Dropdown(options=(('Open Water', 11), ('Developed, High Intensity', 24), ('Cultivated Crops', 82), ('Woody Wet…"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "nlcd_options = list(set([(name, value) for name, value in zip(table['nlcd lulc'], table['nlcd'])]))\n",
+ "nlcd = widgets.Dropdown(\n",
+ " options=nlcd_options\n",
+ ")\n",
+ "display(nlcd)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 63,
+ "id": "78cd8bc0-9df4-4865-a43d-885ffd1b0734",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "fe0ffa5e33cf420e9491731ff49cad67",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "Dropdown(options=(('Conservation | Private easement | Wildlife conservation', 531), ('Water | Natural - area |…"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "t = table.loc[table.nlcd == nlcd.value]\n",
+ "nlud_options = list(set([(' | '.join([name1, name2, name3]), value) for name1, name2, name3, value in zip(t['nlud tier 1'], t['nlud tier 2'], t['nlud tier 3'] , t['nlud'])]))\n",
+ "nlud = widgets.Dropdown(\n",
+ " options=nlud_options\n",
+ ")\n",
+ "display(nlud)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 66,
+ "id": "bf3f8d0d-3f54-46cf-a842-a7e187bd5b36",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " lucode | \n",
+ " code | \n",
+ " nlud | \n",
+ " nlud tier 1 | \n",
+ " nlud tier 2 | \n",
+ " nlud tier 3 | \n",
+ " nlud colors | \n",
+ " nlcd | \n",
+ " nlcd lulc | \n",
+ " nlcd colors | \n",
+ " tree | \n",
+ " tree canopy cover | \n",
+ " tree colors | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 1440 | \n",
+ " 1440 | \n",
+ " 221110 | \n",
+ " 221 | \n",
+ " Built-up | \n",
+ " Commercial | \n",
+ " Office | \n",
+ " #df73ff | \n",
+ " 11 | \n",
+ " Open Water | \n",
+ " #476BA0 | \n",
+ " 0 | \n",
+ " none | \n",
+ " #ffffff | \n",
+ "
\n",
+ " \n",
+ " 1441 | \n",
+ " 1441 | \n",
+ " 221111 | \n",
+ " 221 | \n",
+ " Built-up | \n",
+ " Commercial | \n",
+ " Office | \n",
+ " #df73ff | \n",
+ " 11 | \n",
+ " Open Water | \n",
+ " #476BA0 | \n",
+ " 1 | \n",
+ " low | \n",
+ " #e5f5e0 | \n",
+ "
\n",
+ " \n",
+ " 1442 | \n",
+ " 1442 | \n",
+ " 221112 | \n",
+ " 221 | \n",
+ " Built-up | \n",
+ " Commercial | \n",
+ " Office | \n",
+ " #df73ff | \n",
+ " 11 | \n",
+ " Open Water | \n",
+ " #476BA0 | \n",
+ " 2 | \n",
+ " medium | \n",
+ " #a1d99b | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " lucode code nlud nlud tier 1 nlud tier 2 nlud tier 3 nlud colors \\\n",
+ "1440 1440 221110 221 Built-up Commercial Office #df73ff \n",
+ "1441 1441 221111 221 Built-up Commercial Office #df73ff \n",
+ "1442 1442 221112 221 Built-up Commercial Office #df73ff \n",
+ "\n",
+ " nlcd nlcd lulc nlcd colors tree tree canopy cover tree colors \n",
+ "1440 11 Open Water #476BA0 0 none #ffffff \n",
+ "1441 11 Open Water #476BA0 1 low #e5f5e0 \n",
+ "1442 11 Open Water #476BA0 2 medium #a1d99b "
+ ]
+ },
+ "execution_count": 66,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "table.loc[(table.nlcd == nlcd.value) & (table.nlud == nlud.value)]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 67,
+ "id": "34ffe44a-7b95-4cda-a2fd-5e104d7af69d",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "14"
+ ]
+ },
+ "execution_count": 67,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "counts[1440]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "id": "0f3ddc57-0474-495a-bbaf-ca97b2f785b8",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "TypeError",
+ "evalue": "'>' not supported between instances of 'Counter' and 'int'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[1;32mIn[18], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[43mcounts\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m>\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;241;43m1000\u001b[39;49m\n",
+ "\u001b[1;31mTypeError\u001b[0m: '>' not supported between instances of 'Counter' and 'int'"
+ ]
+ }
+ ],
+ "source": [
+ "counts > 1000"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "fe45e36b-2eb3-42ce-860f-e764129a2c78",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.4"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/scripts/lulc_crosswalk.py b/scripts/lulc_crosswalk.py
new file mode 100644
index 0000000..8cd75b2
--- /dev/null
+++ b/scripts/lulc_crosswalk.py
@@ -0,0 +1,23 @@
+"""Create json-format lulc crosswalk for use in frontend.
+
+The resulting json is checked-in to the application source code,
+So this script need only be run if the source CSV file changes.
+"""
+import json
+import pandas
+
+df = pandas.read_csv('../appdata/lulc_crosswalk.csv')
+df = df.fillna('')
+
+data = {}
+for idx, row in df.iterrows():
+ data[row.lucode] = {
+ 'nlcd': str(row.nlcd),
+ 'nlud': str(row.nlud_simple),
+ 'tree': str(row.tree)
+ }
+
+
+with open('../appdata/lulc_crosswalk.json', 'w', encoding='utf-8') as file:
+ jsonstring = json.dumps(data)
+ file.write(jsonstring + '\n')
diff --git a/scripts/prepare_lulc.py b/scripts/prepare_lulc.py
new file mode 100644
index 0000000..2780886
--- /dev/null
+++ b/scripts/prepare_lulc.py
@@ -0,0 +1,32 @@
+"""LULC rasters from Chris need some processing to be ready for a webmap.
+
+1. warp to web-mercator
+2. build overviews
+"""
+
+import os
+
+import pygeoprocessing
+from osgeo import osr
+
+shared_drive = 'H:/Shared drives/Online Urban ES Modeling Tool/Data from Chris/NLUD 2023'
+base_raster_path = os.path.join(shared_drive, 'overlay_simple.tif')
+target_raster_path = '../appdata/lulc_overlay_3857.tif'
+
+base_info = pygeoprocessing.get_raster_info(base_raster_path)
+print(base_info)
+
+srs = osr.SpatialReference()
+srs.ImportFromEPSG(3857)
+target_proj_wkt = srs.ExportToWkt()
+
+pygeoprocessing.warp_raster(
+ base_raster_path=base_raster_path,
+ target_pixel_size=base_info['pixel_size'],
+ target_raster_path=target_raster_path,
+ resample_method='near',
+ target_projection_wkt=target_proj_wkt)
+
+pygeoprocessing.build_overviews(
+ target_raster_path, internal=True, resample_method='near',
+ overwrite=True, levels='auto')
diff --git a/server/sql_app/crud.py b/server/sql_app/crud.py
index 45d9930..8efc456 100644
--- a/server/sql_app/crud.py
+++ b/server/sql_app/crud.py
@@ -5,6 +5,7 @@
import sys
import time
import uuid
+from collections import Counter
from fastapi import HTTPException
from sqlalchemy.orm import Session
@@ -320,3 +321,49 @@ def update_invest(db: Session, scenario_id: int, job_id: int,
db.commit()
db.refresh(db_invest)
return STATUS_SUCCESS
+
+
+def get_nlud_tier_2(db: Session):
+ data = db.query(models.LulcCrosswalk.nlud_simple_class).distinct()
+ LOGGER.info(data)
+ return data
+
+
+def get_nlud_tier_3(db: Session, nlud_tier_2: str):
+ return db.query(
+ models.LulcCrosswalk.nlud_simple_subclass).filter(
+ models.LulcCrosswalk.nlud_simple_class == nlud_tier_2).distinct()
+
+
+def get_nlcd(db: Session, nlud_tier_2: str, nlud_tier_3: str):
+ return db.query(
+ models.LulcCrosswalk.nlcd_lulc).filter(
+ models.LulcCrosswalk.nlud_simple_class == nlud_tier_2,
+ models.LulcCrosswalk.nlud_simple_subclass == nlud_tier_3).distinct()
+
+
+# TODO: this set of queries is not optimal because LulcCrosswalk is
+# not a normalized database. We could query more efficiently if it was
+# normalized into multiple tables.
+def get_lucode(db: Session, nlud_tier_2: str, nlud_tier_3: str, nlcd: str, tree: str):
+ return db.query(
+ models.LulcCrosswalk.lucode).filter(
+ models.LulcCrosswalk.nlud_simple_class == nlud_tier_2,
+ models.LulcCrosswalk.nlud_simple_subclass == nlud_tier_3,
+ models.LulcCrosswalk.nlcd_lulc == nlcd,
+ models.LulcCrosswalk.tree_canopy_cover == tree).first()
+
+
+def explode_lulc_counts(db: Session, stats_dict):
+ data = {
+ 'nlcd': Counter(),
+ 'nlud': Counter(),
+ 'tree': Counter()
+ }
+ for lucode, count in stats_dict.items():
+ row = db.query(models.LulcCrosswalk).filter(
+ models.LulcCrosswalk.lucode == lucode).first()
+ data['nlud'][row.nlud_simple] += count
+ data['nlcd'][row.nlcd] += count
+ data['tree'][row.tree] += count
+ return data
diff --git a/server/sql_app/main.py b/server/sql_app/main.py
index d816d82..f6e2f58 100644
--- a/server/sql_app/main.py
+++ b/server/sql_app/main.py
@@ -1,29 +1,25 @@
+import csv
import json
import logging
import os
import queue
import sys
+from typing import Optional
import shapely.geometry
import shapely.wkt
from fastapi.middleware.cors import CORSMiddleware
from fastapi import Depends, FastAPI, HTTPException, Request
-from fastapi.testclient import TestClient
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY
from sqlalchemy.orm import Session
+from sqlalchemy import event
from . import crud, models, schemas
from .database import SessionLocal, engine
-
-# This will help with flexibility of where we store our files and DB
-# When gathering URL result for frontend request build the URL with this:
-WORKING_ENV = "/opt/appdata"
-BASE_LULC = "NLCD_2016_epsg3857.tif"
-
logging.basicConfig(
level=logging.DEBUG,
format=(
@@ -32,9 +28,11 @@
stream=sys.stdout)
LOGGER = logging.getLogger(__name__)
-# Create the db tables
-models.Base.metadata.create_all(bind=engine)
-
+# This will help with flexibility of where we store our files and DB
+# When gathering URL result for frontend request build the URL with this:
+WORKING_ENV = "/opt/appdata"
+BASE_LULC = "lulc_overlay_3857.tif"
+LULC_CSV_PATH = os.path.join(WORKING_ENV, 'lulc_crosswalk.csv')
# Create a queue that we will use to store our "workload".
QUEUE = queue.PriorityQueue()
@@ -68,24 +66,37 @@
}
+def insert_lulc_data(target, connection, **kw):
+ LOGGER.info('importing LULC Crosswalk table')
+ # https://docs.sqlalchemy.org/en/20/_modules/examples/performance/bulk_inserts.html
+ with open(LULC_CSV_PATH, 'r') as file:
+ reader = csv.DictReader(file)
+ connection.execute(
+ models.LulcCrosswalk.__table__.insert(),
+ [row for row in reader]
+ )
+
+
+# create_all() will check if tables already exist before creating them.
+# if this table did not exist, populate it from the CSV.
+# TODO: use some type of hash to check if the CSV file
+# has changed, not just checking if the db table already exists.
+event.listen(models.LulcCrosswalk.__table__, 'after_create', insert_lulc_data)
+
# Normally you would probably initialize your db (create tables, etc) with
# Alembic. Would also use Alembic for "migrations" (that's its main job).
# A "migration" is the set of steps needed whenever you change the structure
# of your SQLA models, add a new attribute, etc. to replicate those changes
# in the db, add a new column, a new table, etc.
+models.Base.metadata.create_all(bind=engine)
app = FastAPI()
-
-
-origins = [
- "http://localhost:3000",
-]
-
+origins = ["http://localhost:3000"]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
- allow_methods=["*"], # despite this *, I could not get PATCH to pass CORS
+ allow_methods=["*"], # despite this *, PATCH does not pass CORS
allow_headers=["*"],
)
@@ -100,34 +111,31 @@ async def validation_exception_handler(
return JSONResponse(
content=content, status_code=HTTP_422_UNPROCESSABLE_ENTITY)
-# We need to have an independent db session / connection (SessionLocal) per
-# request, use the same session through all the request and then close it after
-# the request is finished.
-
-# Then a new session will be created for the next request.
-
-# Our dependency will create a new SQLA SessionLocal that will be used in a
-# single request, and then close it once the request is finished.
# Dependency
def get_db():
+ # We need to have an independent db session / connection (SessionLocal) per
+ # request, use the same session through all the request and then close it after
+ # the request is finished.
+
+ # Then a new session will be created for the next request.
+
+ # Our dependency will create a new SQLA SessionLocal that will be used in a
+ # single request, and then close it once the request is finished.
+ # We are creating the db session before each request in the dependency with
+ # 'yield', and then closing it afterwards.
+
+ # Then we can create the required dependency in the path operation function,
+ # to get that session directly.
+
+ # With that, we can just call crud.get_user directly from inside of the path
+ # operation function and use that session.
db = SessionLocal()
try:
yield db
finally:
db.close()
-# We are creating the db session before each request in the dependency with
-# 'yield', and then closing it afterwards.
-
-# Then we can create the required dependency in the path operation function,
-# to get that session directly.
-
-# With that, we can just call crud.get_user directly from inside of the path
-# operation function and use that session.
-###
-
-### Session Endpoints ###
@app.post("/sessions/", response_model=schemas.SessionResponse)
def create_session(db: Session = Depends(get_db)):
@@ -139,13 +147,6 @@ def create_session(db: Session = Depends(get_db)):
return crud.create_session(db=db)
-# Type annotations in the function arguments will give you editor support
-# inside of your function, with error checks, completion, etc.
-# So, with that type declaration, FastAPI gives you automatic request
-# "parsing". With the same Python type declaration, FastAPI gives you data
-# validation. All the data validation is performed under the hood by Pydantic,
-# so you get all the benefits from it.
-
@app.get("/session/{session_id}", response_model=schemas.Session)
def read_session(session_id: str, db: Session = Depends(get_db)):
db_session = crud.get_session(db, session_id=session_id)
@@ -154,8 +155,6 @@ def read_session(session_id: str, db: Session = Depends(get_db)):
return db_session
-### Study Area and Scenario Endpoints ###
-
@app.post("/study_area/{session_id}", response_model=schemas.StudyArea)
def create_study_area(
session_id: str, new_area: schemas.StudyAreaCreateRequest,
@@ -171,7 +170,7 @@ def create_study_area(
@app.get("/study_area/{session_id}/{study_area_id}",
response_model=schemas.StudyArea)
def get_study_area(
- session_id: str, study_area_id: int, db: Session = Depends(get_db)):
+ session_id: str, study_area_id: int, db: Session = Depends(get_db)):
# check that the session exists
db_session = crud.get_session(db, session_id=session_id)
if db_session is None:
@@ -179,9 +178,8 @@ def get_study_area(
db_study_area = crud.get_study_area(db, study_area_id=study_area_id)
return db_study_area
-# TODO: patch method blocked by CORS? fails preflight request with 400
-@app.put("/study_area/{session_id}",
- response_model=schemas.StudyArea)
+
+@app.put("/study_area/{session_id}", response_model=schemas.StudyArea)
def update_study_area(session_id: str, study_area: schemas.StudyArea,
db: Session = Depends(get_db)):
# check that the session exists
@@ -242,8 +240,6 @@ def delete_scenario(scenario_id: int, db: Session = Depends(get_db)):
return crud.delete_scenario(db=db, scenario_id=scenario_id)
-### Worker Endpoints ###
-
@app.get("/jobsqueue/")
async def worker_job_request(db: Session = Depends(get_db)):
"""If there's work to be done in the queue send it to the worker."""
@@ -315,14 +311,14 @@ def worker_invest_response(
@app.post("/jobsqueue/scenario")
def worker_scenario_response(
- scenario_job: schemas.WorkerResponse, db: Session = Depends(get_db)):
+ scenario_job: schemas.WorkerResponse, db: Session = Depends(get_db)):
"""Update the db given the job details from the worker.
Returned URL result will be partial to allow for local vs cloud stored
depending on production vs dev environment.
Args:
- scenario_job (pydantic model): a pydantic model with the following
+ scenario_job (pydantic model): a pydantic model with the following
key/vals
"result": {
@@ -350,9 +346,10 @@ def worker_scenario_response(
status=STATUS_SUCCESS,
name=job_db.name, description=job_db.description)
# Update the scenario lulc path and stats
+ lulc_stats = crud.explode_lulc_counts(db, scenario_job.result['lulc_stats'])
scenario_update = schemas.ScenarioUpdate(
lulc_url_result=scenario_job.result['lulc_path'],
- lulc_stats=json.dumps(scenario_job.result['lulc_stats']))
+ lulc_stats=json.dumps(lulc_stats))
else:
# Update the job status in the DB to "failed"
job_update = schemas.JobBase(
@@ -373,7 +370,8 @@ def worker_scenario_response(
@app.post("/jobsqueue/parcel_stats")
def worker_parcel_stats_response(
- parcel_stats_job: schemas.WorkerResponse, db: Session = Depends(get_db)):
+ parcel_stats_job: schemas.WorkerResponse,
+ db: Session = Depends(get_db)):
"""Update the db given the job details from the worker."""
LOGGER.debug("Entering jobsqueue/parcel_stats")
LOGGER.debug(parcel_stats_job)
@@ -387,8 +385,10 @@ def worker_parcel_stats_response(
status=STATUS_SUCCESS,
name=job_db.name, description=job_db.description)
# Update the scenario lulc path and stats
+ LOGGER.info(parcel_stats_job.result['lulc_stats']['base'])
+ data = crud.explode_lulc_counts(db, parcel_stats_job.result['lulc_stats']['base'])
stats_update = schemas.ParcelStatsUpdate(
- lulc_stats=json.dumps(parcel_stats_job.result['lulc_stats']))
+ lulc_stats=json.dumps(data))
else:
# Update the job status in the DB to "failed"
job_update = schemas.JobBase(
@@ -408,14 +408,14 @@ def worker_parcel_stats_response(
@app.post("/jobsqueue/pattern")
def worker_pattern_response(
- pattern_job: schemas.WorkerResponse, db: Session = Depends(get_db)):
+ pattern_job: schemas.WorkerResponse, db: Session = Depends(get_db)):
"""Update the db given the job details from the worker.
Returned URL result will be partial to allow for local vs cloud stored
depending on production vs dev environment.
Args:
- pattern_job (pydantic model): a pydantic model with the following
+ pattern_job (pydantic model): a pydantic model with the following
key/vals
{
@@ -484,18 +484,6 @@ def read_jobs(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
return jobs
-### Task Endpoints ###
-
-@app.post("/lulc_codes/", response_model=schemas.JobResponse)
-def get_lulc_info(db: Session = Depends(get_db)):
- """Get the lulc class codes, names, and color representation."""
- #TODO: determine if this should act like the rest of our job endpoints
- # or if this operation should happen locally or if it should happen at
- # server start.
-
- pass
-
-
@app.post("/pattern/{session_id}", response_model=schemas.PatternResponse)
def create_pattern(session_id: str, pattern: schemas.PatternBase,
db: Session = Depends(get_db)):
@@ -520,7 +508,7 @@ def create_pattern(session_id: str, pattern: schemas.PatternBase,
},
"job_args": {
"pattern_wkt": pattern_db.wkt,
- "lulc_source_url": os.path.join(WORKING_ENV,BASE_LULC),
+ "lulc_source_url": os.path.join(WORKING_ENV, BASE_LULC),
}
}
@@ -590,7 +578,7 @@ def wallpaper(wallpaper: schemas.Wallpaper, db: Session = Depends(get_db)):
@app.post("/lulc_fill/", response_model=schemas.JobResponse)
def lulc_fill(lulc_fill: schemas.ParcelFill,
- db: Session = Depends(get_db)):
+ db: Session = Depends(get_db)):
# Get Scenario details from scenario_id
scenario_db = crud.get_scenario(db, lulc_fill.scenario_id)
study_area_id = scenario_db.study_area_id
@@ -613,7 +601,7 @@ def lulc_fill(lulc_fill: schemas.ParcelFill,
},
"job_args": {
"target_parcel_wkt": study_area_wkt,
- "lulc_class": lulc_fill.lulc_class, #TODO: make sure this is a WKT string and no just a bounding box
+ "lulc_class": lulc_fill.lulc_class,
"lulc_source_url": f'{WORKING_ENV}/{scenario_db.lulc_url_base}',
}
}
@@ -810,23 +798,43 @@ def get_invest_results(scenario_id: int, db: Session = Depends(get_db)):
}
-### Testing ideas from tutorial ###
-
-client = TestClient(app)
-
-
-def test_read_main():
- response = client.get("/")
- assert response.status_code == 200
- assert response.json() == {"msg": "Hello World: prototype test"}
-
-def test_add_jobs():
- response = client.get("/")
- assert response.status_code == 200
- assert response.json() == {"msg": "Hello World"}
-
- # read status of job
- response = client.get("/")
- assert response.status_code == 200
- assert response.json() == {"msg": "Hello World"}
-
+@app.get("/lucodes/nlud_tier_2")
+def get_nlud_tier_2(db: Session = Depends(get_db)) -> list[str]:
+ db_list = crud.get_nlud_tier_2(db)
+ return [row.nlud_simple_class for row in db_list]
+
+
+@app.post("/lucodes/nlud_tier_3")
+def get_nlud_tier_3(nlud_dict: dict[str, str],
+ db: Session = Depends(get_db)) -> list[str]:
+ db_list = crud.get_nlud_tier_3(
+ db,
+ nlud_tier_2=nlud_dict['nlud_tier_2'])
+ return [row.nlud_simple_subclass for row in db_list]
+
+
+@app.post("/lucodes/nlcd")
+def get_nlcd(nlud_dict: dict[str, str],
+ db: Session = Depends(get_db)) -> list[str]:
+ db_list = crud.get_nlcd(
+ db,
+ nlud_tier_2=nlud_dict['nlud_tier_2'],
+ nlud_tier_3=nlud_dict['nlud_tier_3'])
+ return [row.nlcd_lulc for row in db_list]
+
+
+# TODO: will all 3 tree cover classes always be present for each category?
+# or do we need another query to find out which are present?
+# related to https://github.com/natcap/urban-online-workflow/issues/124
+@app.post("/lucodes/lucode")
+def get_lucode(lulc_dict: schemas.LulcRequest,
+ db: Session = Depends(get_db)) -> Optional[int]:
+ row = crud.get_lucode(
+ db,
+ nlud_tier_2=lulc_dict.nlud_tier_2,
+ nlud_tier_3=lulc_dict.nlud_tier_3,
+ nlcd=lulc_dict.nlcd,
+ tree=lulc_dict.tree)
+ if row:
+ return row.lucode
+ return None
diff --git a/server/sql_app/models.py b/server/sql_app/models.py
index 36d4513..479ead0 100644
--- a/server/sql_app/models.py
+++ b/server/sql_app/models.py
@@ -74,7 +74,7 @@ class Scenario(Base):
name = Column(String, index=True)
lulc_url_result = Column(String)
lulc_stats = Column(String)
- lulc_url_base = Column(String, default="NLCD_2016_epsg3857.tif")
+ lulc_url_base = Column(String, default="lulc_overlay_3857.tif")
operation = Column(String)
# each scenario has an associated study area owner
study_area_id = Column(String, ForeignKey("study_area.id"))
@@ -134,3 +134,18 @@ class InvestResult(Base):
serviceshed = Column(String)
#scenario = relationship("Scenario", back_populates="invest_results")
+
+
+class LulcCrosswalk(Base):
+ """Lookup table for landuse-landcover codes and labels."""
+ __tablename__ = "lulc_crosswalk"
+
+ lucode = Column(Integer, primary_key=True)
+ nlud_simple_class = Column(String)
+ nlud_simple_subclass = Column(String)
+ nlud_simple = Column(Integer)
+ nlcd = Column(Integer)
+ nlcd_lulc = Column(String)
+ tree = Column(Integer)
+ tree_canopy_cover = Column(String)
+
diff --git a/server/sql_app/schemas.py b/server/sql_app/schemas.py
index 60a2b57..65555cf 100644
--- a/server/sql_app/schemas.py
+++ b/server/sql_app/schemas.py
@@ -222,3 +222,9 @@ class ParcelFill(BaseModel):
class Config:
orm_mode = True
+
+class LulcRequest(BaseModel):
+ nlud_tier_2: str
+ nlud_tier_3: str
+ nlcd: str
+ tree: str