diff --git a/client/package.json b/client/package.json index 422973e..25cb18b 100644 --- a/client/package.json +++ b/client/package.json @@ -79,6 +79,7 @@ "code": 130 } ], + "vuejs-accessibility/click-events-have-key-events": "off", "vue/no-setup-props-destructure": 0, "sort-imports": [ "error", diff --git a/client/src/MapStore.ts b/client/src/MapStore.ts index aad1653..150c149 100644 --- a/client/src/MapStore.ts +++ b/client/src/MapStore.ts @@ -2,7 +2,9 @@ import { Ref, computed, reactive, ref, } from 'vue'; import { + AnnotationTypes, ClickedProps, + ColorFilters, Context, Dataset, LayerCollection, @@ -24,7 +26,7 @@ async function isVectorBaseMapAvailable(vectorMapUrl: string) { type SideBarCard = 'indicators' | 'charts'; export default class MapStore { - public static osmBaseMap = ref<'none' | 'osm-raster' | 'osm-vector'>('osm-vector'); + public static osmBaseMap = ref<'none' | 'osm-raster' | 'osm-vector'>('osm-raster'); public static userIsStaff = computed(() => !!UVdatApi.user?.is_staff); @@ -254,4 +256,31 @@ export default class MapStore { MapStore.sideBarCardSettings.value[key as SideBarCard].enabled = false; }); }; + + public static vectorColorFilters: Ref = ref([]); + + public static toggleColorFilter = (layerId: number, layerType: (AnnotationTypes | 'all'), key: string, value: string) => { + const foundIndex = MapStore.vectorColorFilters.value.findIndex( + (item) => item.layerId === layerId && layerType === item.layerType && key === item.key, + ); + if (foundIndex === -1) { + MapStore.vectorColorFilters.value.push({ + layerId, + layerType, + type: 'not in', + key, + values: new Set([value]), + }); + } else { + const found = MapStore.vectorColorFilters.value[foundIndex]; + if (found.values.has(value)) { + found.values.delete(value); + if (found.values.size === 0) { + MapStore.vectorColorFilters.value.splice(foundIndex, 1); + } + } else { + found.values.add(value); + } + } + }; } diff --git a/client/src/api/UVDATApi.ts b/client/src/api/UVDATApi.ts index 08e210d..381a024 100644 --- a/client/src/api/UVDATApi.ts +++ b/client/src/api/UVDATApi.ts @@ -538,4 +538,27 @@ export default class UVdatApi { }); return response.data; } + + public static async getMetadataFilters(): Promise> { + return (await UVdatApi.apiClient.get('/metadata-filters/get_filters/')).data; + } + + public static async filterOnMetadata( + metdataFilters: Record, + search?: string, + ): Promise<{ id: number, type: AbstractMapLayer['type'], matches: string[], name: string }[]> { + return (await UVdatApi.apiClient.post('metadata-filters/filter_layers/', { filters: metdataFilters, search })).data; + } + + public static async getMapLayerList( + layerIds: number[], + layerTypes : AbstractMapLayer['type'][], + ): Promise<(VectorMapLayer | RasterMapLayer | NetCDFLayer)[]> { + const params = new URLSearchParams(); + + layerIds.forEach((id) => params.append('mapLayerIds', id.toString())); + layerTypes.forEach((id) => params.append('mapLayerTypes', id.toString())); + + return (await UVdatApi.apiClient.get('/map-layers/', { params })).data; + } } diff --git a/client/src/components/FeatureSelection/vectorFeatureGraphUtils.ts b/client/src/components/FeatureSelection/vectorFeatureGraphUtils.ts index 598e4eb..50a40f6 100644 --- a/client/src/components/FeatureSelection/vectorFeatureGraphUtils.ts +++ b/client/src/components/FeatureSelection/vectorFeatureGraphUtils.ts @@ -61,7 +61,7 @@ const renderVectorFeatureGraph = ( y.domain(d3.extent(allYValues) as [number, number]); - const maxYValue = Math.max(...allYValues); + const maxYValue = Math.max(allYValues); const maxYLabel = maxYValue.toFixed(2); // Format to 2 decimal places const maxCharacters = maxYLabel.length; diff --git a/client/src/components/LayerTypeConfig.vue b/client/src/components/LayerTypeConfig.vue index 4db6e1e..bcea092 100644 --- a/client/src/components/LayerTypeConfig.vue +++ b/client/src/components/LayerTypeConfig.vue @@ -54,7 +54,7 @@ export default defineComponent({ return enabled; }); - type LayerActionItems = 'enabled' | 'selectable' | 'hoverable' | 'opacity' | 'zoomMinMax' | 'selectColor' | 'defaultSize' | 'legend' | 'color' | 'text' | 'heatmapControls'; + type LayerActionItems = 'enabled' | 'selectable' | 'hoverable' | 'opacity' | 'zoomMinMax' | 'selectColor' | 'defaultSize' | 'legend' | 'color' | 'text' | 'heatmapControls' | 'drawPoints'; const layerActionItemsMap: Record = { enabled: ['line', 'fill', 'circle', 'fill-extrusion', 'text', 'heatmap'], selectable: ['line', 'fill', 'circle', 'fill-extrusion'], @@ -67,11 +67,12 @@ export default defineComponent({ color: ['line', 'fill', 'circle', 'fill-extrusion', 'text'], text: ['text'], heatmapControls: ['heatmap'], + drawPoints: ['line'], }; const actionItemVisible = computed(() => { const enabledItems = new Set(); - const itemList: LayerActionItems[] = ['enabled', 'selectable', 'hoverable', 'legend', 'opacity', 'zoomMinMax', 'selectColor', 'defaultSize', 'color', 'text', 'heatmapControls']; + const itemList: LayerActionItems[] = ['enabled', 'selectable', 'hoverable', 'legend', 'opacity', 'zoomMinMax', 'selectColor', 'defaultSize', 'color', 'text', 'heatmapControls', 'drawPoints']; itemList.forEach((key) => { if (layerActionItemsMap[key].includes(props.layerType)) { enabledItems.add(key); @@ -102,6 +103,10 @@ export default defineComponent({ if (field === 'legend') { displayConfig.legend = val; } + if (field === 'drawPoints') { + displayConfig.drawPoints = val; + } + if (field === 'opacity') { if (val) { displayConfig.opacity = 0.75; @@ -683,6 +688,32 @@ export default defineComponent({ + + + + + + + + + {{ + valueDisplayCheckbox('drawPoints') ? 'mdi-checkbox-marked' : 'mdi-checkbox-blank-outline' }} + + Draw Points + +
diff --git a/client/src/components/Map.vue b/client/src/components/Map.vue index e7f7583..2a592f3 100644 --- a/client/src/components/Map.vue +++ b/client/src/components/Map.vue @@ -5,7 +5,7 @@ import { Protocol as PMTilesProtocol } from 'pmtiles'; import { Ref, defineComponent, onMounted, ref, watch, } from 'vue'; -import MapStore, { VECTOR_PMTILES_URL } from '../MapStore'; +import MapStore from '../MapStore'; import { updateSelected, } from '../map/mapVectorLayers'; @@ -81,10 +81,6 @@ export default defineComponent({ tileSize: 256, attribution: '© OpenStreetMap contributors', }, - [OSM_VECTOR_ID]: { - type: 'vector', - url: `pmtiles://${VECTOR_PMTILES_URL}`, - }, 'tva-region': { type: 'geojson', data: TVA_GEOJSON, @@ -125,7 +121,6 @@ export default defineComponent({ minzoom: 0, maxzoom: 19, }, - ...VECTOR_LAYERS, { id: 'naip-imagery-tiles', type: 'raster', diff --git a/client/src/components/MapLegends/ColorKey.vue b/client/src/components/MapLegends/ColorKey.vue index 41e2bdc..724448f 100644 --- a/client/src/components/MapLegends/ColorKey.vue +++ b/client/src/components/MapLegends/ColorKey.vue @@ -1,3 +1,4 @@ + + + + + diff --git a/client/src/components/NetCDFLayerConfig.vue b/client/src/components/NetCDFLayerConfig.vue index 88c1a52..85259fd 100644 --- a/client/src/components/NetCDFLayerConfig.vue +++ b/client/src/components/NetCDFLayerConfig.vue @@ -58,7 +58,7 @@ export default defineComponent({ return mapSlicer; }); const updateIndex = () => { - updateNetCDFLayer(props.layer.id, currentIndex.value); + updateNetCDFLayer(props.layer.id, { index: currentIndex.value }); }; const throttledUpdateLayerFilter = throttle(updateIndex, 50); @@ -66,7 +66,7 @@ export default defineComponent({ throttledUpdateLayerFilter(); }); watch([layerOpacity], () => { - updateNetCDFLayer(props.layer.id, undefined, layerOpacity.value); + updateNetCDFLayer(props.layer.id, { opacity: layerOpacity.value }); }); return { diff --git a/client/src/map/mapFilters.ts b/client/src/map/mapFilters.ts index 6bc973e..c04fd82 100644 --- a/client/src/map/mapFilters.ts +++ b/client/src/map/mapFilters.ts @@ -4,6 +4,7 @@ import { FilterSpecification } from 'maplibre-gl'; import { AnnotationTypes, BooleanEqualsFilter, + ColorFilters, Filter, NumberBetweenFilter, NumberComparisonFilter, @@ -13,6 +14,24 @@ import { VectorLayerDisplayConfig, VectorMapLayer, } from '../types'; +import MapStore from '../MapStore'; + +const getLayerDefaultFilter = (type: AnnotationTypes, layer?: VectorMapLayer) => { + let drawPoints = false; + if (type === 'circle' && layer?.default_style.layers && layer.default_style.layers.line) { + if (layer.default_style.layers.line !== true) { + drawPoints = !!layer.default_style.layers.line.drawPoints; + } + } + if (['fill', 'fill-extrusion'].includes(type)) { + return ['==', ['geometry-type'], 'Polygon'] as FilterSpecification; + } + if (!drawPoints && ['circle'].includes(type)) { + return ['==', ['geometry-type'], 'Point'] as FilterSpecification; + } + + return true as FilterSpecification; +}; function filterToMapLibreExpression(filter: Filter): any[] { switch (filter.type) { @@ -63,30 +82,47 @@ function filterToMapLibreExpression(filter: Filter): any[] { return []; } +const colorFilterToExpression = (filter: ColorFilters) => { + const expression = ['!', ['in', ['get', filter.key], ['literal', Array.from(filter.values)]]]; + return expression; +}; + const updateFilters = (map: maplibregl.Map, layer: VectorMapLayer) => { - if (layer.default_style?.filters) { + const colorFilter = MapStore.vectorColorFilters.value.find((item) => item.layerId === layer.id); + if (layer.default_style?.filters || colorFilter) { const annotationFilters: Record = { line: [], fill: [], circle: [], 'fill-extrusion': [], text: [], + heatmap: [], }; - for (let i = 0; i < layer.default_style.filters.length; i += 1) { - const filter = layer.default_style.filters[i]; - const layerTypes = filter.layers; - if (filter.enabled) { - const expression = filterToMapLibreExpression(filter); - layerTypes.forEach((layerType) => { - if (annotationFilters[layerType] === undefined) { - annotationFilters[layerType] = []; - } - annotationFilters[layerType].push(expression); - }); - } else { - layerTypes.forEach((layerType) => { - const layerName = `Layer_${layer.id}_${layerType}`; - map.setFilter(layerName, null); + if (layer.default_style?.filters) { + for (let i = 0; i < layer.default_style.filters.length; i += 1) { + const filter = layer.default_style.filters[i]; + const layerTypes = filter.layers; + if (filter.enabled) { + const expression = filterToMapLibreExpression(filter); + layerTypes.forEach((layerType) => { + if (annotationFilters[layerType] === undefined) { + annotationFilters[layerType] = []; + } + annotationFilters[layerType].push(expression); + }); + } else { + layerTypes.forEach((layerType) => { + const layerName = `Layer_${layer.id}_${layerType}`; + map.setFilter(layerName, null); + }); + } + } + } + if (colorFilter) { + if (colorFilter.layerType === 'all') { + (Object.keys(annotationFilters) as AnnotationTypes[]).forEach((key) => { + const expression = colorFilterToExpression(colorFilter); + annotationFilters[key].push(expression); }); } } @@ -96,28 +132,32 @@ const updateFilters = (map: maplibregl.Map, layer: VectorMapLayer) => { if (!(layer.default_style.layers[key] as VectorLayerDisplayConfig).enabled) { return; } + const layerConfig = (layer.default_style.layers[key] as VectorLayerDisplayConfig); const layerName = `Layer_${layer.id}_${key}`; const typeFilters = annotationFilters[key]; - if (typeFilters.length === 0) { + if (typeFilters.length === 0 && !layerConfig.drawPoints) { return; } const lineFilter = []; if (['fill', 'fill-extrusion'].includes(key)) { lineFilter.push(['==', ['geometry-type'], 'Polygon'] as FilterSpecification); } + if (['circle'].includes(key)) { + lineFilter.push(['==', ['geometry-type'], 'Point'] as FilterSpecification); + } if (typeFilters.length) { - const filterSpecification = typeFilters.length > 0 ? ['all'] : []; + let filterSpecification = typeFilters.length > 0 ? ['all'] : []; if (lineFilter.length) { - filterSpecification.push(lineFilter); + filterSpecification = filterSpecification.concat(lineFilter); } const outputFilter = filterSpecification.concat(typeFilters); if (outputFilter.length) { map.setFilter(layerName, outputFilter as FilterSpecification); } } else { - const filterSpecification = []; + let filterSpecification = []; if (lineFilter.length) { - filterSpecification.push(lineFilter); + filterSpecification = filterSpecification.concat(lineFilter); } if (filterSpecification.length) { map.setFilter(layerName, filterSpecification as FilterSpecification); @@ -125,7 +165,13 @@ const updateFilters = (map: maplibregl.Map, layer: VectorMapLayer) => { } } }); + } else { + const annotationTypes: AnnotationTypes[] = ['fill', 'line', 'circle', 'fill-extrusion', 'text']; + annotationTypes.forEach((item) => { + const layerName = `Layer_${layer.id}_${item}`; + const filterSpecification = getLayerDefaultFilter(item, layer); + map.setFilter(layerName, filterSpecification as FilterSpecification); + }); } }; - -export { filterToMapLibreExpression, updateFilters }; +export { filterToMapLibreExpression, updateFilters, getLayerDefaultFilter }; diff --git a/client/src/map/mapNetCDFLayer.ts b/client/src/map/mapNetCDFLayer.ts index 2e5af00..13b72dc 100644 --- a/client/src/map/mapNetCDFLayer.ts +++ b/client/src/map/mapNetCDFLayer.ts @@ -24,8 +24,8 @@ const toggleNetCDFMapLayers = async (map: maplibregl.Map) => { if (index === -1) { // eslint-disable-next-line no-await-in-loop const newData = await UVdatApi.getNetCDFLayerImages(addLayer.id); - const modifiedData = { - ...newData, currentIndex: 0, opacity: 0.75, name: addLayer.name, + const modifiedData: NetCDFImageWorking = { + ...newData, currentIndex: 0, opacity: 0.75, name: addLayer.name, resampling: 'linear', }; visibleNetCDFLayers.value.push(modifiedData); // Coordinates need to be top-left then clockwise @@ -59,12 +59,13 @@ const toggleNetCDFMapLayers = async (map: maplibregl.Map) => { } }; -const updateNetCDFLayer = (layer: number, newindex?: number, newOpacity?: number) => { +const updateNetCDFLayer = (layer: number, data: { index?: number, opacity?: number, resampling?: 'nearest' | 'linear' }) => { + const { index, opacity, resampling } = data; const foundLayer = visibleNetCDFLayers.value.find((item) => item.netCDFLayer === layer); if (foundLayer && internalMap.value) { - if (newindex !== undefined) { + if (index !== undefined) { const source = internalMap.value.getSource(`NetCDFSource_${layer}`); - const newURL = foundLayer.images[newindex]; + const newURL = foundLayer.images[index]; const baseCoordinates = foundLayer.parent_bounds[0].slice(0, 4); const coordinates = [baseCoordinates[3], baseCoordinates[2], baseCoordinates[1], baseCoordinates[0]] as MapLibreCoordinates; if (source && newURL) { @@ -73,10 +74,13 @@ const updateNetCDFLayer = (layer: number, newindex?: number, newOpacity?: number coordinates, }); } - foundLayer.currentIndex = newindex; + foundLayer.currentIndex = index; } - if (newOpacity !== undefined) { - internalMap.value.setPaintProperty(`NetCDFLayer_${layer}`, 'raster-opacity', newOpacity); + if (opacity !== undefined) { + internalMap.value.setPaintProperty(`NetCDFLayer_${layer}`, 'raster-opacity', opacity); + } + if (resampling) { + internalMap.value.setPaintProperty(`NetCDFLayer_${layer}`, 'raster-resampling', resampling); } } visibleNetCDFLayers.value = visibleNetCDFLayers.value.map((item) => item); diff --git a/client/src/map/mapVectorLayers.ts b/client/src/map/mapVectorLayers.ts index 0de6c18..c901176 100644 --- a/client/src/map/mapVectorLayers.ts +++ b/client/src/map/mapVectorLayers.ts @@ -7,7 +7,7 @@ import { AnnotationTypes, VectorMapLayer } from '../types'; import MapStore from '../MapStore'; import { calculateColors } from './mapColors'; import { updateProps } from './mapProperties'; -import { updateFilters } from './mapFilters'; +import { getLayerDefaultFilter, updateFilters } from './mapFilters'; import { subLayerMapping, updateHeatmap } from './mapHeatmap'; const addedLayers: Ref = ref([]); @@ -96,14 +96,6 @@ const updateSelected = (map: maplibregl.Map) => { }); }; -const getLayerFilter = (type: AnnotationTypes) => { - if (['fill', 'fill-extrusion'].includes(type)) { - return ['==', ['geometry-type'], 'Polygon'] as FilterSpecification; - } - - return true as FilterSpecification; -}; - const baseVectorSource = new URL( (import.meta.env.VUE_APP_API_ROOT as string || 'http://localhost:8000/api/v1'), window.location.origin, @@ -194,7 +186,7 @@ const toggleVectorMapLayers = (map: maplibregl.Map) => { type: 'circle', source: `VectorTile_${layer.id}`, 'source-layer': 'default', - filter: getLayerFilter('circle'), + filter: getLayerDefaultFilter('circle', layer), paint: { 'circle-color': getSelected(), 'circle-radius': getCircleRadius(), @@ -208,7 +200,7 @@ const toggleVectorMapLayers = (map: maplibregl.Map) => { type: 'line', source: `VectorTile_${layer.id}`, 'source-layer': 'default', - filter: getLayerFilter('line'), + filter: getLayerDefaultFilter('line'), layout: { 'line-join': 'round', 'line-cap': 'round', @@ -222,7 +214,7 @@ const toggleVectorMapLayers = (map: maplibregl.Map) => { type: 'fill', source: `VectorTile_${layer.id}`, 'source-layer': 'default', - filter: getLayerFilter('fill'), + filter: getLayerDefaultFilter('fill'), paint: { // "fill-color": getAnnotationColor(), 'fill-color': 'blue', @@ -235,7 +227,7 @@ const toggleVectorMapLayers = (map: maplibregl.Map) => { source: `VectorTile_${layer.id}`, 'source-layer': 'default', type: 'fill-extrusion', - filter: getLayerFilter('fill-extrusion'), + filter: getLayerDefaultFilter('fill-extrusion'), paint: { // "fill-extrusion-color": getAnnotationColor(), 'fill-extrusion-color': '#888888', @@ -361,6 +353,15 @@ const updateVectorLayer = (layer: VectorMapLayer) => { ); } } + if (!layerDisplayConfig.drawPoints && layerType === 'line' && !layer.default_style.filters?.length) { + setLayerFilter( + internalMap.value as maplibregl.Map, + `Layer_${layer.id}_circle`, + ['==', ['geometry-type'], 'Point'] as FilterSpecification, + ); + } else if (layerType === 'line') { + setLayerFilter(internalMap.value as maplibregl.Map, `Layer_${layer.id}_circle`, true as FilterSpecification); + } } else { toggleLayerTypeVisibility(internalMap.value as maplibregl.Map, layer.id, layerType, false); } diff --git a/client/src/types.ts b/client/src/types.ts index 65681d0..4ae1127 100644 --- a/client/src/types.ts +++ b/client/src/types.ts @@ -292,6 +292,7 @@ export interface VectorLayerDisplayConfig { max?: number; }, heatmap?: HeatMapConfig; + drawPoints?: boolean; } export interface HeatMapConfig { @@ -448,7 +449,8 @@ export interface NetCDFImages { } // Working type for setting index/opacity -export type NetCDFImageWorking = NetCDFImages & { currentIndex: number, opacity: number, name: string }; +export type NetCDFImageWorking = NetCDFImages +& { currentIndex: number; opacity: number; resampling: 'linear' | 'nearest'; name: string }; export interface NetCDFVariable { max: number; min: number; @@ -565,7 +567,7 @@ export interface KeyProcessedType { // Type for color configuration export type KeyColorConfig = | { type: 'solid'; color: string } - | { attribute: string, type: 'categorical'; pairs: { value: number | string; color: string }[] } + | { attribute: string, type: 'categorical'; pairs: { value: number | string; color: string, disabled?: boolean }[] } | { attribute: string, type: 'linear'; colors: ColorLinearNumber['numberColorPairs'], name: string } | { name: string, type: 'categorical-raster'; pairs: { value: number | string; color: string }[], value:string } | { @@ -798,3 +800,19 @@ export interface FeatureGraphData { indexer: string | number; }> } + +export interface ColorFilterCategorical { + layerId: number; + layerType: AnnotationTypes | 'all'; + type: 'not in'; + key: string; + values: Set; +} + +export interface ColorFilterLinear { + type: 'between'; + min: number; + max: number; +} + +export type ColorFilters = ColorFilterCategorical; diff --git a/client/src/utils.ts b/client/src/utils.ts index b0e1fa2..afc00d9 100644 --- a/client/src/utils.ts +++ b/client/src/utils.ts @@ -133,6 +133,10 @@ const colorSchemes = [ { name: 'd3.YlGn', colors: ['#ffffe5', '#f7fcc4', '#e4f4ac', '#c7e89b', '#a2d88a', '#78c578', '#4eaf63', '#2f944e', '#15793f', '#036034', '#004529'] }, { name: 'd3.YlOrBr', colors: ['#ffffe5', '#fff8c4', '#feeaa1', '#fed676', '#feba4a', '#fb992c', '#ee7918', '#d85b0a', '#b74304', '#8f3204', '#662506'] }, { name: 'd3.YlOrRd', colors: ['#ffffcc', '#fff0a9', '#fee087', '#fec965', '#feab4b', '#fd893c', '#fa5c2e', '#ec3023', '#d31121', '#af0225', '#800026'] }, + { name: 'd3.Blues', colors: ['#f7fbff', '#e3eef9', '#cfe1f2', '#b5d4e9', '#93c3df', '#6daed5', '#4b97c9', '#2f7ebc', '#1864aa', '#0a4a90', '#08306b'] }, + { name: 'd3.Reds', colors: ['#fff5f0', '#fee3d6', '#fdc9b4', '#fcaa8e', '#fc8a6b', '#f9694c', '#ef4533', '#d92723', '#bb151a', '#970b13', '#67000d'] }, + { name: 'd3.Greens', colors: ['#f7fcf5', '#e8f6e3', '#d3eecd', '#b7e2b1', '#97d494', '#73c378', '#4daf62', '#2f984f', '#157f3b', '#036429', '#00441b'] }, + ]; const createColorNumberPairs = (min: number, max: number, scheme: string) => { diff --git a/client/src/views/SourceSelection.vue b/client/src/views/SourceSelection.vue index 25ac9a3..d7a3b9a 100644 --- a/client/src/views/SourceSelection.vue +++ b/client/src/views/SourceSelection.vue @@ -7,6 +7,7 @@ import Datasets from '../components/DataSelection/Datasets.vue'; import Context from '../components/DataSelection/Context.vue'; import Selected from '../components/DataSelection/Selected.vue'; import MapStore from '../MapStore'; +import MetadataLayerFilter from '../components/MetadataLayerFilter/MetadataLayerFilter.vue'; export default defineComponent({ components: { @@ -14,10 +15,11 @@ export default defineComponent({ Selected, Collection, Datasets, + MetadataLayerFilter, }, setup() { onMounted(() => MapStore.loadCollections()); // Load for tab display if collections exists - const tab: Ref<'Scenarios' | 'Datasets' | 'Collections'> = ref('Scenarios'); + const tab: Ref<'Scenarios' | 'Datasets' | 'Collections' | 'Metadata Filters'> = ref('Scenarios'); const selectedLayersCount = computed(() => MapStore.selectedMapLayers.value.length); return { tab, @@ -42,6 +44,9 @@ export default defineComponent({ Collections + + Metadata mdi-filter + + diff --git a/sample_data/divers-h.json b/sample_data/divers-h.json new file mode 100644 index 0000000..affd271 --- /dev/null +++ b/sample_data/divers-h.json @@ -0,0 +1,5473 @@ +[ + { + "type": "Context", + "name": "Input/Outputs", + "default_map_center": [ + 34.8019, + -86.1794 + ], + "default_map_zoom": 6, + "datasets": [ + { + "name": "Inputs", + "description": "DIVERS-H Inputs", + "category": "inputs", + "metadata": {}, + "files": [ + { + "name": "pr_Amon_CESM2_ssp585_r10i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/pr_Amon_CESM2_ssp585_r10i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de90de1cd5c0d8ba6611/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "pr_Amon_CESM2_ssp585_r10i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "pr", + "sliding_variable": "time", + "color_map": "Greens" + } + ], + "tags": { + "filters": { + "Variable": "pr", + "Model": "CESM2", + "Scenario": "ssp585", + "Ensemble": "r10i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + }, + { + "name": "tas_Amon_CESM2_ssp126_r11i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/tas_Amon_CESM2_ssp126_r11i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de91de1cd5c0d8ba6614/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "tas_Amon_CESM2_ssp126_r11i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "tas", + "sliding_variable": "time", + "color_map": "Reds" + } + ], + "tags": { + "filters": { + "Variable": "tas", + "Model": "CESM2", + "Scenario": "ssp126", + "Ensemble": "r11i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + }, + { + "name": "pr_Amon_CESM2_ssp585_r4i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/pr_Amon_CESM2_ssp585_r4i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de91de1cd5c0d8ba6617/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "pr_Amon_CESM2_ssp585_r4i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "pr", + "sliding_variable": "time", + "color_map": "Greens" + } + ], + "tags": { + "filters": { + "Variable": "pr", + "Model": "CESM2", + "Scenario": "ssp585", + "Ensemble": "r4i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + }, + { + "name": "evspsbl_Amon_CESM2_ssp126_r10i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/evspsbl_Amon_CESM2_ssp126_r10i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de91de1cd5c0d8ba661a/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "evspsbl_Amon_CESM2_ssp126_r10i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "evspsbl", + "sliding_variable": "time", + "color_map": "Blues" + } + ], + "tags": { + "filters": { + "Variable": "evspsbl", + "Model": "CESM2", + "Scenario": "ssp126", + "Ensemble": "r10i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + }, + { + "name": "pr_Amon_CESM2_ssp126_r4i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/pr_Amon_CESM2_ssp126_r4i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de92de1cd5c0d8ba661d/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "pr_Amon_CESM2_ssp126_r4i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "pr", + "sliding_variable": "time", + "color_map": "Greens" + } + ], + "tags": { + "filters": { + "Variable": "pr", + "Model": "CESM2", + "Scenario": "ssp126", + "Ensemble": "r4i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + }, + { + "name": "pr_Amon_CNRM-CM6-1_ssp245_r4i1p1f2_gr_201501-210012", + "path": "./data/DIVERS-H/Input/pr_Amon_CNRM-CM6-1_ssp245_r4i1p1f2_gr_201501-210012.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de92de1cd5c0d8ba6620/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "pr_Amon_CNRM-CM6-1_ssp245_r4i1p1f2_gr_201501-210012", + "x_variable": "lon", + "y_variable": "lat", + "variable": "pr", + "sliding_variable": "time", + "color_map": "Greens" + } + ], + "tags": { + "filters": { + "Variable": "pr", + "Model": "CNRM-CM6-1", + "Scenario": "ssp245", + "Ensemble": "r4i1p1f2", + "Grid": "gr", + "Time Range": "201501-210012", + "Input/Output": "Input" + } + } + } + }, + { + "name": "evspsbl_Amon_CESM2_ssp585_r10i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/evspsbl_Amon_CESM2_ssp585_r10i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de93de1cd5c0d8ba6623/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "evspsbl_Amon_CESM2_ssp585_r10i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "evspsbl", + "sliding_variable": "time", + "color_map": "Blues" + } + ], + "tags": { + "filters": { + "Variable": "evspsbl", + "Model": "CESM2", + "Scenario": "ssp585", + "Ensemble": "r10i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + }, + { + "name": "evspsbl_Amon_CNRM-CM6-1_ssp245_r6i1p1f2_gr_201501-210012", + "path": "./data/DIVERS-H/Input/evspsbl_Amon_CNRM-CM6-1_ssp245_r6i1p1f2_gr_201501-210012.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de93de1cd5c0d8ba6626/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "evspsbl_Amon_CNRM-CM6-1_ssp245_r6i1p1f2_gr_201501-210012", + "x_variable": "lon", + "y_variable": "lat", + "variable": "evspsbl", + "sliding_variable": "time", + "color_map": "Blues" + } + ], + "tags": { + "filters": { + "Variable": "evspsbl", + "Model": "CNRM-CM6-1", + "Scenario": "ssp245", + "Ensemble": "r6i1p1f2", + "Grid": "gr", + "Time Range": "201501-210012", + "Input/Output": "Input" + } + } + } + }, + { + "name": "pr_Amon_CESM2_ssp126_r10i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/pr_Amon_CESM2_ssp126_r10i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de94de1cd5c0d8ba6629/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "pr_Amon_CESM2_ssp126_r10i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "pr", + "sliding_variable": "time", + "color_map": "Greens" + } + ], + "tags": { + "filters": { + "Variable": "pr", + "Model": "CESM2", + "Scenario": "ssp126", + "Ensemble": "r10i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + }, + { + "name": "evspsbl_Amon_CESM2_ssp245_r4i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/evspsbl_Amon_CESM2_ssp245_r4i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de94de1cd5c0d8ba662c/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "evspsbl_Amon_CESM2_ssp245_r4i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "evspsbl", + "sliding_variable": "time", + "color_map": "Blues" + } + ], + "tags": { + "filters": { + "Variable": "evspsbl", + "Model": "CESM2", + "Scenario": "ssp245", + "Ensemble": "r4i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + }, + { + "name": "tas_Amon_CNRM-CM6-1_ssp245_r6i1p1f2_gr_201501-210012", + "path": "./data/DIVERS-H/Input/tas_Amon_CNRM-CM6-1_ssp245_r6i1p1f2_gr_201501-210012.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de95de1cd5c0d8ba662f/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "tas_Amon_CNRM-CM6-1_ssp245_r6i1p1f2_gr_201501-210012", + "x_variable": "lon", + "y_variable": "lat", + "variable": "tas", + "sliding_variable": "time", + "color_map": "Reds" + } + ], + "tags": { + "filters": { + "Variable": "tas", + "Model": "CNRM-CM6-1", + "Scenario": "ssp245", + "Ensemble": "r6i1p1f2", + "Grid": "gr", + "Time Range": "201501-210012", + "Input/Output": "Input" + } + } + } + }, + { + "name": "tas_Amon_CESM2_ssp585_r11i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/tas_Amon_CESM2_ssp585_r11i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de95de1cd5c0d8ba6632/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "tas_Amon_CESM2_ssp585_r11i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "tas", + "sliding_variable": "time", + "color_map": "Reds" + } + ], + "tags": { + "filters": { + "Variable": "tas", + "Model": "CESM2", + "Scenario": "ssp585", + "Ensemble": "r11i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + }, + { + "name": "pr_Amon_CESM2_ssp245_r11i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/pr_Amon_CESM2_ssp245_r11i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de95de1cd5c0d8ba6635/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "pr_Amon_CESM2_ssp245_r11i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "pr", + "sliding_variable": "time", + "color_map": "Greens" + } + ], + "tags": { + "filters": { + "Variable": "pr", + "Model": "CESM2", + "Scenario": "ssp245", + "Ensemble": "r11i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + }, + { + "name": "tas_Amon_CESM2_ssp245_r4i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/tas_Amon_CESM2_ssp245_r4i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de96de1cd5c0d8ba6638/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "tas_Amon_CESM2_ssp245_r4i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "tas", + "sliding_variable": "time", + "color_map": "Reds" + } + ], + "tags": { + "filters": { + "Variable": "tas", + "Model": "CESM2", + "Scenario": "ssp245", + "Ensemble": "r4i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + }, + { + "name": "evspsbl_Amon_CESM2_ssp245_r11i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/evspsbl_Amon_CESM2_ssp245_r11i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de96de1cd5c0d8ba663b/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "evspsbl_Amon_CESM2_ssp245_r11i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "evspsbl", + "sliding_variable": "time", + "color_map": "Blues" + } + ], + "tags": { + "filters": { + "Variable": "evspsbl", + "Model": "CESM2", + "Scenario": "ssp245", + "Ensemble": "r11i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + }, + { + "name": "pr_Amon_CNRM-CM6-1_ssp245_r6i1p1f2_gr_201501-210012", + "path": "./data/DIVERS-H/Input/pr_Amon_CNRM-CM6-1_ssp245_r6i1p1f2_gr_201501-210012.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de97de1cd5c0d8ba663e/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "pr_Amon_CNRM-CM6-1_ssp245_r6i1p1f2_gr_201501-210012", + "x_variable": "lon", + "y_variable": "lat", + "variable": "pr", + "sliding_variable": "time", + "color_map": "Greens" + } + ], + "tags": { + "filters": { + "Variable": "pr", + "Model": "CNRM-CM6-1", + "Scenario": "ssp245", + "Ensemble": "r6i1p1f2", + "Grid": "gr", + "Time Range": "201501-210012", + "Input/Output": "Input" + } + } + } + }, + { + "name": "evspsbl_Amon_CNRM-CM6-1_ssp245_r4i1p1f2_gr_201501-210012", + "path": "./data/DIVERS-H/Input/evspsbl_Amon_CNRM-CM6-1_ssp245_r4i1p1f2_gr_201501-210012.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de97de1cd5c0d8ba6641/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "evspsbl_Amon_CNRM-CM6-1_ssp245_r4i1p1f2_gr_201501-210012", + "x_variable": "lon", + "y_variable": "lat", + "variable": "evspsbl", + "sliding_variable": "time", + "color_map": "Blues" + } + ], + "tags": { + "filters": { + "Variable": "evspsbl", + "Model": "CNRM-CM6-1", + "Scenario": "ssp245", + "Ensemble": "r4i1p1f2", + "Grid": "gr", + "Time Range": "201501-210012", + "Input/Output": "Input" + } + } + } + }, + { + "name": "tas_Amon_CESM2_ssp245_r10i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/tas_Amon_CESM2_ssp245_r10i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de98de1cd5c0d8ba6644/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "tas_Amon_CESM2_ssp245_r10i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "tas", + "sliding_variable": "time", + "color_map": "Reds" + } + ], + "tags": { + "filters": { + "Variable": "tas", + "Model": "CESM2", + "Scenario": "ssp245", + "Ensemble": "r10i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + }, + { + "name": "tas_Amon_CNRM-CM6-1_ssp245_r4i1p1f2_gr_201501-210012", + "path": "./data/DIVERS-H/Input/tas_Amon_CNRM-CM6-1_ssp245_r4i1p1f2_gr_201501-210012.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de98de1cd5c0d8ba6647/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "tas_Amon_CNRM-CM6-1_ssp245_r4i1p1f2_gr_201501-210012", + "x_variable": "lon", + "y_variable": "lat", + "variable": "tas", + "sliding_variable": "time", + "color_map": "Reds" + } + ], + "tags": { + "filters": { + "Variable": "tas", + "Model": "CNRM-CM6-1", + "Scenario": "ssp245", + "Ensemble": "r4i1p1f2", + "Grid": "gr", + "Time Range": "201501-210012", + "Input/Output": "Input" + } + } + } + }, + { + "name": "tas_Amon_CESM2_ssp245_r11i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/tas_Amon_CESM2_ssp245_r11i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de98de1cd5c0d8ba664a/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "tas_Amon_CESM2_ssp245_r11i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "tas", + "sliding_variable": "time", + "color_map": "Reds" + } + ], + "tags": { + "filters": { + "Variable": "tas", + "Model": "CESM2", + "Scenario": "ssp245", + "Ensemble": "r11i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + }, + { + "name": "evspsbl_Amon_CNRM-CM6-1_ssp585_r6i1p1f2_gr_201501-210012", + "path": "./data/DIVERS-H/Input/evspsbl_Amon_CNRM-CM6-1_ssp585_r6i1p1f2_gr_201501-210012.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de99de1cd5c0d8ba664d/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "evspsbl_Amon_CNRM-CM6-1_ssp585_r6i1p1f2_gr_201501-210012", + "x_variable": "lon", + "y_variable": "lat", + "variable": "evspsbl", + "sliding_variable": "time", + "color_map": "Blues" + } + ], + "tags": { + "filters": { + "Variable": "evspsbl", + "Model": "CNRM-CM6-1", + "Scenario": "ssp585", + "Ensemble": "r6i1p1f2", + "Grid": "gr", + "Time Range": "201501-210012", + "Input/Output": "Input" + } + } + } + }, + { + "name": "evspsbl_Amon_CESM2_ssp585_r4i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/evspsbl_Amon_CESM2_ssp585_r4i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de99de1cd5c0d8ba6650/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "evspsbl_Amon_CESM2_ssp585_r4i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "evspsbl", + "sliding_variable": "time", + "color_map": "Blues" + } + ], + "tags": { + "filters": { + "Variable": "evspsbl", + "Model": "CESM2", + "Scenario": "ssp585", + "Ensemble": "r4i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + }, + { + "name": "tas_Amon_CNRM-CM6-1_ssp585_r6i1p1f2_gr_201501-210012", + "path": "./data/DIVERS-H/Input/tas_Amon_CNRM-CM6-1_ssp585_r6i1p1f2_gr_201501-210012.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de9ade1cd5c0d8ba6653/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "tas_Amon_CNRM-CM6-1_ssp585_r6i1p1f2_gr_201501-210012", + "x_variable": "lon", + "y_variable": "lat", + "variable": "tas", + "sliding_variable": "time", + "color_map": "Reds" + } + ], + "tags": { + "filters": { + "Variable": "tas", + "Model": "CNRM-CM6-1", + "Scenario": "ssp585", + "Ensemble": "r6i1p1f2", + "Grid": "gr", + "Time Range": "201501-210012", + "Input/Output": "Input" + } + } + } + }, + { + "name": "evspsbl_Amon_CESM2_ssp245_r10i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/evspsbl_Amon_CESM2_ssp245_r10i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de9ade1cd5c0d8ba6656/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "evspsbl_Amon_CESM2_ssp245_r10i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "evspsbl", + "sliding_variable": "time", + "color_map": "Blues" + } + ], + "tags": { + "filters": { + "Variable": "evspsbl", + "Model": "CESM2", + "Scenario": "ssp245", + "Ensemble": "r10i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + }, + { + "name": "pr_Amon_CNRM-CM6-1_ssp585_r4i1p1f2_gr_201501-210012", + "path": "./data/DIVERS-H/Input/pr_Amon_CNRM-CM6-1_ssp585_r4i1p1f2_gr_201501-210012.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de9bde1cd5c0d8ba6659/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "pr_Amon_CNRM-CM6-1_ssp585_r4i1p1f2_gr_201501-210012", + "x_variable": "lon", + "y_variable": "lat", + "variable": "pr", + "sliding_variable": "time", + "color_map": "Greens" + } + ], + "tags": { + "filters": { + "Variable": "pr", + "Model": "CNRM-CM6-1", + "Scenario": "ssp585", + "Ensemble": "r4i1p1f2", + "Grid": "gr", + "Time Range": "201501-210012", + "Input/Output": "Input" + } + } + } + }, + { + "name": "evspsbl_Amon_CNRM-CM6-1_ssp126_r6i1p1f2_gr_201501-210012", + "path": "./data/DIVERS-H/Input/evspsbl_Amon_CNRM-CM6-1_ssp126_r6i1p1f2_gr_201501-210012.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de9bde1cd5c0d8ba665c/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "evspsbl_Amon_CNRM-CM6-1_ssp126_r6i1p1f2_gr_201501-210012", + "x_variable": "lon", + "y_variable": "lat", + "variable": "evspsbl", + "sliding_variable": "time", + "color_map": "Blues" + } + ], + "tags": { + "filters": { + "Variable": "evspsbl", + "Model": "CNRM-CM6-1", + "Scenario": "ssp126", + "Ensemble": "r6i1p1f2", + "Grid": "gr", + "Time Range": "201501-210012", + "Input/Output": "Input" + } + } + } + }, + { + "name": "evspsbl_Amon_CESM2_ssp126_r4i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/evspsbl_Amon_CESM2_ssp126_r4i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de9cde1cd5c0d8ba665f/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "evspsbl_Amon_CESM2_ssp126_r4i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "evspsbl", + "sliding_variable": "time", + "color_map": "Blues" + } + ], + "tags": { + "filters": { + "Variable": "evspsbl", + "Model": "CESM2", + "Scenario": "ssp126", + "Ensemble": "r4i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + }, + { + "name": "tas_Amon_CNRM-CM6-1_ssp126_r6i1p1f2_gr_201501-210012", + "path": "./data/DIVERS-H/Input/tas_Amon_CNRM-CM6-1_ssp126_r6i1p1f2_gr_201501-210012.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de9cde1cd5c0d8ba6662/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "tas_Amon_CNRM-CM6-1_ssp126_r6i1p1f2_gr_201501-210012", + "x_variable": "lon", + "y_variable": "lat", + "variable": "tas", + "sliding_variable": "time", + "color_map": "Reds" + } + ], + "tags": { + "filters": { + "Variable": "tas", + "Model": "CNRM-CM6-1", + "Scenario": "ssp126", + "Ensemble": "r6i1p1f2", + "Grid": "gr", + "Time Range": "201501-210012", + "Input/Output": "Input" + } + } + } + }, + { + "name": "pr_Amon_CESM2_ssp245_r10i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/pr_Amon_CESM2_ssp245_r10i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de9dde1cd5c0d8ba6665/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "pr_Amon_CESM2_ssp245_r10i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "pr", + "sliding_variable": "time", + "color_map": "Greens" + } + ], + "tags": { + "filters": { + "Variable": "pr", + "Model": "CESM2", + "Scenario": "ssp245", + "Ensemble": "r10i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + }, + { + "name": "pr_Amon_CNRM-CM6-1_ssp126_r4i1p1f2_gr_201501-210012", + "path": "./data/DIVERS-H/Input/pr_Amon_CNRM-CM6-1_ssp126_r4i1p1f2_gr_201501-210012.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de9dde1cd5c0d8ba6668/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "pr_Amon_CNRM-CM6-1_ssp126_r4i1p1f2_gr_201501-210012", + "x_variable": "lon", + "y_variable": "lat", + "variable": "pr", + "sliding_variable": "time", + "color_map": "Greens" + } + ], + "tags": { + "filters": { + "Variable": "pr", + "Model": "CNRM-CM6-1", + "Scenario": "ssp126", + "Ensemble": "r4i1p1f2", + "Grid": "gr", + "Time Range": "201501-210012", + "Input/Output": "Input" + } + } + } + }, + { + "name": "pr_Amon_CESM2_ssp245_r4i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/pr_Amon_CESM2_ssp245_r4i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de9dde1cd5c0d8ba666b/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "pr_Amon_CESM2_ssp245_r4i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "pr", + "sliding_variable": "time", + "color_map": "Greens" + } + ], + "tags": { + "filters": { + "Variable": "pr", + "Model": "CESM2", + "Scenario": "ssp245", + "Ensemble": "r4i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + }, + { + "name": "evspsbl_Amon_CNRM-CM6-1_ssp585_r4i1p1f2_gr_201501-210012", + "path": "./data/DIVERS-H/Input/evspsbl_Amon_CNRM-CM6-1_ssp585_r4i1p1f2_gr_201501-210012.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de9ede1cd5c0d8ba666e/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "evspsbl_Amon_CNRM-CM6-1_ssp585_r4i1p1f2_gr_201501-210012", + "x_variable": "lon", + "y_variable": "lat", + "variable": "evspsbl", + "sliding_variable": "time", + "color_map": "Blues" + } + ], + "tags": { + "filters": { + "Variable": "evspsbl", + "Model": "CNRM-CM6-1", + "Scenario": "ssp585", + "Ensemble": "r4i1p1f2", + "Grid": "gr", + "Time Range": "201501-210012", + "Input/Output": "Input" + } + } + } + }, + { + "name": "tas_Amon_CESM2_ssp126_r4i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/tas_Amon_CESM2_ssp126_r4i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de9ede1cd5c0d8ba6671/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "tas_Amon_CESM2_ssp126_r4i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "tas", + "sliding_variable": "time", + "color_map": "Reds" + } + ], + "tags": { + "filters": { + "Variable": "tas", + "Model": "CESM2", + "Scenario": "ssp126", + "Ensemble": "r4i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + }, + { + "name": "tas_Amon_CESM2_ssp585_r10i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/tas_Amon_CESM2_ssp585_r10i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de9fde1cd5c0d8ba6674/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "tas_Amon_CESM2_ssp585_r10i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "tas", + "sliding_variable": "time", + "color_map": "Reds" + } + ], + "tags": { + "filters": { + "Variable": "tas", + "Model": "CESM2", + "Scenario": "ssp585", + "Ensemble": "r10i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + }, + { + "name": "pr_Amon_CESM2_ssp126_r11i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/pr_Amon_CESM2_ssp126_r11i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0de9fde1cd5c0d8ba6677/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "pr_Amon_CESM2_ssp126_r11i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "pr", + "sliding_variable": "time", + "color_map": "Greens" + } + ], + "tags": { + "filters": { + "Variable": "pr", + "Model": "CESM2", + "Scenario": "ssp126", + "Ensemble": "r11i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + }, + { + "name": "tas_Amon_CNRM-CM6-1_ssp585_r4i1p1f2_gr_201501-210012", + "path": "./data/DIVERS-H/Input/tas_Amon_CNRM-CM6-1_ssp585_r4i1p1f2_gr_201501-210012.nc", + "url": "https://data.kitware.com/api/v1/file/67c0dea0de1cd5c0d8ba667a/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "tas_Amon_CNRM-CM6-1_ssp585_r4i1p1f2_gr_201501-210012", + "x_variable": "lon", + "y_variable": "lat", + "variable": "tas", + "sliding_variable": "time", + "color_map": "Reds" + } + ], + "tags": { + "filters": { + "Variable": "tas", + "Model": "CNRM-CM6-1", + "Scenario": "ssp585", + "Ensemble": "r4i1p1f2", + "Grid": "gr", + "Time Range": "201501-210012", + "Input/Output": "Input" + } + } + } + }, + { + "name": "evspsbl_Amon_CESM2_ssp585_r11i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/evspsbl_Amon_CESM2_ssp585_r11i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0dea0de1cd5c0d8ba667d/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "evspsbl_Amon_CESM2_ssp585_r11i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "evspsbl", + "sliding_variable": "time", + "color_map": "Blues" + } + ], + "tags": { + "filters": { + "Variable": "evspsbl", + "Model": "CESM2", + "Scenario": "ssp585", + "Ensemble": "r11i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + }, + { + "name": "pr_Amon_CNRM-CM6-1_ssp585_r6i1p1f2_gr_201501-210012", + "path": "./data/DIVERS-H/Input/pr_Amon_CNRM-CM6-1_ssp585_r6i1p1f2_gr_201501-210012.nc", + "url": "https://data.kitware.com/api/v1/file/67c0dea0de1cd5c0d8ba6680/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "pr_Amon_CNRM-CM6-1_ssp585_r6i1p1f2_gr_201501-210012", + "x_variable": "lon", + "y_variable": "lat", + "variable": "pr", + "sliding_variable": "time", + "color_map": "Greens" + } + ], + "tags": { + "filters": { + "Variable": "pr", + "Model": "CNRM-CM6-1", + "Scenario": "ssp585", + "Ensemble": "r6i1p1f2", + "Grid": "gr", + "Time Range": "201501-210012", + "Input/Output": "Input" + } + } + } + }, + { + "name": "evspsbl_Amon_CNRM-CM6-1_ssp126_r4i1p1f2_gr_201501-210012", + "path": "./data/DIVERS-H/Input/evspsbl_Amon_CNRM-CM6-1_ssp126_r4i1p1f2_gr_201501-210012.nc", + "url": "https://data.kitware.com/api/v1/file/67c0dea1de1cd5c0d8ba6683/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "evspsbl_Amon_CNRM-CM6-1_ssp126_r4i1p1f2_gr_201501-210012", + "x_variable": "lon", + "y_variable": "lat", + "variable": "evspsbl", + "sliding_variable": "time", + "color_map": "Blues" + } + ], + "tags": { + "filters": { + "Variable": "evspsbl", + "Model": "CNRM-CM6-1", + "Scenario": "ssp126", + "Ensemble": "r4i1p1f2", + "Grid": "gr", + "Time Range": "201501-210012", + "Input/Output": "Input" + } + } + } + }, + { + "name": "evspsbl_Amon_CESM2_ssp126_r11i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/evspsbl_Amon_CESM2_ssp126_r11i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0dea1de1cd5c0d8ba6686/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "evspsbl_Amon_CESM2_ssp126_r11i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "evspsbl", + "sliding_variable": "time", + "color_map": "Blues" + } + ], + "tags": { + "filters": { + "Variable": "evspsbl", + "Model": "CESM2", + "Scenario": "ssp126", + "Ensemble": "r11i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + }, + { + "name": "tas_Amon_CESM2_ssp585_r4i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/tas_Amon_CESM2_ssp585_r4i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0dea2de1cd5c0d8ba6689/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "tas_Amon_CESM2_ssp585_r4i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "tas", + "sliding_variable": "time", + "color_map": "Reds" + } + ], + "tags": { + "filters": { + "Variable": "tas", + "Model": "CESM2", + "Scenario": "ssp585", + "Ensemble": "r4i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + }, + { + "name": "tas_Amon_CNRM-CM6-1_ssp126_r4i1p1f2_gr_201501-210012", + "path": "./data/DIVERS-H/Input/tas_Amon_CNRM-CM6-1_ssp126_r4i1p1f2_gr_201501-210012.nc", + "url": "https://data.kitware.com/api/v1/file/67c0dea3de1cd5c0d8ba668c/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "tas_Amon_CNRM-CM6-1_ssp126_r4i1p1f2_gr_201501-210012", + "x_variable": "lon", + "y_variable": "lat", + "variable": "tas", + "sliding_variable": "time", + "color_map": "Reds" + } + ], + "tags": { + "filters": { + "Variable": "tas", + "Model": "CNRM-CM6-1", + "Scenario": "ssp126", + "Ensemble": "r4i1p1f2", + "Grid": "gr", + "Time Range": "201501-210012", + "Input/Output": "Input" + } + } + } + }, + { + "name": "tas_Amon_CESM2_ssp126_r10i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/tas_Amon_CESM2_ssp126_r10i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0dea3de1cd5c0d8ba668f/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "tas_Amon_CESM2_ssp126_r10i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "tas", + "sliding_variable": "time", + "color_map": "Reds" + } + ], + "tags": { + "filters": { + "Variable": "tas", + "Model": "CESM2", + "Scenario": "ssp126", + "Ensemble": "r10i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + }, + { + "name": "pr_Amon_CNRM-CM6-1_ssp126_r6i1p1f2_gr_201501-210012", + "path": "./data/DIVERS-H/Input/pr_Amon_CNRM-CM6-1_ssp126_r6i1p1f2_gr_201501-210012.nc", + "url": "https://data.kitware.com/api/v1/file/67c0dea4de1cd5c0d8ba6692/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "pr_Amon_CNRM-CM6-1_ssp126_r6i1p1f2_gr_201501-210012", + "x_variable": "lon", + "y_variable": "lat", + "variable": "pr", + "sliding_variable": "time", + "color_map": "Greens" + } + ], + "tags": { + "filters": { + "Variable": "pr", + "Model": "CNRM-CM6-1", + "Scenario": "ssp126", + "Ensemble": "r6i1p1f2", + "Grid": "gr", + "Time Range": "201501-210012", + "Input/Output": "Input" + } + } + } + }, + { + "name": "pr_Amon_CESM2_ssp585_r11i1p1f1_gn_201501-206412", + "path": "./data/DIVERS-H/Input/pr_Amon_CESM2_ssp585_r11i1p1f1_gn_201501-206412.nc", + "url": "https://data.kitware.com/api/v1/file/67c0dea4de1cd5c0d8ba6695/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "pr_Amon_CESM2_ssp585_r11i1p1f1_gn_201501-206412", + "x_variable": "lon", + "y_variable": "lat", + "variable": "pr", + "sliding_variable": "time", + "color_map": "Greens" + } + ], + "tags": { + "filters": { + "Variable": "pr", + "Model": "CESM2", + "Scenario": "ssp585", + "Ensemble": "r11i1p1f1", + "Grid": "gn", + "Time Range": "201501-206412", + "Input/Output": "Input" + } + } + } + } + ] + }, + { + "name": "Outputs", + "description": "DIVERS-H Outputs", + "category": "outputs", + "metadata": {}, + "files": [ + { + "name": "PminusE_Amon_CESM2_ssp126_r10i1p1f1_2015-2055", + "path": "./data/DIVERS-H/Output/PminusE_Amon_CESM2_ssp126_r10i1p1f1_2015-2055.nc", + "url": "https://data.kitware.com/api/v1/file/67c0dea5de1cd5c0d8ba6698/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "PminusE_Amon_CESM2_ssp126_r10i1p1f1_2015-2055", + "x_variable": "lon", + "y_variable": "lat", + "variable": "P_minus_E", + "sliding_variable": "time", + "color_map": "turbo" + } + ], + "tags": { + "filters": { + "Variable": "PminusE", + "Model": "CESM2", + "Scenario": "ssp126", + "Ensemble": "r10i1p1f1", + "Grid": null, + "Time Range": "2015-2055", + "Input/Output": "Output" + } + } + } + }, + { + "name": "PminusE_Amon_CNRM-CM6-1_ssp126_r6i1p1f2_2015-2055", + "path": "./data/DIVERS-H/Output/PminusE_Amon_CNRM-CM6-1_ssp126_r6i1p1f2_2015-2055.nc", + "url": "https://data.kitware.com/api/v1/file/67c0dea6de1cd5c0d8ba669b/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "PminusE_Amon_CNRM-CM6-1_ssp126_r6i1p1f2_2015-2055", + "x_variable": "lon", + "y_variable": "lat", + "variable": "P_minus_E", + "sliding_variable": "time", + "color_map": "turbo" + } + ], + "tags": { + "filters": { + "Variable": "PminusE", + "Model": "CNRM-CM6-1", + "Scenario": "ssp126", + "Ensemble": "r6i1p1f2", + "Grid": null, + "Time Range": "2015-2055", + "Input/Output": "Output" + } + } + } + }, + { + "name": "PminusE_Amon_CNRM-CM6-1_ssp126_r5i1p1f2_2015-2055", + "path": "./data/DIVERS-H/Output/PminusE_Amon_CNRM-CM6-1_ssp126_r5i1p1f2_2015-2055.nc", + "url": "https://data.kitware.com/api/v1/file/67c0dea7de1cd5c0d8ba669e/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "PminusE_Amon_CNRM-CM6-1_ssp126_r5i1p1f2_2015-2055", + "x_variable": "lon", + "y_variable": "lat", + "variable": "P_minus_E", + "sliding_variable": "time", + "color_map": "turbo" + } + ], + "tags": { + "filters": { + "Variable": "PminusE", + "Model": "CNRM-CM6-1", + "Scenario": "ssp126", + "Ensemble": "r5i1p1f2", + "Grid": null, + "Time Range": "2015-2055", + "Input/Output": "Output" + } + } + } + }, + { + "name": "PminusE_Amon_CESM2_ssp245_r4i1p1f1_2015-2055", + "path": "./data/DIVERS-H/Output/PminusE_Amon_CESM2_ssp245_r4i1p1f1_2015-2055.nc", + "url": "https://data.kitware.com/api/v1/file/67c0dea8de1cd5c0d8ba66a1/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "PminusE_Amon_CESM2_ssp245_r4i1p1f1_2015-2055", + "x_variable": "lon", + "y_variable": "lat", + "variable": "P_minus_E", + "sliding_variable": "time", + "color_map": "turbo" + } + ], + "tags": { + "filters": { + "Variable": "PminusE", + "Model": "CESM2", + "Scenario": "ssp245", + "Ensemble": "r4i1p1f1", + "Grid": null, + "Time Range": "2015-2055", + "Input/Output": "Output" + } + } + } + }, + { + "name": "PminusE_Amon_CNRM-CM6-1_ssp585_r4i1p1f2_2015-2055", + "path": "./data/DIVERS-H/Output/PminusE_Amon_CNRM-CM6-1_ssp585_r4i1p1f2_2015-2055.nc", + "url": "https://data.kitware.com/api/v1/file/67c0dea9de1cd5c0d8ba66a4/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "PminusE_Amon_CNRM-CM6-1_ssp585_r4i1p1f2_2015-2055", + "x_variable": "lon", + "y_variable": "lat", + "variable": "P_minus_E", + "sliding_variable": "time", + "color_map": "turbo" + } + ], + "tags": { + "filters": { + "Variable": "PminusE", + "Model": "CNRM-CM6-1", + "Scenario": "ssp585", + "Ensemble": "r4i1p1f2", + "Grid": null, + "Time Range": "2015-2055", + "Input/Output": "Output" + } + } + } + }, + { + "name": "PminusE_Amon_CESM2_ssp585_r11i1p1f1_2015-2055", + "path": "./data/DIVERS-H/Output/PminusE_Amon_CESM2_ssp585_r11i1p1f1_2015-2055.nc", + "url": "https://data.kitware.com/api/v1/file/67c0dea9de1cd5c0d8ba66a7/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "PminusE_Amon_CESM2_ssp585_r11i1p1f1_2015-2055", + "x_variable": "lon", + "y_variable": "lat", + "variable": "P_minus_E", + "sliding_variable": "time", + "color_map": "turbo" + } + ], + "tags": { + "filters": { + "Variable": "PminusE", + "Model": "CESM2", + "Scenario": "ssp585", + "Ensemble": "r11i1p1f1", + "Grid": null, + "Time Range": "2015-2055", + "Input/Output": "Output" + } + } + } + }, + { + "name": "PminusE_Amon_CNRM-CM6-1_ssp245_r4i1p1f2_2015-2055", + "path": "./data/DIVERS-H/Output/PminusE_Amon_CNRM-CM6-1_ssp245_r4i1p1f2_2015-2055.nc", + "url": "https://data.kitware.com/api/v1/file/67c0deabde1cd5c0d8ba66aa/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "PminusE_Amon_CNRM-CM6-1_ssp245_r4i1p1f2_2015-2055", + "x_variable": "lon", + "y_variable": "lat", + "variable": "P_minus_E", + "sliding_variable": "time", + "color_map": "turbo" + } + ], + "tags": { + "filters": { + "Variable": "PminusE", + "Model": "CNRM-CM6-1", + "Scenario": "ssp245", + "Ensemble": "r4i1p1f2", + "Grid": null, + "Time Range": "2015-2055", + "Input/Output": "Output" + } + } + } + }, + { + "name": "PminusE_Amon_CESM2_ssp245_r10i1p1f1_2015-2055", + "path": "./data/DIVERS-H/Output/PminusE_Amon_CESM2_ssp245_r10i1p1f1_2015-2055.nc", + "url": "https://data.kitware.com/api/v1/file/67c0deacde1cd5c0d8ba66ad/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "PminusE_Amon_CESM2_ssp245_r10i1p1f1_2015-2055", + "x_variable": "lon", + "y_variable": "lat", + "variable": "P_minus_E", + "sliding_variable": "time", + "color_map": "turbo" + } + ], + "tags": { + "filters": { + "Variable": "PminusE", + "Model": "CESM2", + "Scenario": "ssp245", + "Ensemble": "r10i1p1f1", + "Grid": null, + "Time Range": "2015-2055", + "Input/Output": "Output" + } + } + } + }, + { + "name": "PminusE_Amon_CESM2_ssp585_r4i1p1f1_2015-2055", + "path": "./data/DIVERS-H/Output/PminusE_Amon_CESM2_ssp585_r4i1p1f1_2015-2055.nc", + "url": "https://data.kitware.com/api/v1/file/67c0deadde1cd5c0d8ba66b0/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "PminusE_Amon_CESM2_ssp585_r4i1p1f1_2015-2055", + "x_variable": "lon", + "y_variable": "lat", + "variable": "P_minus_E", + "sliding_variable": "time", + "color_map": "turbo" + } + ], + "tags": { + "filters": { + "Variable": "PminusE", + "Model": "CESM2", + "Scenario": "ssp585", + "Ensemble": "r4i1p1f1", + "Grid": null, + "Time Range": "2015-2055", + "Input/Output": "Output" + } + } + } + }, + { + "name": "PminusE_Amon_CNRM-CM6-1_ssp585_r6i1p1f2_2015-2055", + "path": "./data/DIVERS-H/Output/PminusE_Amon_CNRM-CM6-1_ssp585_r6i1p1f2_2015-2055.nc", + "url": "https://data.kitware.com/api/v1/file/67c0deaede1cd5c0d8ba66b3/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "PminusE_Amon_CNRM-CM6-1_ssp585_r6i1p1f2_2015-2055", + "x_variable": "lon", + "y_variable": "lat", + "variable": "P_minus_E", + "sliding_variable": "time", + "color_map": "turbo" + } + ], + "tags": { + "filters": { + "Variable": "PminusE", + "Model": "CNRM-CM6-1", + "Scenario": "ssp585", + "Ensemble": "r6i1p1f2", + "Grid": null, + "Time Range": "2015-2055", + "Input/Output": "Output" + } + } + } + }, + { + "name": "PminusE_Amon_CNRM-CM6-1_ssp245_r5i1p1f2_2015-2055", + "path": "./data/DIVERS-H/Output/PminusE_Amon_CNRM-CM6-1_ssp245_r5i1p1f2_2015-2055.nc", + "url": "https://data.kitware.com/api/v1/file/67c0deafde1cd5c0d8ba66b6/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "PminusE_Amon_CNRM-CM6-1_ssp245_r5i1p1f2_2015-2055", + "x_variable": "lon", + "y_variable": "lat", + "variable": "P_minus_E", + "sliding_variable": "time", + "color_map": "turbo" + } + ], + "tags": { + "filters": { + "Variable": "PminusE", + "Model": "CNRM-CM6-1", + "Scenario": "ssp245", + "Ensemble": "r5i1p1f2", + "Grid": null, + "Time Range": "2015-2055", + "Input/Output": "Output" + } + } + } + }, + { + "name": "PminusE_Amon_CESM2_ssp245_r11i1p1f1_2015-2055", + "path": "./data/DIVERS-H/Output/PminusE_Amon_CESM2_ssp245_r11i1p1f1_2015-2055.nc", + "url": "https://data.kitware.com/api/v1/file/67c0deafde1cd5c0d8ba66b9/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "PminusE_Amon_CESM2_ssp245_r11i1p1f1_2015-2055", + "x_variable": "lon", + "y_variable": "lat", + "variable": "P_minus_E", + "sliding_variable": "time", + "color_map": "turbo" + } + ], + "tags": { + "filters": { + "Variable": "PminusE", + "Model": "CESM2", + "Scenario": "ssp245", + "Ensemble": "r11i1p1f1", + "Grid": null, + "Time Range": "2015-2055", + "Input/Output": "Output" + } + } + } + }, + { + "name": "PminusE_Amon_CESM2_ssp585_r10i1p1f1_2015-2055", + "path": "./data/DIVERS-H/Output/PminusE_Amon_CESM2_ssp585_r10i1p1f1_2015-2055.nc", + "url": "https://data.kitware.com/api/v1/file/67c0deb0de1cd5c0d8ba66bc/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "PminusE_Amon_CESM2_ssp585_r10i1p1f1_2015-2055", + "x_variable": "lon", + "y_variable": "lat", + "variable": "P_minus_E", + "sliding_variable": "time", + "color_map": "turbo" + } + ], + "tags": { + "filters": { + "Variable": "PminusE", + "Model": "CESM2", + "Scenario": "ssp585", + "Ensemble": "r10i1p1f1", + "Grid": null, + "Time Range": "2015-2055", + "Input/Output": "Output" + } + } + } + }, + { + "name": "PminusE_Amon_CNRM-CM6-1_ssp245_r6i1p1f2_2015-2055", + "path": "./data/DIVERS-H/Output/PminusE_Amon_CNRM-CM6-1_ssp245_r6i1p1f2_2015-2055.nc", + "url": "https://data.kitware.com/api/v1/file/67c0deb1de1cd5c0d8ba66bf/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "PminusE_Amon_CNRM-CM6-1_ssp245_r6i1p1f2_2015-2055", + "x_variable": "lon", + "y_variable": "lat", + "variable": "P_minus_E", + "sliding_variable": "time", + "color_map": "turbo" + } + ], + "tags": { + "filters": { + "Variable": "PminusE", + "Model": "CNRM-CM6-1", + "Scenario": "ssp245", + "Ensemble": "r6i1p1f2", + "Grid": null, + "Time Range": "2015-2055", + "Input/Output": "Output" + } + } + } + }, + { + "name": "PminusE_Amon_CNRM-CM6-1_ssp585_r5i1p1f2_2015-2055", + "path": "./data/DIVERS-H/Output/PminusE_Amon_CNRM-CM6-1_ssp585_r5i1p1f2_2015-2055.nc", + "url": "https://data.kitware.com/api/v1/file/67c0deb2de1cd5c0d8ba66c2/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "PminusE_Amon_CNRM-CM6-1_ssp585_r5i1p1f2_2015-2055", + "x_variable": "lon", + "y_variable": "lat", + "variable": "P_minus_E", + "sliding_variable": "time", + "color_map": "turbo" + } + ], + "tags": { + "filters": { + "Variable": "PminusE", + "Model": "CNRM-CM6-1", + "Scenario": "ssp585", + "Ensemble": "r5i1p1f2", + "Grid": null, + "Time Range": "2015-2055", + "Input/Output": "Output" + } + } + } + }, + { + "name": "PminusE_Amon_CNRM-CM6-1_ssp126_r4i1p1f2_2015-2055", + "path": "./data/DIVERS-H/Output/PminusE_Amon_CNRM-CM6-1_ssp126_r4i1p1f2_2015-2055.nc", + "url": "https://data.kitware.com/api/v1/file/67c0deb3de1cd5c0d8ba66c5/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "PminusE_Amon_CNRM-CM6-1_ssp126_r4i1p1f2_2015-2055", + "x_variable": "lon", + "y_variable": "lat", + "variable": "P_minus_E", + "sliding_variable": "time", + "color_map": "turbo" + } + ], + "tags": { + "filters": { + "Variable": "PminusE", + "Model": "CNRM-CM6-1", + "Scenario": "ssp126", + "Ensemble": "r4i1p1f2", + "Grid": null, + "Time Range": "2015-2055", + "Input/Output": "Output" + } + } + } + }, + { + "name": "PminusE_Amon_CESM2_ssp126_r4i1p1f1_2015-2055", + "path": "./data/DIVERS-H/Output/PminusE_Amon_CESM2_ssp126_r4i1p1f1_2015-2055.nc", + "url": "https://data.kitware.com/api/v1/file/67c0deb3de1cd5c0d8ba66c8/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "PminusE_Amon_CESM2_ssp126_r4i1p1f1_2015-2055", + "x_variable": "lon", + "y_variable": "lat", + "variable": "P_minus_E", + "sliding_variable": "time", + "color_map": "turbo" + } + ], + "tags": { + "filters": { + "Variable": "PminusE", + "Model": "CESM2", + "Scenario": "ssp126", + "Ensemble": "r4i1p1f1", + "Grid": null, + "Time Range": "2015-2055", + "Input/Output": "Output" + } + } + } + }, + { + "name": "PminusE_Amon_CESM2_ssp126_r11i1p1f1_2015-2055", + "path": "./data/DIVERS-H/Output/PminusE_Amon_CESM2_ssp126_r11i1p1f1_2015-2055.nc", + "url": "https://data.kitware.com/api/v1/file/67c0deb4de1cd5c0d8ba66cb/download", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "PminusE_Amon_CESM2_ssp126_r11i1p1f1_2015-2055", + "x_variable": "lon", + "y_variable": "lat", + "variable": "P_minus_E", + "sliding_variable": "time", + "color_map": "turbo" + } + ], + "tags": { + "filters": { + "Variable": "PminusE", + "Model": "CESM2", + "Scenario": "ssp126", + "Ensemble": "r11i1p1f1", + "Grid": null, + "Time Range": "2015-2055", + "Input/Output": "Output" + } + } + } + } + ] + }, + { + "name": "PowerPlants", + "description": "DIVERS-H PowerPlant data", + "category": "merged", + "metadata": {}, + "files": [ + { + "name": "PowerPlant_CNRM-CM6-1_ssp585_r4i1p1f2_tabular", + "path": "./data/DIVERS-H/PowerPlants/TVAPowerPlants.geojson", + "url": "https://data.kitware.com/api/v1/file/67c0deb5de1cd5c0d8ba66ce/download", + "type": "geojson", + "metadata": { + "tabular": { + "path": "./data/DIVERS-H/PowerPlants/PowerPlant_CNRM-CM6-1_ssp585_r4i1p1f2_tabular.json", + "name": "PowerPlant_CNRM-CM6-1_ssp585_r4i1p1f2_tabular_data", + "url": "https://data.kitware.com/api/v1/file/67c0deb5de1cd5c0d8ba66d1/download", + "featurePropertyMatcher": "Plant_Code" + }, + "tags": { + "filters": { + "Model": "CNRM-CM6-1", + "Scenario": "ssp585", + "Ensemble": "r4i1p1f2", + "Input/Output": "Ouput" + } + }, + "default_style": { + "layers": { + "fill": { + "color": "#888888", + "enabled": false + }, + "line": { + "size": 1, + "color": "#000000", + "enabled": false + }, + "text": { + "size": { + "type": "SizeZoom", + "zoomLevels": [ + [ + 10, + 12 + ], + [ + 12, + 9 + ], + [ + 16, + 10 + ] + ] + }, + "text": { + "key": "Plant_Name" + }, + "zoom": { + "max": 24, + "min": 7 + }, + "color": "#000000", + "enabled": true + }, + "circle": { + "color": "#888888", + "enabled": true, + "selectable": "singleSelect", + "selectColor": "#00FFFF" + }, + "fill-extrusion": { + "color": "#888888", + "enabled": false + } + }, + "properties": { + "selectionDisplay": true, + "availableProperties": { + "Total_MW": { + "key": "Total_MW", + "max": 3661.7, + "min": 0.9, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Total_MW" + }, + "tech_desc": { + "key": "tech_desc", + "type": "string", + "values": [ + "Batteries; Solar Photovoltaic;", + "Conventional Hydroelectric", + "Conventional Steam Coal", + "Conventional Steam Coal; Natural Gas Fired Combustion Turbine;", + "Hydroelectric Pumped Storage", + "Hydroelectric Pumped Storage; Conventional Hydroelectric;", + "Landfill Gas", + "Natural Gas Fired Combined Cycle", + "Natural Gas Fired Combined Cycle; Natural Gas Fired Combustion Turbine;", + "Natural Gas Fired Combined Cycle; Petroleum Liquids;", + "Natural Gas Fired Combustion Turbine", + "Natural Gas Internal Combustion Engine; Petroleum Liquids;", + "Nuclear", + "Onshore Wind Turbine", + "Other Gases", + "Other Waste Biomass; Petroleum Liquids;", + "Petroleum Liquids", + "Solar Photovoltaic", + "Wood/Wood Waste Biomass" + ], + "display": true, + "tooltip": false, + "description": "", + "displayName": "tech_desc" + }, + "Plant_Code": { + "key": "Plant_Code", + "max": 65642, + "min": 20, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Plant_Code" + }, + "Plant_Name": { + "key": "Plant_Name", + "type": "string", + "unique": 121, + "display": true, + "tooltip": false, + "searchable": true, + "description": "", + "displayName": "Plant_Name" + } + } + }, + "vectorFeatureTableGraphs": [ + { + "name": "tas", + "type": "tas_pr_evspsbl_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "tas_pr_evspsbl_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "evspsbl", + "type": "tas_pr_evspsbl_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "P_minus_E", + "type": "tas_pr_evspsbl_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ], + "mapLayerFeatureTableGraphs": [ + { + "name": "tas", + "type": "tas_pr_evspsbl_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "tas_pr_evspsbl_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "evspsbl", + "type": "tas_pr_evspsbl_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "P_minus_E", + "type": "tas_pr_evspsbl_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ] + } + } + }, + { + "name": "PowerPlant_CESM2_ssp126_r11i1p1f1_tabular", + "path": "./data/DIVERS-H/PowerPlants/TVAPowerPlants.geojson", + "url": "https://data.kitware.com/api/v1/file/67c0deb5de1cd5c0d8ba66ce/download", + "type": "geojson", + "metadata": { + "tabular": { + "path": "./data/DIVERS-H/PowerPlants/PowerPlant_CESM2_ssp126_r11i1p1f1_tabular.json", + "name": "PowerPlant_CESM2_ssp126_r11i1p1f1_tabular_data", + "url": "https://data.kitware.com/api/v1/file/67c0deb6de1cd5c0d8ba66d4/download", + "featurePropertyMatcher": "Plant_Code" + }, + "tags": { + "filters": { + "Model": "CESM2", + "Scenario": "ssp126", + "Ensemble": "r11i1p1f1", + "Input/Output": "Ouput" + } + }, + "default_style": { + "layers": { + "fill": { + "color": "#888888", + "enabled": false + }, + "line": { + "size": 1, + "color": "#000000", + "enabled": false + }, + "text": { + "size": { + "type": "SizeZoom", + "zoomLevels": [ + [ + 10, + 12 + ], + [ + 12, + 9 + ], + [ + 16, + 10 + ] + ] + }, + "text": { + "key": "Plant_Name" + }, + "zoom": { + "max": 24, + "min": 7 + }, + "color": "#000000", + "enabled": true + }, + "circle": { + "color": "#888888", + "enabled": true, + "selectable": "singleSelect", + "selectColor": "#00FFFF" + }, + "fill-extrusion": { + "color": "#888888", + "enabled": false + } + }, + "properties": { + "selectionDisplay": true, + "availableProperties": { + "Total_MW": { + "key": "Total_MW", + "max": 3661.7, + "min": 0.9, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Total_MW" + }, + "tech_desc": { + "key": "tech_desc", + "type": "string", + "values": [ + "Batteries; Solar Photovoltaic;", + "Conventional Hydroelectric", + "Conventional Steam Coal", + "Conventional Steam Coal; Natural Gas Fired Combustion Turbine;", + "Hydroelectric Pumped Storage", + "Hydroelectric Pumped Storage; Conventional Hydroelectric;", + "Landfill Gas", + "Natural Gas Fired Combined Cycle", + "Natural Gas Fired Combined Cycle; Natural Gas Fired Combustion Turbine;", + "Natural Gas Fired Combined Cycle; Petroleum Liquids;", + "Natural Gas Fired Combustion Turbine", + "Natural Gas Internal Combustion Engine; Petroleum Liquids;", + "Nuclear", + "Onshore Wind Turbine", + "Other Gases", + "Other Waste Biomass; Petroleum Liquids;", + "Petroleum Liquids", + "Solar Photovoltaic", + "Wood/Wood Waste Biomass" + ], + "display": true, + "tooltip": false, + "description": "", + "displayName": "tech_desc" + }, + "Plant_Code": { + "key": "Plant_Code", + "max": 65642, + "min": 20, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Plant_Code" + }, + "Plant_Name": { + "key": "Plant_Name", + "type": "string", + "unique": 121, + "display": true, + "tooltip": false, + "searchable": true, + "description": "", + "displayName": "Plant_Name" + } + } + }, + "vectorFeatureTableGraphs": [ + { + "name": "evspsbl", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "tas", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "P_minus_E", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ], + "mapLayerFeatureTableGraphs": [ + { + "name": "evspsbl", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "tas", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "P_minus_E", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ] + } + } + }, + { + "name": "PowerPlant_CNRM-CM6-1_ssp245_r4i1p1f2_tabular", + "path": "./data/DIVERS-H/PowerPlants/TVAPowerPlants.geojson", + "url": "https://data.kitware.com/api/v1/file/67c0deb5de1cd5c0d8ba66ce/download", + "type": "geojson", + "metadata": { + "tabular": { + "path": "./data/DIVERS-H/PowerPlants/PowerPlant_CNRM-CM6-1_ssp245_r4i1p1f2_tabular.json", + "name": "PowerPlant_CNRM-CM6-1_ssp245_r4i1p1f2_tabular_data", + "url": "https://data.kitware.com/api/v1/file/67c0deb7de1cd5c0d8ba66d7/download", + "featurePropertyMatcher": "Plant_Code" + }, + "tags": { + "filters": { + "Model": "CNRM-CM6-1", + "Scenario": "ssp245", + "Ensemble": "r4i1p1f2", + "Input/Output": "Ouput" + } + }, + "default_style": { + "layers": { + "fill": { + "color": "#888888", + "enabled": false + }, + "line": { + "size": 1, + "color": "#000000", + "enabled": false + }, + "text": { + "size": { + "type": "SizeZoom", + "zoomLevels": [ + [ + 10, + 12 + ], + [ + 12, + 9 + ], + [ + 16, + 10 + ] + ] + }, + "text": { + "key": "Plant_Name" + }, + "zoom": { + "max": 24, + "min": 7 + }, + "color": "#000000", + "enabled": true + }, + "circle": { + "color": "#888888", + "enabled": true, + "selectable": "singleSelect", + "selectColor": "#00FFFF" + }, + "fill-extrusion": { + "color": "#888888", + "enabled": false + } + }, + "properties": { + "selectionDisplay": true, + "availableProperties": { + "Total_MW": { + "key": "Total_MW", + "max": 3661.7, + "min": 0.9, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Total_MW" + }, + "tech_desc": { + "key": "tech_desc", + "type": "string", + "values": [ + "Batteries; Solar Photovoltaic;", + "Conventional Hydroelectric", + "Conventional Steam Coal", + "Conventional Steam Coal; Natural Gas Fired Combustion Turbine;", + "Hydroelectric Pumped Storage", + "Hydroelectric Pumped Storage; Conventional Hydroelectric;", + "Landfill Gas", + "Natural Gas Fired Combined Cycle", + "Natural Gas Fired Combined Cycle; Natural Gas Fired Combustion Turbine;", + "Natural Gas Fired Combined Cycle; Petroleum Liquids;", + "Natural Gas Fired Combustion Turbine", + "Natural Gas Internal Combustion Engine; Petroleum Liquids;", + "Nuclear", + "Onshore Wind Turbine", + "Other Gases", + "Other Waste Biomass; Petroleum Liquids;", + "Petroleum Liquids", + "Solar Photovoltaic", + "Wood/Wood Waste Biomass" + ], + "display": true, + "tooltip": false, + "description": "", + "displayName": "tech_desc" + }, + "Plant_Code": { + "key": "Plant_Code", + "max": 65642, + "min": 20, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Plant_Code" + }, + "Plant_Name": { + "key": "Plant_Name", + "type": "string", + "unique": 121, + "display": true, + "tooltip": false, + "searchable": true, + "description": "", + "displayName": "Plant_Name" + } + } + }, + "vectorFeatureTableGraphs": [ + { + "name": "evspsbl", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "tas", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "P_minus_E", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ], + "mapLayerFeatureTableGraphs": [ + { + "name": "evspsbl", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "tas", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "P_minus_E", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ] + } + } + }, + { + "name": "PowerPlant_CESM2_ssp126_r4i1p1f1_tabular", + "path": "./data/DIVERS-H/PowerPlants/TVAPowerPlants.geojson", + "url": "https://data.kitware.com/api/v1/file/67c0deb5de1cd5c0d8ba66ce/download", + "type": "geojson", + "metadata": { + "tabular": { + "path": "./data/DIVERS-H/PowerPlants/PowerPlant_CESM2_ssp126_r4i1p1f1_tabular.json", + "name": "PowerPlant_CESM2_ssp126_r4i1p1f1_tabular_data", + "url": "https://data.kitware.com/api/v1/file/67c0deb7de1cd5c0d8ba66da/download", + "featurePropertyMatcher": "Plant_Code" + }, + "tags": { + "filters": { + "Model": "CESM2", + "Scenario": "ssp126", + "Ensemble": "r4i1p1f1", + "Input/Output": "Ouput" + } + }, + "default_style": { + "layers": { + "fill": { + "color": "#888888", + "enabled": false + }, + "line": { + "size": 1, + "color": "#000000", + "enabled": false + }, + "text": { + "size": { + "type": "SizeZoom", + "zoomLevels": [ + [ + 10, + 12 + ], + [ + 12, + 9 + ], + [ + 16, + 10 + ] + ] + }, + "text": { + "key": "Plant_Name" + }, + "zoom": { + "max": 24, + "min": 7 + }, + "color": "#000000", + "enabled": true + }, + "circle": { + "color": "#888888", + "enabled": true, + "selectable": "singleSelect", + "selectColor": "#00FFFF" + }, + "fill-extrusion": { + "color": "#888888", + "enabled": false + } + }, + "properties": { + "selectionDisplay": true, + "availableProperties": { + "Total_MW": { + "key": "Total_MW", + "max": 3661.7, + "min": 0.9, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Total_MW" + }, + "tech_desc": { + "key": "tech_desc", + "type": "string", + "values": [ + "Batteries; Solar Photovoltaic;", + "Conventional Hydroelectric", + "Conventional Steam Coal", + "Conventional Steam Coal; Natural Gas Fired Combustion Turbine;", + "Hydroelectric Pumped Storage", + "Hydroelectric Pumped Storage; Conventional Hydroelectric;", + "Landfill Gas", + "Natural Gas Fired Combined Cycle", + "Natural Gas Fired Combined Cycle; Natural Gas Fired Combustion Turbine;", + "Natural Gas Fired Combined Cycle; Petroleum Liquids;", + "Natural Gas Fired Combustion Turbine", + "Natural Gas Internal Combustion Engine; Petroleum Liquids;", + "Nuclear", + "Onshore Wind Turbine", + "Other Gases", + "Other Waste Biomass; Petroleum Liquids;", + "Petroleum Liquids", + "Solar Photovoltaic", + "Wood/Wood Waste Biomass" + ], + "display": true, + "tooltip": false, + "description": "", + "displayName": "tech_desc" + }, + "Plant_Code": { + "key": "Plant_Code", + "max": 65642, + "min": 20, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Plant_Code" + }, + "Plant_Name": { + "key": "Plant_Name", + "type": "string", + "unique": 121, + "display": true, + "tooltip": false, + "searchable": true, + "description": "", + "displayName": "Plant_Name" + } + } + }, + "vectorFeatureTableGraphs": [ + { + "name": "evspsbl", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "tas", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "P_minus_E", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ], + "mapLayerFeatureTableGraphs": [ + { + "name": "evspsbl", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "tas", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "P_minus_E", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ] + } + } + }, + { + "name": "PowerPlant_CNRM-CM6-1_ssp126_r6i1p1f2_tabular", + "path": "./data/DIVERS-H/PowerPlants/TVAPowerPlants.geojson", + "url": "https://data.kitware.com/api/v1/file/67c0deb5de1cd5c0d8ba66ce/download", + "type": "geojson", + "metadata": { + "tabular": { + "path": "./data/DIVERS-H/PowerPlants/PowerPlant_CNRM-CM6-1_ssp126_r6i1p1f2_tabular.json", + "name": "PowerPlant_CNRM-CM6-1_ssp126_r6i1p1f2_tabular_data", + "url": "https://data.kitware.com/api/v1/file/67c0deb8de1cd5c0d8ba66dd/download", + "featurePropertyMatcher": "Plant_Code" + }, + "tags": { + "filters": { + "Model": "CNRM-CM6-1", + "Scenario": "ssp126", + "Ensemble": "r6i1p1f2", + "Input/Output": "Ouput" + } + }, + "default_style": { + "layers": { + "fill": { + "color": "#888888", + "enabled": false + }, + "line": { + "size": 1, + "color": "#000000", + "enabled": false + }, + "text": { + "size": { + "type": "SizeZoom", + "zoomLevels": [ + [ + 10, + 12 + ], + [ + 12, + 9 + ], + [ + 16, + 10 + ] + ] + }, + "text": { + "key": "Plant_Name" + }, + "zoom": { + "max": 24, + "min": 7 + }, + "color": "#000000", + "enabled": true + }, + "circle": { + "color": "#888888", + "enabled": true, + "selectable": "singleSelect", + "selectColor": "#00FFFF" + }, + "fill-extrusion": { + "color": "#888888", + "enabled": false + } + }, + "properties": { + "selectionDisplay": true, + "availableProperties": { + "Total_MW": { + "key": "Total_MW", + "max": 3661.7, + "min": 0.9, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Total_MW" + }, + "tech_desc": { + "key": "tech_desc", + "type": "string", + "values": [ + "Batteries; Solar Photovoltaic;", + "Conventional Hydroelectric", + "Conventional Steam Coal", + "Conventional Steam Coal; Natural Gas Fired Combustion Turbine;", + "Hydroelectric Pumped Storage", + "Hydroelectric Pumped Storage; Conventional Hydroelectric;", + "Landfill Gas", + "Natural Gas Fired Combined Cycle", + "Natural Gas Fired Combined Cycle; Natural Gas Fired Combustion Turbine;", + "Natural Gas Fired Combined Cycle; Petroleum Liquids;", + "Natural Gas Fired Combustion Turbine", + "Natural Gas Internal Combustion Engine; Petroleum Liquids;", + "Nuclear", + "Onshore Wind Turbine", + "Other Gases", + "Other Waste Biomass; Petroleum Liquids;", + "Petroleum Liquids", + "Solar Photovoltaic", + "Wood/Wood Waste Biomass" + ], + "display": true, + "tooltip": false, + "description": "", + "displayName": "tech_desc" + }, + "Plant_Code": { + "key": "Plant_Code", + "max": 65642, + "min": 20, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Plant_Code" + }, + "Plant_Name": { + "key": "Plant_Name", + "type": "string", + "unique": 121, + "display": true, + "tooltip": false, + "searchable": true, + "description": "", + "displayName": "Plant_Name" + } + } + }, + "vectorFeatureTableGraphs": [ + { + "name": "evspsbl", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "tas", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "P_minus_E", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ], + "mapLayerFeatureTableGraphs": [ + { + "name": "evspsbl", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "tas", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "P_minus_E", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ] + } + } + }, + { + "name": "PowerPlant_CESM2_ssp585_r10i1p1f1_tabular", + "path": "./data/DIVERS-H/PowerPlants/TVAPowerPlants.geojson", + "url": "https://data.kitware.com/api/v1/file/67c0deb5de1cd5c0d8ba66ce/download", + "type": "geojson", + "metadata": { + "tabular": { + "path": "./data/DIVERS-H/PowerPlants/PowerPlant_CESM2_ssp585_r10i1p1f1_tabular.json", + "name": "PowerPlant_CESM2_ssp585_r10i1p1f1_tabular_data", + "url": "https://data.kitware.com/api/v1/file/67c0deb9de1cd5c0d8ba66e0/download", + "featurePropertyMatcher": "Plant_Code" + }, + "tags": { + "filters": { + "Model": "CESM2", + "Scenario": "ssp585", + "Ensemble": "r10i1p1f1", + "Input/Output": "Ouput" + } + }, + "default_style": { + "layers": { + "fill": { + "color": "#888888", + "enabled": false + }, + "line": { + "size": 1, + "color": "#000000", + "enabled": false + }, + "text": { + "size": { + "type": "SizeZoom", + "zoomLevels": [ + [ + 10, + 12 + ], + [ + 12, + 9 + ], + [ + 16, + 10 + ] + ] + }, + "text": { + "key": "Plant_Name" + }, + "zoom": { + "max": 24, + "min": 7 + }, + "color": "#000000", + "enabled": true + }, + "circle": { + "color": "#888888", + "enabled": true, + "selectable": "singleSelect", + "selectColor": "#00FFFF" + }, + "fill-extrusion": { + "color": "#888888", + "enabled": false + } + }, + "properties": { + "selectionDisplay": true, + "availableProperties": { + "Total_MW": { + "key": "Total_MW", + "max": 3661.7, + "min": 0.9, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Total_MW" + }, + "tech_desc": { + "key": "tech_desc", + "type": "string", + "values": [ + "Batteries; Solar Photovoltaic;", + "Conventional Hydroelectric", + "Conventional Steam Coal", + "Conventional Steam Coal; Natural Gas Fired Combustion Turbine;", + "Hydroelectric Pumped Storage", + "Hydroelectric Pumped Storage; Conventional Hydroelectric;", + "Landfill Gas", + "Natural Gas Fired Combined Cycle", + "Natural Gas Fired Combined Cycle; Natural Gas Fired Combustion Turbine;", + "Natural Gas Fired Combined Cycle; Petroleum Liquids;", + "Natural Gas Fired Combustion Turbine", + "Natural Gas Internal Combustion Engine; Petroleum Liquids;", + "Nuclear", + "Onshore Wind Turbine", + "Other Gases", + "Other Waste Biomass; Petroleum Liquids;", + "Petroleum Liquids", + "Solar Photovoltaic", + "Wood/Wood Waste Biomass" + ], + "display": true, + "tooltip": false, + "description": "", + "displayName": "tech_desc" + }, + "Plant_Code": { + "key": "Plant_Code", + "max": 65642, + "min": 20, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Plant_Code" + }, + "Plant_Name": { + "key": "Plant_Name", + "type": "string", + "unique": 121, + "display": true, + "tooltip": false, + "searchable": true, + "description": "", + "displayName": "Plant_Name" + } + } + }, + "vectorFeatureTableGraphs": [ + { + "name": "evspsbl", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "tas", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "P_minus_E", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ], + "mapLayerFeatureTableGraphs": [ + { + "name": "evspsbl", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "tas", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "P_minus_E", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ] + } + } + }, + { + "name": "PowerPlant_CESM2_ssp245_r11i1p1f1_tabular", + "path": "./data/DIVERS-H/PowerPlants/TVAPowerPlants.geojson", + "url": "https://data.kitware.com/api/v1/file/67c0deb5de1cd5c0d8ba66ce/download", + "type": "geojson", + "metadata": { + "tabular": { + "path": "./data/DIVERS-H/PowerPlants/PowerPlant_CESM2_ssp245_r11i1p1f1_tabular.json", + "name": "PowerPlant_CESM2_ssp245_r11i1p1f1_tabular_data", + "url": "https://data.kitware.com/api/v1/file/67c0debade1cd5c0d8ba66e3/download", + "featurePropertyMatcher": "Plant_Code" + }, + "tags": { + "filters": { + "Model": "CESM2", + "Scenario": "ssp245", + "Ensemble": "r11i1p1f1", + "Input/Output": "Ouput" + } + }, + "default_style": { + "layers": { + "fill": { + "color": "#888888", + "enabled": false + }, + "line": { + "size": 1, + "color": "#000000", + "enabled": false + }, + "text": { + "size": { + "type": "SizeZoom", + "zoomLevels": [ + [ + 10, + 12 + ], + [ + 12, + 9 + ], + [ + 16, + 10 + ] + ] + }, + "text": { + "key": "Plant_Name" + }, + "zoom": { + "max": 24, + "min": 7 + }, + "color": "#000000", + "enabled": true + }, + "circle": { + "color": "#888888", + "enabled": true, + "selectable": "singleSelect", + "selectColor": "#00FFFF" + }, + "fill-extrusion": { + "color": "#888888", + "enabled": false + } + }, + "properties": { + "selectionDisplay": true, + "availableProperties": { + "Total_MW": { + "key": "Total_MW", + "max": 3661.7, + "min": 0.9, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Total_MW" + }, + "tech_desc": { + "key": "tech_desc", + "type": "string", + "values": [ + "Batteries; Solar Photovoltaic;", + "Conventional Hydroelectric", + "Conventional Steam Coal", + "Conventional Steam Coal; Natural Gas Fired Combustion Turbine;", + "Hydroelectric Pumped Storage", + "Hydroelectric Pumped Storage; Conventional Hydroelectric;", + "Landfill Gas", + "Natural Gas Fired Combined Cycle", + "Natural Gas Fired Combined Cycle; Natural Gas Fired Combustion Turbine;", + "Natural Gas Fired Combined Cycle; Petroleum Liquids;", + "Natural Gas Fired Combustion Turbine", + "Natural Gas Internal Combustion Engine; Petroleum Liquids;", + "Nuclear", + "Onshore Wind Turbine", + "Other Gases", + "Other Waste Biomass; Petroleum Liquids;", + "Petroleum Liquids", + "Solar Photovoltaic", + "Wood/Wood Waste Biomass" + ], + "display": true, + "tooltip": false, + "description": "", + "displayName": "tech_desc" + }, + "Plant_Code": { + "key": "Plant_Code", + "max": 65642, + "min": 20, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Plant_Code" + }, + "Plant_Name": { + "key": "Plant_Name", + "type": "string", + "unique": 121, + "display": true, + "tooltip": false, + "searchable": true, + "description": "", + "displayName": "Plant_Name" + } + } + }, + "vectorFeatureTableGraphs": [ + { + "name": "evspsbl", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "tas", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "P_minus_E", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ], + "mapLayerFeatureTableGraphs": [ + { + "name": "evspsbl", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "tas", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "P_minus_E", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ] + } + } + }, + { + "name": "PowerPlant_CNRM-CM6-1_ssp126_r5i1p1f2_tabular", + "path": "./data/DIVERS-H/PowerPlants/TVAPowerPlants.geojson", + "url": "https://data.kitware.com/api/v1/file/67c0deb5de1cd5c0d8ba66ce/download", + "type": "geojson", + "metadata": { + "tabular": { + "path": "./data/DIVERS-H/PowerPlants/PowerPlant_CNRM-CM6-1_ssp126_r5i1p1f2_tabular.json", + "name": "PowerPlant_CNRM-CM6-1_ssp126_r5i1p1f2_tabular_data", + "url": "https://data.kitware.com/api/v1/file/67c0debade1cd5c0d8ba66e6/download", + "featurePropertyMatcher": "Plant_Code" + }, + "tags": { + "filters": { + "Model": "CNRM-CM6-1", + "Scenario": "ssp126", + "Ensemble": "r5i1p1f2", + "Input/Output": "Ouput" + } + }, + "default_style": { + "layers": { + "fill": { + "color": "#888888", + "enabled": false + }, + "line": { + "size": 1, + "color": "#000000", + "enabled": false + }, + "text": { + "size": { + "type": "SizeZoom", + "zoomLevels": [ + [ + 10, + 12 + ], + [ + 12, + 9 + ], + [ + 16, + 10 + ] + ] + }, + "text": { + "key": "Plant_Name" + }, + "zoom": { + "max": 24, + "min": 7 + }, + "color": "#000000", + "enabled": true + }, + "circle": { + "color": "#888888", + "enabled": true, + "selectable": "singleSelect", + "selectColor": "#00FFFF" + }, + "fill-extrusion": { + "color": "#888888", + "enabled": false + } + }, + "properties": { + "selectionDisplay": true, + "availableProperties": { + "Total_MW": { + "key": "Total_MW", + "max": 3661.7, + "min": 0.9, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Total_MW" + }, + "tech_desc": { + "key": "tech_desc", + "type": "string", + "values": [ + "Batteries; Solar Photovoltaic;", + "Conventional Hydroelectric", + "Conventional Steam Coal", + "Conventional Steam Coal; Natural Gas Fired Combustion Turbine;", + "Hydroelectric Pumped Storage", + "Hydroelectric Pumped Storage; Conventional Hydroelectric;", + "Landfill Gas", + "Natural Gas Fired Combined Cycle", + "Natural Gas Fired Combined Cycle; Natural Gas Fired Combustion Turbine;", + "Natural Gas Fired Combined Cycle; Petroleum Liquids;", + "Natural Gas Fired Combustion Turbine", + "Natural Gas Internal Combustion Engine; Petroleum Liquids;", + "Nuclear", + "Onshore Wind Turbine", + "Other Gases", + "Other Waste Biomass; Petroleum Liquids;", + "Petroleum Liquids", + "Solar Photovoltaic", + "Wood/Wood Waste Biomass" + ], + "display": true, + "tooltip": false, + "description": "", + "displayName": "tech_desc" + }, + "Plant_Code": { + "key": "Plant_Code", + "max": 65642, + "min": 20, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Plant_Code" + }, + "Plant_Name": { + "key": "Plant_Name", + "type": "string", + "unique": 121, + "display": true, + "tooltip": false, + "searchable": true, + "description": "", + "displayName": "Plant_Name" + } + } + }, + "vectorFeatureTableGraphs": [ + { + "name": "P_minus_E", + "type": "P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ], + "mapLayerFeatureTableGraphs": [ + { + "name": "P_minus_E", + "type": "P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ] + } + } + }, + { + "name": "PowerPlant_CNRM-CM6-1_ssp126_r4i1p1f2_tabular", + "path": "./data/DIVERS-H/PowerPlants/TVAPowerPlants.geojson", + "url": "https://data.kitware.com/api/v1/file/67c0deb5de1cd5c0d8ba66ce/download", + "type": "geojson", + "metadata": { + "tabular": { + "path": "./data/DIVERS-H/PowerPlants/PowerPlant_CNRM-CM6-1_ssp126_r4i1p1f2_tabular.json", + "name": "PowerPlant_CNRM-CM6-1_ssp126_r4i1p1f2_tabular_data", + "url": "https://data.kitware.com/api/v1/file/67c0debbde1cd5c0d8ba66e9/download", + "featurePropertyMatcher": "Plant_Code" + }, + "tags": { + "filters": { + "Model": "CNRM-CM6-1", + "Scenario": "ssp126", + "Ensemble": "r4i1p1f2", + "Input/Output": "Ouput" + } + }, + "default_style": { + "layers": { + "fill": { + "color": "#888888", + "enabled": false + }, + "line": { + "size": 1, + "color": "#000000", + "enabled": false + }, + "text": { + "size": { + "type": "SizeZoom", + "zoomLevels": [ + [ + 10, + 12 + ], + [ + 12, + 9 + ], + [ + 16, + 10 + ] + ] + }, + "text": { + "key": "Plant_Name" + }, + "zoom": { + "max": 24, + "min": 7 + }, + "color": "#000000", + "enabled": true + }, + "circle": { + "color": "#888888", + "enabled": true, + "selectable": "singleSelect", + "selectColor": "#00FFFF" + }, + "fill-extrusion": { + "color": "#888888", + "enabled": false + } + }, + "properties": { + "selectionDisplay": true, + "availableProperties": { + "Total_MW": { + "key": "Total_MW", + "max": 3661.7, + "min": 0.9, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Total_MW" + }, + "tech_desc": { + "key": "tech_desc", + "type": "string", + "values": [ + "Batteries; Solar Photovoltaic;", + "Conventional Hydroelectric", + "Conventional Steam Coal", + "Conventional Steam Coal; Natural Gas Fired Combustion Turbine;", + "Hydroelectric Pumped Storage", + "Hydroelectric Pumped Storage; Conventional Hydroelectric;", + "Landfill Gas", + "Natural Gas Fired Combined Cycle", + "Natural Gas Fired Combined Cycle; Natural Gas Fired Combustion Turbine;", + "Natural Gas Fired Combined Cycle; Petroleum Liquids;", + "Natural Gas Fired Combustion Turbine", + "Natural Gas Internal Combustion Engine; Petroleum Liquids;", + "Nuclear", + "Onshore Wind Turbine", + "Other Gases", + "Other Waste Biomass; Petroleum Liquids;", + "Petroleum Liquids", + "Solar Photovoltaic", + "Wood/Wood Waste Biomass" + ], + "display": true, + "tooltip": false, + "description": "", + "displayName": "tech_desc" + }, + "Plant_Code": { + "key": "Plant_Code", + "max": 65642, + "min": 20, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Plant_Code" + }, + "Plant_Name": { + "key": "Plant_Name", + "type": "string", + "unique": 121, + "display": true, + "tooltip": false, + "searchable": true, + "description": "", + "displayName": "Plant_Name" + } + } + }, + "vectorFeatureTableGraphs": [ + { + "name": "evspsbl", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "tas", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "P_minus_E", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ], + "mapLayerFeatureTableGraphs": [ + { + "name": "evspsbl", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "tas", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "P_minus_E", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ] + } + } + }, + { + "name": "PowerPlant_CESM2_ssp245_r10i1p1f1_tabular", + "path": "./data/DIVERS-H/PowerPlants/TVAPowerPlants.geojson", + "url": "https://data.kitware.com/api/v1/file/67c0deb5de1cd5c0d8ba66ce/download", + "type": "geojson", + "metadata": { + "tabular": { + "path": "./data/DIVERS-H/PowerPlants/PowerPlant_CESM2_ssp245_r10i1p1f1_tabular.json", + "name": "PowerPlant_CESM2_ssp245_r10i1p1f1_tabular_data", + "url": "https://data.kitware.com/api/v1/file/67c0debcde1cd5c0d8ba66ec/download", + "featurePropertyMatcher": "Plant_Code" + }, + "tags": { + "filters": { + "Model": "CESM2", + "Scenario": "ssp245", + "Ensemble": "r10i1p1f1", + "Input/Output": "Ouput" + } + }, + "default_style": { + "layers": { + "fill": { + "color": "#888888", + "enabled": false + }, + "line": { + "size": 1, + "color": "#000000", + "enabled": false + }, + "text": { + "size": { + "type": "SizeZoom", + "zoomLevels": [ + [ + 10, + 12 + ], + [ + 12, + 9 + ], + [ + 16, + 10 + ] + ] + }, + "text": { + "key": "Plant_Name" + }, + "zoom": { + "max": 24, + "min": 7 + }, + "color": "#000000", + "enabled": true + }, + "circle": { + "color": "#888888", + "enabled": true, + "selectable": "singleSelect", + "selectColor": "#00FFFF" + }, + "fill-extrusion": { + "color": "#888888", + "enabled": false + } + }, + "properties": { + "selectionDisplay": true, + "availableProperties": { + "Total_MW": { + "key": "Total_MW", + "max": 3661.7, + "min": 0.9, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Total_MW" + }, + "tech_desc": { + "key": "tech_desc", + "type": "string", + "values": [ + "Batteries; Solar Photovoltaic;", + "Conventional Hydroelectric", + "Conventional Steam Coal", + "Conventional Steam Coal; Natural Gas Fired Combustion Turbine;", + "Hydroelectric Pumped Storage", + "Hydroelectric Pumped Storage; Conventional Hydroelectric;", + "Landfill Gas", + "Natural Gas Fired Combined Cycle", + "Natural Gas Fired Combined Cycle; Natural Gas Fired Combustion Turbine;", + "Natural Gas Fired Combined Cycle; Petroleum Liquids;", + "Natural Gas Fired Combustion Turbine", + "Natural Gas Internal Combustion Engine; Petroleum Liquids;", + "Nuclear", + "Onshore Wind Turbine", + "Other Gases", + "Other Waste Biomass; Petroleum Liquids;", + "Petroleum Liquids", + "Solar Photovoltaic", + "Wood/Wood Waste Biomass" + ], + "display": true, + "tooltip": false, + "description": "", + "displayName": "tech_desc" + }, + "Plant_Code": { + "key": "Plant_Code", + "max": 65642, + "min": 20, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Plant_Code" + }, + "Plant_Name": { + "key": "Plant_Name", + "type": "string", + "unique": 121, + "display": true, + "tooltip": false, + "searchable": true, + "description": "", + "displayName": "Plant_Name" + } + } + }, + "vectorFeatureTableGraphs": [ + { + "name": "evspsbl", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "tas", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "P_minus_E", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ], + "mapLayerFeatureTableGraphs": [ + { + "name": "evspsbl", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "tas", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "P_minus_E", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ] + } + } + }, + { + "name": "PowerPlant_CESM2_ssp245_r4i1p1f1_tabular", + "path": "./data/DIVERS-H/PowerPlants/TVAPowerPlants.geojson", + "url": "https://data.kitware.com/api/v1/file/67c0deb5de1cd5c0d8ba66ce/download", + "type": "geojson", + "metadata": { + "tabular": { + "path": "./data/DIVERS-H/PowerPlants/PowerPlant_CESM2_ssp245_r4i1p1f1_tabular.json", + "name": "PowerPlant_CESM2_ssp245_r4i1p1f1_tabular_data", + "url": "https://data.kitware.com/api/v1/file/67c0debcde1cd5c0d8ba66ef/download", + "featurePropertyMatcher": "Plant_Code" + }, + "tags": { + "filters": { + "Model": "CESM2", + "Scenario": "ssp245", + "Ensemble": "r4i1p1f1", + "Input/Output": "Ouput" + } + }, + "default_style": { + "layers": { + "fill": { + "color": "#888888", + "enabled": false + }, + "line": { + "size": 1, + "color": "#000000", + "enabled": false + }, + "text": { + "size": { + "type": "SizeZoom", + "zoomLevels": [ + [ + 10, + 12 + ], + [ + 12, + 9 + ], + [ + 16, + 10 + ] + ] + }, + "text": { + "key": "Plant_Name" + }, + "zoom": { + "max": 24, + "min": 7 + }, + "color": "#000000", + "enabled": true + }, + "circle": { + "color": "#888888", + "enabled": true, + "selectable": "singleSelect", + "selectColor": "#00FFFF" + }, + "fill-extrusion": { + "color": "#888888", + "enabled": false + } + }, + "properties": { + "selectionDisplay": true, + "availableProperties": { + "Total_MW": { + "key": "Total_MW", + "max": 3661.7, + "min": 0.9, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Total_MW" + }, + "tech_desc": { + "key": "tech_desc", + "type": "string", + "values": [ + "Batteries; Solar Photovoltaic;", + "Conventional Hydroelectric", + "Conventional Steam Coal", + "Conventional Steam Coal; Natural Gas Fired Combustion Turbine;", + "Hydroelectric Pumped Storage", + "Hydroelectric Pumped Storage; Conventional Hydroelectric;", + "Landfill Gas", + "Natural Gas Fired Combined Cycle", + "Natural Gas Fired Combined Cycle; Natural Gas Fired Combustion Turbine;", + "Natural Gas Fired Combined Cycle; Petroleum Liquids;", + "Natural Gas Fired Combustion Turbine", + "Natural Gas Internal Combustion Engine; Petroleum Liquids;", + "Nuclear", + "Onshore Wind Turbine", + "Other Gases", + "Other Waste Biomass; Petroleum Liquids;", + "Petroleum Liquids", + "Solar Photovoltaic", + "Wood/Wood Waste Biomass" + ], + "display": true, + "tooltip": false, + "description": "", + "displayName": "tech_desc" + }, + "Plant_Code": { + "key": "Plant_Code", + "max": 65642, + "min": 20, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Plant_Code" + }, + "Plant_Name": { + "key": "Plant_Name", + "type": "string", + "unique": 121, + "display": true, + "tooltip": false, + "searchable": true, + "description": "", + "displayName": "Plant_Name" + } + } + }, + "vectorFeatureTableGraphs": [ + { + "name": "evspsbl", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "tas", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "P_minus_E", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ], + "mapLayerFeatureTableGraphs": [ + { + "name": "evspsbl", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "tas", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "P_minus_E", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ] + } + } + }, + { + "name": "PowerPlant_CESM2_ssp585_r4i1p1f1_tabular", + "path": "./data/DIVERS-H/PowerPlants/TVAPowerPlants.geojson", + "url": "https://data.kitware.com/api/v1/file/67c0deb5de1cd5c0d8ba66ce/download", + "type": "geojson", + "metadata": { + "tabular": { + "path": "./data/DIVERS-H/PowerPlants/PowerPlant_CESM2_ssp585_r4i1p1f1_tabular.json", + "name": "PowerPlant_CESM2_ssp585_r4i1p1f1_tabular_data", + "url": "https://data.kitware.com/api/v1/file/67c0debdde1cd5c0d8ba66f2/download", + "featurePropertyMatcher": "Plant_Code" + }, + "tags": { + "filters": { + "Model": "CESM2", + "Scenario": "ssp585", + "Ensemble": "r4i1p1f1", + "Input/Output": "Ouput" + } + }, + "default_style": { + "layers": { + "fill": { + "color": "#888888", + "enabled": false + }, + "line": { + "size": 1, + "color": "#000000", + "enabled": false + }, + "text": { + "size": { + "type": "SizeZoom", + "zoomLevels": [ + [ + 10, + 12 + ], + [ + 12, + 9 + ], + [ + 16, + 10 + ] + ] + }, + "text": { + "key": "Plant_Name" + }, + "zoom": { + "max": 24, + "min": 7 + }, + "color": "#000000", + "enabled": true + }, + "circle": { + "color": "#888888", + "enabled": true, + "selectable": "singleSelect", + "selectColor": "#00FFFF" + }, + "fill-extrusion": { + "color": "#888888", + "enabled": false + } + }, + "properties": { + "selectionDisplay": true, + "availableProperties": { + "Total_MW": { + "key": "Total_MW", + "max": 3661.7, + "min": 0.9, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Total_MW" + }, + "tech_desc": { + "key": "tech_desc", + "type": "string", + "values": [ + "Batteries; Solar Photovoltaic;", + "Conventional Hydroelectric", + "Conventional Steam Coal", + "Conventional Steam Coal; Natural Gas Fired Combustion Turbine;", + "Hydroelectric Pumped Storage", + "Hydroelectric Pumped Storage; Conventional Hydroelectric;", + "Landfill Gas", + "Natural Gas Fired Combined Cycle", + "Natural Gas Fired Combined Cycle; Natural Gas Fired Combustion Turbine;", + "Natural Gas Fired Combined Cycle; Petroleum Liquids;", + "Natural Gas Fired Combustion Turbine", + "Natural Gas Internal Combustion Engine; Petroleum Liquids;", + "Nuclear", + "Onshore Wind Turbine", + "Other Gases", + "Other Waste Biomass; Petroleum Liquids;", + "Petroleum Liquids", + "Solar Photovoltaic", + "Wood/Wood Waste Biomass" + ], + "display": true, + "tooltip": false, + "description": "", + "displayName": "tech_desc" + }, + "Plant_Code": { + "key": "Plant_Code", + "max": 65642, + "min": 20, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Plant_Code" + }, + "Plant_Name": { + "key": "Plant_Name", + "type": "string", + "unique": 121, + "display": true, + "tooltip": false, + "searchable": true, + "description": "", + "displayName": "Plant_Name" + } + } + }, + "vectorFeatureTableGraphs": [ + { + "name": "evspsbl", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "tas", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "P_minus_E", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ], + "mapLayerFeatureTableGraphs": [ + { + "name": "evspsbl", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "tas", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "P_minus_E", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ] + } + } + }, + { + "name": "PowerPlant_CESM2_ssp585_r11i1p1f1_tabular", + "path": "./data/DIVERS-H/PowerPlants/TVAPowerPlants.geojson", + "url": "https://data.kitware.com/api/v1/file/67c0deb5de1cd5c0d8ba66ce/download", + "type": "geojson", + "metadata": { + "tabular": { + "path": "./data/DIVERS-H/PowerPlants/PowerPlant_CESM2_ssp585_r11i1p1f1_tabular.json", + "name": "PowerPlant_CESM2_ssp585_r11i1p1f1_tabular_data", + "url": "https://data.kitware.com/api/v1/file/67c0debede1cd5c0d8ba66f5/download", + "featurePropertyMatcher": "Plant_Code" + }, + "tags": { + "filters": { + "Model": "CESM2", + "Scenario": "ssp585", + "Ensemble": "r11i1p1f1", + "Input/Output": "Ouput" + } + }, + "default_style": { + "layers": { + "fill": { + "color": "#888888", + "enabled": false + }, + "line": { + "size": 1, + "color": "#000000", + "enabled": false + }, + "text": { + "size": { + "type": "SizeZoom", + "zoomLevels": [ + [ + 10, + 12 + ], + [ + 12, + 9 + ], + [ + 16, + 10 + ] + ] + }, + "text": { + "key": "Plant_Name" + }, + "zoom": { + "max": 24, + "min": 7 + }, + "color": "#000000", + "enabled": true + }, + "circle": { + "color": "#888888", + "enabled": true, + "selectable": "singleSelect", + "selectColor": "#00FFFF" + }, + "fill-extrusion": { + "color": "#888888", + "enabled": false + } + }, + "properties": { + "selectionDisplay": true, + "availableProperties": { + "Total_MW": { + "key": "Total_MW", + "max": 3661.7, + "min": 0.9, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Total_MW" + }, + "tech_desc": { + "key": "tech_desc", + "type": "string", + "values": [ + "Batteries; Solar Photovoltaic;", + "Conventional Hydroelectric", + "Conventional Steam Coal", + "Conventional Steam Coal; Natural Gas Fired Combustion Turbine;", + "Hydroelectric Pumped Storage", + "Hydroelectric Pumped Storage; Conventional Hydroelectric;", + "Landfill Gas", + "Natural Gas Fired Combined Cycle", + "Natural Gas Fired Combined Cycle; Natural Gas Fired Combustion Turbine;", + "Natural Gas Fired Combined Cycle; Petroleum Liquids;", + "Natural Gas Fired Combustion Turbine", + "Natural Gas Internal Combustion Engine; Petroleum Liquids;", + "Nuclear", + "Onshore Wind Turbine", + "Other Gases", + "Other Waste Biomass; Petroleum Liquids;", + "Petroleum Liquids", + "Solar Photovoltaic", + "Wood/Wood Waste Biomass" + ], + "display": true, + "tooltip": false, + "description": "", + "displayName": "tech_desc" + }, + "Plant_Code": { + "key": "Plant_Code", + "max": 65642, + "min": 20, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Plant_Code" + }, + "Plant_Name": { + "key": "Plant_Name", + "type": "string", + "unique": 121, + "display": true, + "tooltip": false, + "searchable": true, + "description": "", + "displayName": "Plant_Name" + } + } + }, + "vectorFeatureTableGraphs": [ + { + "name": "evspsbl", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "tas", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "P_minus_E", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ], + "mapLayerFeatureTableGraphs": [ + { + "name": "evspsbl", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "tas", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "P_minus_E", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ] + } + } + }, + { + "name": "PowerPlant_CNRM-CM6-1_ssp245_r5i1p1f2_tabular", + "path": "./data/DIVERS-H/PowerPlants/TVAPowerPlants.geojson", + "url": "https://data.kitware.com/api/v1/file/67c0deb5de1cd5c0d8ba66ce/download", + "type": "geojson", + "metadata": { + "tabular": { + "path": "./data/DIVERS-H/PowerPlants/PowerPlant_CNRM-CM6-1_ssp245_r5i1p1f2_tabular.json", + "name": "PowerPlant_CNRM-CM6-1_ssp245_r5i1p1f2_tabular_data", + "url": "https://data.kitware.com/api/v1/file/67c0debede1cd5c0d8ba66f8/download", + "featurePropertyMatcher": "Plant_Code" + }, + "tags": { + "filters": { + "Model": "CNRM-CM6-1", + "Scenario": "ssp245", + "Ensemble": "r5i1p1f2", + "Input/Output": "Ouput" + } + }, + "default_style": { + "layers": { + "fill": { + "color": "#888888", + "enabled": false + }, + "line": { + "size": 1, + "color": "#000000", + "enabled": false + }, + "text": { + "size": { + "type": "SizeZoom", + "zoomLevels": [ + [ + 10, + 12 + ], + [ + 12, + 9 + ], + [ + 16, + 10 + ] + ] + }, + "text": { + "key": "Plant_Name" + }, + "zoom": { + "max": 24, + "min": 7 + }, + "color": "#000000", + "enabled": true + }, + "circle": { + "color": "#888888", + "enabled": true, + "selectable": "singleSelect", + "selectColor": "#00FFFF" + }, + "fill-extrusion": { + "color": "#888888", + "enabled": false + } + }, + "properties": { + "selectionDisplay": true, + "availableProperties": { + "Total_MW": { + "key": "Total_MW", + "max": 3661.7, + "min": 0.9, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Total_MW" + }, + "tech_desc": { + "key": "tech_desc", + "type": "string", + "values": [ + "Batteries; Solar Photovoltaic;", + "Conventional Hydroelectric", + "Conventional Steam Coal", + "Conventional Steam Coal; Natural Gas Fired Combustion Turbine;", + "Hydroelectric Pumped Storage", + "Hydroelectric Pumped Storage; Conventional Hydroelectric;", + "Landfill Gas", + "Natural Gas Fired Combined Cycle", + "Natural Gas Fired Combined Cycle; Natural Gas Fired Combustion Turbine;", + "Natural Gas Fired Combined Cycle; Petroleum Liquids;", + "Natural Gas Fired Combustion Turbine", + "Natural Gas Internal Combustion Engine; Petroleum Liquids;", + "Nuclear", + "Onshore Wind Turbine", + "Other Gases", + "Other Waste Biomass; Petroleum Liquids;", + "Petroleum Liquids", + "Solar Photovoltaic", + "Wood/Wood Waste Biomass" + ], + "display": true, + "tooltip": false, + "description": "", + "displayName": "tech_desc" + }, + "Plant_Code": { + "key": "Plant_Code", + "max": 65642, + "min": 20, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Plant_Code" + }, + "Plant_Name": { + "key": "Plant_Name", + "type": "string", + "unique": 121, + "display": true, + "tooltip": false, + "searchable": true, + "description": "", + "displayName": "Plant_Name" + } + } + }, + "vectorFeatureTableGraphs": [ + { + "name": "P_minus_E", + "type": "P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ], + "mapLayerFeatureTableGraphs": [ + { + "name": "P_minus_E", + "type": "P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ] + } + } + }, + { + "name": "PowerPlant_CNRM-CM6-1_ssp585_r6i1p1f2_tabular", + "path": "./data/DIVERS-H/PowerPlants/TVAPowerPlants.geojson", + "url": "https://data.kitware.com/api/v1/file/67c0deb5de1cd5c0d8ba66ce/download", + "type": "geojson", + "metadata": { + "tabular": { + "path": "./data/DIVERS-H/PowerPlants/PowerPlant_CNRM-CM6-1_ssp585_r6i1p1f2_tabular.json", + "name": "PowerPlant_CNRM-CM6-1_ssp585_r6i1p1f2_tabular_data", + "url": "https://data.kitware.com/api/v1/file/67c0debfde1cd5c0d8ba66fb/download", + "featurePropertyMatcher": "Plant_Code" + }, + "tags": { + "filters": { + "Model": "CNRM-CM6-1", + "Scenario": "ssp585", + "Ensemble": "r6i1p1f2", + "Input/Output": "Ouput" + } + }, + "default_style": { + "layers": { + "fill": { + "color": "#888888", + "enabled": false + }, + "line": { + "size": 1, + "color": "#000000", + "enabled": false + }, + "text": { + "size": { + "type": "SizeZoom", + "zoomLevels": [ + [ + 10, + 12 + ], + [ + 12, + 9 + ], + [ + 16, + 10 + ] + ] + }, + "text": { + "key": "Plant_Name" + }, + "zoom": { + "max": 24, + "min": 7 + }, + "color": "#000000", + "enabled": true + }, + "circle": { + "color": "#888888", + "enabled": true, + "selectable": "singleSelect", + "selectColor": "#00FFFF" + }, + "fill-extrusion": { + "color": "#888888", + "enabled": false + } + }, + "properties": { + "selectionDisplay": true, + "availableProperties": { + "Total_MW": { + "key": "Total_MW", + "max": 3661.7, + "min": 0.9, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Total_MW" + }, + "tech_desc": { + "key": "tech_desc", + "type": "string", + "values": [ + "Batteries; Solar Photovoltaic;", + "Conventional Hydroelectric", + "Conventional Steam Coal", + "Conventional Steam Coal; Natural Gas Fired Combustion Turbine;", + "Hydroelectric Pumped Storage", + "Hydroelectric Pumped Storage; Conventional Hydroelectric;", + "Landfill Gas", + "Natural Gas Fired Combined Cycle", + "Natural Gas Fired Combined Cycle; Natural Gas Fired Combustion Turbine;", + "Natural Gas Fired Combined Cycle; Petroleum Liquids;", + "Natural Gas Fired Combustion Turbine", + "Natural Gas Internal Combustion Engine; Petroleum Liquids;", + "Nuclear", + "Onshore Wind Turbine", + "Other Gases", + "Other Waste Biomass; Petroleum Liquids;", + "Petroleum Liquids", + "Solar Photovoltaic", + "Wood/Wood Waste Biomass" + ], + "display": true, + "tooltip": false, + "description": "", + "displayName": "tech_desc" + }, + "Plant_Code": { + "key": "Plant_Code", + "max": 65642, + "min": 20, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Plant_Code" + }, + "Plant_Name": { + "key": "Plant_Name", + "type": "string", + "unique": 121, + "display": true, + "tooltip": false, + "searchable": true, + "description": "", + "displayName": "Plant_Name" + } + } + }, + "vectorFeatureTableGraphs": [ + { + "name": "tas", + "type": "tas_pr_evspsbl_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "tas_pr_evspsbl_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "evspsbl", + "type": "tas_pr_evspsbl_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "P_minus_E", + "type": "tas_pr_evspsbl_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ], + "mapLayerFeatureTableGraphs": [ + { + "name": "tas", + "type": "tas_pr_evspsbl_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "tas_pr_evspsbl_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "evspsbl", + "type": "tas_pr_evspsbl_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "P_minus_E", + "type": "tas_pr_evspsbl_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ] + } + } + }, + { + "name": "PowerPlant_CNRM-CM6-1_ssp585_r5i1p1f2_tabular", + "path": "./data/DIVERS-H/PowerPlants/TVAPowerPlants.geojson", + "url": "https://data.kitware.com/api/v1/file/67c0deb5de1cd5c0d8ba66ce/download", + "type": "geojson", + "metadata": { + "tabular": { + "path": "./data/DIVERS-H/PowerPlants/PowerPlant_CNRM-CM6-1_ssp585_r5i1p1f2_tabular.json", + "name": "PowerPlant_CNRM-CM6-1_ssp585_r5i1p1f2_tabular_data", + "url": "https://data.kitware.com/api/v1/file/67c0dec0de1cd5c0d8ba66fe/download", + "featurePropertyMatcher": "Plant_Code" + }, + "tags": { + "filters": { + "Model": "CNRM-CM6-1", + "Scenario": "ssp585", + "Ensemble": "r5i1p1f2", + "Input/Output": "Ouput" + } + }, + "default_style": { + "layers": { + "fill": { + "color": "#888888", + "enabled": false + }, + "line": { + "size": 1, + "color": "#000000", + "enabled": false + }, + "text": { + "size": { + "type": "SizeZoom", + "zoomLevels": [ + [ + 10, + 12 + ], + [ + 12, + 9 + ], + [ + 16, + 10 + ] + ] + }, + "text": { + "key": "Plant_Name" + }, + "zoom": { + "max": 24, + "min": 7 + }, + "color": "#000000", + "enabled": true + }, + "circle": { + "color": "#888888", + "enabled": true, + "selectable": "singleSelect", + "selectColor": "#00FFFF" + }, + "fill-extrusion": { + "color": "#888888", + "enabled": false + } + }, + "properties": { + "selectionDisplay": true, + "availableProperties": { + "Total_MW": { + "key": "Total_MW", + "max": 3661.7, + "min": 0.9, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Total_MW" + }, + "tech_desc": { + "key": "tech_desc", + "type": "string", + "values": [ + "Batteries; Solar Photovoltaic;", + "Conventional Hydroelectric", + "Conventional Steam Coal", + "Conventional Steam Coal; Natural Gas Fired Combustion Turbine;", + "Hydroelectric Pumped Storage", + "Hydroelectric Pumped Storage; Conventional Hydroelectric;", + "Landfill Gas", + "Natural Gas Fired Combined Cycle", + "Natural Gas Fired Combined Cycle; Natural Gas Fired Combustion Turbine;", + "Natural Gas Fired Combined Cycle; Petroleum Liquids;", + "Natural Gas Fired Combustion Turbine", + "Natural Gas Internal Combustion Engine; Petroleum Liquids;", + "Nuclear", + "Onshore Wind Turbine", + "Other Gases", + "Other Waste Biomass; Petroleum Liquids;", + "Petroleum Liquids", + "Solar Photovoltaic", + "Wood/Wood Waste Biomass" + ], + "display": true, + "tooltip": false, + "description": "", + "displayName": "tech_desc" + }, + "Plant_Code": { + "key": "Plant_Code", + "max": 65642, + "min": 20, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Plant_Code" + }, + "Plant_Name": { + "key": "Plant_Name", + "type": "string", + "unique": 121, + "display": true, + "tooltip": false, + "searchable": true, + "description": "", + "displayName": "Plant_Name" + } + } + }, + "vectorFeatureTableGraphs": [ + { + "name": "P_minus_E", + "type": "P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ], + "mapLayerFeatureTableGraphs": [ + { + "name": "P_minus_E", + "type": "P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ] + } + } + }, + { + "name": "PowerPlant_CNRM-CM6-1_ssp245_r6i1p1f2_tabular", + "path": "./data/DIVERS-H/PowerPlants/TVAPowerPlants.geojson", + "url": "https://data.kitware.com/api/v1/file/67c0deb5de1cd5c0d8ba66ce/download", + "type": "geojson", + "metadata": { + "tabular": { + "path": "./data/DIVERS-H/PowerPlants/PowerPlant_CNRM-CM6-1_ssp245_r6i1p1f2_tabular.json", + "name": "PowerPlant_CNRM-CM6-1_ssp245_r6i1p1f2_tabular_data", + "url": "https://data.kitware.com/api/v1/file/67c0dec1de1cd5c0d8ba6701/download", + "featurePropertyMatcher": "Plant_Code" + }, + "tags": { + "filters": { + "Model": "CNRM-CM6-1", + "Scenario": "ssp245", + "Ensemble": "r6i1p1f2", + "Input/Output": "Ouput" + } + }, + "default_style": { + "layers": { + "fill": { + "color": "#888888", + "enabled": false + }, + "line": { + "size": 1, + "color": "#000000", + "enabled": false + }, + "text": { + "size": { + "type": "SizeZoom", + "zoomLevels": [ + [ + 10, + 12 + ], + [ + 12, + 9 + ], + [ + 16, + 10 + ] + ] + }, + "text": { + "key": "Plant_Name" + }, + "zoom": { + "max": 24, + "min": 7 + }, + "color": "#000000", + "enabled": true + }, + "circle": { + "color": "#888888", + "enabled": true, + "selectable": "singleSelect", + "selectColor": "#00FFFF" + }, + "fill-extrusion": { + "color": "#888888", + "enabled": false + } + }, + "properties": { + "selectionDisplay": true, + "availableProperties": { + "Total_MW": { + "key": "Total_MW", + "max": 3661.7, + "min": 0.9, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Total_MW" + }, + "tech_desc": { + "key": "tech_desc", + "type": "string", + "values": [ + "Batteries; Solar Photovoltaic;", + "Conventional Hydroelectric", + "Conventional Steam Coal", + "Conventional Steam Coal; Natural Gas Fired Combustion Turbine;", + "Hydroelectric Pumped Storage", + "Hydroelectric Pumped Storage; Conventional Hydroelectric;", + "Landfill Gas", + "Natural Gas Fired Combined Cycle", + "Natural Gas Fired Combined Cycle; Natural Gas Fired Combustion Turbine;", + "Natural Gas Fired Combined Cycle; Petroleum Liquids;", + "Natural Gas Fired Combustion Turbine", + "Natural Gas Internal Combustion Engine; Petroleum Liquids;", + "Nuclear", + "Onshore Wind Turbine", + "Other Gases", + "Other Waste Biomass; Petroleum Liquids;", + "Petroleum Liquids", + "Solar Photovoltaic", + "Wood/Wood Waste Biomass" + ], + "display": true, + "tooltip": false, + "description": "", + "displayName": "tech_desc" + }, + "Plant_Code": { + "key": "Plant_Code", + "max": 65642, + "min": 20, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Plant_Code" + }, + "Plant_Name": { + "key": "Plant_Name", + "type": "string", + "unique": 121, + "display": true, + "tooltip": false, + "searchable": true, + "description": "", + "displayName": "Plant_Name" + } + } + }, + "vectorFeatureTableGraphs": [ + { + "name": "tas", + "type": "tas_pr_evspsbl_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "tas_pr_evspsbl_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "evspsbl", + "type": "tas_pr_evspsbl_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "P_minus_E", + "type": "tas_pr_evspsbl_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ], + "mapLayerFeatureTableGraphs": [ + { + "name": "tas", + "type": "tas_pr_evspsbl_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "tas_pr_evspsbl_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "evspsbl", + "type": "tas_pr_evspsbl_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "P_minus_E", + "type": "tas_pr_evspsbl_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ] + } + } + }, + { + "name": "PowerPlant_CESM2_ssp126_r10i1p1f1_tabular", + "path": "./data/DIVERS-H/PowerPlants/TVAPowerPlants.geojson", + "url": "https://data.kitware.com/api/v1/file/67c0deb5de1cd5c0d8ba66ce/download", + "type": "geojson", + "metadata": { + "tabular": { + "path": "./data/DIVERS-H/PowerPlants/PowerPlant_CESM2_ssp126_r10i1p1f1_tabular.json", + "name": "PowerPlant_CESM2_ssp126_r10i1p1f1_tabular_data", + "url": "https://data.kitware.com/api/v1/file/67c0dec1de1cd5c0d8ba6704/download", + "featurePropertyMatcher": "Plant_Code" + }, + "tags": { + "filters": { + "Model": "CESM2", + "Scenario": "ssp126", + "Ensemble": "r10i1p1f1", + "Input/Output": "Ouput" + } + }, + "default_style": { + "layers": { + "fill": { + "color": "#888888", + "enabled": false + }, + "line": { + "size": 1, + "color": "#000000", + "enabled": false + }, + "text": { + "size": { + "type": "SizeZoom", + "zoomLevels": [ + [ + 10, + 12 + ], + [ + 12, + 9 + ], + [ + 16, + 10 + ] + ] + }, + "text": { + "key": "Plant_Name" + }, + "zoom": { + "max": 24, + "min": 7 + }, + "color": "#000000", + "enabled": true + }, + "circle": { + "color": "#888888", + "enabled": true, + "selectable": "singleSelect", + "selectColor": "#00FFFF" + }, + "fill-extrusion": { + "color": "#888888", + "enabled": false + } + }, + "properties": { + "selectionDisplay": true, + "availableProperties": { + "Total_MW": { + "key": "Total_MW", + "max": 3661.7, + "min": 0.9, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Total_MW" + }, + "tech_desc": { + "key": "tech_desc", + "type": "string", + "values": [ + "Batteries; Solar Photovoltaic;", + "Conventional Hydroelectric", + "Conventional Steam Coal", + "Conventional Steam Coal; Natural Gas Fired Combustion Turbine;", + "Hydroelectric Pumped Storage", + "Hydroelectric Pumped Storage; Conventional Hydroelectric;", + "Landfill Gas", + "Natural Gas Fired Combined Cycle", + "Natural Gas Fired Combined Cycle; Natural Gas Fired Combustion Turbine;", + "Natural Gas Fired Combined Cycle; Petroleum Liquids;", + "Natural Gas Fired Combustion Turbine", + "Natural Gas Internal Combustion Engine; Petroleum Liquids;", + "Nuclear", + "Onshore Wind Turbine", + "Other Gases", + "Other Waste Biomass; Petroleum Liquids;", + "Petroleum Liquids", + "Solar Photovoltaic", + "Wood/Wood Waste Biomass" + ], + "display": true, + "tooltip": false, + "description": "", + "displayName": "tech_desc" + }, + "Plant_Code": { + "key": "Plant_Code", + "max": 65642, + "min": 20, + "type": "number", + "display": true, + "tooltip": false, + "description": "", + "displayName": "Plant_Code" + }, + "Plant_Name": { + "key": "Plant_Name", + "type": "string", + "unique": 121, + "display": true, + "tooltip": false, + "searchable": true, + "description": "", + "displayName": "Plant_Name" + } + } + }, + "vectorFeatureTableGraphs": [ + { + "name": "evspsbl", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "tas", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "P_minus_E", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ], + "mapLayerFeatureTableGraphs": [ + { + "name": "evspsbl", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "evspsbl", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "evspsbl" + }, + { + "name": "tas", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "tas", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "tas" + }, + { + "name": "pr", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "pr", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "pr" + }, + { + "name": "P_minus_E", + "type": "evspsbl_tas_pr_P_minus_E", + "xAxis": "unix_time", + "yAxis": "P_minus_E", + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": "P_minus_E" + } + ] + } + } + } + ] + } + ] + } +] \ No newline at end of file diff --git a/sample_data/overture.json b/sample_data/overture.json new file mode 100644 index 0000000..c4616d9 --- /dev/null +++ b/sample_data/overture.json @@ -0,0 +1,26 @@ +[{ + "type": "Context", + "name": "Boston Overture", + "default_map_center": [ + 42.3555, + -71.0565 + ], + "default_map_zoom": 6, + "datasets": [ + { + "name": "Overture Data", + "description": "Overture Data", + "category": "overture", + "metadata": {}, + "files": [ + { + "path": "./data/tva/overture.zip", + "url": "https://data.kitware.com/api/v1/item/67bc9e26de1cd5c0d8ba62d5/download", + "name": "Overture Data", + "type": "zip", + "metadata":{} + } + ] + } + ] +}] \ No newline at end of file diff --git a/sample_data/tester.json b/sample_data/tester.json new file mode 100644 index 0000000..42ed286 --- /dev/null +++ b/sample_data/tester.json @@ -0,0 +1,103 @@ +[{ + "type": "Context", + "name": "Input/Outputs", + "default_map_center": [ + 34.8019, + -86.1794 + ], + "default_map_zoom": 6, + "datasets": [ + { + "name": "Input/Outputs", + "description": "DIVERS-H Input/Outputs", + "category": "raster", + "metadata": {}, + "files": [ + { + "path": "./data/tva/evaporation_CONUS.nc", + "url": "https://data.kitware.com/api/v1/file/67b4ccbf146ff7c60286eaa5/download", + "name": "Evaporation CONUS 2015-2063", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "Evaporation Layer", + "variable": "evspsbl", + "color_map": "OrRd", + "sliding_variable": "time", + "x_variable": "lon", + "y_variable": "lat" + } + ] + } + }, + { + "path": "./data/tva/precipitation_CONUS.nc", + "url": "https://data.kitware.com/api/v1/file/67b4cc60146ff7c60286ea9d/download", + "name": "Precipitation CONUS 2015-2063", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "Precipitation Layer", + "variable": "pr", + "color_map": "GnBu", + "sliding_variable": "time", + "x_variable": "lon", + "y_variable": "lat" + } + ] + } + }, + { + "path": "./data/tva/surfaceairtemp_CONUS.nc", + "url": "https://data.kitware.com/api/v1/file/67b4cc8c146ff7c60286eaa1/download", + "name": "Surface Air Temperature CONUS 2015-2063", + "type": "netcdf", + "metadata": { + "generate": [ + { + "name": "Surface Air Temperature", + "variable": "tas", + "sliding_variable": "time", + "x_variable": "lon", + "color_map": "Blues", + "y_variable": "lat" + } + ] + } + }, + { + "name": "PminusE_Amon_CNRM-CM6_1_ssp585_r6i1p1f2_2015-2055", + "path": "./data/DIVERS-H/Output/PminusE_Amon_CNRM-CM6_1_ssp585_r6i1p1f2_2015-2055.nc", + "url": "https://data.kitware.com/api/v1/item/67bdd096de1cd5c0d8ba63f9/download", + "type": "netcdf", + "action": "replace", + "metadata": { + "generate": [ + { + "name": "PminusE_Amon_CNRM-CM6_1_ssp585_r6i1p1f2_2015-2055", + "x_variable": "lon", + "y_variable": "lat", + "variable": "P_minus_E", + "sliding_variable": "time", + "color_map": "turbo" + } + ], + "tags": { + "filters": { + "Variable": "PminusE", + "Model": "CNRM-CM6_1", + "Scenario": "ssp585", + "Ensemble": "r6i1p1f2", + "Grid": null, + "Time Range": "2015-2055", + "Input/Output": "Output" + } + } + } + } + ] + } + ] +}] \ No newline at end of file diff --git a/sample_data/tva.json b/sample_data/tva.json index d0db486..3a6e2b4 100644 --- a/sample_data/tva.json +++ b/sample_data/tva.json @@ -73,7 +73,6 @@ "description": "TVA Power Plants", "category": "vector", "metadata": {}, - "action": "replace", "files": [ { "path": "./data/tva/hydrostations.geojson", @@ -389,7 +388,6 @@ "description": "DIVERS-H Input/Outputs", "category": "raster", "metadata": {}, - "action": "replace", "files": [ { "path": "./data/tva/evaporation_CONUS.nc", @@ -439,7 +437,7 @@ "variable": "tas", "sliding_variable": "time", "x_variable": "lon", - "color_map": "turbo", + "color_map": "Blues", "y_variable": "lat" } ] diff --git a/scripts/groupAndMergeNetcdf.py b/scripts/groupAndMergeNetcdf.py new file mode 100644 index 0000000..256ef41 --- /dev/null +++ b/scripts/groupAndMergeNetcdf.py @@ -0,0 +1,205 @@ +import click +import xarray as xr +import geopandas as gpd +import json +import numpy as np +import pandas as pd +import re +from datetime import datetime +import cftime + +# Global flag to skip uploading +skip_upload = False + +def convert_time(obj, output='compact'): + if isinstance(obj, str): # Handle ctime (string) + dt_obj = datetime.strptime(obj, '%a %b %d %H:%M:%S %Y') + elif isinstance(obj, np.datetime64): # Handle datetime64 + dt_obj = pd.Timestamp(obj).to_pydatetime() + elif isinstance(obj, pd.Timestamp): # Handle pandas Timestamp explicitly + dt_obj = obj.to_pydatetime() + elif isinstance(obj, datetime): # Handle Python datetime objects + dt_obj = obj + elif isinstance( + obj, + ( + cftime.DatetimeNoLeap, + cftime.DatetimeAllLeap, + cftime.Datetime360Day, + cftime.DatetimeJulian, + ), + ): + dt_obj = datetime(obj.year, obj.month, obj.day, obj.hour, obj.minute, obj.second) + elif isinstance(obj, (int, float)): + if obj > 1e18: # Assume nanoseconds timestamp + dt_obj = datetime.fromtimestamp(obj / 1e9) + elif obj > 1e10: # Assume milliseconds timestamp + dt_obj = datetime.fromtimestamp(obj / 1000) + else: # Assume seconds timestamp + dt_obj = datetime.fromtimestamp(obj) + else: + return obj # Return as-is if the type is unrecognized + + if output == 'iso': + return dt_obj.isoformat() + elif output == 'datetime': + return dt_obj + elif output == 'compact': + return int(dt_obj.strftime('%Y%m%d%H%M%S')) + elif output == 'unix': + return dt_obj.timestamp() + +def convert_longitude(lon): + """ + Converts longitude values from 0-360 to -180 to 180. + This ensures compatibility with NetCDF data that uses either range. + """ + lon = np.array(lon) + lon[lon > 180] -= 360 # If lon > 180, convert it to the -180 to 180 range. + return lon + +def parse_filename(filename): + pattern = ( + r'(?P\w+)_Amon_(?P[\w\-]+)_ssp(?P\d+)_' + r'(?Pr\d+i\d+p\d+f?\d*)_?(?P\w+)?_(?P\d{4,6}-\d{4,6})\.nc' + ) + match = re.match(pattern, filename) + if match: + return { + 'Variable': match.group('variable'), + 'Model': match.group('model'), + 'Scenario': f'ssp{match.group("scenario")}', + 'Ensemble': match.group('ensemble'), + 'Grid': match.group('grid'), + 'Time Range': match.group('time_range') + } + else: + return {'Filename': filename} + +@click.command() +@click.argument('geojson_file', type=click.Path(exists=True)) +@click.argument('netcdf_files', nargs=-1, type=click.Path(exists=True)) +@click.option('--sliding-variable', default='time', show_default=True, help="The variable representing time or another sliding dimension.") +@click.option('--x-variable', default='lon', show_default=True, help="The variable representing longitude.") +@click.option('--y-variable', default='lat', show_default=True, help="The variable representing latitude.") +@click.option('--output-json', default='mergednetcdf.json', show_default=True, help="Output JSON file name.") +def extract_netcdf_data(geojson_file, netcdf_files, sliding_variable, x_variable, y_variable, output_json): + """Extracts NetCDF data for each feature in the GEOJSON file and merges multiple NetCDF files by time index.""" + + # Load GeoJSON + gdf = gpd.read_file(geojson_file) + + # Generate the listing of Model, Scenario, Ensemble from NetCDF files + model_scenario_ensemble_files = {} + + for netcdf_file in netcdf_files: + print(netcdf_file) + parsed = parse_filename(netcdf_file) + model_scenario_ensemble = f"{parsed['Model']}_{parsed['Scenario']}_{parsed['Ensemble']}" + + if model_scenario_ensemble not in model_scenario_ensemble_files: + model_scenario_ensemble_files[model_scenario_ensemble] = [] + model_scenario_ensemble_files[model_scenario_ensemble].append(netcdf_file) + + output_data = {} + + for model_scenario_ensemble, netcdf_group in model_scenario_ensemble_files.items(): + # Storage for merged data for this group + merged_data = {"time": []} + variable_descriptions = {} + variable_names = [] + + for netcdf_file in netcdf_group: + ds = xr.open_dataset(netcdf_file) + + # Ensure necessary variables exist + if sliding_variable not in ds or x_variable not in ds or y_variable not in ds: + raise ValueError(f"One or more specified variables not found in {netcdf_file}.") + + # Process each feature in the GeoJSON + for _, feature in gdf.iterrows(): + feature_id = str(feature.get("Plant_Code", feature.get("id", _))) # Ensure feature_id is a string + x, y = feature.geometry.centroid.x, feature.geometry.centroid.y + + # Convert longitude if necessary (0-360 to -180 to 180) + x = convert_longitude(x) + + # Find nearest grid cell + x_idx = np.abs(ds[x_variable] - x).argmin().item() + y_idx = np.abs(ds[y_variable] - y).argmin().item() + + for var in ds.data_vars: + if sliding_variable in ds[var].dims: + df = ds[var].isel({x_variable: x_idx, y_variable: y_idx}).to_pandas() + + # Check if the variable is a DataFrame + if isinstance(df, pd.DataFrame) and sliding_variable in df.columns: + # Convert time to UNIX time (seconds) and update the header + df[sliding_variable] = df[sliding_variable].apply(lambda t: convert_time(t, 'unix')) + df.rename(columns={sliding_variable: 'unix_time'}, inplace=True) + elif isinstance(df, pd.Series) and sliding_variable in df.index: + # Convert time in Series if present + df = df.apply(lambda t: convert_time(t, 'unix')) + df.name = 'unix_time' + + var_name = f"{var}" # Append filename to differentiate variables + variable_names.append(var_name) + # Extract description from NetCDF metadata + description = ds[var].attrs.get("long_name") or ds[var].attrs.get("standard_name") or "No description available" + variable_descriptions[var_name] = description + + # Merge time index + if not merged_data["time"]: + merged_data["time"] = sorted(df.index) + + # Use 'unix_time' as the index for reindexing + merged_data[var_name] = df.reindex(merged_data["time"]).dropna().tolist() + + # Convert to structured format + headers = list(merged_data.keys()) + headers[headers.index("time")] = "unix_time" + + data_obj = { + "name": f"merged_data_{model_scenario_ensemble}", + "description": "Merged NetCDF data from multiple sources", + "type": "_".join(variable_names), + "header": headers, + "rows": [list(row) for row in zip(*merged_data.values())] + } + + # Convert pandas Timestamps to a serializable format + for row in data_obj["rows"]: + for idx, value in enumerate(row): + row[idx] = convert_time(value, 'unix') + + # Generate summary stats + summary = {} + for column_name, values in zip(data_obj["header"], zip(*data_obj["rows"])): + values = np.array(values, dtype=object) + if np.issubdtype(values.dtype, np.number) and not np.isnan(values).all(): + summary[column_name] = { + "type": "number", + "min": float(np.nanmin(values)), + "max": float(np.nanmax(values)), + "description": variable_descriptions.get(column_name, "No description available") + } + else: + unique_values = set(filter(pd.notna, values)) + summary[column_name] = { + "type": "string", + "description": variable_descriptions.get(column_name, "No description available") + } + if len(unique_values) < 100: + summary[column_name]["unique_values"] = list(unique_values) + + data_obj["summary"] = summary + output_data[model_scenario_ensemble] = [data_obj] + + # Save output to JSON file + with open(output_json, 'w') as f: + json.dump(output_data, f, indent=2) + + click.echo(f"Extraction complete. Output saved to {output_json}") + +if __name__ == '__main__': + extract_netcdf_data() diff --git a/scripts/groupMetadataFiles.py b/scripts/groupMetadataFiles.py new file mode 100644 index 0000000..db02116 --- /dev/null +++ b/scripts/groupMetadataFiles.py @@ -0,0 +1,264 @@ +import os +import re +import click +import xarray as xr +import geopandas as gpd +import json +import numpy as np +import pandas as pd +from datetime import datetime +import cftime +# Global flag to skip uploading +skip_upload = False + +def parse_filename(filename): + pattern = ( + r'(?P\w+)_Amon_(?P[\w\-]+)_ssp(?P\d+)_' + r'(?Pr\d+i\d+p\d+f?\d*)_?(?P\w+)?_(?P\d{4,6}-\d{4,6})\.nc' + ) + match = re.match(pattern, filename) + if match: + return { + 'Variable': match.group('variable'), + 'Model': match.group('model'), + 'Scenario': f'ssp{match.group("scenario")}', + 'Ensemble': match.group('ensemble'), + 'Grid': match.group('grid'), + 'Time Range': match.group('time_range') + } + else: + return {'Filename': filename} + + +def extract_netcdf_metadata(file_path, variable_name=None): + ds = xr.open_dataset(file_path) + + # Select variable with at least 3 dimensions if variable_name is not provided or doesn't match + if variable_name not in ds.variables: + var = next((v for v in ds.data_vars.values() if len(v.dims) >= 3), None) + else: + var = ds[variable_name] + + if var is None: + raise ValueError("No suitable variable with at least 3 dimensions found.") + + dimensions = list(var.dims) + x_dim = next((dim for dim in dimensions if 'lon' in dim.lower() or 'longitude' in dim.lower()), None) + y_dim = next((dim for dim in dimensions if 'lat' in dim.lower() or 'latitude' in dim.lower()), None) + time_dim = next((dim for dim in dimensions if 'time' in dim.lower()), None) + + # Extract long_name or standard_name + long_name = var.attrs.get('long_name', None) + standard_name = var.attrs.get('standard_name', None) + + ds.close() + + return { + 'x_dim': x_dim, + 'y_dim': y_dim, + 'time_dim': time_dim, + 'variable_name': var.name, + 'long_name': long_name if long_name else standard_name + } + +def generate_model_scenario_ensemble_listing(input_folder, output_folder): + model_scenario_ensemble_files = {} + + # Process Input files + for root, _, files in os.walk(input_folder): + for file in files: + local_file_path = os.path.join(root, file) + parsed = parse_filename(file) + model_scenario_ensemble = f"{parsed['Model']}_{parsed['Scenario']}_{parsed['Ensemble']}" + + if model_scenario_ensemble not in model_scenario_ensemble_files: + model_scenario_ensemble_files[model_scenario_ensemble] = [] + model_scenario_ensemble_files[model_scenario_ensemble].append(local_file_path) + + # Process Output files + for root, _, files in os.walk(output_folder): + for file in files: + local_file_path = os.path.join(root, file) + parsed = parse_filename(file) + model_scenario_ensemble = f"{parsed['Model']}_{parsed['Scenario']}_{parsed['Ensemble']}" + + if model_scenario_ensemble not in model_scenario_ensemble_files: + model_scenario_ensemble_files[model_scenario_ensemble] = [] + model_scenario_ensemble_files[model_scenario_ensemble].append(local_file_path) + + return model_scenario_ensemble_files + +def convert_time(obj, output='compact'): + if isinstance(obj, str): # Handle ctime (string) + dt_obj = datetime.strptime(obj, '%a %b %d %H:%M:%S %Y') + elif isinstance(obj, np.datetime64): # Handle datetime64 + dt_obj = pd.Timestamp(obj).to_pydatetime() + elif isinstance(obj, pd.Timestamp): # Handle pandas Timestamp explicitly + dt_obj = obj.to_pydatetime() + elif isinstance(obj, datetime): # Handle Python datetime objects + dt_obj = obj + elif isinstance( + obj, + ( + cftime.DatetimeNoLeap, + cftime.DatetimeAllLeap, + cftime.Datetime360Day, + cftime.DatetimeJulian, + ), + ): + dt_obj = datetime(obj.year, obj.month, obj.day, obj.hour, obj.minute, obj.second) + elif isinstance(obj, (int, float)): + if obj > 1e18: # Assume nanoseconds timestamp + dt_obj = datetime.fromtimestamp(obj / 1e9) + elif obj > 1e10: # Assume milliseconds timestamp + dt_obj = datetime.fromtimestamp(obj / 1000) + else: # Assume seconds timestamp + dt_obj = datetime.fromtimestamp(obj) + else: + return obj # Return as-is if the type is unrecognized + + if output == 'iso': + return dt_obj.isoformat() + elif output == 'datetime': + return dt_obj + elif output == 'compact': + return int(dt_obj.strftime('%Y%m%d%H%M%S')) + elif output == 'unix': + return dt_obj.timestamp() + +def convert_longitude(lon): + """ + Converts longitude values from 0-360 to -180 to 180. + This ensures compatibility with NetCDF data that uses either range. + """ + lon = np.array(lon) + lon[lon > 180] -= 360 # If lon > 180, convert it to the -180 to 180 range. + return lon + +def extract_netcdf_data(geojson_file='input.geojson', netcdf_files=['input.nc'], sliding_variable='time', + x_variable='lon', y_variable='lat', output_json='mergednetcdf.json'): + """Extracts NetCDF data for each feature in the GEOJSON file and merges multiple NetCDF files by time index.""" + + # Load GeoJSON + gdf = gpd.read_file(geojson_file) + + output_data = {} + + for _, feature in gdf.iterrows(): + feature_id = str(feature.get("Plant_Code", feature.get("id", _))) # Ensure feature_id is a string + x, y = feature.geometry.centroid.x, feature.geometry.centroid.y + + # Convert longitude if necessary (0-360 to -180 to 180) + x = convert_longitude(x) + + # Storage for merged data + merged_data = {"time": []} + variable_descriptions = {} + variable_names = [] + for netcdf_file in netcdf_files: + ds = xr.open_dataset(netcdf_file) + + # Ensure necessary variables exist + if sliding_variable not in ds or x_variable not in ds or y_variable not in ds: + raise ValueError(f"One or more specified variables not found in {netcdf_file}.") + + # Find nearest grid cell + x_idx = np.abs(ds[x_variable] - x).argmin().item() + y_idx = np.abs(ds[y_variable] - y).argmin().item() + + for var in ds.data_vars: + if sliding_variable in ds[var].dims: + df = ds[var].isel({x_variable: x_idx, y_variable: y_idx}).to_pandas() + + # Check if the variable is a DataFrame + if isinstance(df, pd.DataFrame) and sliding_variable in df.columns: + # Convert time to UNIX time (seconds) and update the header + df[sliding_variable] = df[sliding_variable].apply(lambda t: convert_time(t, 'unix')) + df.rename(columns={sliding_variable: 'unix_time'}, inplace=True) + elif isinstance(df, pd.Series) and sliding_variable in df.index: + # Convert time in Series if present + df = df.apply(lambda t: convert_time(t, 'unix')) + df.name = 'unix_time' + + var_name = f"{var}" # Append filename to differentiate variables + variable_names.append(var_name) + # Extract description from NetCDF metadata + description = ds[var].attrs.get("long_name") or ds[var].attrs.get("standard_name") or "No description available" + variable_descriptions[var_name] = description + + # Merge time index + if not merged_data["time"]: + merged_data["time"] = sorted(df.index) + + # Use 'unix_time' as the index for reindexing + merged_data[var_name] = df.reindex(merged_data["time"]).dropna().tolist() + + # Convert to structured format + headers = list(merged_data.keys()) + headers[headers.index("time")] = "unix_time" + + data_obj = { + "name": f"merged_data_{feature_id}", + "description": "Merged NetCDF data from multiple sources", + "type": "_".join(variable_names), + "header": headers, + "rows": [list(row) for row in zip(*merged_data.values())] + } + + # Convert pandas Timestamps to a serializable format + for row in data_obj["rows"]: + for idx, value in enumerate(row): + row[idx] = convert_time(value, 'unix') + + # Generate summary stats + summary = {} + for column_name, values in zip(data_obj["header"], zip(*data_obj["rows"])): + values = np.array(values, dtype=object) + if isinstance(values[0], (int, float)) or np.issubdtype(values.dtype, np.number) and not np.isnan(values).all(): + summary[column_name] = { + "type": "number", + "min": float(np.nanmin(values)), + "max": float(np.nanmax(values)), + "description": variable_descriptions.get(column_name, "No description available") + } + else: + unique_values = set(filter(pd.notna, values)) + summary[column_name] = { + "type": "string", + "description": variable_descriptions.get(column_name, "No description available") + } + if len(unique_values) < 100: + summary[column_name]["unique_values"] = list(unique_values) + + data_obj["summary"] = summary + output_data[feature_id] = [data_obj] + + # Save output to JSON file + with open(output_json, 'w') as f: + json.dump(output_data, f, indent=2) + + print(f"Extraction complete. Output saved to {output_json}") + +@click.command() +@click.argument('input_folder', type=click.Path(exists=True)) +@click.argument('output_folder', type=click.Path(exists=True)) +@click.argument('geojson_matcher', default="TVAPowerPlants.geojson", type=click.Path(exists=True)) +@click.option('--output-file', default='model_scenario_ensemble_listing.json', help='Output file to save the listing of model, scenario, and ensemble.') +def main(input_folder, output_folder, geojson_matcher, output_file): + # Generate the listing of Model, Scenario, and Ensemble from input and output folders + model_scenario_ensemble_files = generate_model_scenario_ensemble_listing(input_folder, output_folder) + + # Save the listing to a JSON file + with open(output_file, 'w') as f: + json.dump(model_scenario_ensemble_files, f, indent=4) + + total = len(model_scenario_ensemble_files.keys()) + count = 0 + for item in model_scenario_ensemble_files.keys(): + output_name = f'{output_folder}/PowerPlant_{item}_tabular.json' + print(f'Processing: {item} - {count} of {total}') + extract_netcdf_data(geojson_matcher, netcdf_files=model_scenario_ensemble_files[item], output_json=output_name) + count += 1 + +if __name__ == '__main__': + main() diff --git a/scripts/netcdfVectorMerge.py b/scripts/netcdfVectorMerge.py index 689451d..5ce3bdd 100644 --- a/scripts/netcdfVectorMerge.py +++ b/scripts/netcdfVectorMerge.py @@ -12,6 +12,8 @@ def convert_time(obj, output='compact'): dt_obj = datetime.strptime(obj, '%a %b %d %H:%M:%S %Y') elif isinstance(obj, np.datetime64): # Handle datetime64 dt_obj = pd.Timestamp(obj).to_pydatetime() + elif isinstance(obj, pd.Timestamp): # Handle pandas Timestamp explicitly + dt_obj = obj.to_pydatetime() elif isinstance(obj, datetime): # Handle Python datetime objects dt_obj = obj elif isinstance( @@ -25,7 +27,9 @@ def convert_time(obj, output='compact'): ): dt_obj = datetime(obj.year, obj.month, obj.day, obj.hour, obj.minute, obj.second) elif isinstance(obj, (int, float)): - if obj > 1e10: # Assume milliseconds timestamp + if obj > 1e18: # Assume nanoseconds timestamp + dt_obj = datetime.fromtimestamp(obj / 1e9) + elif obj > 1e10: # Assume milliseconds timestamp dt_obj = datetime.fromtimestamp(obj / 1000) else: # Assume seconds timestamp dt_obj = datetime.fromtimestamp(obj) @@ -41,6 +45,15 @@ def convert_time(obj, output='compact'): elif output == 'unix': return dt_obj.timestamp() +def convert_longitude(lon): + """ + Converts longitude values from 0-360 to -180 to 180. + This ensures compatibility with NetCDF data that uses either range. + """ + lon = np.array(lon) + lon[lon > 180] -= 360 # If lon > 180, convert it to the -180 to 180 range. + return lon + @click.command() @click.argument('geojson_file', type=click.Path(exists=True)) @click.argument('netcdf_files', nargs=-1, type=click.Path(exists=True)) @@ -60,10 +73,13 @@ def extract_netcdf_data(geojson_file, netcdf_files, sliding_variable, x_variable feature_id = str(feature.get("Plant_Code", feature.get("id", _))) # Ensure feature_id is a string x, y = feature.geometry.centroid.x, feature.geometry.centroid.y + # Convert longitude if necessary (0-360 to -180 to 180) + x = convert_longitude(x) + # Storage for merged data merged_data = {"time": []} variable_descriptions = {} - + variable_names = [] for netcdf_file in netcdf_files: ds = xr.open_dataset(netcdf_file) @@ -89,8 +105,8 @@ def extract_netcdf_data(geojson_file, netcdf_files, sliding_variable, x_variable df = df.apply(lambda t: convert_time(t, 'unix')) df.name = 'unix_time' - var_name = f"{var}_{netcdf_file.split('/')[-1]}" # Append filename to differentiate variables - + var_name = f"{var}" # Append filename to differentiate variables + variable_names.append(var_name) # Extract description from NetCDF metadata description = ds[var].attrs.get("long_name") or ds[var].attrs.get("standard_name") or "No description available" variable_descriptions[var_name] = description @@ -109,7 +125,7 @@ def extract_netcdf_data(geojson_file, netcdf_files, sliding_variable, x_variable data_obj = { "name": f"merged_data_{feature_id}", "description": "Merged NetCDF data from multiple sources", - "type": f"{sliding_variable}_{netcdf_file}", + "type": "_".join(variable_names), "header": headers, "rows": [list(row) for row in zip(*merged_data.values())] } @@ -117,8 +133,7 @@ def extract_netcdf_data(geojson_file, netcdf_files, sliding_variable, x_variable # Convert pandas Timestamps to a serializable format for row in data_obj["rows"]: for idx, value in enumerate(row): - if isinstance(value, pd.Timestamp): - row[idx] = value.timestamp() # Convert to UNIX timestamp if it's a Timestamp + row[idx] = convert_time(value, 'unix') # Generate summary stats summary = {} diff --git a/scripts/uploadDIVERS-H.py b/scripts/uploadDIVERS-H.py new file mode 100644 index 0000000..e249d28 --- /dev/null +++ b/scripts/uploadDIVERS-H.py @@ -0,0 +1,331 @@ +import os +import json +import re +import click +import xarray as xr +from girder_client import GirderClient +import matplotlib.pyplot as plt + +baseApiKey = 'GIRDER API KEY HERE' + + +def authenticate(client: GirderClient): + client.authenticate(apiKey=baseApiKey) + + +def create_folder(client, parent_id, name): + folder = client.createFolder(parent_id, name, reuseExisting=True) + return folder['_id'] + + +def parse_nc_filename(filename): + pattern = ( + r'(?P\w+)_Amon_(?P[\w\-]+)_ssp(?P\d+)_' + r'(?Pr\d+i\d+p\d+f?\d*)_?(?P\w+)?_(?P\d{4,6}-\d{4,6})\.nc' + ) + match = re.match(pattern, filename) + if match: + return { + 'Variable': match.group('variable'), + 'Model': match.group('model'), + 'Scenario': f'ssp{match.group("scenario")}', + 'Ensemble': match.group('ensemble'), + 'Grid': match.group('grid'), + 'Time Range': match.group('time_range') + } + else: + return {'Filename': filename} + +def parse_geojson_filename(filename): + pattern = ( + r'PowerPlant_(?P[\w\-]+)_ssp(?P\d+)_' + r'(?Pr\d+i\d+p\d+f?\d*)_tabular\.json' + ) + match = re.match(pattern, filename) + if match: + return { + 'Model': match.group('model'), + 'Scenario': f'ssp{match.group("scenario")}', + 'Ensemble': match.group('ensemble'), + } + else: + return {'Filename': filename} + + +def extract_netcdf_metadata(file_path, variable_name=None): + ds = xr.open_dataset(file_path) + + # Select variable with at least 3 dimensions if variable_name is not provided or doesn't match + if variable_name not in ds.variables: + var = next((v for v in ds.data_vars.values() if len(v.dims) >= 3), None) + else: + var = ds[variable_name] + + if var is None: + raise ValueError("No suitable variable with at least 3 dimensions found.") + + dimensions = list(var.dims) + x_dim = next((dim for dim in dimensions if 'lon' in dim.lower() or 'longitude' in dim.lower()), None) + y_dim = next((dim for dim in dimensions if 'lat' in dim.lower() or 'latitude' in dim.lower()), None) + time_dim = next((dim for dim in dimensions if 'time' in dim.lower()), None) + + # Extract long_name or standard_name + long_name = var.attrs.get('long_name', None) + standard_name = var.attrs.get('standard_name', None) + + ds.close() + + return { + 'x_dim': x_dim, + 'y_dim': y_dim, + 'time_dim': time_dim, + 'variable_name': var.name, + 'long_name': long_name if long_name else standard_name + } + + +def get_color_map(variable): + color_maps = { + 'evspsbl': 'Blues', + 'pr': 'Greens', + 'tas': 'Reds', + 'PminusE': 'turbo' + } + return color_maps.get(variable, 'viridis') + +def get_public_folder(gc: GirderClient): + current_user = gc.sendRestRequest('GET', 'user/me') + userId = current_user['_id'] + folders = gc.sendRestRequest('GET', f'folder?parentType=user&parentId={userId}&text=Public&limit=50&sort=lowerName&sortdir=1') + if len(folders) > 0: + uploadFolder = folders[0] + else: + print('No folder found for the user') + return uploadFolder + + +def upload_nc_files(client: GirderClient, local_folder, remote_folder_id, base_path): + file_metadata = [] + for root, _, files in os.walk(local_folder): + count = 0 + for file in files: + if not file.endswith('.nc'): + continue + local_file_path = os.path.join(root, file) + existing_item = list(client.listItem(remote_folder_id, name=file)) + print(f'Uploading File: {file} {count} of {len(files)}') + if len(existing_item) > 0: + file_id = existing_item[0]['_id'] + file_url = f'https://data.kitware.com/api/v1/file/{file_id}/download' + else: + item = client.uploadFileToFolder(remote_folder_id, local_file_path) + file_url = f'https://data.kitware.com/api/v1/file/{item["_id"]}/download' + + parsed = parse_nc_filename(file) + print(file) + print(parsed) + netcdf_metadata = extract_netcdf_metadata(local_file_path, parsed['Variable']) + x_dim = netcdf_metadata['x_dim'] + y_dim = netcdf_metadata['y_dim'] + time_dim = netcdf_metadata['time_dim'] + long_name = netcdf_metadata['long_name'] + variable_name = netcdf_metadata['variable_name'] + name = variable_name + if long_name: + name = long_name + color_scheme = get_color_map(parsed['Variable']) + + main_tag = 'Input' + if 'Output' in base_path: + main_tag = 'Output' + parsed['Input/Output'] = main_tag + file_metadata.append({ + 'name': os.path.splitext(file)[0], + 'path': f'./data/{base_path}/{file}', + 'url': file_url, + 'type': 'netcdf', + 'metadata': { + 'generate': [ + { + 'name': os.path.splitext(file)[0], + 'x_variable': x_dim, + 'y_variable': y_dim, + 'variable': variable_name, + 'sliding_variable': time_dim, + 'color_map': color_scheme + } + ], + 'tags': { + 'filters': parsed, + } + } + }) + count += 1 + return file_metadata + + +def upload_tabular_files(client: GirderClient, local_folder, remote_folder_id, base_path, powerplant_geojson, base_default_style): + file_metadata = [] + existing_power_plantitem = list(client.listItem(remote_folder_id, name=powerplant_geojson)) + powerplant_url = '' + base_default_style_dict= {} + with open(base_default_style, "r") as f: + base_default_style_dict = json.load(f) # data is now a Python dictionary + + if len(existing_power_plantitem) > 0: + powerplant_id = existing_power_plantitem[0]['_id'] + powerplant_url = f'https://data.kitware.com/api/v1/file/{powerplant_id}/download' + else: + item = client.uploadFileToFolder(remote_folder_id, powerplant_geojson) + powerplant_url = f'https://data.kitware.com/api/v1/file/{item["_id"]}/download' + + for root, _, files in os.walk(local_folder): + count = 0 + for file in files: + if not file.endswith('.json'): + continue + local_file_path = os.path.join(root, file) + existing_item = list(client.listItem(remote_folder_id, name=file)) + if len(existing_item) > 0: + file_id = existing_item[0]['_id'] + file_url = f'https://data.kitware.com/api/v1/file/{file_id}/download' + else: + print(f'Uploading File: {file} {count} of {len(files)}') + item = client.uploadFileToFolder(remote_folder_id, local_file_path) + file_url = f'https://data.kitware.com/api/v1/file/{item["_id"]}/download' + + parsed = parse_geojson_filename(file) + + # now we open the file and check for the table name + with open(local_file_path, "r") as f: + tabular_data = json.load(f) # data is now a Python dictionary + table_name = '' + headers = [] + for key in tabular_data.keys(): + tab_data = tabular_data[key][0] + table_name = tab_data['type'] + headers = tab_data['header'] + break + vectorFeatureTableGraphs = [] + mapLayerFeatureTableGraphs = [] + for item in headers: + if item != 'unix_time': + vectorFeatureTableGraphs.append({ + "name": item, + "type": table_name, + "xAxis": "unix_time", + "yAxis": item, + "xAxisLabel": "Date", + "yAxisLabel": item + }) + mapLayerFeatureTableGraphs.append({ + "name": item, + "type": table_name, + "xAxis": "unix_time", + "yAxis": item, + "indexer": "Plant_Name", + "xAxisLabel": "Date", + "yAxisLabel": item + }) + default_style = base_default_style_dict.copy() + default_style['vectorFeatureTableGraphs'] = vectorFeatureTableGraphs + default_style['mapLayerFeatureTableGraphs'] = mapLayerFeatureTableGraphs + print(file) + print(table_name) + print(default_style['mapLayerFeatureTableGraphs']) + main_tag = 'Ouput' + parsed['Input/Output'] = main_tag + file_metadata.append({ + 'name': f'{os.path.splitext(file)[0]}', + 'path': f'./data/{base_path}/{powerplant_geojson}', + 'url': powerplant_url, + 'type': 'geojson', + 'metadata': { + "tabular": { + 'path': f'./data/{base_path}/{file}', + 'name': f'{os.path.splitext(file)[0]}_data', + 'url': file_url, + 'featurePropertyMatcher': 'Plant_Code' + }, + 'tags': { + 'filters': parsed, + }, + 'default_style': default_style, + } + }) + count += 1 + return file_metadata + + +@click.command() +@click.argument('input_folder', type=click.Path(exists=True)) +@click.argument('output_folder', type=click.Path(exists=True)) +@click.argument('powerplant_geojson', default='TVAPowerPlants.geojson', type=click.Path(exists=True)) +@click.argument('base_powerplant_style', default='base_default_style.json', type=click.Path(exists=True)) +@click.option('--save-path', default='uploaded_file_context.json', help='Path to save the context JSON.') +def main(input_folder, output_folder, powerplant_geojson, base_powerplant_style, save_path): + client = GirderClient(apiUrl='https://data.kitware.com/api/v1') + authenticate(client) + + # Get the Public folder ID + public_folder = get_public_folder(client) + uvdat_folder = list(client.listFolder(public_folder['_id'], name='UVDAT'))[0] + + # Create DIVERS-H folder + divers_h_folder_id = create_folder(client, uvdat_folder['_id'], 'DIVERS-H') + + # Create Input and Output folders + input_folder_id = create_folder(client, divers_h_folder_id, 'Input') + output_folder_id = create_folder(client, divers_h_folder_id, 'Output') + tab_folder_id = create_folder(client, divers_h_folder_id, 'PowerPlants') + + # Upload files + input_files = upload_nc_files(client, input_folder, input_folder_id, 'DIVERS-H/Input') + output_files = upload_nc_files(client, output_folder, output_folder_id, 'DIVERS-H/Output') + tabular_files = upload_tabular_files(client, output_folder, tab_folder_id, 'DIVERS-H/PowerPlants', powerplant_geojson, base_powerplant_style) + + # Save context JSON + context = { + "type": "Context", + "name": "Input/Outputs", + "default_map_center": [ + 34.8019, + -86.1794 + ], + "default_map_zoom": 6, + "datasets": [] + } + input_dataset = { + "name": "Inputs", + "description": "DIVERS-H Inputs", + "category": "inputs", + "metadata": {}, + "files": input_files + } + output_dataset = { + "name": "Outputs", + "description": "DIVERS-H Outputs", + "category": "outputs", + "metadata": {}, + "files": output_files + } + + tabular_dataset = { + "name": "PowerPlants", + "description": "DIVERS-H PowerPlant data", + "category": "merged", + "metadata": {}, + "files": tabular_files + } + + context['datasets'].append(input_dataset) + context['datasets'].append(output_dataset) + context['datasets'].append(tabular_dataset) + with open(save_path, 'w') as f: + json.dump([context], f, indent=4) + + click.echo(f'Context with download URLs saved to {save_path}') + + +if __name__ == '__main__': + main() diff --git a/uvdat/core/admin.py b/uvdat/core/admin.py index 13f0fd5..2490d78 100644 --- a/uvdat/core/admin.py +++ b/uvdat/core/admin.py @@ -147,6 +147,7 @@ class NetCDFLayerAdmin(admin.ModelAdmin): 'netcdf_data', 'name', 'parameters', + 'metadata', 'description', 'color_scheme', 'bounds', diff --git a/uvdat/core/management/commands/ingest_data.py b/uvdat/core/management/commands/ingest_data.py index 1a7493b..1f81fb7 100644 --- a/uvdat/core/management/commands/ingest_data.py +++ b/uvdat/core/management/commands/ingest_data.py @@ -320,6 +320,7 @@ def ingest_file( # process tabular and add file if needed if file_metadata.get('tabular'): + self.stdout.write(f'\Processing Tabular: {file_metadata.get("tabular")}') self.process_tabular_data(new_file_item, dataset, file_metadata, replace, action) return True diff --git a/uvdat/core/migrations/0002_netcdflayer_metadata.py b/uvdat/core/migrations/0002_netcdflayer_metadata.py new file mode 100644 index 0000000..6272324 --- /dev/null +++ b/uvdat/core/migrations/0002_netcdflayer_metadata.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.7 on 2025-02-25 14:53 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='netcdflayer', + name='metadata', + field=models.JSONField(blank=True, null=True), + ), + ] diff --git a/uvdat/core/models/netcdf.py b/uvdat/core/models/netcdf.py index 30527ec..50744d5 100644 --- a/uvdat/core/models/netcdf.py +++ b/uvdat/core/models/netcdf.py @@ -19,6 +19,7 @@ class NetCDFLayer(TimeStampedModel): netcdf_data = models.ForeignKey(NetCDFData, on_delete=models.CASCADE, null=False) name = models.CharField(max_length=255, unique=False, blank=True) parameters = models.JSONField() + metadata = models.JSONField(blank=True, null=True) description = models.TextField(null=True, blank=True) color_scheme = models.CharField(max_length=255, unique=False, blank=True) bounds = geomodels.PolygonField( diff --git a/uvdat/core/rest/__init__.py b/uvdat/core/rest/__init__.py index e5a372f..8bed03e 100644 --- a/uvdat/core/rest/__init__.py +++ b/uvdat/core/rest/__init__.py @@ -2,6 +2,7 @@ from .context import ContextViewSet from .dataset import DatasetViewSet from .file_item import FileItemViewSet +from .filter_metadata import MetadataFilterViewSet from .layer_collection import LayerCollectionViewSet from .layer_representation import LayerRepresentationViewSet from .map_layers import MapLayerViewSet, RasterMapLayerViewSet, VectorMapLayerViewSet @@ -36,4 +37,5 @@ UserViewSet, VectorFeatureTableDataViewSet, TasksAPIView, + MetadataFilterViewSet, ] diff --git a/uvdat/core/rest/filter_metadata.py b/uvdat/core/rest/filter_metadata.py new file mode 100644 index 0000000..6a1af3b --- /dev/null +++ b/uvdat/core/rest/filter_metadata.py @@ -0,0 +1,88 @@ +import logging + +from django.db.models import Q +from rest_framework import viewsets +from rest_framework.decorators import action +from rest_framework.response import Response + +from uvdat.core.models import NetCDFLayer, RasterMapLayer, VectorMapLayer + +logger = logging.getLogger(__name__) + + +class MetadataFilterViewSet(viewsets.GenericViewSet): + # Custom action to handle metadata filtering (GET request) + @action(detail=False, methods=['get']) + def get_filters(self, request, *args, **kwargs): + models = [RasterMapLayer, VectorMapLayer, NetCDFLayer] + + filters = {} + + for model in models: + layers = model.objects.all() + + for layer in layers: + if layer.metadata is None: + continue + metadata = layer.metadata.get('tags', {}).get('filters', {}) + for key, value in metadata.items(): + if value is not None: + if key not in filters: + filters[key] = set() + filters[key].update( + value if (isinstance(value, list) and len(value)) else [value] + ) + + # Convert sets to lists for JSON response + filters = {key: list(value) for key, value in filters.items()} + return Response(filters) + + # Custom action to handle filtering layers based on provided filters (POST request) + @action(detail=False, methods=['post']) + def filter_layers(self, request, *args, **kwargs): + filters = request.data.get('filters', {}) # DRF will automatically parse the JSON body + search_query = request.data.get('search', '').strip().lower() # Search term + + # Collecting all models + models = [RasterMapLayer, VectorMapLayer, NetCDFLayer] + matching_ids = [] + type_mapper = { + 'RasterMapLayer': 'raster', + 'VectorMapLayer': 'vector', + 'NetCDFLayer': 'netcdf', + } + for model in models: + layers = model.objects.all() + + # Apply search filtering if provided + if search_query: + layers = layers.filter(Q(name__icontains=search_query)) + + for layer in layers: + if layer.metadata is None: + continue + + metadata = layer.metadata.get('tags', {}).get('filters', {}) + + matches = {} + filter_length = sum(1 for values in filters.values() if values) + match = 0 + # Check if all filter criteria match + for key, values in filters.items(): + if key in metadata and metadata[key] is not None: + for value in values: + if value in metadata[key]: + match += 1 + matches[key] = value + + logger.info(filters) + if match == filter_length: + matching_ids.append( + { + 'id': layer.id, + 'name': layer.name, + 'type': type_mapper[model.__name__], + 'matches': matches, + } + ) + return Response(matching_ids) diff --git a/uvdat/core/rest/map_layers.py b/uvdat/core/rest/map_layers.py index f66cc2f..c6630ff 100644 --- a/uvdat/core/rest/map_layers.py +++ b/uvdat/core/rest/map_layers.py @@ -1,6 +1,7 @@ import json import logging +from django.contrib.contenttypes.models import ContentType from django.contrib.gis.db.models import Extent from django.db import connection from django.http import HttpResponse, JsonResponse @@ -494,6 +495,61 @@ def create(self, request, *args, **kwargs): # Return the combined data return Response(response_data, status=status.HTTP_200_OK) + def list(self, request, *args, **kwargs): + map_layer_ids = request.query_params.getlist('mapLayerIds', []) + map_layer_types = request.query_params.getlist('mapLayerTypes', []) + + if not map_layer_ids: + return Response([], status=status.HTTP_200_OK) + + response_data = [] + + # Query for layers based on ID and type + for index in range(len(map_layer_ids)): + layer_id = map_layer_ids[index] + layer_type = map_layer_types[index] + map_layer = None + serializer = None + if 'raster' == layer_type: + map_layer = RasterMapLayer.objects.filter(id=layer_id).first() + serializer_class = RasterMapLayerSerializer + if not map_layer and 'vector' == layer_type: + map_layer = VectorMapLayer.objects.filter(id=layer_id).first() + serializer_class = VectorMapLayerSerializer + if not map_layer and 'netcdf' == layer_type: + map_layer = NetCDFLayer.objects.filter(id=layer_id).first() + serializer_class = NetCDFLayerSerializer + + if not map_layer: + continue # Skip if no matching layer is found + + # Serialize layer data + serializer = serializer_class(map_layer) + layer_response = serializer.data + layer_response['type'] = ( + 'raster' + if isinstance(map_layer, RasterMapLayer) + else ('vector' if isinstance(map_layer, VectorMapLayer) else 'netcdf') + ) + + # Check for LayerRepresentation if provided + layer_representation = None + if layer_type == 'raster' or layer_type == 'vector': + layer_representation = LayerRepresentation.objects.filter( + object_id=map_layer.id, map_type=ContentType.objects.get_for_model(map_layer) + ) + + if layer_representation and layer_representation.exists(): + layer_rep_obj = layer_representation.first() + layer_response['default_style'] = layer_rep_obj.default_style or layer_response.get( + 'default_style' + ) + layer_response['layerRepresentationId'] = layer_rep_obj.id + + response_data.append(layer_response) + + return Response(response_data, status=status.HTTP_200_OK) + @action( detail=False, methods=['get'], diff --git a/uvdat/core/tasks/dataset.py b/uvdat/core/tasks/dataset.py index c4d1541..76f9e10 100644 --- a/uvdat/core/tasks/dataset.py +++ b/uvdat/core/tasks/dataset.py @@ -46,8 +46,15 @@ def convert_dataset( continue # Handle Vector files + tags = file_metadata.get('tags', False) + metadata_modified = {} + if tags: + metadata_modified = {'tags': tags} vector_map_layers = create_vector_map_layer( - file_to_convert, style_options=style_options, name=file_to_convert.name + file_to_convert, + style_options=style_options, + name=file_to_convert.name, + metadata=metadata_modified, ) for vector_map_layer in vector_map_layers: if network_options: diff --git a/uvdat/core/tasks/map_layers.py b/uvdat/core/tasks/map_layers.py index b23e4a1..701b584 100644 --- a/uvdat/core/tasks/map_layers.py +++ b/uvdat/core/tasks/map_layers.py @@ -297,7 +297,7 @@ def create_raster_map_layer_from_file(file_item, file_path, style_options, name= return new_map_layer -def create_vector_map_layer(file_item, style_options, name='', index=None): +def create_vector_map_layer(file_item, style_options, name='', index=None, metadata=None): """Save a VectorMapLayer from a FileItem's contents.""" geojson_array = [] if file_item.file_type == 'zip': @@ -321,14 +321,16 @@ def create_vector_map_layer(file_item, style_options, name='', index=None): if len(geojson_array) > 1: layer_name = data['name'] new_map_layer = create_vector_map_from_json( - file_item, geojson, style_options, layer_name, index + file_item, geojson, style_options, layer_name, index, metadata ) new_map_layers.append(new_map_layer) return new_map_layers -def create_vector_map_from_json(file_item, geojson_data, style_options, name='', index=None): +def create_vector_map_from_json( + file_item, geojson_data, style_options, name='', index=None, metadata=None +): updated_style_options = calculate_styling(geojson_data, style_options) layer_index = file_item.index if index is not None: @@ -336,13 +338,15 @@ def create_vector_map_from_json(file_item, geojson_data, style_options, name='', new_map_layer = VectorMapLayer.objects.create( dataset=file_item.dataset, name=name, - metadata={}, + metadata=metadata, default_style=updated_style_options, index=layer_index, ) print('\t', f'VectorMapLayer {new_map_layer.id} created with name: {name}') new_map_layer.write_geojson_data(geojson_data.to_json()) new_map_layer.save() + print('\t', 'Done Writing GeoJSON file to Map Layer') + return new_map_layer @@ -370,6 +374,55 @@ def convert_zip_to_geojson(file_item): with zipfile.ZipFile(archive_path) as zip_archive: filenames = zip_archive.namelist() + for filename in filenames: + if filename.endswith(('.geojson', '.json')): + if filename.startswith('__MACOSX/') or Path(filename).name.startswith('._'): + logger.info(f'Skipping macOS metadata file: {filename}') + continue + + logger.info(f'Processing GeoJSON file: {filename}') + + with zip_archive.open(filename) as geojson_file: + raw_content = geojson_file.read() + + # Try decoding with UTF-8 first + for encoding in ('utf-8', 'iso-8859-1', 'windows-1252'): + try: + content = raw_content.decode(encoding).strip() + break # Stop at the first successful decode + except UnicodeDecodeError: + logger.warning( + f'Failed to decode {filename} with {encoding}, trying next.' + ) + else: + logger.error( + f'Could not decode {filename} with any common encoding, skipping.' + ) + continue # Skip the file if all decoding attempts fail + + if not content: + logger.error(f'File {filename} is empty!') + continue # Skip empty files + + try: + source_data = json.loads(content) + except json.JSONDecodeError as e: + logger.error(f'Error decoding JSON in {filename}: {e}') + continue # Skip invalid JSON files + + source_projection = ( + source_data.get('crs', {}).get('properties', {}).get('name') + ) + geojson_data = geopandas.GeoDataFrame.from_features( + source_data.get('features') + ) + if source_projection: + geojson_data = geojson_data.set_crs( + source_projection, allow_override=True + ) + geojson_data = geojson_data.to_crs(4326) + geodata_list.append({'geojson': geojson_data, 'name': Path(filename).stem}) + # Group shapefile components by basename shapefile_groups = defaultdict(list) for filename in filenames: @@ -488,7 +541,6 @@ def save_vector_features(vector_map_layer: VectorMapLayer): ) created = VectorFeature.objects.bulk_create(vector_features) - print('\t', f'{len(created)} vector features created.') return created diff --git a/uvdat/core/tasks/netcdf.py b/uvdat/core/tasks/netcdf.py index 20fc529..4b54156 100644 --- a/uvdat/core/tasks/netcdf.py +++ b/uvdat/core/tasks/netcdf.py @@ -12,6 +12,7 @@ from django.contrib.gis.geos import Polygon from django.contrib.gis.geos.error import GEOSException from django.core.files.base import ContentFile +from django.db import transaction from matplotlib import cm import numpy as np import pandas as pd @@ -27,6 +28,8 @@ def convert_time(obj, output='compact'): dt_obj = datetime.strptime(obj, '%a %b %d %H:%M:%S %Y') elif isinstance(obj, np.datetime64): # Handle datetime64 dt_obj = pd.Timestamp(obj).to_pydatetime() + elif isinstance(obj, pd.Timestamp): # Handle pandas Timestamp explicitly + dt_obj = obj.to_pydatetime() elif isinstance(obj, datetime): # Handle Python datetime objects dt_obj = obj elif isinstance( @@ -40,7 +43,9 @@ def convert_time(obj, output='compact'): ): dt_obj = datetime(obj.year, obj.month, obj.day, obj.hour, obj.minute, obj.second) elif isinstance(obj, (int, float)): - if obj > 1e10: # Assume milliseconds timestamp + if obj > 1e18: # Assume nanoseconds timestamp + dt_obj = datetime.fromtimestamp(obj / 1e9) + elif obj > 1e10: # Assume milliseconds timestamp dt_obj = datetime.fromtimestamp(obj / 1000) else: # Assume seconds timestamp dt_obj = datetime.fromtimestamp(obj) @@ -138,9 +143,6 @@ def create_netcdf_data_layer(file_item, metadata): try: var_min = float(variable.min().values) if variable.size > 0 else None var_max = float(variable.max().values) if variable.size > 0 else None - if 'datetime' in str(variable.dtype): - var_info['startDate'] = str(variable.min().values) - var_info['endDate'] = str(variable.max().values) if 'time' in var_name: var_info['min'] = convert_time(var_min, 'unix') var_info['max'] = convert_time(var_max, 'unix') @@ -148,6 +150,9 @@ def create_netcdf_data_layer(file_item, metadata): var_info['endDate'] = convert_time(var_max, 'iso') var_info['timeType'] = 'unix' + elif 'datetime' in str(variable.dtype): + var_info['startDate'] = str(variable.min().values) + var_info['endDate'] = str(variable.max().values) else: var_info['min'] = var_min var_info['max'] = var_max @@ -163,12 +168,16 @@ def create_netcdf_data_layer(file_item, metadata): elif re.search(r'\blat\b|\blatitude\b', var_name, re.IGNORECASE): if -90 <= var_min <= 90 and -90 <= var_max <= 90: var_info['geospatial'] = 'latitude' - except Exception: + except Exception as e: var_info['min'] = 0 var_info['max'] = variable.size var_info['steps'] = variable.size + logger.warning(f'Variable Min/Max Exception {var_name}: {e}') + logger.warning(f'Variable info {var_info}') description['variables'][var_name] = var_info + if metadata.get('tags', False): + description['tags'] = metadata.get('tags') # Create the NetCDF Layer Item created_netcdf = NetCDFData.objects.create( @@ -450,8 +459,6 @@ def create_netcdf_slices( == 'longitude360' ) # Handle the case of being 360 degrees and having no x_range - if longitude360 and x_range is None: - x_range = [ds[x_variable].values.min() - 180, ds[x_variable].values.max() - 180] degrees_east = ( netcdf_data.metadata.get('variables', {}) @@ -460,6 +467,15 @@ def create_netcdf_slices( .get('units', '') == 'degrees_east' ) + + if longitude360 and x_range is None and degrees_east is False: + x_range = [ds[x_variable].values.min() - 180, ds[x_variable].values.max() - 180] + elif longitude360 and x_range is None and degrees_east: + x_range = [ + 360 - (ds[x_variable].values.min() + 180), + 360 - (ds[x_variable].values.max() + 180), + ] + x_range_updated = x_range # This is a little complicated but we have latitude of -180 to 180 where 0 is greenwich # then there is the data in the system where it is 0 to 360 where 0 is greenwich @@ -486,7 +502,7 @@ def create_netcdf_slices( x_min, x_max = ds[x_variable].values.min(), ds[x_variable].values.max() if not (x_min <= x_range_updated[0] <= x_max and x_min <= x_range_updated[1] <= x_max): raise ValueError( - f'x_range {x_range_updated} is outside the bounds of {x_min} to {x_max}.' + f'x_range {x_range_updated} and {x_range} is outside the bounds of {x_min} to {x_max}.' ) # if we cross the 0 boundary we need to keep the filtering but use an OR # this is to get the values about the 180 range and the values below @@ -536,10 +552,15 @@ def create_netcdf_slices( ds[sliding_variable].values.min(), ds[sliding_variable].values.max(), ) - if np.issubdtype(ds[sliding_variable].dtype, np.datetime64): # Convert slicer_range to datetime64 if sliding_variable is a datetime - slicer_range = [np.datetime64(int(ts), 'ms') for ts in slicer_range] + temp_time = int(slicer_range[0]) + if temp_time > 1e18: + slicer_range = [np.datetime64(int(ts), 'ns') for ts in slicer_range] + elif temp_time > 1e10: + slicer_range = [np.datetime64(int(ts), 'ms') for ts in slicer_range] + elif temp_time: + slicer_range = [np.datetime64(int(ts), 's') for ts in slicer_range] # Check if slicer_range is a valid range of integers is_range_of_integers = ( @@ -548,7 +569,9 @@ def create_netcdf_slices( and all(isinstance(x, int) for x in slicer_range) ) - if is_range_of_integers: + if is_range_of_integers and not ( + np.issubdtype(ds[sliding_variable].dtype, np.datetime64) + ): # Check if range is within the number of layers num_layers = len(ds[sliding_variable]) if not ( @@ -587,7 +610,7 @@ def create_netcdf_slices( ds = ds.sortby(ds[y_variable], ascending=False) data_var = ds.get(variable) variables_data = data_var.dims - dim_size = ds.dims.get(sliding_variable) + dim_size = ds.sizes.get(sliding_variable) end = dim_size if end is None else end base_variables = (x_variable, y_variable, sliding_variable) @@ -673,7 +696,6 @@ def create_netcdf_slices( if degrees_east: x_bbox_range = [-(x + 180) for x in x_bbox_range] x_bbox_range.sort() - logger.info(f'XBOXRANGE: {x_bbox_range}') bounds = Polygon.from_bbox((x_bbox_range[0], y_min, x_bbox_range[1], y_max)) except GEOSException as geos_err: error = f'Error constructing polygon bounds: {geos_err}' @@ -730,25 +752,38 @@ def create_netcdf_slices( if start_date and end_date: parameters['sliding_dimension']['startDate'] = start_date parameters['sliding_dimension']['endDate'] = end_date + metadata = None + if netcdf_data.metadata.get('tags', False): + metadata = {'tags': netcdf_data.metadata.get('tags')} netcdf_layer = NetCDFLayer.objects.create( netcdf_data=netcdf_data, name=name, + metadata=metadata, color_scheme=color_map, description=description, parameters=parameters, bounds=bounds, ) # Iterate through the dimension to create slices and save images + + # Precompute the global min/max for the data + slice_min = np.nanmin(data_var.values) + slice_max = np.nanmax(data_var.values) + + # Collect all the images to be created + image_objects = [] + for i in range(start, end): - # Extract a slice along the specified dimension + logger.info(f'Creating image: {i} of {end}') indexers = {sliding_variable: i} for item in extra_variables: indexers[item['variable']] = item['index'] slice_data = data_var.isel(indexers).values # Normalize data to 0-1 for colormap application - slice_min = np.nanmin(slice_data) - slice_max = np.nanmax(slice_data) + # Uncomment for per-image normalization + # slice_min = np.nanmin(slice_data) + # slice_max = np.nanmax(slice_data) normalized_data = (slice_data - slice_min) / (slice_max - slice_min) # Apply the colormap @@ -765,13 +800,20 @@ def create_netcdf_slices( image_name = f'{variable}_{sliding_variable}_{i}.png' image_content = ContentFile(image_buffer.getvalue(), name=image_name) - # Create the NetCDFImage object - NetCDFImage.objects.create( - netcdf_layer=netcdf_layer, - image=image_content, # Save the image to the S3 field - slider_index=i, - bounds=bounds, # Reuse the bounds calculated earlier + # Collect the NetCDFImage objects for bulk creation later + image_objects.append( + NetCDFImage( + netcdf_layer=netcdf_layer, + image=image_content, # Save the image to the S3 field + slider_index=i, + bounds=bounds, # Reuse the bounds calculated earlier + ) ) + + # Bulk create the NetCDFImage objects in a single database transaction + logger.info('Creating Image Objects') + with transaction.atomic(): + NetCDFImage.objects.bulk_create(image_objects) if processing_task: processing_task.update( status=ProcessingTask.Status.COMPLETE, diff --git a/uvdat/urls.py b/uvdat/urls.py index e282ed7..a8052d9 100644 --- a/uvdat/urls.py +++ b/uvdat/urls.py @@ -14,6 +14,7 @@ LayerCollectionViewSet, LayerRepresentationViewSet, MapLayerViewSet, + MetadataFilterViewSet, NetCDFDataView, NetworkEdgeViewSet, NetworkNodeViewSet, @@ -60,6 +61,7 @@ router.register(r'processing-tasks', ProcessingTaskView, basename='processing-tasks') router.register(r'users', UserViewSet, basename='users') router.register(r'tasks', TasksAPIView, basename='tasks') +router.register(r'metadata-filters', MetadataFilterViewSet, basename='metadata-filters') urlpatterns = [ path('accounts/', include('allauth.urls')),