Skip to content

MVW How to add a new file based layer

Grace-Amondi edited this page Apr 24, 2021 · 2 revisions

MVW How to add a new file-based layer

This page shows how to add into the MapViewer a new layer that loads data stored in files. fAPAR Anomaly is taken as a sample in the next lines.

The following steps must be done:

  • Determine type (raster or vector) and location (full path) of source data.
  • If the layer displays a time series, determine its periodicity and how the reference to a single date appears in the file name and path.
  • Define the new layer in a MapServer mapfile, with settings to load source data, classify them and make them available to the MapViewer via WMS.
  • Define the new layer in mapConfig.js, setting its properties within the MapViewer.
  • If the layer displays a time series, add an entry in layerDates.js, in order to set the last available date.
Determine type and location of source data

The new layer can load a single file, e.g. a GeoTIFF, or a set of files, like for shapefiles. The layer can have raster or vector type, according to the source data. In our sample, fAPAR Anomaly data are provided as GeoTIFF images. Each GeoTIFF image is read by a Python program which takes the values and uses them to fill the database and to produce quicklook images saved in PNG format. Three types of layers could be defined to present fAPAR Anomaly according to the three available source data types:

  • a raster layer loading GeoTIFF images;
  • a raster layer loading quicklook PNG images;
  • a vector layer loading data coming from the PostgreSQL database and geo-referenced using the correspondent grid, by means of PostGIS.

We continue here creating a raster layer loading directly GeoTIFF images.

Data periodicity and how it affects file paths

If source data we want to display in the new layer are a time series, e.g. containing monthly precipitation values from 1980 up to now, they could be organized with a single file for each time instance, e.g. one single file of precipitation data for each month. But in a more compact way, a single data file could contain more time instances in itself, for example all the months of a single year. This can be done with GeoTIFF, using different bands, or NetCDF files.

In the following, for our fAPAR Anomaly sample we consider the former case. Such data have a 10-daily periodicity, as shown in the next table:

10-day period (dekad) Involved days Ordinal reference in dates Cardinal reference in dates
First from 1 to 10 1st 01
Second from 11 to 20 2nd 11
Third from 21 to the last day of the month 3rd 21

Source files reflect this periodicity and their full path can have a syntax like this:

/fix_part_of_the_path/{YYYY}/filename_prefix{YYYY}{MM}{DD}filename_suffix.extension,

where {YYYY} is the year, {MM} the month (with leading zero) and {DD} is the cardinal reference to the dekad (01, 11, or 21).

For example, the full path of fAPAR Anomaly quicklook of the second dekad of March 2019 is ./mapserver/gisdata/continental/east_africa/fapar/fapar_anom/qkl/2019/fpa_ea_20190311_t.png, while the full path of fAPAR Anomaly GeoTIFF of the third dekad of November 2007 is ./mapserver/gisdata/continental/east_africa/fapar/fapar_anom/gtiff/2007/fpa_ea_20071121_t.tif.

Define the new layer in a MapServer mapfile

Within the MapServer mapfiles' directory, i.e. ./mapserver/mapfiles/mukau/, there are two mapfiles, base.map and mukau.map. The former is thought for layers used as geographic background (e.g. "Countries" or "Water surfaces"), the latter for drought indicators (e.g. "Monthly Precipitation" or "SPI 1 dd").

Therefore, let's use mukau.map to add our fAPAR Anomaly layer loading GeoTIFF images. The code snippet defining the Layer Object is:

LAYER
    NAME "fapar_anom_gtiff"
    TYPE RASTER
    STATUS OFF
    DATA "./mapserver/gisdata/continental/east_africa/fapar/fapar_anom/gtiff/%SELECTED_YEAR%/fam_ea_%SELECTED_YEAR%%SELECTED_MONTH%%SELECTED_TENDAYS%_t.tif"
    PROJECTION
      "init=epsg:4326"
    END # PROJECTION
    VALIDATION
        "SELECTED_YEAR" "[0-9]{4}"
        "SELECTED_MONTH" "[0-9]{2}"
        "SELECTED_TENDAYS" "[0-9]{2}"
    END
    METADATA
        "wms_title"	"fapar_anom_gtiff"
        "wms_srs"	"EPSG:4326 EPSG:900913"
        "wms_abstract"	"Anomaly of fAPAR (fraction of Absorbed Photosynthetically Active Radiation): 10-day time composite, 1/12 dd spatial resolution, derived from the Moderate resolution imaging spectroradiometer (MODIS) global coverage satellite products."
        "wms_title"	"Vegetation Productivity Anomaly (fAPAR Anomaly)"
        "LAST_UPDATE"	"2020/01/22"
    END
    INCLUDE "./classifications/fapar.anom.classes.map"
END

The first three parameters set the name, the type and the status of the layer respectively. Please note that the values of type and status are not quoted since they are keywords.

The fourth parameter, DATA, is the path of the source files, given using variables, if necessary. Variables are included into two % characters. In our case three variables define year (%SELECTED_YEAR%), month (%SELECTED_MONTH%) and dekad (%SELECTED_TENDAYS%) respectively. Such variables are replaced by actual values set through the correspondent URL parameters included into the URL calling the layer's WMS service. For security reasons, the passed values must be validated against a range of allowed values, specified into the validation block by means of regular expressions. The reference system used by DATA is set by the Projection object.

The Metadata Object contains wms_* metadata, used for providing a WMS service, and additional custom metadata, like LAST_UPDATED, used to register the date of the last update of the layer definition.

Since the source GeoTIFFs contain data and haven't colours for them, a classification must be defined to colorize the layer into the map. It's a good practice to store the classification in a separate file, since the classification can be shared by different layers and could make the layer block too long if written directly in it. The classification layer can be included into the main mapfile using the INCLUDE parameter, as for fapar.anom.classes.map in our example. The piece of mapfile containing the classification is a list of Class Objects, one for each defined class. In turn, each class contains one or more Style Objects to define colours and other graphic properties. The classification we use for fAPAR Anomaly is expressed like this:

CLASS 
    NAME "≤ -2" 
    EXPRESSION ([PIXEL]>-99 AND [PIXEL]<=-2) 
    STYLE 
        COLOR 215 48 99 
        OUTLINECOLOR 215 48 99 
    END 
END  
CLASS NAME "-2 to -1.5" EXPRESSION ([PIXEL]>-2 AND [PIXEL]<=-1.5) STYLE COLOR 252 141 149 OUTLINECOLOR 252 141 149 END END
CLASS NAME "-1.5 to -1" EXPRESSION ([PIXEL]>-1.5 AND [PIXEL]<=-1) STYLE COLOR 254 224 199 OUTLINECOLOR 254 224 199 END END
CLASS NAME "-1 to 1" EXPRESSION ([PIXEL]>-1 AND [PIXEL]<=1) STYLE COLOR 255 255 255 OUTLINECOLOR 255 255 255 END END
CLASS NAME "1 to 1.5" EXPRESSION ([PIXEL]>1 AND [PIXEL]<=1.5) STYLE COLOR 175 237 81 OUTLINECOLOR 175 237 81 END END
CLASS NAME "1.5 to 2" EXPRESSION ([PIXEL]>1.5 AND [PIXEL]<=2) STYLE COLOR 75 166 0 OUTLINECOLOR 75 166 0 END END
CLASS NAME "&ge; 2" EXPRESSION ([PIXEL]>2) STYLE COLOR 19 111 0 OUTLINECOLOR 19 111 0 END END
CLASS NAME "No data" EXPRESSION ([PIXEL]=-99) STYLE COLOR 200 200 200 OUTLINECOLOR 200 200 200 END END

As you can see, the first class is displayed with one line for each parameter, while the others are in a more compact presentation. EXPRESSION is the core parameter of the Class Object, because it expresses the condition a data value needs to met to belong to the class, while NAME is used to display the class label in a legend. In a Style Object, COLOR and OUTLINECOLOR set the colour of the filling and the border of the geographical feature respectively.

Define the new layer in mapConfig.js

A layer must be defined in mapConfig.js to be displayed into the MapViewer, with at least three actions:

  • definition of the layer as an OpenLayers' layer;
  • addition of the layer to the map layers to be visualized within the map;
  • addition of the layer to the GeoExt store to be visualized within the layer tree.

In our case we want to add a new "fAPAR Anomaly (from GeoTIFF)" layer that displays "fapar_anom_gtiff", previously defined in mapfile. The code to do that is:

 var fapar_anom_gtiff = new OpenLayers.Layer.WMS(
    "fAPAR Anomaly (from GeoTIFF)",
	eiu(MUKAU_MSWMS,globalWmsEnv),
    {
        layers: "fapar_anom_gtiff", format: "image/png", transparent: true
    },
    {
        isBaseLayer: false, visibility: false, opacity: globalRasterOpacity, 
        year:2019, month:12, tendays:21, firstYear: "2001", lastYear: "2019",
        metadata: ">FROM_MAPFILE;fapar_anom_gtiff;wms_abstract", 
        singleTile: (GE_MAP_SINGLETILE_ALL!=null?GE_MAP_SINGLETILE_ALL:false),
        legend: getMsCgiLegendTag(MUKAU_MSWMS,"fapar_anom_gtiff",globalWmsEnv,10,true), 
        wmsLayer: "fapar_anom_gtiff"  
	} 
);  

As you can see, the layer is of OpenLayers.Layer.WMS type, instantiated with four arguments: the desired layer name, the URL of the target WMS service, retrieved with the eiu() function, an object with properly WMS parameters (layers, with the reference to the mapfile layer "fapar_anom_gtiff", format and transparent), and an object with optional parameters. For all the attributes present in this definition please see MVW mapConfig.js.

Once defined, the new layer must be added to the layers visualized into the map, just including the layer's JavaScript variable into the aLayersToAdd array:

  aLayersToAdd=[    
    // Base Layers
    natEarth,landmassSea  
    // Geographic Background, polygons or filled rasters
    ,fao_land_mgmt
    // Precipitation, polygons or raster
    ,monrain,spi_mon
    // Vegetation
    ,fapar_anom_gtiff
    ...
  ];

At the end, the layer must be included into the MapViewer's layer tree too. For doing that, the layer's variable must be registered into the GeoExt store which deals with the layer tree group with. In our case, the fAPAR Anomaly layer must be added to the store of vegetation layers:

	vegetStore = new GeoExt.data.LayerStore({
        layers: [fapar_anom_gtiff]
	});

If the store has been activated with this layer (i.e. it and its subgroup in the layer tree were not present before), its subgroup must be activated into the layer tree as well, with dedicated settings in the a_SUBGROUPGRAPHICS associative array:

a_SUBGROUPGRAPHICS["Vegetation"]={ keyimage_on:"veget-icon", treeExpanded:false, text:"Vegetation" }; 
Define layer's date variables in layerDates.js

The object of custom attributes defined above contains also some date parameters specifying the extreme years of the time series (firstYear and lastYear) and year, month and 10-day period (tendays) of the last available dekad (2019-12-21), to be sent to the WMS server as default date.

Such parameters can be more easily managed and updated if kept in a separate file and referenced with JavaScript variables from within mapConfig.js. The look-up file of last available dates is layerDates.js and contains all such date parameters excepting fistYear, since its value is fix.

For the new fAPAR Anomaly layer, let's define the following variables in layerDates.js:

// fAPAR Anomaly ("fapar_anom_gtiff")
var fapar_anom_YEAR="2019"; 	// Updated 2020-01-22, 12:05
var fapar_anom_MONTH="12"; 	// Updated 2020-01-22, 12:05
var fapar_anom_DAY="21"; 	// Updated 2020-01-22, 12:05
var fapar_anom_LASTYEAR=fapar_anom_YEAR;

A JavaScript comment can be optionally used to indicate the date and time when a variable has been updated the last time.

The layer definition in mapConfig.js varies in this way:

 var fapar_anom_gtiff = new OpenLayers.Layer.WMS(
    "fAPAR Anomaly (from GeoTIFF)", eiu(MUKAU_MSWMS,globalWmsEnv),
    { layers: "fapar_anom_gtiff", format: "image/png", transparent: true },
    {
        isBaseLayer: false, visibility: false, opacity: globalRasterOpacity, 
        year:fapar_anom_YEAR, month:fapar_anom_MONTH, tendays:fapar_anom_DAY, 
        firstYear: "2001", lastYear: fapar_anom_LASTYEAR, 
        ...  
	} 
);  

The values of year, month and tendays are set with the date present in layerDates.js only when the layer is turned on the first time. Subsequently, their values can be changed at any time acting with the time selector. The values of such parameter are then sent to the WMS server to fill the URL parameters SELECTED_YEAR, SELECTED_MONTH and SELECTED_TENDAYS seen before, in turn used to replace the variables in the DATA parameter of the correspondent layer in mukau.map.

Clone this wiki locally