Module 1c, Learning the basic concepts of GeoDMS, calculations over multiple domains

learning objective: learning how to make calculations across multiple domain units

introduction

In modelling, data often needs to be related or (dis)aggregated between multiple domain units. In a relational database, this is done with join and group-by statements. In the GeoDMS, this is done through explicitly configured relations.

what is a relation?

A relation is an attribute that connects two domain units. Concretely: for each element in domain unit A, the relation records the corresponding position (index number) in domain unit B.

For example, suppose you have municipalities and provinces as two domain units. A relation from municipality to province tells you, for each municipality, which province it belongs to:

municipality (domain A) municipality_rel (→ index in province)
Amsterdam 2 (Noord-Holland)
Rotterdam 3 (Zuid-Holland)
Utrecht 4 (Utrecht)
Eindhoven 6 (Noord-Brabant)

The values unit of the relation is the domain unit being pointed to — in this case province. The domain unit of the relation is the source domain — municipality.

This leads to the definition:

A relation is an attribute with domain unit A and values unit B (where B is also a domain unit). It relates attributes between domain units A and B.

By using index numbers rather than string keys, the GeoDMS can evaluate relations very efficiently, even on large datasets.

Naming convention: use the name of the target domain unit with the suffix _rel as the relation name. A relation towards province should be named province_rel, a relation towards municipality should be named municipality_rel.

how to make a relation

The GeoDMS provides several functions that produce a relation. The three most common approaches are:

1. Based on matching keys or codes

If both domain units share a common identifier (such as a municipality code), use rlookup to create a relation:

// CBS neighbourhood table has a municipality code attribute.
// rlookup finds the position of each neighbourhood's code in the municipality code list:
attribute<municipality> municipality_rel (neighbourhood) :=
    rlookup(neighbourhood/municipality_code, municipality/code);

2. Based on a geographic relationship

For spatial joins — for example, finding which province each municipality centroid falls in — use point_in_polygon:

attribute<province> province_rel (municipality) :=
    point_in_polygon(municipality/centroid, province/geometry);

3. Based on a classification

Numeric attributes can be classified into class units using a classify function. The result is a relation from the original domain to the class domain:

attribute<size_class> size_class_rel (province) :=
    classify(province/inhabitants, size_class/ClassBreaks);

This connects province to size_class based on which class each province’s population falls into. Classifications are covered in detail in Module 1d.

Other GeoDMS functions also produce relations — see the documentation of individual functions for their signatures.

how to use a relation

Once you have a relation, you can use it in two main ways:

Lookup: bringing an attribute from one domain to another

The [] operator performs an index lookup — it maps a value from domain B to each element of domain A using the relation:

// For each municipality, look up the province name:
attribute<string> province_name (municipality) :=
    province/name[municipality/province_rel];

Read this as: “for each municipality, take the index stored in province_rel and use it to look up the corresponding value from province/name”.

You also see this pattern when working with selections. Selection functions create a new (smaller) domain unit and produce an org_rel attribute — a relation from the selection back to the original domain:

// select only provinces with more than 1 million inhabitants:
unit<uint32> large_province := select_with_org_rel(province/inhabitants > 1000000[nr_inh]);

// bring attributes from the original domain to the selection:
attribute<string> name (large_province) := province/name[large_province/org_rel];

Aggregation: computing group statistics

Relations also enable aggregation — computing a summary value per group. For example, summing the number of inhabitants per province, given neighbourhood-level data:

attribute<nr_inh> total_inhabitants (province) :=
    sum(neighbourhood/inhabitants, neighbourhood/province_rel);

The second argument to sum is the relation — it tells the GeoDMS which province each neighbourhood belongs to.

ezgif com-animated-gif-maker

Reading tip: for an overview of all aggregation functions, see aggregation functions

try it yourself!

In this exercise, you will create a relation between two postcode domain units and use it to count elements.

  • Download the project here and unzip it to a project folder such as C:/prj/GeoDMSAcademy.
  • Open exercise.dms (in the GeoDMS_Academy/basics_multiple_domains/cfg subfolder) in a text editor. The configuration contains a PC4_points domain (4-digit postcode centroids).

Work through the following steps:

  1. Create a new attribute with the first two characters of each PC4 code — this is the PC2 code for each point.
  2. Use the unique operator to create a new domain unit PC2_points from the unique PC2 values. unique takes an attribute and returns a new domain unit containing each distinct value exactly once, along with a values attribute holding those values.
  3. Create a relation pc2_rel from the PC4_points domain to the new PC2_points domain using rlookup.
  4. Count the number of PC4 points per PC2 point using sum or count with the relation.

Try to solve these steps yourself first. The reference solution is in result.dms in the same cfg subfolder.


Go to previous module: Module 1b, Learning the basic concepts of GeoDMS, understanding units

Go to next module: Module 1d, Learning the basic concepts of GeoDMS, classifying and visualising data