From d379ae837011aa67b9afc6bd3a96ec5d6ca9dbb4 Mon Sep 17 00:00:00 2001 From: Jeff Bliss Date: Mon, 26 Aug 2024 08:56:55 -0400 Subject: [PATCH] pushing up to move computers --- python_map_scripts/forwarn3_products_1yr.map | 128 +++++++ python_map_scripts/make_maps.py | 90 +++++ python_map_scripts/map_template.map | 83 ++++ python_map_scripts/masks.map | 355 ++++++++++++++++++ ...ecological_impact_dev_products_3yr_dev.map | 123 ++++++ ...ecological_impact_dev_products_4yr_dev.map | 123 ++++++ ...ecological_impact_dev_products_5yr_dev.map | 123 ++++++ python_map_scripts/raster_layers_template.map | 38 ++ src/App.jsx | 145 ++++--- src/config.js | 12 +- src/utils.js | 16 +- 11 files changed, 1184 insertions(+), 52 deletions(-) create mode 100644 python_map_scripts/forwarn3_products_1yr.map create mode 100644 python_map_scripts/make_maps.py create mode 100644 python_map_scripts/map_template.map create mode 100644 python_map_scripts/masks.map create mode 100644 python_map_scripts/net_ecological_impact_dev_products_3yr_dev.map create mode 100644 python_map_scripts/net_ecological_impact_dev_products_4yr_dev.map create mode 100644 python_map_scripts/net_ecological_impact_dev_products_5yr_dev.map create mode 100644 python_map_scripts/raster_layers_template.map diff --git a/python_map_scripts/forwarn3_products_1yr.map b/python_map_scripts/forwarn3_products_1yr.map new file mode 100644 index 00000000..3634912d --- /dev/null +++ b/python_map_scripts/forwarn3_products_1yr.map @@ -0,0 +1,128 @@ +MAP + # background color of image if transparency + # is not requested + IMAGECOLOR 255 255 255 + + # default output image dimensions + SIZE 600 400 + MAXSIZE 4000 + # always returns a map + STATUS ON + + # set top level projection + PROJECTION + "init=epsg:3857" + END + + # image format options + OUTPUTFORMAT + NAME png + DRIVER "GD/PNG" + MIMETYPE "image/png" + IMAGEMODE RGB + EXTENSION "png" + END + + OUTPUTFORMAT + NAME "GEOTIFF" + DRIVER "GDAL/GTiff" + MIMETYPE "image/tiff" + IMAGEMODE "BYTE" + EXTENSION "tif" + END + + # minx miny maxx maxy + # sets: + # /WMT_MS_Capabilities/Capability/Layer/LatLonBoundingBox(@minx @miny @maxx @maxx) + EXTENT -180 -90 180 90 # World + + # add def pointers for symbols + SYMBOLSET "./symbols/symbols35.sym" + FONTSET "./fonts/fonts.list" + + # Start of web interface definition + WEB + # this is the real filepath to the temp dir for intermediate file creation + IMAGEPATH "./tmp" + # this is the web-accessible path to IMAGEPATH + IMAGEURL "/tmp/" + HEADER "./templates/query_header.html" + FOOTER "./templates/query_footer.html" + METADATA + "ows_enable_request" "*" + "wms_title" "NEMAC WMS" + "wms_abstract" "NEMAC WMS" + "wms_contactperson" "nemac@unca.edu" + "wms_rootlayer_name" "" # this sets queryable=0 for root layer + "wms_onlineresource" "https://mapserver.nemac.org/?map=/etc/mapserver/ecs_test_map_files/forwarn3_products_1yr.map" + "wms_keywordlist" "2024-05-09_2024-06-01.napolygon.1yrdeparture.LAEA.img, + 2024-05-17_2024-06-09.napolygon.1yrdeparture.LAEA.img, + 2024-05-25_2024-06-17.napolygon.1yrdeparture.LAEA.img, + 2024-06-02_2024-06-25.napolygon.1yrdeparture.LAEA.img, + 2024-06-10_2024-07-03.napolygon.1yrdeparture.LAEA.img, + 2024-06-18_2024-07-11.napolygon.1yrdeparture.LAEA.img, + 2024-06-26_2024-07-19.napolygon.1yrdeparture.LAEA.img, + 2024-07-04_2024-07-27.napolygon.1yrdeparture.LAEA.img" + "wms_srs" "EPSG:4326 EPSG:2163 EPSG:3857 EPSG:900913" + "wcs_label" "forwarn3_products_1yr.map" + "wcs_srs" "EPSG:2163" + "ows_contactorganization" "UNCA's NEMAC" + END # end METADATA + END # end WEB + + QUERYMAP + STATUS OFF + END # end QUERYMAP + + LEGEND + STATUS ON + LABEL + COLOR 0 0 0 + FONT "vera_serif" + TYPE truetype + SIZE 9 + POSITION cl + END # end LABEL + END # end LEGEND + + LAYER + NAME "forwarn3_products_1yr" + PROJECTION + "+proj=laea" + "+lat_0=45" + "+lon_0=-100" + "+x_0=0" + "+y_0=0" + "+a=6370997" + "+b=6370997" + "+units=m" + "+no_defs" + END # END PROJECTION + TYPE RASTER + STATUS OFF + VALIDATION + "mask" "^[a-zA-Z0-9_]+$" + "default_mask" "empty_mask" + END # END VALIDATION + DATA /etc/mapserver/forwarn3_products/1yr/%data% + TEMPLATE layer_query_body.html # THIS DOES NOT EXIST AT THE MOMENT BUT IT IS NEEDED TO HAVE queryable=1 + #GROUP "forwarn3_products_1yr" + INCLUDE "new-forwarn2-standard-2.cmap" + METADATA + "wms_title" "forwarn3_products_1yr" + #"wms_group_title" "forwarn3_products_1yr" + "wms_extent" "-2401951.937575, -2238222.70389, 2345858.525679, 967021.455769" + "wms_abstract" "forwarn3_products_1yr" + "wcs_label" "forwarn3_products_1yr" + "wcs_rangeset_name" "forwarn3_products_1yr" + "wcs_rangeset_label" "forwarn3_products_1yr" + "wcs_bandcount" "1" + "wcs_formats" "GEOTIFF" + "wcs_nativeformat" "8-bit GeoTIF" + "gml_include_items" "value_0" + END # end METADATA + MASK '%mask%' + END # end LAYER + + INCLUDE "masks.map" +END diff --git a/python_map_scripts/make_maps.py b/python_map_scripts/make_maps.py new file mode 100644 index 00000000..ac37f185 --- /dev/null +++ b/python_map_scripts/make_maps.py @@ -0,0 +1,90 @@ +import os +import glob +import re + +DATA_DIR = "forwarn" +EXCLUDE_DIRS = ["archive", "bill_c", "forwarn2_build_prod", "forwarn2_products", + "forwarn3_test", "graph_data", "jspruce", "masks", "precursors", + "rescaled_precursors", "scripts"] +DATA_LOCATION_DIRECTORY = "/etc/mapserver" # where ECS container expects data to be + +def extract_date_range(filename): + # Use a regular expression to find the date range + match = re.search(r'(\d{4}-\d{2}-\d{2})_(\d{4}-\d{2}-\d{2})', filename) + if match: + return match.group(2) + return None + +def extract_subdirs(file_path, base_dir): + # Get the relative path + rel_path = os.path.relpath(file_path, base_dir) + # Split the path into parts + parts = rel_path.split(os.sep) + # Return all parts except the last one (filename) + return os.sep.join(parts[:-1]) + +def create_layers_from_template(map_template_file, raster_template_file, data_dir): + with open(map_template_file, 'r', encoding='utf-8') as f: + map_template = f.read() + + with open(raster_template_file, 'r', encoding='utf-8') as f: + raster_template = f.read() + + # Get list of .img files + img_files = [ + f for f in glob.glob(os.path.join(data_dir, '**/*.img'), recursive=True) + if not any(exclude_dir in f.split(os.sep) for exclude_dir in EXCLUDE_DIRS) + if "muted" not in os.path.basename(f).lower() + ] + # img_files = glob.glob(os.path.join(data_dir, '**/*.img'), recursive=True) + img_files.sort() + + # Group files by subdirectory + subdirectory_files = {} + for absolute_path in img_files: + subdirs = extract_subdirs(absolute_path, data_dir) + if subdirs not in subdirectory_files: + subdirectory_files[subdirs] = [] + subdirectory_files[subdirs].append(absolute_path) + + # Process each subdirectory + for subdirs, files in subdirectory_files.items(): + layers = [] + layer_filenames = [] + layer_content = raster_template.format( + layer_name = subdirs.replace(os.sep, '_'), + group_name = subdirs.replace(os.sep, '_'), + metadata_name = subdirs.replace(os.sep, '_'), + data_location = os.path.join(DATA_LOCATION_DIRECTORY, subdirs, "%data%") + ) + layers.append(layer_content) + for absolute_path in files: + filename = os.path.basename(absolute_path) + layer_filenames.append(filename) + grouped = [layer_filenames[i:i+1] for i in range(0, len(layer_filenames), 1)] + final_string = ',\n '.join(','.join(group) for group in grouped) +# date_range = extract_date_range(filename) +# if date_range: +# layer_content = raster_template.format( +# layer_name = f"{subdirs.replace(os.sep, '_')}_{date_range.replace('-', '')}", +# group_name = subdirs.replace(os.sep, '_'), +# metadata_name = f"{subdirs.replace(os.sep, '_')}_{date_range}", +# metadata_date = date_range.replace('-', ''), +# data_location = os.path.join(DATA_LOCATION_DIRECTORY, absolute_path) +# ) +# layers.append(layer_content) +# layer_filenames.append(filename) +# else: +# print(f"Warning: Could not extract date range from {filename}") + + layers_str = "\n".join(layers) + output_filename = f"{subdirs.replace(os.sep, '_')}.map" + map_content = map_template.format(layers=layers_str, layer_filenames=final_string, map_file_name=output_filename) + with open(output_filename, 'w', encoding='utf-8') as f: + f.write(map_content) + + print(f"Created map file: {output_filename}") + +MAP_TEMPLATE = "map_template.map" +RASTER_TEMPLATE = "raster_layers_template.map" +create_layers_from_template(MAP_TEMPLATE, RASTER_TEMPLATE, DATA_DIR) diff --git a/python_map_scripts/map_template.map b/python_map_scripts/map_template.map new file mode 100644 index 00000000..133a84e1 --- /dev/null +++ b/python_map_scripts/map_template.map @@ -0,0 +1,83 @@ +MAP + # background color of image if transparency + # is not requested + IMAGECOLOR 255 255 255 + + # default output image dimensions + SIZE 600 400 + MAXSIZE 4000 + # always returns a map + STATUS ON + + # set top level projection + PROJECTION + "init=epsg:3857" + END + + # image format options + OUTPUTFORMAT + NAME png + DRIVER "GD/PNG" + MIMETYPE "image/png" + IMAGEMODE RGB + EXTENSION "png" + END + + OUTPUTFORMAT + NAME "GEOTIFF" + DRIVER "GDAL/GTiff" + MIMETYPE "image/tiff" + IMAGEMODE "BYTE" + EXTENSION "tif" + END + + # minx miny maxx maxy + # sets: + # /WMT_MS_Capabilities/Capability/Layer/LatLonBoundingBox(@minx @miny @maxx @maxx) + EXTENT -180 -90 180 90 # World + + # add def pointers for symbols + SYMBOLSET "./symbols/symbols35.sym" + FONTSET "./fonts/fonts.list" + + # Start of web interface definition + WEB + # this is the real filepath to the temp dir for intermediate file creation + IMAGEPATH "./tmp" + # this is the web-accessible path to IMAGEPATH + IMAGEURL "/tmp/" + HEADER "./templates/query_header.html" + FOOTER "./templates/query_footer.html" + METADATA + "ows_enable_request" "*" + "wms_title" "NEMAC WMS" + "wms_abstract" "NEMAC WMS" + "wms_contactperson" "nemac@unca.edu" + "wms_rootlayer_name" "" # this sets queryable=0 for root layer + "wms_onlineresource" "https://mapserver.nemac.org/?map=/etc/mapserver/ecs_test_map_files/{map_file_name}" + "wms_keywordlist" "{layer_filenames}" + "wms_srs" "EPSG:4326 EPSG:2163 EPSG:3857 EPSG:900913" + "wcs_label" "{map_file_name}" + "wcs_srs" "EPSG:2163" + "ows_contactorganization" "UNCA's NEMAC" + END # end METADATA + END # end WEB + + QUERYMAP + STATUS OFF + END # end QUERYMAP + + LEGEND + STATUS ON + LABEL + COLOR 0 0 0 + FONT "vera_serif" + TYPE truetype + SIZE 9 + POSITION cl + END # end LABEL + END # end LEGEND + + {layers} + INCLUDE "masks.map" +END diff --git a/python_map_scripts/masks.map b/python_map_scripts/masks.map new file mode 100644 index 00000000..47e56cbd --- /dev/null +++ b/python_map_scripts/masks.map @@ -0,0 +1,355 @@ +LAYER + NAME empty_mask + STATUS OFF + TYPE POLYGON + PROJECTION + "+proj=laea" + "+lat_0=45" + "+lon_0=-100" + "+x_0=0" + "+y_0=0" + "+a=6370997" + "+b=6370997" + "+units=m" + "+no_defs" + END + FEATURE + POINTS + -2401951.937575 -2238222.70389 + 2345858.525679 -2238222.70389 + 2345858.525679 967021.455769 + -2401951.937575 967021.455769 + -2401951.937575 -2238222.70389 + END + END + CLASS + STYLE + OPACITY 100 + COLOR 255 255 255 + END + END + METADATA + "is_empty_mask" "true" + END +END + +LAYER + NAME MaskForForest + PROJECTION + "+proj=laea" + "+lat_0=45" + "+lon_0=-100" + "+x_0=0" + "+y_0=0" + "+a=6370997" + "+b=6370997" + "+units=m" + "+no_defs" + END + TYPE RASTER + STATUS OFF + DATA ../fsdata1/fsdata-internal/efetac_nasa/Mask/updated_masks_2020_2021/fw3_all_forests_mask.img + CLASS + EXPRESSION ([pixel] > 0) + STYLE + COLOR 0 0 0 + END + END + METADATA + "wms_title" "MaskForForest_Mask_file" + "wms_extent" "-2401951.937575, -2238222.70389, 2345858.525679, 967021.455769" + "wms_abstract" "MaskForForest" + "wcs_label" "MaskForForest" + "wcs_rangeset_name" "MaskForForest" + "wcs_rangeset_label" "MaskForForest" + END # end METADATA +END # end LAYER + +LAYER + NAME MaskForAgriculture + PROJECTION + "+proj=laea" + "+lat_0=45" + "+lon_0=-100" + "+x_0=0" + "+y_0=0" + "+a=6370997" + "+b=6370997" + "+units=m" + "+no_defs" + END + GROUP Masks + TYPE RASTER + STATUS OFF + DATA ../fsdata1/fsdata-internal/efetac_nasa/Mask/updated_masks_2020_2021/fw3_crops_mask.img + CLASS + EXPRESSION ([pixel] = 1) + STYLE + COLOR 0 0 0 + END + END + METADATA + "wms_title" "MaskForAgriculture_Mask_File" + "wms_extent" "-2401951.937575, -2238222.70389, 2345858.525679, 967021.455769" + "wms_abstract" "MaskForAgriculture" + "wcs_label" "MaskForAgriculture" + "wcs_rangeset_name" "MaskForAgriculture" + "wcs_rangeset_label" "MaskForAgriculture" + END # end METADATA +END # end LAYER + +LAYER + NAME MaskForConiferForest + PROJECTION + "+proj=laea" + "+lat_0=45" + "+lon_0=-100" + "+x_0=0" + "+y_0=0" + "+a=6370997" + "+b=6370997" + "+units=m" + "+no_defs" + END + TYPE RASTER + STATUS OFF + DATA ../fsdata1/fsdata-internal/efetac_nasa/Mask/updated_masks_2020_2021/fw3_evergreen_forest_mask.img + CLASS + EXPRESSION ([pixel] > 0) + STYLE + COLOR 0 0 0 + END + END + METADATA + "wms_title" "MaskForConiferForest" + "wms_extent" "-2401951.937575, -2238222.70389, 2345858.525679, 967021.455769" + "wms_abstract" "MaskForConiferForest" + "wcs_label" "MaskForConiferForest" + "wcs_rangeset_name" "MaskForConiferForest" + "wcs_rangeset_label" "MaskForConiferForest" + END # end METADATA +END # end LAYER + +LAYER + NAME MaskForDeciduousForest + PROJECTION + "+proj=laea" + "+lat_0=45" + "+lon_0=-100" + "+x_0=0" + "+y_0=0" + "+a=6370997" + "+b=6370997" + "+units=m" + "+no_defs" + END + TYPE RASTER + STATUS OFF + DATA ../fsdata1/fsdata-internal/efetac_nasa/Mask/updated_masks_2020_2021/fw3_deciduous_forest_mask.img + CLASS + EXPRESSION ([pixel] > 0) + STYLE + COLOR 0 0 0 + END + END + METADATA + "wms_title" "MaskForDeciduousForest" + "wms_extent" "-2401951.937575, -2238222.70389, 2345858.525679, 967021.455769" + "wms_abstract" "MaskForDeciduousForest" + "wcs_label" "MaskForDeciduousForest" + "wcs_rangeset_name" "MaskForDeciduousForest" + "wcs_rangeset_label" "MaskForDeciduousForest" + END # end METADATA +END # end LAYER + +LAYER + NAME MaskForGrass + PROJECTION + "+proj=laea" + "+lat_0=45" + "+lon_0=-100" + "+x_0=0" + "+y_0=0" + "+a=6370997" + "+b=6370997" + "+units=m" + "+no_defs" + END + TYPE RASTER + STATUS OFF + DATA ../fsdata1/fsdata-internal/efetac_nasa/Mask/updated_masks_2020_2021/fw3_grass_mask.img + CLASS + EXPRESSION ([pixel] > 0) + STYLE + COLOR 0 0 0 + END + END + METADATA + "wms_title" "MaskForGrass" + "wms_extent" "-2401951.937575, -2238222.70389, 2345858.525679, 967021.455769" + "wms_abstract" "MaskForGrass" + "wcs_label" "MaskForGrass" + "wcs_rangeset_name" "MaskForGrass" + "wcs_rangeset_label" "MaskForGrass" + END # end METADATA +END # end LAYER + +LAYER + NAME MaskForMixedForest + PROJECTION + "+proj=laea" + "+lat_0=45" + "+lon_0=-100" + "+x_0=0" + "+y_0=0" + "+a=6370997" + "+b=6370997" + "+units=m" + "+no_defs" + END + TYPE RASTER + STATUS OFF + DATA ../fsdata1/fsdata-internal/efetac_nasa/Mask/updated_masks_2020_2021/fw3_mixed_forest_mask.img + CLASS + EXPRESSION ([pixel] > 0) + STYLE + COLOR 0 0 0 + END + END + METADATA + "wms_title" "MaskForMixedForest" + "wms_extent" "-2401951.937575, -2238222.70389, 2345858.525679, 967021.455769" + "wms_abstract" "MaskForMixedForest" + "wcs_label" "MaskForMixedForest" + "wcs_rangeset_name" "MaskForMixedForest" + "wcs_rangeset_label" "MaskForMixedForest" + END # end METADATA +END # end LAYER + +LAYER + NAME MaskForNonVegetated + PROJECTION + "+proj=laea" + "+lat_0=45" + "+lon_0=-100" + "+x_0=0" + "+y_0=0" + "+a=6370997" + "+b=6370997" + "+units=m" + "+no_defs" + END + TYPE RASTER + STATUS OFF + DATA ../fsdata1/fsdata-internal/efetac_nasa/Mask/updated_masks_2020_2021/fw3_non_vegetated_mask.img + CLASS + EXPRESSION ([pixel] > 0) + STYLE + COLOR 0 0 0 + END + END + METADATA + "wms_title" "MaskForNonVegetated" + "wms_extent" "-2401951.937575, -2238222.70389, 2345858.525679, 967021.455769" + "wms_abstract" "MaskForNonVegetated" + "wcs_label" "MaskForNonVegetated" + "wcs_rangeset_name" "MaskForNonVegetated" + "wcs_rangeset_label" "MaskForNonVegetated" + END # end METADATA +END # end LAYER + +LAYER + NAME MaskForShrubland + PROJECTION + "+proj=laea" + "+lat_0=45" + "+lon_0=-100" + "+x_0=0" + "+y_0=0" + "+a=6370997" + "+b=6370997" + "+units=m" + "+no_defs" + END + TYPE RASTER + STATUS OFF + DATA ../fsdata1/fsdata-internal/efetac_nasa/Mask/updated_masks_2020_2021/fw3_shrubland_mask.img + CLASS + EXPRESSION ([pixel] > 0) + STYLE + COLOR 0 0 0 + END + END + METADATA + "wms_title" "MaskForShrubland" + "wms_extent" "-2401951.937575, -2238222.70389, 2345858.525679, 967021.455769" + "wms_abstract" "MaskForShrubland" + "wcs_label" "MaskForShrubland" + "wcs_rangeset_name" "MaskForShrubland" + "wcs_rangeset_label" "MaskForShrubland" + END # end METADATA +END # end LAYER + +LAYER + NAME MaskForUrban + PROJECTION + "+proj=laea" + "+lat_0=45" + "+lon_0=-100" + "+x_0=0" + "+y_0=0" + "+a=6370997" + "+b=6370997" + "+units=m" + "+no_defs" + END + TYPE RASTER + STATUS OFF + DATA ../fsdata1/fsdata-internal/efetac_nasa/Mask/updated_masks_2020_2021/fw3_urban_mask.img + CLASS + EXPRESSION ([pixel] > 0) + STYLE + COLOR 0 0 0 + END + END + METADATA + "wms_title" "MaskForUrban" + "wms_extent" "-2401951.937575, -2238222.70389, 2345858.525679, 967021.455769" + "wms_abstract" "MaskForUrban" + "wcs_label" "MaskForUrban" + "wcs_rangeset_name" "MaskForUrban" + "wcs_rangeset_label" "MaskForUrban" + END # end METADATA +END # end LAYER + +LAYER + NAME MaskForWetland + PROJECTION + "+proj=laea" + "+lat_0=45" + "+lon_0=-100" + "+x_0=0" + "+y_0=0" + "+a=6370997" + "+b=6370997" + "+units=m" + "+no_defs" + END + TYPE RASTER + STATUS OFF + DATA ../fsdata1/fsdata-internal/efetac_nasa/Mask/updated_masks_2020_2021/fw3_non_woody_wetland_mask.img + CLASS + EXPRESSION ([pixel] > 0) + STYLE + COLOR 0 0 0 + END + END + METADATA + "wms_title" "MaskForWetland" + "wms_extent" "-2401951.937575, -2238222.70389, 2345858.525679, 967021.455769" + "wms_abstract" "MaskForWetland" + "wcs_label" "MaskForWetland" + "wcs_rangeset_name" "MaskForWetland" + "wcs_rangeset_label" "MaskForWetland" + END # end METADATA +END # end LAYER \ No newline at end of file diff --git a/python_map_scripts/net_ecological_impact_dev_products_3yr_dev.map b/python_map_scripts/net_ecological_impact_dev_products_3yr_dev.map new file mode 100644 index 00000000..08ec3d4a --- /dev/null +++ b/python_map_scripts/net_ecological_impact_dev_products_3yr_dev.map @@ -0,0 +1,123 @@ +MAP + # background color of image if transparency + # is not requested + IMAGECOLOR 255 255 255 + + # default output image dimensions + SIZE 600 400 + MAXSIZE 4000 + # always returns a map + STATUS ON + + # set top level projection + PROJECTION + "init=epsg:3857" + END + + # image format options + OUTPUTFORMAT + NAME png + DRIVER "GD/PNG" + MIMETYPE "image/png" + IMAGEMODE RGB + EXTENSION "png" + END + + OUTPUTFORMAT + NAME "GEOTIFF" + DRIVER "GDAL/GTiff" + MIMETYPE "image/tiff" + IMAGEMODE "BYTE" + EXTENSION "tif" + END + + # minx miny maxx maxy + # sets: + # /WMT_MS_Capabilities/Capability/Layer/LatLonBoundingBox(@minx @miny @maxx @maxx) + EXTENT -180 -90 180 90 # World + + # add def pointers for symbols + SYMBOLSET "./symbols/symbols35.sym" + FONTSET "./fonts/fonts.list" + + # Start of web interface definition + WEB + # this is the real filepath to the temp dir for intermediate file creation + IMAGEPATH "./tmp" + # this is the web-accessible path to IMAGEPATH + IMAGEURL "/tmp/" + HEADER "./templates/query_header.html" + FOOTER "./templates/query_footer.html" + METADATA + "ows_enable_request" "*" + "wms_title" "NEMAC WMS" + "wms_abstract" "NEMAC WMS" + "wms_contactperson" "nemac@unca.edu" + "wms_rootlayer_name" "" # this sets queryable=0 for root layer + "wms_onlineresource" "https://mapserver.nemac.org/?map=/etc/mapserver/ecs_test_map_files/net_ecological_impact_dev_products_3yr_dev.map" + "wms_keywordlist" "2023-11-25_2023-12-02.napolygon.auc3yrdeparture.pct.LAEA.datumfix.img, + 2023-12-03_2023-12-10.napolygon.auc3yrdeparture.pct.LAEA.datumfix.img, + 2023-12-11_2023-12-18.napolygon.auc3yrdeparture.pct.LAEA.datumfix.img" + "wms_srs" "EPSG:4326 EPSG:2163 EPSG:3857 EPSG:900913" + "wcs_label" "net_ecological_impact_dev_products_3yr_dev.map" + "wcs_srs" "EPSG:2163" + "ows_contactorganization" "UNCA's NEMAC" + END # end METADATA + END # end WEB + + QUERYMAP + STATUS OFF + END # end QUERYMAP + + LEGEND + STATUS ON + LABEL + COLOR 0 0 0 + FONT "vera_serif" + TYPE truetype + SIZE 9 + POSITION cl + END # end LABEL + END # end LEGEND + + LAYER + NAME "net_ecological_impact_dev_products_3yr_dev" + PROJECTION + "+proj=laea" + "+lat_0=45" + "+lon_0=-100" + "+x_0=0" + "+y_0=0" + "+a=6370997" + "+b=6370997" + "+units=m" + "+no_defs" + END # END PROJECTION + TYPE RASTER + STATUS OFF + VALIDATION + "mask" "^[a-zA-Z0-9_]+$" + "default_mask" "empty_mask" + END # END VALIDATION + DATA /etc/mapserver/net_ecological_impact_dev_products/3yr_dev/%data% + TEMPLATE layer_query_body.html # THIS DOES NOT EXIST AT THE MOMENT BUT IT IS NEEDED TO HAVE queryable=1 + #GROUP "net_ecological_impact_dev_products_3yr_dev" + INCLUDE "new-forwarn2-standard-2.cmap" + METADATA + "wms_title" "net_ecological_impact_dev_products_3yr_dev" + #"wms_group_title" "net_ecological_impact_dev_products_3yr_dev" + "wms_extent" "-2401951.937575, -2238222.70389, 2345858.525679, 967021.455769" + "wms_abstract" "net_ecological_impact_dev_products_3yr_dev" + "wcs_label" "net_ecological_impact_dev_products_3yr_dev" + "wcs_rangeset_name" "net_ecological_impact_dev_products_3yr_dev" + "wcs_rangeset_label" "net_ecological_impact_dev_products_3yr_dev" + "wcs_bandcount" "1" + "wcs_formats" "GEOTIFF" + "wcs_nativeformat" "8-bit GeoTIF" + "gml_include_items" "value_0" + END # end METADATA + MASK '%mask%' + END # end LAYER + + INCLUDE "masks.map" +END diff --git a/python_map_scripts/net_ecological_impact_dev_products_4yr_dev.map b/python_map_scripts/net_ecological_impact_dev_products_4yr_dev.map new file mode 100644 index 00000000..4090a758 --- /dev/null +++ b/python_map_scripts/net_ecological_impact_dev_products_4yr_dev.map @@ -0,0 +1,123 @@ +MAP + # background color of image if transparency + # is not requested + IMAGECOLOR 255 255 255 + + # default output image dimensions + SIZE 600 400 + MAXSIZE 4000 + # always returns a map + STATUS ON + + # set top level projection + PROJECTION + "init=epsg:3857" + END + + # image format options + OUTPUTFORMAT + NAME png + DRIVER "GD/PNG" + MIMETYPE "image/png" + IMAGEMODE RGB + EXTENSION "png" + END + + OUTPUTFORMAT + NAME "GEOTIFF" + DRIVER "GDAL/GTiff" + MIMETYPE "image/tiff" + IMAGEMODE "BYTE" + EXTENSION "tif" + END + + # minx miny maxx maxy + # sets: + # /WMT_MS_Capabilities/Capability/Layer/LatLonBoundingBox(@minx @miny @maxx @maxx) + EXTENT -180 -90 180 90 # World + + # add def pointers for symbols + SYMBOLSET "./symbols/symbols35.sym" + FONTSET "./fonts/fonts.list" + + # Start of web interface definition + WEB + # this is the real filepath to the temp dir for intermediate file creation + IMAGEPATH "./tmp" + # this is the web-accessible path to IMAGEPATH + IMAGEURL "/tmp/" + HEADER "./templates/query_header.html" + FOOTER "./templates/query_footer.html" + METADATA + "ows_enable_request" "*" + "wms_title" "NEMAC WMS" + "wms_abstract" "NEMAC WMS" + "wms_contactperson" "nemac@unca.edu" + "wms_rootlayer_name" "" # this sets queryable=0 for root layer + "wms_onlineresource" "https://mapserver.nemac.org/?map=/etc/mapserver/ecs_test_map_files/net_ecological_impact_dev_products_4yr_dev.map" + "wms_keywordlist" "2023-11-25_2023-12-02.napolygon.auc4yrdeparture.pct.LAEA.datumfix.img, + 2023-12-03_2023-12-10.napolygon.auc4yrdeparture.pct.LAEA.datumfix.img, + 2023-12-11_2023-12-18.napolygon.auc4yrdeparture.pct.LAEA.datumfix.img" + "wms_srs" "EPSG:4326 EPSG:2163 EPSG:3857 EPSG:900913" + "wcs_label" "net_ecological_impact_dev_products_4yr_dev.map" + "wcs_srs" "EPSG:2163" + "ows_contactorganization" "UNCA's NEMAC" + END # end METADATA + END # end WEB + + QUERYMAP + STATUS OFF + END # end QUERYMAP + + LEGEND + STATUS ON + LABEL + COLOR 0 0 0 + FONT "vera_serif" + TYPE truetype + SIZE 9 + POSITION cl + END # end LABEL + END # end LEGEND + + LAYER + NAME "net_ecological_impact_dev_products_4yr_dev" + PROJECTION + "+proj=laea" + "+lat_0=45" + "+lon_0=-100" + "+x_0=0" + "+y_0=0" + "+a=6370997" + "+b=6370997" + "+units=m" + "+no_defs" + END # END PROJECTION + TYPE RASTER + STATUS OFF + VALIDATION + "mask" "^[a-zA-Z0-9_]+$" + "default_mask" "empty_mask" + END # END VALIDATION + DATA /etc/mapserver/net_ecological_impact_dev_products/4yr_dev/%data% + TEMPLATE layer_query_body.html # THIS DOES NOT EXIST AT THE MOMENT BUT IT IS NEEDED TO HAVE queryable=1 + #GROUP "net_ecological_impact_dev_products_4yr_dev" + INCLUDE "new-forwarn2-standard-2.cmap" + METADATA + "wms_title" "net_ecological_impact_dev_products_4yr_dev" + #"wms_group_title" "net_ecological_impact_dev_products_4yr_dev" + "wms_extent" "-2401951.937575, -2238222.70389, 2345858.525679, 967021.455769" + "wms_abstract" "net_ecological_impact_dev_products_4yr_dev" + "wcs_label" "net_ecological_impact_dev_products_4yr_dev" + "wcs_rangeset_name" "net_ecological_impact_dev_products_4yr_dev" + "wcs_rangeset_label" "net_ecological_impact_dev_products_4yr_dev" + "wcs_bandcount" "1" + "wcs_formats" "GEOTIFF" + "wcs_nativeformat" "8-bit GeoTIF" + "gml_include_items" "value_0" + END # end METADATA + MASK '%mask%' + END # end LAYER + + INCLUDE "masks.map" +END diff --git a/python_map_scripts/net_ecological_impact_dev_products_5yr_dev.map b/python_map_scripts/net_ecological_impact_dev_products_5yr_dev.map new file mode 100644 index 00000000..3387f877 --- /dev/null +++ b/python_map_scripts/net_ecological_impact_dev_products_5yr_dev.map @@ -0,0 +1,123 @@ +MAP + # background color of image if transparency + # is not requested + IMAGECOLOR 255 255 255 + + # default output image dimensions + SIZE 600 400 + MAXSIZE 4000 + # always returns a map + STATUS ON + + # set top level projection + PROJECTION + "init=epsg:3857" + END + + # image format options + OUTPUTFORMAT + NAME png + DRIVER "GD/PNG" + MIMETYPE "image/png" + IMAGEMODE RGB + EXTENSION "png" + END + + OUTPUTFORMAT + NAME "GEOTIFF" + DRIVER "GDAL/GTiff" + MIMETYPE "image/tiff" + IMAGEMODE "BYTE" + EXTENSION "tif" + END + + # minx miny maxx maxy + # sets: + # /WMT_MS_Capabilities/Capability/Layer/LatLonBoundingBox(@minx @miny @maxx @maxx) + EXTENT -180 -90 180 90 # World + + # add def pointers for symbols + SYMBOLSET "./symbols/symbols35.sym" + FONTSET "./fonts/fonts.list" + + # Start of web interface definition + WEB + # this is the real filepath to the temp dir for intermediate file creation + IMAGEPATH "./tmp" + # this is the web-accessible path to IMAGEPATH + IMAGEURL "/tmp/" + HEADER "./templates/query_header.html" + FOOTER "./templates/query_footer.html" + METADATA + "ows_enable_request" "*" + "wms_title" "NEMAC WMS" + "wms_abstract" "NEMAC WMS" + "wms_contactperson" "nemac@unca.edu" + "wms_rootlayer_name" "" # this sets queryable=0 for root layer + "wms_onlineresource" "https://mapserver.nemac.org/?map=/etc/mapserver/ecs_test_map_files/net_ecological_impact_dev_products_5yr_dev.map" + "wms_keywordlist" "2023-11-25_2023-12-02.napolygon.auc5yrdeparture.pct.LAEA.datumfix.img, + 2023-12-03_2023-12-10.napolygon.auc5yrdeparture.pct.LAEA.datumfix.img, + 2023-12-11_2023-12-18.napolygon.auc5yrdeparture.pct.LAEA.datumfix.img" + "wms_srs" "EPSG:4326 EPSG:2163 EPSG:3857 EPSG:900913" + "wcs_label" "net_ecological_impact_dev_products_5yr_dev.map" + "wcs_srs" "EPSG:2163" + "ows_contactorganization" "UNCA's NEMAC" + END # end METADATA + END # end WEB + + QUERYMAP + STATUS OFF + END # end QUERYMAP + + LEGEND + STATUS ON + LABEL + COLOR 0 0 0 + FONT "vera_serif" + TYPE truetype + SIZE 9 + POSITION cl + END # end LABEL + END # end LEGEND + + LAYER + NAME "net_ecological_impact_dev_products_5yr_dev" + PROJECTION + "+proj=laea" + "+lat_0=45" + "+lon_0=-100" + "+x_0=0" + "+y_0=0" + "+a=6370997" + "+b=6370997" + "+units=m" + "+no_defs" + END # END PROJECTION + TYPE RASTER + STATUS OFF + VALIDATION + "mask" "^[a-zA-Z0-9_]+$" + "default_mask" "empty_mask" + END # END VALIDATION + DATA /etc/mapserver/net_ecological_impact_dev_products/5yr_dev/%data% + TEMPLATE layer_query_body.html # THIS DOES NOT EXIST AT THE MOMENT BUT IT IS NEEDED TO HAVE queryable=1 + #GROUP "net_ecological_impact_dev_products_5yr_dev" + INCLUDE "new-forwarn2-standard-2.cmap" + METADATA + "wms_title" "net_ecological_impact_dev_products_5yr_dev" + #"wms_group_title" "net_ecological_impact_dev_products_5yr_dev" + "wms_extent" "-2401951.937575, -2238222.70389, 2345858.525679, 967021.455769" + "wms_abstract" "net_ecological_impact_dev_products_5yr_dev" + "wcs_label" "net_ecological_impact_dev_products_5yr_dev" + "wcs_rangeset_name" "net_ecological_impact_dev_products_5yr_dev" + "wcs_rangeset_label" "net_ecological_impact_dev_products_5yr_dev" + "wcs_bandcount" "1" + "wcs_formats" "GEOTIFF" + "wcs_nativeformat" "8-bit GeoTIF" + "gml_include_items" "value_0" + END # end METADATA + MASK '%mask%' + END # end LAYER + + INCLUDE "masks.map" +END diff --git a/python_map_scripts/raster_layers_template.map b/python_map_scripts/raster_layers_template.map new file mode 100644 index 00000000..33b02d8a --- /dev/null +++ b/python_map_scripts/raster_layers_template.map @@ -0,0 +1,38 @@ + LAYER + NAME "{layer_name}" + PROJECTION + "+proj=laea" + "+lat_0=45" + "+lon_0=-100" + "+x_0=0" + "+y_0=0" + "+a=6370997" + "+b=6370997" + "+units=m" + "+no_defs" + END # END PROJECTION + TYPE RASTER + STATUS OFF + VALIDATION + "mask" "^[a-zA-Z0-9_]+$" + "default_mask" "empty_mask" + END # END VALIDATION + DATA {data_location} + TEMPLATE layer_query_body.html # THIS DOES NOT EXIST AT THE MOMENT BUT IT IS NEEDED TO HAVE queryable=1 + #GROUP "{group_name}" + INCLUDE "new-forwarn2-standard-2.cmap" + METADATA + "wms_title" "{metadata_name}" + #"wms_group_title" "{group_name}" + "wms_extent" "-2401951.937575, -2238222.70389, 2345858.525679, 967021.455769" + "wms_abstract" "{metadata_name}" + "wcs_label" "{metadata_name}" + "wcs_rangeset_name" "{metadata_name}" + "wcs_rangeset_label" "{metadata_name}" + "wcs_bandcount" "1" + "wcs_formats" "GEOTIFF" + "wcs_nativeformat" "8-bit GeoTIF" + "gml_include_items" "value_0" + END # end METADATA + MASK '%mask%' + END # end LAYER diff --git a/src/App.jsx b/src/App.jsx index 228c47d4..69aed575 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,15 +1,15 @@ import React from 'react'; import dayjs from 'dayjs'; -import { MapContainer, WMSTileLayer } from "react-leaflet"; -import Paper from '@mui/material/Paper'; -import Typography from '@mui/material/Typography'; +import { MapContainer, useMapEvents, WMSTileLayer } from "react-leaflet"; import Slider from '@mui/material/Slider'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { DatePicker } from '@mui/x-date-pickers/DatePicker'; +import {IconButton} from "@mui/material"; import Grid from '@mui/material/Unstable_Grid2'; // Grid version 2 import PlayArrowIcon from '@mui/icons-material/PlayArrow'; import PauseIcon from '@mui/icons-material/Pause'; +import ShowChartIcon from '@mui/icons-material/ShowChart'; import styled from "@emotion/styled"; import { useQuery, @@ -23,24 +23,25 @@ import BasicButton from './components/BasicButton'; import BasicDatePicker from './components/BasicDatePicker'; import DateSlider from './components/DateSlider'; import { config } from './config'; -import { webMercatorToLatLng, convertStringToDate } from "./utils.js"; +import {webMercatorToLatLng, convertStringToDate, parseDateString} from "./utils.js"; import BasicText from "./components/BasicText.jsx"; export const StyledMapContainer = styled(MapContainer)(() => ({ height: '100%', - width: '100%' + width: '100%', })); function App() { + const [map, setMap] = React.useState(null) const [changeProduct, setChangeProduct] = React.useState(config.wmsLayers['FW3 1 year']); const [mask, setMask] = React.useState(config.masks['MaskForForest']); - const [overlay, setOverlay] = React.useState(config.vectorLayers['Tropical Cyclone Lines 2022']); + const [overlay, setOverlay] = React.useState(config.vectorLayers['Tropical Cyclone Lines Since 1980']); const [basemap, setBasemap] = React.useState(config.basemaps['ArcGIS Imagery']); const [availableLayers, setAvailableLayers] = React.useState([]); const [activeLayerIndex, setActiveLayerIndex] = React.useState(0); const [rasterOpacity, setRasterOpacity] = React.useState(75); const [startDate, setStartDate] = React.useState(dayjs('2024-07-01')); - const [endDate, setEndDate] = React.useState(dayjs('2024-07-31')); + const [endDate, setEndDate] = React.useState(dayjs('2024-07-08')); const [isPlaying, setIsPlaying] = React.useState(false); const [playSpeed, setPlaySpeed] = React.useState(config.playSpeeds['2x']); const [unFilteredLayers, setUnfilteredLayers] = React.useState([]); @@ -87,8 +88,8 @@ function App() { }; const handleMaskChange = (event) => { - const selectedMask = config.masks(event.target.value); - setMask(selectedMask); + const selectedMask = event.target.value; + setMask(config.masks[selectedMask]); } const handleOverlayChange = (event) => { @@ -101,6 +102,36 @@ function App() { setBasemap(config.basemaps[selectedBasemap]); } + const NdviChartButton = () => { + const map = useMapEvents({ + click() { + if(map.getContainer().style.cursor === 'crosshair') { + console.log('map click for graph') + map.getContainer().style.cursor = 'grab' + } + } + }) + const chartOnClick = (event) => { + event.stopPropagation(); + if(map.getContainer().style.cursor === 'grab') { + map.getContainer().style.cursor = 'crosshair'; + return + } + map.getContainer().style.cursor = 'grab'; + } + + return ( + chartOnClick(event)} + > + + + ) + } + const handleIsPlayingPress = (event) => { let currentLayerIndex = activeLayerIndex; if (isPlaying) { @@ -135,7 +166,6 @@ function App() { // Update available layers when the getCapabilities query has returned React.useEffect(() => { if (!data) return; - // const layerName = event.target.value; const layers = data?.getElementsByTagName('Layer'); const queryableLayers = layers.filter(layer => layer.attributes.queryable === "1"); const availableLayers = []; @@ -168,10 +198,11 @@ function App() { const northEast = webMercatorToLatLng(maxX, maxY); const southEast = webMercatorToLatLng(maxX, minY); -// Calculate the center + // Calculate the center const centerLat = (southWest[0] + northWest[0] + northEast[0] + southEast[0]) / 4; const centerLng = (southWest[1] + northWest[1] + northEast[1] + southEast[1]) / 4; + return ( @@ -243,53 +274,69 @@ function App() { onClick={(event) => handleIsPlayingPress(event)} /> - - - - {availableLayers.map((layer, index) => ( + + + + {/*{availableLayers.map((layer, index) => (*/} + {/* */} + {/*))}*/} - ))} - -
-
- + +
+
+ +
-
-
-
- +
+
+ +
-
- - - +
+
+ +
+
+ + + ) } diff --git a/src/config.js b/src/config.js index ee20fc58..940c00ab 100644 --- a/src/config.js +++ b/src/config.js @@ -18,9 +18,14 @@ export const config = { url: wmsUrl.concat('forwarn3_products_1yr.map'), layer_regex: /^forwarn3_products_1yr_(\d{4})(\d{2})(\d{2})$/ }, + 'forwarn3_products_1yr': { + name: 'forwarn3_products_1yr', + url: wmsUrl.concat('test_runtime_sub.map'), + layer_regex: /^forwarn3_products_1yr_(\d{4})(\d{2})(\d{2})$/ + }, 'FW3 2 year Early Detect': { name: 'FW3 2 year Early Detect', - url: wmsUrlFull, + url: wmsUrl, layer_regex: /^forwarn3_products_2yrED_(\d{4})(\d{2})(\d{2})$/ }, 'FW3 2 year Early Early Detect': { @@ -129,6 +134,11 @@ export const config = { name: 'Tropical Cyclone Lines 2023', url: wmsUrl.concat('vlayers.map'), layerName: 'tropical_cyclone_lines_2023' + }, + 'Tropical Cyclone Lines Since 1980': { + name: 'Tropical Cyclone Lines Since 1980', + url: wmsUrl.concat('vector_map_files/tropical_cyclone_lines.map'), + layerName: 'tropical_cyclone_lines_since_1980' } }, masks: { diff --git a/src/utils.js b/src/utils.js index 7beafb09..4ca0c731 100644 --- a/src/utils.js +++ b/src/utils.js @@ -25,9 +25,21 @@ export function calculateCenterAndZoom(extent) { return { center: [center.lat, center.lng], zoom }; } -export const convertStringToDate = (dateString) => { +export function convertStringToDate(dateString) { const year = dateString.slice(0, 4); const month = dateString.slice(4, 6); const day = dateString.slice(6, 8); return new Date(`${year}-${month}-${day}T00:00:00-04:00`); -}; \ No newline at end of file +}; + +// parses "2024-06-26_2024-07-19.napolygon.1yrdeparture.LAEA.img" into "20240719 +export function parseDateString(inputString) { + // Split the string by underscore and period + const parts = inputString.split('_')[1].split('.'); + + // Extract the date part (2024-07-19) + const datePart = parts[0]; + + // Remove hyphens and return only the digits + return datePart.replace(/-/g, ''); +} \ No newline at end of file