In Snap4City Origin-Destination Matrices (ODM) can be represented in two ways:
- Using MGRS cells [https://mgrs-data.org/] of different sizes (100 km, 10 km, 1 km, 100 m, 10 m, 1 m);
- Using administrative areas defined by public organizations. In this case, the GADM data (v3.6) [https://gadm.org/] are used to describe areas worldwide down to the precision of individual municipalities. Higher precision down to census areas are available for Italy only, exploiting data obtained from ISTAT [https://www.istat.it/notizia/confini-delle-unita-amministrative-a-fini-statistici-al-1-gennaio-2018-2/]
All geographical representations are reported in EPSG 4326 (WGS84), as latitude and longitude, for an immediate visualization with tools and libraries adopted in the Snap4City dashboards.
Three main APIs have been developed in Python to handle ODM ingestion:
- od-build, API to construct OD matrix structure starting from vector of coordinates (in case of MGRS ODM) of areas IDs (in case of ISTAT census areas).
- od-insert, API to insert the actual OD flows.
- od-get, API retrieve the OD data and eventually present them in a dashboard.
Source code is available at https://github.com/disit/snap4city/tree/master/Snap4City-OD-API/
The API leverages a PostGIS database [https://postgis.net/] in which OD areas and flows are saved.
In PostGIS there are tables where the administrative areas are stored. To limit the data volume and allow easy delivery of the docker containers, in the MicroX installation of Snap4City [https://www.snap4city.org/
docker-generator/selecting_model] are preloaded only 17 areas describing the municipalities of the province of Florence. Currently, to add additional areas it is required to insert them manually into the database, for example using the shp2pgsql-gui tool (included in the PostGIS release) to transform shapefile into valid format to be inserted in the database.
PostGIS database tables for OD areas
gadm36
Used to store administrative areas worldwide up to municipalities. Data in this table is not included in the MicroX installation.
Fig.1
The shp2pgsql-gui tool is used to produce the geom encoding.
italy_epgs4326
Used to store administrative areas listed according to ISTAT codes, and arbitrary Point of Interest (POI)
Fig.2
A region will be listed with only the cod_reg different from NULL, a province will have both cod_red and cod_prov different from NULL, and so on.
A POI instead requires the poi_id different from NULL, the other _id columns can be left at NULL. Since POI are usually defined by an organization, poi_id must be defined with string that includes the organization name, e.g., POI_<organization>_<poi identifier>
The shp2pgsql-gui tool is used to produce the geom encoding.
OD BUILD API
This API expect a POST request with vectors of coordinates (in case of MGRS ODM and GADM areas) or area IDs (in case of ISTAT census areas) and return the information (cell coordinates or uid) that must be used to ingest the OD flow with the od-insert API.
MGRS Areas
In the case of MGRS, the API is able to create OD areas following the MGRS standard using different precisions specified by the user. In this case the OD areas are created on-the-fly and do not require to previously insert in the database the area information (as instead required when using administrative areas or POI).
Two endpoints can be used:
- /build
- /buildcompressed
In both cases the API expects to receive a POST request with array of coordinates of origins and destinations, plus the indication of the required precision (100 km, 10 km, 1 km, 100 m, 10 m, 1 m). The difference lies in the fact that the latter accept compressed data in the request body.
Node that the /buildcompressed is very impractical to be used into NodeRED due to the compression modality implemented that is not compatible with the numpy compression.
The data to be sent to the request must include:
- x_orig, l'array delle coordinate x di origine. Esempio: [11.10, 11.11, 11.13]
- y_orig, l'array delle coordinate y di origine. Esempio: [43.10, 43.11, 43.20]
- x_dest, l'array delle coordinate x di destinazione. Esempio: [11.11, 11.12, 11.20]
- y_dest, l'array delle coordinate y di destinazione. Esempio: [43.11, 43.12, 43.13]
- precision, la lunghezza del quadrato usato per calcolare il flusso in metri. Esempio: 100
Python example
import numpy as np
import io
import json
import requests
x_orig = [11.10, 11.11, 11.12]
y_orig = [43.10, 43.11, 43.12]
x_dest = [11.13, 11.14, 11.20]
y_dest = [43.13, 43.14, 43.20]
IP = '192.168.1.235'
PORT = '3000'
print("Uncompressed")
data = {
"x_orig": x_orig,
"y_orig": y_orig,
"x_dest": x_dest,
"y_dest": y_dest,
"precision": 100
}
response = requests.post('http://' + IP + ':' + PORT + '/build', data=json.dumps(data), headers={'Content-Type': 'application/json'})
print(response)
dd_data = json.loads(response.text)
print(dd_data)
print("Compressed")
buf = io.BytesIO()
np.savez_compressed(buf,
x_orig=x_orig,
y_orig=y_orig,
x_dest=x_dest,
y_dest=y_dest,
precision=100
)
buf.seek(0)
response = requests.post('http://' + IP + ':' + PORT + '/buildcompressed', data=buf)
print(response)
dd_data = json.loads(response.text)
print(dd_data)
Output:
Uncompressed
[{'x_orig': 11.098848109688397, 'y_orig': 43.09948020025908, 'x_dest': 11.12938133786214, 'y_dest': 43.12953112155714, 'value': 1}, {'x_orig': 11.109012198290031, 'y_orig': 43.10919820617726, 'x_dest': 11.139555322781908, 'y_dest': 43.13924615601713, 'value': 1}, {'x_orig': 11.119210600518597, 'y_orig': 43.11981509817159, 'x_dest': 11.199502300813256, 'y_dest': 43.1993388329592, 'value': 1}]
Compressed
[{'x_orig': 11.098848109688397, 'y_orig': 43.09948020025908, 'x_dest': 11.12938133786214, 'y_dest': 43.12953112155714, 'value': 1}, {'x_orig': 11.109012198290031, 'y_orig': 43.10919820617726, 'x_dest': 11.139555322781908, 'y_dest': 43.13924615601713, 'value': 1}, {'x_orig': 11.119210600518597, 'y_orig': 43.11981509817159, 'x_dest': 11.199502300813256, 'y_dest': 43.1993388329592, 'value': 1}]
Administrative areas
To build OD using administrative areas the /buildcommunes endpoint must be invoked. This endpoint can be used to work with the GADM areas and the ISTAT areas (and POI).
The API uses the GADM or the ISTAT areas according to the data sent in the post request body.
GADM Areas (legacy)
In the case of administrative area using the GADM data (stored in table gadm36) the OD BUILD API expects arrays of latitude/longitude coordinates to describe origin and destination points.
The request body must include the following keys:
- x_orig
- y_orig
- x_dest
- y_dest
where x stands for longitude and y for latitude.
Note that the API expects compressed data.
Node that the /buildcommunes (with GADM) is very impractical to be used into NodeRED due to the compression modality implemented that is not compatible with the numpy compression.
The API searches into the DB table the area containing the points and retrieves the area uid. Additionally, the API counts the number of times it found the same origin/destination pair, thus returning also the value of the OD flow.
Python example
import numpy as np
import io
import json
import requests
'''
Firenze 43.78755386935608, 11.253283529320194
Impruneta 43.68395500620326, 11.254224622517292
Calenzano 43.8648446568991, 11.167166955936286
Fiesole 43.806420216210135, 11.29326591697936
'''
x_orig = [11.254224622517292, 11.167166955936286, 11.29326591697936]
y_orig = [43.68395500620326, 43.8648446568991, 43.806420216210135]
x_dest = [11.253283529320194, 11.253283529320194, 11.253283529320194]
y_dest = [43.78755386935608, 43.78755386935608, 43.78755386935608]
IP = '192.168.1.235'
PORT = '3000'
print("Compressed GADM")
buf = io.BytesIO()
np.savez_compressed(buf,
x_orig=x_orig,
y_orig=y_orig,
x_dest=x_dest,
y_dest=y_dest
)
buf.seek(0)
response = requests.post('http://' + IP + ':' + PORT + '/buildcommunes', data=buf)
print(response)
dd_data = json.loads(response.text)
print(dd_data)
Output:
[{'orig_commune': '99530', 'dest_commune': '100178', 'value': 1}, {'orig_commune': '99988', 'dest_commune': '100178', 'value': 1}, {'orig_commune': '100718', 'dest_commune': '100178', 'value': 1}]
ISTAT Areas
In the case of administrative area using the ISTAT data (stored in table italy_epgs4326) the OD BUILD API expect arrays encoding the ISTAT codes for region, province, municipality, census area, census section.
For example, a request body in JavaScript including a buffer as
buf = [
{
filename: "orig_region_id",
payload: JSON.stringify(orig_reg)
},
{
filename: "dest_region_id",
payload: JSON.stringify(dest_reg)
},
{
filename: "orig_province_id",
payload: JSON.stringify(orig_prov)
},
{
filename: "dest_province_id",
payload: JSON.stringify(dest_prov)
},
{
filename: "orig_municipality_id",
payload: JSON.stringify(orig_comm)
},
{
filename: "dest_municipality_id",
payload: JSON.stringify(dest_comm)
}
];
can be used to build OD on municipality areas. Removing the orig/dest_municipality_id fields, would produce OD on provinces, while adding fields as orig/dest_ACE_id would create OD on census area. Available options are:
- orig/dest_region_id
- orig/dest_province_id
- orig/dest_municipality_id
- orig/dest_ACE_id
- orig/dest_section_id
At least region ID must be specified, as minimum detail level. Additionally, there is the possibility to use arbitrary areas (that must be previously loaded into the database table), named Point of Interest (POI), that can be specified using the field orig/dest_poi_id. Using POI is mutually exclusive w.r.t using administrative areas.
Note that the API expects compressed data.
The API returns the uid associated with the specified areas. Note that, even if in output a value attribute is reported, differently from the other cases, in this case it is fixed to 1 and should not be used in the following steps.
Python example
import numpy as np
import io
import json
import requests
orig_reg = ['9', '9', '9']
orig_prov = ['48', '48', '48']
orig_comm = ['48017', '48017', '48017']
dest_reg = ['9', '9', '9']
dest_prov = ['48', '48', '48']
dest_comm = ['48001', '48043', '48041']
IP = '192.168.1.235'
PORT = '3000'
print("Compressed ISTAT")
buf = io.BytesIO()
np.savez_compressed(buf,
orig_region_id = orig_reg,
orig_province_id = orig_prov,
orig_municipality_id = orig_comm,
dest_region_id = dest_reg,
dest_province_id = dest_prov,
dest_municipality_id = dest_comm
)
buf.seek(0)
response = requests.post('http://' + IP + ':' + PORT + '/buildcommunes', data=buf)
print(response)
dd_data = json.loads(response.text)
print(dd_data)
Output:
[{'orig_commune': 4818, 'dest_commune': 4777, 'value': 1}, {'orig_commune': 4818, 'dest_commune': 4838, 'value': 1}, {'orig_commune': 4818, 'dest_commune': 4828, 'value': 1}]
OD-INSERT API
Once obtained the OD cell references (as coordinates for the MGRS or ad UID for the administrative areas) it is possible to use the OD-INSERT API to send into the DB flow data and metadata to store the ODMs.
MGRS Areas
OD flows using MRGS areas can be inserted calling the /insert endpoint specifying the following field foreach flow:
- od_id: ODM identified, it must be equal for all the flow related to the same OD
- x_orig, y_orig, x_dest, y_dest: MRSG cell coordinates as given in output by the OD-BUILD API
- from_date: starting datetime of the flow
- to_date: end datetime of the flow
- precision: MGRS dimension, it must be equal to the one passed to the OD-BUILD API
- values: number of elements moving from the origin to the destination
- value_type: type of the elements
- value_unit: unit of the elements
- description: description of the OD
- organization: organization owner of the OD
- kind: kind of the flows
- mode: mode of the flows
- transport: transportation modality
- purpose: purpose of the flow
Among all these parameters the fundamental to be specified are od_id, x_orig, y_orig, x_dest, y_dest, from_date, to_date, precision, and value. The remaining attributes are useful but not essential metadata.
Note that, to facilitate the ODM retrieval, od_id must be composed as follows:
od_id := <unique-od-identifier>_<organization>_<precision>
where <precision> indicates the precision of the MGRS area. Also, do not user underscore (“_”) characters in any of the od_id parts. Such od_id format helps to groups different instances of the same ODM represented with different precisions, e.g., using MGRS cells of 10m and 100m. As will be illustrated in the following, this idea is extended also to the administrative areas.
Inserted data populate two tables in the DB:
- od_data_mgrs, that contains the actual flows
- od_metadata, to store the ODM metadata
Python example
(follow the previous example)
print("Insert")
od_name = "test_MGRS_v1"
organization = "ORG"
od_id = od_name + "_" + organization + "_" + str(precision)
data_insert = {
"od_id": od_id,
"x_orig": [item['x_orig'] for item in dd_data],
"y_orig": [item['y_orig'] for item in dd_data],
"x_dest": [item['x_dest'] for item in dd_data],
"y_dest": [item['y_dest'] for item in dd_data],
"from_date": "2024-01-01 09:00:00",
"to_date": "2024-01-01 09:59:59",
"precision": precision,
"values": [item['value'] for item in dd_data],
"value_type": "test",
"value_unit": "test",
"description": "test",
"organization": organization,
"kind": "test",
"mode": "test",
"transport": "test",
"purpose": "test"
}
response = requests.post('http://' + IP + ':' + PORT_INSERT + '/insert', data=json.dumps(data_insert), headers={'Content-Type': 'application/json'})
print(response)
Administrative Areas
Following a similar approach, Administrative areas can be inserted using the /insertcommunes endpoint. Values to be specified in the request body are:
- od_id
- orig_communes
- dest_communes
- from_date
- to_date
- values
- value_type
- value_unit
- description
- organization
- kind
- mode
- transport
- purpose
- source
od_id must be specified are indicated previously
od_id := <unique-od-identifier>_<organization>_<precision>
In this case precision must be specified with one of the following values:
- communes, for all the ODM inserted using the GADM area
- poi, for ODM using POI area
- ace, for ODM using ACE ISTAT area
- municipality, for ODM using MUNICIPALITY ISTAT area
- province, for ODM using PROVINCE ISTAT area
- region, for ODM using REGION ISTAT area
Differently from the MGRS, in this case the field precision is not required in the request. Instead, the field source is introduced. When using areas from GADM, the source field can be not specified or set to communes. When using the ISTAT areas, the source field is mandatory and must be set to italy_epgs4326.
In this case the involved DB tables are
- od_data, that contains the actual flows
- od_metadata, for the OD metadata
Python examples
GADM
(follow the previous example)
print("Insert")
od_name = "odTestV1"
organization = "ORG"
od_id = od_name + "_" + organization + "_communes"
data_insert = {
"od_id": od_id,
"orig_communes": [item['orig_commune'] for item in dd_data],
"dest_communes": [item['dest_commune'] for item in dd_data],
"from_date": "2024-01-01 09:00:00",
"to_date": "2024-01-01 09:59:59",
"values": [item['value'] for item in dd_data],
"value_type": "test",
"value_unit": "test",
"description": "test",
"organization": organization,
"kind": "test",
"mode": "test",
"transport": "test",
"purpose": "test"
}
response = requests.post('http://' + IP + ':' + PORT_INSERT + '/insertcommunes', data=json.dumps(data_insert), headers={'Content-Type': 'application/json'})
print(response)
ISTAT
(follow the previous example)
print("Insert")
od_name = "odTestV1"
organization = "ORG"
od_id = od_name + "_" + organization + "_municipality"
values = [10, 43, 27]
data_insert = {
"od_id": od_id,
"orig_communes": [item['orig_commune'] for item in dd_data],
"dest_communes": [item['dest_commune'] for item in dd_data],
"from_date": "2024-01-01 09:00:00",
"to_date": "2024-01-01 09:59:59",
"values": [v for v in values],
"value_type": "test",
"value_unit": "test",
"description": "test",
"organization": organization,
"kind": "test",
"mode": "test",
"transport": "test",
"purpose": "test",
"source": "italy_epgs4326"
}
response = requests.post('http://' + IP + ':' + PORT_INSERT + '/insertcommunes', data=json.dumps(data_insert), headers={'Content-Type': 'application/json'})
print(response)
OD-GET API
This last API is designed to retrieve the ingested ODM. This API include the following endpoints:
/get
Used to retrieve the flow of ODM defined over the administrative area that include the lat/lon point. It responds to GET request with the following parameters:
- longitude – longitude of a point in an area to be inspected
- latitude – latitude of a point in an area to be inspected
- precision – can assume values as communes, region, province, municipality, ace, section, poi
- from_date
- organization
- inflow – can assume values True or False. If true, it returns the flow entering in the area in which the lat/lon point falls. If false, it returns the flow exiting the area.
- od_id
- perc – can assume values True or False. If true, it returns percentage values w.r.t. the total inflow/outflow values. If false, it returns absolute values.
/polygon
This endpoint is used to retrieve the shape of the area that include the lat/lon point. It responds to a GET request with the following parameters:
- longitude - longitude of a point in an area
- latitude - latitude of a point in an area
- type – if left empty, polygons will be searched among the GADM areas, otherwise it accepts one of the following values: region, province, municipality, ace, section, poi. In the second case polygons will be searched among the ISTAT and POI areas.
- organization – this is used only when POI are searched. Organization is required to search among the POI defined by the organization (following the POI naming convention POI_<organization>_<poi identifier>).
/get_mgrs
Used to retrieve the flow of ODM defined over MGRS area that include the lat/lon point. It responds to GET request with the following parameters (similarly to the /get request):
- longitude
- latitude
- precision
- from_date
- organization
- inFlow
/mgrs_polygon
This endpoint is used to compute and return the shape of the MGRS area that include the lat/lon point according to the specified precision. It responds to a GET request with the following parameters:
- longitude
- latitude
- precision
/mgrs_polygon_center
This endpoint is used to compute and return the center of the MGRS area that include the lat/lon point according to the specified precision. It responds to a GET request with the following parameters:
- longitude
- latitude
- precision
/color
This can be used to retrieve a colormap to be associated with the ODM to color the areas according to the inflow/outflow values (note that colormaps can be defined using dedicated Snap4City interfaces). This is a GET request requiring the metric_name parameter.
/get_stats
NOTE: at this moment, it only works on ISTAT and POI areas (defined in table italy_epgs4326).
Endpoint to get statistics stored in a OD matrix (i.e., od_id) for a given polygon (i.e., dest_id). A GET request with the following parameters:
- od_id
- dest_id
- from_date
- invalid_id
- invalid_label
The invalid_id is used to identify dest_id not previously defined (e.g., -9999). The invalid_label is used to fill the txt name filed of the response for invalid_id found
/get_all_polygons
NOTE: at this moment, it only works on ISTAT and POI areas (defined in table italy_epgs4326).
Endpoint used to retrieve all the polygons of a given type encompassed in a bounding box. It is a GET request with the following parameters:
- latitude_ne – latitude of the north-east corner of the bounding box
- longitude_ne – longitude of the north-east corner of bounding box
- latitude_sw – latitude of the south-west corner of bounding box
- longitude_sw – longitude of the south-west corner of bounding box
- type – type of the areas to retrieve. It accepts region, province, municipality, ace, section, poi
- organization – this is used only when POI are searched. Organization is required to search among the POI defined by the organization (following the POI naming convention POI_<organization>_<poi identifier>).
The OD-GET API are exploited and already implemented into the Snap4City MultiDataMap widget (https://
github.com/disit/dashboard-builder/blob/master/dashboard_frontend/widgets/widgetMap.php). In the next section a guide to build a dashboard to show ODM is reported.
MultiDataMap for Origin-Destination Matrices
An Origin-Destination (OD) matrix can represent the flow of entities (people, vehicles, etc.) from a starting area to one or more destinations (named outflows) or vice versa (i.e., inflows).
Even if a single geo-localized point can be considered an origin or destination area, more typically, flows are grouped on the basis of zones, as for example Regions, Provinces, Municipalities, or finer geographical subdivisions such as census sections (e.g., the Aree di Censimento – ACE – defined by the ISTAT in Italy). Also, the Military Grid Reference System (MGRS) can be used to divide an area of interest into smaller sections.
In the Snap4City platform, OD matrices are stored in a PostGIS database, that is a spatial database that extends the PostgreSQL object-relational database by adding support for geographic objects and allows location queries to be run in SQL. In this way, polygonal descriptions of the origin and destination areas can be associated with flow information and easily retrieved.
The MultiDataMap for OD representation is shown in the following figure
Fig.3
The MultiData Map is composed by two main entities: the actual map, and a Selector menu with which different kind of information can be loaded dynamically on user demand. Each field of the Selector can be configured with an URL that is used to generate specific event in order to load data into the map.
The OD map can be controlled using the control-panel:
- [switch] Show all polygon: if ON, all the polygonal shapes in the area are shown, according to the specified Precision
- [selector/switch] Time period: if the switch is set to ON, the map is animated by showing the different OD data for several days, according to the time span specified in the selector (accepted values are week and month)
- [label] Precision: show the kind of represented area used to show the OD flows
- [selector] Flow: inflow or outflow data can be showed according to the value selected
- [slider] Max Opacity: used to choose the color opacity value used to draw the polygonal areas
- [button/data and time picker] Date/Time Control: the date and time of the OD data can be changed on daily steps using the [<Prev] and [Next>] buttons (if data are available) or using the [<<] and [>>] buttons to move by a wider time span (week or month). By clicking the date time text, a calendar is shown and the user can pick a specific date and time directly
Fig.4
Under the control-panel, a data-panel is shown: here information about the flows for the selected area are reported. Alternatively, such information can be presented in a popup-panel over the selected area.
Fig.5
Finally, in the bottom-left corner of the map, a colormap is shown, indicating the color representing specific flow percentages. Such colors are used to fill the polygonal shapes according to their flow values.
Selector configuration and map parameters
In the case of OD matrix visualization, the URL to be used in the Selector must have the following syntax:
https://odmm.snap4city.org/api/get?<list_of_parameters>
Note that, in case of on-premise installations, the first part of the URL must be changed accordingly.
The <list_of_parametes> contains the following parameter:
- precision [mandatory] indicates the kind of polygonal shapes used to represents origin and destination areas. According to the data collected into the PostGIS, this value can be region, province, municipality, ace, section, communes, or mgrs.
- from_date [mandatory] indicate the starting date from which retrieve OD flows. It must be expressed as YYYY-mm-dd HH:MM:SS.
- organization [mandatory] the name/ID of the organization that own the OD data, as saved into the PostGIS.
- latitude [mandatory] together with longitude specify the point to select the initial source area.
- longitude [mandatory] together with latitude specify the point to select the initial source area.
- inflow [mandatory] if set to True, shows inflow data for the source area, if set to False, shows outflow data.
- od_id [mandatory] the ID of the OD matrix to be shown into the map.
- perc [optional, default=True] if set to True, shows the flow data in form of percentages, if set to False, absolute flow values are instead reported.
- color_map [optional, default=ODcolormap1] this parameter let the user specify the metric_name of the colormap to be used to represent the flows. Such metric_name must be present in the dashboarddb.heatmap.color database table of the used Snap4City installation.
- opacity [optional, default=0.6] percentage of initial opacity of the polygons on the map. Note that this value can be changed on user demand through the command panel.
- all_polygon [optional, default=False] if set to True, all the polygon shapes included into the area visualized on the map are shown, even if they do not have associated flow data, according to the precision parameter. If set to False, only the polygons relevant to show the flows are presented into the map.
- all_polygon_color [optional, default=#BF2015 (RGB: 191, 32, 21)] when all_polygon=True, this color is used to represent the border of the polygons. Color must be expressed in the HEX format.
- source_polygon_color [optional, default=#0000FF (RGB: 0, 0, 255)] inner color of the source polygon. Color must be expressed in the HEX format.
- panel_on_shape [optional, default=False] if True, the flow data appears over the associated polygon in a popup-panel, otherwise, if set to False, the flow data appears on the right side of the map in the data-panel under the control-panel.
- panel_bg_color [optional, default=#CCCCCC (RGB: 204, 204, 204)] background color for all the panels of the OD matrix interfaces (i.e. control panel and flow data panel). Color must be expressed in the HEX format.
- panel_font_color [optional, default=#505050 (RGB: 80, 80, 80)] color for the text included into all the panels. Color must be expressed in the HEX format.
- panel_width [optional, default=340px] used to set the width of the control-panel.
- panel_font_size [optional, default=12px] used to set the text font size shown in the control-panel.
- data_panel_width [optional, default=240] used to set the width of the data-panel under the control-panel.
- data_panel_font_size [optional, default=12px] used to set the text font size shown in the data-panel.
- popup_panel_width [optional, default=300] used to set the maximum width of the popup-panel that appear over the shape polygons.
- popup_panel_font_size [optional, default=12px] used to set the text font size shown in the popup-panel.
- cm_font_size [optional, default=12px] used to set the text font size shown in the colormap legend displayed in the bottom-left corner of the map.
- map_name [optional, default=Origin-Destination Map] used to set the title of the map, shown at the top of the control panel. Note that, in order to show spaces, the name must include underscores (e.g. to show Map Name, the parameter must be set to Map_Name).
- stat_id [optional, default=<empty string>] if specified with an OD ID, the related data can be used to show additional information passing through an IoT App (NodeRED). Indeed, the MultiData Map implement also a web socket that on-click event sends data to a specific IoT App exploiting the custom node coordinates-from-map. In addition to latitude and longitude information, in the case of OD matrices, additional data are sent to the IoT App:
- sourceID: source polygon ID
- sourceName: text name of the source polygon
- precision
- from_date
- organization
- inflow
- od_id
- perc
- stat_id
- latitude
- longitude
Such data can then be used to make additional request to the Python API in order to retrieve specific data to be shown using dedicated widget on a dashboard, typically the same dashboard where the MultiData Map is shown.
Representation of presences
The MultiData Map can be used also to represent presences in a specific area. In this case, when data are loaded into the PostGIS database, the source and target area must be set to the same area. Then, the map will show only a single shape on the map, reporting its presence data into the data-panel or popup-panel. Since shown data do not represent flows anymore, the Inflow/Outflow selector is removed from the control-panel, as well as the colormap for the same reason.
Node RED flows
In Snap4City ODM can also be ingested using Node RED flow in the Snap4City IoTApp. As anticipated, at this moment is not possible to use in Node RED the /buildcompressed endpoint for MGRS areas and the /buildcommunes endpoint for the GADM area, due to technical difficulties in replicating the NumPy compression in Node RED. Differently, it is possible to use the /build endpoint for the MGRS, and the /buildcommunes for the ISTAT and POI areas, since the former do not use compression and for the latter, that use compression, e a special case has been devised in the OD-BUILD API.
Two example flows are reported hereafter for MGRS and ISTAT areas.
ODM MGRS ingestion
Fog.6
- A set of 100 origin-destination points are set in GENERATE DATA node and used to generate in body request to be used in calling OD-BUILD
- In SETUP-INSERT the MRGS cells and flow values obtained in response are used to create the request body for the OD-INSERT
The ingested ODM can then be visualized in a dashboard setting in the MultiDataMap Selector the following URL:
ODM ISTAT/POI ingestion
Fig.7
- Initially a set of dates are defined in DATES, then each date is used to generate a single message using the SPLIT node.
- In CREATE OD FLOWS, simulated flow for a series of origin and destination areas (the municipalities of the province of Florence) are generated with random flow values. In this node areas ID are used to create the message buffer structure to pass to the OD-BUILD API. Dates and values are instead outputted on a different flow (they will be recollected after with the JOIN node).
- The buffer structure in compressed with COMPRESS node, and then the POST REQUEST is made and executed.
- Response of the OD-BUILD is then joined with the dates and values (with the JOIN node) and used in the DEFINE INSERT JSON node to create the structure to send to the OD-INSERT API.
- The POST REQUEST is created, with the structure in its body, and executed.
The ingested ODM can then be visualized in a dashboard setting in the MultiDataMap Selector the following URL:
http://<domain>/odmm/api/get?latitude=43.771837562821375&longitude=11.257123947143556&precision=municipality&from_date=2022-07-01+00%3A00%3A00&organization=ORG&inflow=False&od_id=odNodeRed_ORG_municipality&perc=True