Skip to content
Learn QGIS with BNHR

Module 4 · Intermediate

Styling and symbology

Bivariate choropleths, size and color together, rule-based and scale-dependent styling of urban data such as population, roads, and land use.

Module 4Level Intermediate
On this page
  1. Overview
  2. Before we begin
  3. Multi-variable symbologies
  4. 1.1. Bivariate choropleth map of barangays showing population density and annual population rate
  5. What we want to achieve
  6. What we have
  7. Relevant QGIS knowledge/skills
  8. Steps
  9. 1.2. Using both size and color to communicate information about the districts
  10. What we want to achieve
  11. What we have
  12. Relevant QGIS knowledge/skills
  13. Option 1 - Geometry generator approach
  14. Option 2 - Centroid approach
  15. Rule-based and scale-dependent symbologies
  16. 2.1. Styling roads and land-use using rules and symbol levels
  17. What we want to achieve
  18. What we have
  19. Relevant QGIS knowledge/skills
  20. Apply rule-based symbology to the road network data
  21. Rendering roads consistently and cleanly using Symbol Levels
  22. Apply rule-based symbology to the landuse data
  23. 2.2. Showing different features at different zoom levels
  24. What we want to achieve
  25. What we have
  26. Relevant QGIS knowledge/skills
  27. Scale-dependent visibility
  28. Certification and support

Before diving into this module’s exercises, it would be good if you can review and familiarize yourself with styling layers and making maps. You can also look at advanced styling and symbology techniques.

For exercises in this module, you will use the bnhr_qgis-architects-planners-urban-002.gpkg inside the data subfolder in the BNHR_QGIS-for-Architects-Planners-and-Urban-Practitioners folder.

This geopackage contains all the data and projects associated with the exercises.

1.1. Bivariate choropleth map of barangays showing population density and annual population rate

Section titled “1.1. Bivariate choropleth map of barangays showing population density and annual population rate”

Level: Intermediate

Output for 1.1. Bivariate choropleth map of barangays showing population density and annual population rate

For our training participants, you can load the completed/styled layer by loading the bivariate-choropleth project found inside bnhr_qgis-architects-planners-urban-002.gpkg.

  1. A map of Quezon City barangays showing both the population growth rate (2000 to 2020) and the people per 100 square meters.
  1. adm_brgy_quezon_city_pop2000_2020 - the barangay-level admin boundary data generated from a previous exercise with population from 2000 to 2020
  1. Load the adm_brgy_quezon_city_pop2000_2020 layer. Make sure that it already has the fields for population from 2000 to 2020.
Attribute table of adm_brgy_quezon_city_pop2000_2020 showing population data from 2000 to 2020
Attribute table of adm_brgy_quezon_city_pop2000_2020 showing population data from 2000 to 2020
  1. Duplicate the adm_brgy_quezon_city_pop2000_2020 layer. Since we’ll be creating a bivariate choropleth map using blending modes, we need 2 vector layers to show. In this case, we’ll show the annual population growth from 2000-2020 and the number of people per 100sqm in the barangay. Name the two layers brgy_rate and brgy_popden.

To duplicate a layer, right-click on the layer ‣ Duplicate layer.

brgy_rate and brgy_popden layers
brgy_rate and brgy_popden layers
  1. Next, we make a choropleth map for the brgy_rate layer using a Graduated symbology using the following parameters.

    • Symbology: Graduated
    • Value:
      (pop2020-pop2000)/20
    • Classes
      • Low
        • Color: #e8e8e8
        • Values: -500.00 - 0.00
      • Moderate
        • Color: #dfb0d6
        • Values: 0.00 - 500.00
      • High
        • Color: #be64ac
        • Values: 500.00 – 5000.00

Notice the Expression icon (Expression button) to the right of the Value parameter.

This means that we can directly use the Expression computing for the annual population growth from 2000 to 2020 ((pop2020 - pop2000)/20) without needing to create a new field on the layer.

Style parameters for brgy_rate layer
Style parameters for brgy_rate layer
  1. Your brgy_rate layer should look like:
Choropleth map for brgy_rate layer
Choropleth map for brgy_rate layer
  1. Do the same for the brgy_popden layer but our parameters will be:
    • Symbology: Graduated
    • Value:
      100*pop2020/$area
    • Classes
      • Low
        • Color: #e8e8e8
        • Values: 0.000 - 1.500
      • Moderate
        • Color: #ace4e4
        • Values: 1.500 - 3.000
      • High
        • Color: #5ac8c8
        • Values: 3.000 - 15.000
Style parameters for brgy_popden layer
Style parameters for brgy_popden layer
  1. Your brgy_popden layer should look like:
Choropleth map for the brgy_popden layer
Choropleth map for brgy_popden layer
  1. Now that you have the two choropleth maps, create the bivariate choropleth effect by changing the blending mode of the top layer (brgy_popden) to Multiply.
Setting blending mode of brgy_popden layer
Setting blending mode of brgy_popden layer to Multiply
Bivariate choropleth of the population growth (2000-2020) and population per 100sqm in Quezon City barangays
Bivariate choropleth of the population growth (2000-2020) and population per 100sqm in Quezon City barangays

You can use the Bivariate legend plugin to create a legend for the map you created.

The Bivariate legend plugin
The Bivariate legend plugin

There’s a plugin called the Bivariate color polygon renderer that adds an implementation of a bivariate color renderer directly for a polygon layer’s styling options.

The Bivariate color polygon renderer plugin

Try to use this plugin and check what the pros and cons are of this approach vs the approach we took.

1.2. Using both size and color to communicate information about the districts

Section titled “1.2. Using both size and color to communicate information about the districts”

Level: Intermediate

Output for Exercise 1.2. Using both size and color to communicate information about the districts

For our training participants, you can load the completed/styled layer by loading the size-and-color project found inside bnhr_qgis-architects-planners-urban-002.gpkg.

  1. Use circles to show population information about districts in Quezon City where the size pertains to the people per 1000 sqm and the color indicates the annual population growth from 2000 to 2020.
  1. adm_dist_quezon_city_pop2000_2020 - the district-level admin boundary data generated from a previous exercise with population from 2000 to 2020

As with most things in QGIS, there are several ways to approach this problem in order to arrive at the same outcome. Here, I will show two options:

  1. A straightforward option using geometry generators and data-defined overrides that do not require the creation of a new field or a new layer.
  2. An option that requires creating a new field (pop_per_1000sqm) and a centroid layer then applying a graduated symbology with data-defined overrides.
  1. Load the adm_dist_quezon_city_pop2000_2020 and duplicate the layer.
  2. Rename one base and apply a simple single symbol symbology.
  3. On the other layer, select Geometry Generator as its Symbol layer type.
Selecting Geometry Generator as Symbol layer type
  1. Change the Geometry type to Point/MultiPoint and use the following expression to generate a centroid:
    centroid(@geometry)
Creating a point geometry using the centroid expression
  1. On the Simple Marker, use the Assistant to override the Size parameter.
Selecting the Assistant
  1. Use the following parameters:
    • Source
      1000*pop2020/$area
    • Values from 10 to 35
    • Output
      • Size from 500
      • to 3500
Symbol Size parameters for the Assistant
  1. Your layer should now look like below:
District layer styled as differently-sized points
  1. Next, let’s use the Assistant to override the Symbol Fill Color and Symbol Stroke Color parameters. Use the same parameters for both:
    • Source:
      (pop2020-pop2000)/20
    • Values from: 500 to 15000
Symbol Fill Color parameters for the Assistant

Symbol Stroke Color parameters for the Assistant

  1. Add a new field to the adm_dist_quezon_city_pop2000_2020 layer to hold the number of people per 1000 square meters using the following expression:
    1000*pop2020/$area
Creating the pop_per_1000sqm field using the Field Calculator
  1. Run the Centroid processing algorithm to create a new point layer (centroid) based on adm_dist_quezon_city_pop2000_2020.
Parameters of the Centroid processing algorithm
  1. A new layer (Centroid) should be created.
Centroid layer
  1. Apply a Graduated symbology and use the following parameters:
    • Value: pop_per_1000sqm
    • Method: Size
    • Size from: 500 to 3500 Map Units
    • Classes:
      • 10 - 15
      • 15 - 20
      • 20 - 25
      • 25 - 30
      • 30 - 35
Graduated symbology using size for the Centroid
  1. Your Centroid layer should look like below:
Centroid with size-based Graduated symbology
  1. Use the Assistant to override the Symbol Fill Color with the following parameters:
    • Source:
      (pop2020-pop2000)/20
    • Values from: 500 to 15000
Symbol Fill Color parameters for the Assistant
  1. Your layer should look like below:

How will you add a legend on the print layout to reflect this multi-variable symbology?

Rule-based and scale-dependent symbologies

Section titled “Rule-based and scale-dependent symbologies”

2.1. Styling roads and land-use using rules and symbol levels

Section titled “2.1. Styling roads and land-use using rules and symbol levels”

Level: Intermediate

Output for Exercise 2.1. Styling roads using rules and symbol levels

Zoomed in output for Exercise 2.1. Styling roads using rules and symbol levels

For our training participants, you can load the completed/styled layer by loading the rules-and-symbol-levels project found inside bnhr_qgis-architects-planners-urban-002.gpkg.

  1. Style a road network similar in style to the ones we see in web maps by applying rule-based symbology on OpenStreetMap road data.
  2. Apply the same symbology to multiple landuse categories.
  1. adm_municity_quezon_city
  2. osm_roads_quezon_city
  3. osm_landuse_quezon_city
  4. Other relevant layers:
    • satellite image basemap
  1. Load the adm_municity_quezon_city, osm_roads_quezon_city, and osm_landuse_quezon_city layers.
  2. Style adm_municity_quezon_city using Inverted Polygons and apply two fills (a Simple Fill and a Gradient Fill).
The adm_municity_quezon_city styled
The adm_municity_quezon_city styled

The Inverted Polygons symbology allows us to style the area outside the polygon instead of the polygon itself. In this case, this means that we’ll be styling all the area outside the adm_municity_quezon_city layer.

How should your layers be ordered so that the roads and land-use features outside of Quezon City isn’t shown on the map?

Apply rule-based symbology to the road network data

Section titled “Apply rule-based symbology to the road network data”
  1. For the osm_roads_quezon_city layer, you will create 3 rules—one for primary roads, another for secondary roads, and a catch-all (for everything else). The rules will be:
    • Primary roads:
      • Label: primary
      • Filter:
        "fclass" in ('primary')
      • Symbol:
        • Simple Line (1)

          • Color: #fff495
          • Stroke width: 40 meters at scale
          • Stroke style, Join style, Cap style: Solid line, Round, Round
        • Simple Line (2)

          • Color: #ecec32
          • Stroke width: 50 meters at scale
          • Stroke style, Join style, Cap style: Solid line, Round, Round
Rules for styling the primary roads (1)
Rules for styling the primary roads (1)
Rules for styling the primary roads (2)
Rules for styling the primary roads (2)
  • Secondary and tertiary roads:
    • Label: secondary and tertiary
    • Filter:
      "fclass" in ('secondary', 'tertiary')
    • Symbol:
      • Simple Line (1)

        • Color: #fff495
        • Stroke width: 20 meters at scale
        • Stroke style, Join style, Cap style: Solid line, Round, Round
      • Simple Line (2)

        • Color: #ecec32
        • Stroke width: 30 meters at scale
        • Stroke style, Join style, Cap style: Solid line, Round, Round
Rules for styling the secondary & tertiary roads (1)
Rules for styling the secondary & tertiary roads (1)
Rules for styling the secondary & tertiary roads (2)
Rules for styling the secondary & tertiary roads (2)
  • Other roads:
    • Label: others
    • Filter:
      Else
    • Symbol:
      • Simple Line (1)
        • Color: #ffffff
        • Stroke width: 8 meters at scale
        • Stroke style, Join style, Cap style: Solid line, Round, Round
      • Simple Line (2)
        • Color: #d3d3d3
        • Stroke width: 12 meters at scale
        • Stroke style, Join style, Cap style: Solid line, Round, Round
Rules for primary, secondary + tertiary, and other roads
Rules for primary, secondary + tertiary, and other roads

However, if you zoom in to the map, you will notice a bit of an issue.

Zoomed in road layer. Notice the poor overlapping of the different features and symbols.
Zoomed in road layer. Notice the poor overlapping of the different features and symbols.

If you look real close, you will notice that the different road feature overlap in a poor way. What you want to do is control the rendering order so that the primary roads are rendered over the secondary and other roads while the secondary roads are rendered over the other roads. To do this, you can use Symbol Levels.

Rendering roads consistently and cleanly using Symbol Levels

Section titled “Rendering roads consistently and cleanly using Symbol Levels”

Symbol Levels allow you to define the order in which the symbols are rendered. The numbers assigned to symbol rules define when they will be rendered, that means a lower number is rendered first and a higher number will be rendered on top of it. Using this, you can ensure that the other roads are rendered at the bottom and the primary roads are rendered on top.

  1. Click Symbol Levels on the Layer Styling panel or the layer Properties of the osm_roads_quezon_city layer.
Opening the Symbol Levels dialog
Opening the Symbol Levels dialog
  1. Update the Symbol Levels for each of the rules. Make sure that the values for primary are the highest while the values for Others are the lowest.
Symbol level values for the road symbology rules
Symbol level values for the road symbology rules

If you notice that your layer or features are overlapping poorly or not rendering in a way that you want, you can use symbol levels to fine-tune and configure which features should appear on top and which ones should appear on the bottom.

  1. With these symbol level rules applied, your road layer should look like below when zoomed in.
Properly configured symbol levels for roads
Properly configured symbol levels for roads
Road network data styled using rule-based symbology with symbol levels applied
Road network data styled using rule-based symbology with symbol levels applied

By default, QGIS follows the internal ordering of layer features when rendering them on the Map Canvas. If you are styling a road network consisting of roads at different levels/elevations (e.g. underpass, overpasses/flyovers, tunnels, etc,), this can lead to a visual mess that makes it hard for the map reader to understand the relative positions and relationships between the different road segments.

By assigning different Symbol Levels to different road layers (or even different features within a layer), you can ensure that roads at higher elevations are always drawn on top of roads at lower elevations.

Apply rule-based symbology to the landuse data

Section titled “Apply rule-based symbology to the landuse data”

Activate the osm_landuse_quezon_city and notice that there are several land use classes available.

In this case, we want to style only the “green” areas. We can do this by applying a rule-based symbology.

  1. Select the osm_landuse_quezon_city layer.

  2. Select Rule-based for the symbology type.

  3. Add a new rule using the green arrow.

  4. Use the following rule:

    1. Label: green
    2. Filter:
    "fclass" in ('farmland', 'farmyard', 'forest', 'grass', 'meadow', 'nature_reserve', 'orchard', 'park', 'scrub')

  1. Add another rule as a catch-all, label it non-green, and style it as below.

You can combine/refine rule-based symbology with other symbology types (e.g. using categories, ranges, etc.). You can do this using the Refine Selected Rules function.

Aside from using rule-based symbology, you can also apply 1 symbology to multiple landuse values by merging categories when using a Categorized symbology.

Try to do this.

2.2. Showing different features at different zoom levels

Section titled “2.2. Showing different features at different zoom levels”

Level: Intermediate

For our training participants, you can load the completed/styled layer by loading the scale-dependent-rendering project found inside bnhr_qgis-architects-planners-urban-002.gpkg.

For this exercise, your goal is to change which features and layers are shown as you zoom in or out of the map. In a way, you will be changing the level of detail in the map depending on the zoom level. For example:

  • When zoomed out (e.g. scale < 1:50,000): you only want to see the primary, secondary, and tertiary roads as well as the green areas.
  • At middle zoom level (e.g. scale between 1:25,000 and 1:50,000): you want to add the other roads as well as the flood hazard layer.
  • When zoomed in (e.g. scale > 1:25,000): you want to show the building footprints (ms_building_footprints_quezon_city) and hide the non-green land use so the buildings stand out.
  1. adm_municity_quezon_city
  2. osm_roads_quezon_city
  3. osm_landuse_quezon_city
  4. upri_quezon_city_floodhazard_100yr
  5. ms_building_footprints_quezon_city

The trick here is to use Scale Dependent Visibility. In QGIS, you can fine-tune and control the scale range at which layers and features become visible.

  • For layers: you can find this in the Rendering tab of the Layer Properties
  • For features styled using rule-based symbology: you can specify the minimum scale and maximum scale in the style settings.
  1. Load the upri_quezon_city_floodhazard_100yr and ms_building_footprints_quezon_city layers and style them accordingly.
All layers loaded in QGIS
All layers loaded in QGIS
  1. For osm_roads_quezon_city, set the following parameters for the others rule:

    • Min. Scale: 1:50000
    • Max. Scale: 1:1

    Don’t forget to apply your changes.

Applying a scale range to the others rule
Applying a scale range to the others rule
Scale range shown in the rule-based symbology
Scale range shown in the rule-based symbology
  1. Do the same for the non-green rule in osm_landuse_quezon_city but with the following parameters:
    • Min. Scale: 1:10000000
    • Max. Scale: 1:25000

What do the Min Scale and Max Scale values mean for the osm_roads_quezon_city and osm_landuse_quezon_city layers?

  1. For upri_quezon_city_floodhazard_100yr, open its Layer Properties and go to the Rendering tab. Check the Scale Dependent Visibility and put 1:50,000 as the Minimum.
Applying scale-dependent visibility on the upri_quezon_city_floodhazard_100yr
Applying scale-dependent visibility on upri_quezon_city_floodhazard_100yr
  1. Look at your map canvas. You should notice that when you are zoomed out (or when the scale is less than 1:50,000), the other roads and the flood hazard are not visible and when you zoom in (or once the scale is greater than 1:50,000) they appear.
“other” roads and the flood hazard do not appear at 1:90000 scale
“other” roads and the flood hazard appear at 1:30000 scale
  1. For ms_building_footprints_quezon_city, do the same thing that you did for upri_quezon_city_floodhazard_100yr but put the Minimum to 1:25,000.

Take a look at your map canvas again, this time the building data should only appear when the scale is greater than 1:25,000.

Applying scale-dependent visibility on ms_building_footprints_quezon_city
Building footprint appear while non-green landuse disappear at 1:10000 scale
Saved in this browser only

Certification and support

We offer additional resources, certificates, official QGIS certification, ongoing support, and other perks to those who join our instructor-led training.

Join an upcoming training to take this as an instructor-led course, or contact us to arrange one for your team or organization.

Something new

Identify results
LayerTry an exercise
ExerciseDigitizing new buildings
Number3.4, in Making data usable in QGIS
CourseQGIS: Layers and Expressions
DataProvided in the lesson