5

I'm working with some Multipolygons, and I'm suddenly facing a naive question:

is it possible to give a different color -- or whatever styling properties -- to each individual sub-part of a multipart geometry?

This sound like a dumb question, but for example, how could your system be 'aware' of the sub-part order, for example, in a GeoJSON (as per definition, JSON object are unordered structures, but maybe other format could benefit any kind of underlying indexed structure?), so that it can always apply the styling in the same way for different instances of a geometric object.

To make the question more tangible, let's say I have measurements points on each 4 faces of houses. I would like to colorize each point following this pattern:

  • northern face: blue,
  • eastern face: green,
  • southern face: yellow,
  • western face: orange.

And let's say all houses are aligned according the 4 main cardinal orientations for simplicity.

In order to better focus the question, let's say I'd like to apply a different style in QGIS 3.2x.

1 Answer 1

9

Here is an example using QGIS 3.24.2-Tisler and data from a PostGIS (PG:14-3.2) database.

First create some dummy data in a PostGIS database:

-- DROP TABLE IF EXISTS public.measurement;
CREATE TABLE IF NOT EXISTS public.measurement
  ( id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    house TEXT,
    geom GEOMETRY(MULTIPOINT,4326));

INSERT INTO measurement (house, geom) VALUES
('house1',
  ST_SetSrid(
   ST_Collect(ARRAY[
      ST_GeomFromText('POINT(8.5050 47.3032)'), -- northern most 
      ST_GeomFromText('POINT(8.5054 47.3030)'), --  eastern most
      ST_GeomFromText('POINT(8.5050 47.3028)'), -- southern most
      ST_GeomFromText('POINT(8.5046 47.3030)')  --  western most
    ]), 4326 )),
('house2',
  ST_SetSrid(
   ST_Collect(ARRAY[
      ST_GeomFromText('POINT(8.4050 48.2032)'), -- northern most 
      ST_GeomFromText('POINT(8.4054 48.2030)'), --  eastern most
      ST_GeomFromText('POINT(8.4050 48.2028)'), -- southern most
      ST_GeomFromText('POINT(8.4046 48.2030)')  --  western most
    ]), 4326 )),
('house3',
  ST_SetSrid(
   ST_Collect(ARRAY[
      ST_GeomFromText('POINT(8.6050 49.7032)'), -- northern most 
      ST_GeomFromText('POINT(8.6054 49.7030)'), --  eastern most
      ST_GeomFromText('POINT(8.6050 49.7028)'), -- southern most
      ST_GeomFromText('POINT(8.6046 49.7030)')  --  western most
    ]), 4326 ));
SELECT id, house, ST_AsText(geom) AS geom FROM measurement;                         
 id | house  |                                geom  
----+--------+---------------------------------------------------------------------
  1 | house1 | MULTIPOINT(8.505 47.3032,8.5054 47.303,8.505 47.3028,8.5046 47.303)
  2 | house2 | MULTIPOINT(8.405 48.2032,8.4054 48.203,8.405 48.2028,8.4046 48.203)
  3 | house3 | MULTIPOINT(8.605 49.7032,8.6054 49.703,8.605 49.7028,8.6046 49.703)
(3 rows)

Open QGIS, connect to the DB in the DB manager and load the layer in a new project.

In the layer styling window, select "Single Symbol" and "Edit" the color using the drop down menu:

"QGIS Single Symbol Edit" drop down menu

In the "Expression String Builder" window which should normally have opened, use a CASE expression and the geometry_part_num as follow:

"QGIS Expression String Builder" window

CASE
 WHEN @geometry_part_num = 1 THEN '#aa0055de'
 WHEN @geometry_part_num = 2 THEN '#aa0ecc22' 
 WHEN @geometry_part_num = 3 THEN '#aaf0f00a' 
 WHEN @geometry_part_num = 4 THEN '#aaed8b1a'
END

Finally click "OK" and "Apply" the changes:

QGIS Multipoint styling by sub-parts

You may have to play a bit to find the right order but here, the the sub-parts order used in the "Expression String Builder" window (using the geometry_part_num variable) seems to follow the same as the one used when building the geometry in PostGIS.

Each of the 3 defined MultiPoints will have the same style.

For a GeoJSON, for example the first house, when dumped using ST_AsGeoJSON():

$ cat house1.geojson
{
  "type": "MultiPoint",
  "coordinates": [
    [
      8.505,
      47.3032
    ],
    [
      8.5054,
      47.303
    ],
    [
      8.505,
      47.3028
    ],
    [
      8.5046,
      47.303
    ]
  ]
}

If you copy paste the style from your previous layer, you will normally notice that the colors stay the same for each of the 4 sub-points. It seems to simply rely on the logical order of each point inside the GeoJSON structure.

So, now if for example you flip the coordinates of the subpoint 2 (east) <-> subpoint 4 (west):

$ cat house1_flip24.geojson
{
  "type": "MultiPoint",
  "coordinates": [
    [
      8.505,
      47.3032
    ],
    [
      8.505,
      47.3028
    ],
    [
      8.5046,
      47.303
    ],
    [
      8.5054,
      47.303
    ]
  ]
}

You will then notice that the eastern point (2) is now orange (because it became the 4th point), the western one (4) yellow (because it became the second point):

Flipped sub points in GeoJSON

And the same style actually applies if you load such same ordered MutiPoint from PostGIS:

INSERT INTO measurement (house, geom) VALUES
('house1_flip24',
  ST_SetSrid(
   ST_Collect(ARRAY[
      ST_GeomFromText('POINT(7.5050 47.3032)'), -- northern most
      ST_GeomFromText('POINT(7.5046 47.3030)'), --  western most
      ST_GeomFromText('POINT(7.5050 47.3028)'), -- southern most
      ST_GeomFromText('POINT(7.5054 47.3030)')  --  eastern most
    ]), 4326 ));

->

Flipped sub point in PostGIS

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.