|
| 1 | +--- |
| 2 | +title: Configuring the APEx Geospatial Explorer |
| 3 | +--- |
| 4 | +The [APEx Geospatial Explorer](../instantiation/geospatial_explorer.md) is a versatile web application designed to visualize |
| 5 | +and interact with geospatial data. It leverages the OpenLayers library to provide a rich set of features for exploring spatial |
| 6 | +datasets. The application is highly configurable, allowing users to tailor its functionality and appearance to meet specific |
| 7 | +project requirements. This document outlines the configuration options for the APEx Geospatial Explorer, detailing the structure |
| 8 | +and properties of the configuration schema. |
| 9 | + |
| 10 | +## Configuration Schema |
| 11 | + |
| 12 | +The service configuration will be based on a schema that provides administrators with the expected structure and |
| 13 | +contents of the configuration. Taking this approach enables: |
| 14 | + |
| 15 | +* Automated and dynamic instantiation of the service with differing functionality. |
| 16 | +* Configuration validation. |
| 17 | +* Definition of a “contract” for easier documentation of features and their configuration. |
| 18 | + |
| 19 | +The sections below briefly outline the structure of the configuration schema and provide a preliminary description of |
| 20 | +each field/property within. The schema currently consists of four top-level fields and all properties are written in |
| 21 | +camel case. |
| 22 | + |
| 23 | +### Layout - `layout` |
| 24 | + |
| 25 | +An object with properties that modify the elements that the application will render. These properties and elements |
| 26 | +relate specifically to non-geospatial layout components, like navigation and footer. |
| 27 | + |
| 28 | +Currently supported properties: |
| 29 | + |
| 30 | +#### Navigation - `navigation` |
| 31 | + |
| 32 | +An object which supports two properties: |
| 33 | + |
| 34 | +* `logo`: A URL string that points to a logo image asset. |
| 35 | +* `title`: A string to be used as a title for the application. |
| 36 | + |
| 37 | +### Interface Groups - `interfaceGroups` |
| 38 | + |
| 39 | +An optional array of strings to be used as names/keys. This is currently used to configure the grouping of layer UI |
| 40 | +elements, such as the layer cards. This will be expanded in later versions. |
| 41 | + |
| 42 | +### Exclusivity Sets - `exclusivitySets` |
| 43 | + |
| 44 | +An optional array of strings to be used as names/keys. This is currently not in use but is a placeholder for future |
| 45 | +work. |
| 46 | + |
| 47 | +### Sources - `sources` |
| 48 | + |
| 49 | +An array of objects. Each object outlines a particular data source to be configured for display within the application, |
| 50 | +with properties detailing both the geospatial and user interface configuration. |
| 51 | + |
| 52 | +Currently supported properties within a source object are: |
| 53 | + |
| 54 | +#### Name - `name` |
| 55 | + |
| 56 | +A string that is used to identify layers in both the user interface and OpenLayers state |
| 57 | + |
| 58 | +#### Is Active - `isActive` |
| 59 | + |
| 60 | +A boolean. Determines if a layer is currently shown on the map. Setting this to true will show the layer on the map when |
| 61 | +the application loads. |
| 62 | + |
| 63 | +#### Time Frame - `timeframe` |
| 64 | + |
| 65 | +A string that is required to render and control time series layers. It should have a value of either `Days`, `Months`, `Years`. |
| 66 | +This will determine the behavior of the UI for layer groups with time series data configured. |
| 67 | + |
| 68 | +* Days: This will allow the selection of every available date within the configure data sources. |
| 69 | +* Months: This will only allow a user to select a the year and the month for the configured sources. |
| 70 | +* Years: This will allow only a single year to be selected for the dataset. |
| 71 | + |
| 72 | +For the best user experience it's essential to set this correctly for the series of datasets in use. |
| 73 | + |
| 74 | +#### Base Layer - `isBaseLayer` |
| 75 | + |
| 76 | +Optional boolean that determines if the layer should be treated as a base layer. Base layer groups are always active and |
| 77 | +cannot be toggled. |
| 78 | + |
| 79 | +#### Swipe Layer - `isSwipeLayer` |
| 80 | + |
| 81 | +Optional boolean that determines if the layer should be treated as a swipe layers. Swipe layer groups are configured much |
| 82 | +like any other layer group however the individual sources need to be configured with an additional position property with |
| 83 | +a value of either `left` or `right`. |
| 84 | + |
| 85 | +#### Layout - `layout` |
| 86 | + |
| 87 | +An object to determine which interface elements are rendered for the layer. Supports two properties: |
| 88 | + |
| 89 | +##### Layer Card - `layerCard` |
| 90 | + |
| 91 | +An object that will determine if a layer card should be rendered for this layer and what other interface elements should |
| 92 | +be rendered within the card. This is currently the main way to interact with a layer within the application. The layer |
| 93 | +card can show a toggle for the layer, a selection of buttons or controls for the layer, legends and attribution text. |
| 94 | +This currently supports the following properties: |
| 95 | + |
| 96 | +* `toggleable`: A boolean that determines if a toggle switch to enable/disable the layer should be rendered. |
| 97 | +* `controls`: An optional object that configures which buttons to render in the layer card for interaction with |
| 98 | + the layer. This object can contain: |
| 99 | + * `zoomToCenter`: A boolean that renders a button that will zoom the map to the extent of the layer. |
| 100 | + * `opacitySlider`: A boolean that renders a button to open or close the opacity slider control for the layer. |
| 101 | + * `download`: A URL string that will render a link to the given URL. Used for signposting users to the source data or website. |
| 102 | +* `legend`: An optional object that can be configured to show static or dynamic legend elements within the layer card |
| 103 | + when active. Contains a `type` property that has a string value of: `swatch`, `image`, `gradient`. Also requires a `url` |
| 104 | + property with a string value |
| 105 | + if the type is `image`. |
| 106 | + |
| 107 | +##### Interface Group - `interfaceGroup` |
| 108 | + |
| 109 | +An optional string that is used to identify which interface group this layer belongs to. |
| 110 | + |
| 111 | +#### Metadata - `meta` |
| 112 | + |
| 113 | +An object that contains information describing the data source. This is generally used for information that would be used |
| 114 | +in multiple places across the application such as: units used to describe data values, the minimum and maximum value for |
| 115 | +use in UI/Visualisation calculations, attribution etc. |
| 116 | + |
| 117 | +This currently supports the following properties: |
| 118 | + |
| 119 | +* `attribution`: An optional object to render some text or a link for use with attribution of layer datasets. |
| 120 | +* `min`: An integer for the lower limit to use for data values when calculating UI elements such as legends, statistics,\ |
| 121 | +colour ramps. |
| 122 | +* `max`: An integer for the upper limit to use for data values when calculating UI elements such as legends, statistics,\ |
| 123 | +colour ramps. |
| 124 | +* `units`: An optional string that describes the units of any values derived from the data. Used in legends and statistics\ |
| 125 | +panels. |
| 126 | +* `description`: An optional string that describes the dataset. |
| 127 | +* `startColor`: A string describing a valid hex or RGB/A colour value. This is used to render colour ramps and legends. |
| 128 | +* `categories`: An array of objects that contains a `label` (string) property, a `color` (string) property and a `value`\ |
| 129 | +(integer) property. Describes classifications within datasets such as land usage. Used to create swatch legends and statistics |
| 130 | + visualisation. |
| 131 | + |
| 132 | +#### Data - `data` |
| 133 | + |
| 134 | +An array of objects that configures the data to be displayed in the layer. If the length is more than one a layer group |
| 135 | +will be created and all sources will be treated as one layer. |
| 136 | + |
| 137 | +Each object currently supports the following properties: |
| 138 | + |
| 139 | +* `url`: A required URL string that points to the dataset's publicly available resource. |
| 140 | +* `format`: A required string that identifies what kind of dataset is requested. This can be one of the following: `wms`, |
| 141 | +`wmts`, `cog`, `xyz`, `wfs`, `flatgeobuf`, `stac` or `geojson`. |
| 142 | +* `layers`: Only required for sources of format: `wms` and `wmts`. A string that describes the layer to be requested from |
| 143 | + the external service. |
| 144 | +* `typeName`: Only required for sources of format: `wfs`. A string that describes the type to be requested from the |
| 145 | + external service. |
| 146 | +* `zIndex`: Optional integer that determines rendering order within the map. It can be used to override the default |
| 147 | + rendering of Open Layers. |
| 148 | +* `exclusivitySet`: Optional string used to identify a group of other layers that should be disabled when this layer is |
| 149 | + enabled. They must share the same string. |
| 150 | +* `projection`: Optional EPSG code string that describes the projection of the dataset to Open Layers. If the projection |
| 151 | + is supported (and doesn't match the map's configured projection), it will attempt to reproject the data. |
| 152 | +* `style`: Open Layers style object that is passed through to the library to modify the rendering of the layer within |
| 153 | + the map. |
| 154 | +* `normalise`: Only required for sources of format: `cog`. Boolean that configures the map to normalise the raster pixel |
| 155 | + values to between 0 and 1. False by default. |
| 156 | +* `level`: A required integer for sources of type `statistical`. Ideally starting at 0, this integer describes the hierarchy |
| 157 | +of statistical sources. Higher integers should represent more complex and granular vector datasets. Used to provide the |
| 158 | + statistics feature UI and maintain performance for large vector datasets. |
| 159 | +* `position`: A string of either `left` or `right` that is only required for swipe layer groups. This determines which side |
| 160 | +of the swipe control the date will be visualised on. |
| 161 | +* `timestamps`: An optional array of Unix timestamps or ISO8601 date strings. This allows the configuration of time series |
| 162 | +visualisation within the layer group. If multiple timestamps exist within the layer group and the timeframe property is |
| 163 | + set a datepicker/stepper control will be rendered to cycle which layer is visible. |
| 164 | + |
| 165 | +## Example Configurations |
| 166 | + |
| 167 | +Numerous example configurations can be found in the |
| 168 | +[APEx Geospatial Explorer Configurations](https://github.com/ESA-APEx/apex_geospatial_explorer_configs) repository on GitHub. |
| 169 | + |
| 170 | +```{python} |
| 171 | +#| echo: false |
| 172 | +from IPython.display import display, HTML |
| 173 | +import requests |
| 174 | +
|
| 175 | +examples_api_url = "https://api.github.com/repos/ESA-APEx/apex_geospatial_explorer_configs/contents/examples" |
| 176 | +example_base_url = "https://raw.githubusercontent.com/ESA-APEx/apex_geospatial_explorer_configs/main/examples/" |
| 177 | +example_gh_base_url = ( |
| 178 | + "https://github.com/ESA-APEx/apex_geospatial_explorer_configs/tree/main/examples/" |
| 179 | +) |
| 180 | +response = requests.get(examples_api_url) |
| 181 | +examples = response.json() |
| 182 | +cards = [] |
| 183 | +for example in examples: |
| 184 | + result_url = example_base_url + example["name"] + "/result.png" |
| 185 | + example_url = example_gh_base_url + example["name"] |
| 186 | +
|
| 187 | + config_url = example_base_url + example["name"] + "/config.json" |
| 188 | + config_response = requests.get(config_url) |
| 189 | + config = config_response.json() |
| 190 | + title = config["layout"]["navigation"]["title"] |
| 191 | +
|
| 192 | + card = f""" |
| 193 | + <a href='{example_url}'> |
| 194 | + <div class='card' style='width: 300px'"> |
| 195 | + <p class='card-img-top'> |
| 196 | + <img src='{result_url}' class='thumbnail-image card-img' height='150'/> |
| 197 | + </p> |
| 198 | + <div class='card-body pot-contents'> |
| 199 | + <h5 class='card-title listing-title'>{title}</h5> |
| 200 | + </div> |
| 201 | + </div> |
| 202 | + </a> |
| 203 | + """ |
| 204 | + cards.append(card) |
| 205 | +
|
| 206 | +# Join the cards and return the result |
| 207 | +
|
| 208 | +card_container = f""" |
| 209 | +<div style='display: flex; flex-wrap: wrap; gap: 1rem;'> |
| 210 | + {''.join(cards)} |
| 211 | +</div></a> |
| 212 | +""" |
| 213 | +
|
| 214 | +display(HTML(card_container)) |
| 215 | +
|
| 216 | +``` |
0 commit comments