Load a raster layer in QGIS.
Add a new Scratch Layer of Polygon type (in any CRS). Set its Symbology to Inverted Polygons. Use a Geometry Generator as symbol layer type. Set it to LineString/MultiLineString. Enter the expression below and adjust the layer ID (best enter the expression editor and find it in the “layers” tree). Then adjust the scaling factor at the very bottom.
-- UPPER CASE comments below are where you can change things
with_variable(
'raster_layer',
'long_and_complicated_layer_id', -- RASTER LAYER to sample from
-- this collects all the linestrings generated below into one multilinestring
collect_geometries(
-- a loop for each y value of the grid
array_foreach(
-- array_foreach loops over all elements of the series generated below
-- which is a range of numbers from the bottom to the top of y values
-- of the map canvas extent coordinates.
-- the result will be an array of linestrings
generate_series(
y(@map_extent_center)-(@map_extent_height/2), -- bottom y
y(@map_extent_center)+(@map_extent_height/2), -- top y
@map_extent_height/50 -- stepsize -> HOW MANY LINES
),
-- we want to enter another loop so we assign the name 'y' to
-- the current element of the array_foreach loop
with_variable(
'y',
@element,
-- now we are ready to generate the line for this y value
make_line(
-- another loop, this time for the x values. same logic as before
-- the result will be an array of points
array_foreach(
generate_series(
x(@map_extent_center)-(@map_extent_width/2), -- left x
x(@map_extent_center)+(@map_extent_width/2), -- right x
@map_extent_width/50 -- stepsize -> HOW MANY POINTS PER LINE
),
-- and here we create each point of the line
make_point(
@element, -- the current value from the loop over the x value range
@y -- the y value from the outer loop
+ -- will get an additional offset to generate the effect
-- we look for values at _this point_ in the raster, and since
-- the raster might not have any value here, we must use coalesce
-- to use a replacement value in those cases
coalesce( -- coalesce to catch raster null values
raster_value(
@raster_layer,
1, -- band 1, *snore*
-- to look up the raster value we need to look in the right position
-- so we make a sampling point in the same CRS as the raster layer
transform(
make_point(@element, @y),
@map_crs,
layer_property(@raster_layer,'crs')
)
),
0 -- coalesce 0 if raster_value gave null
-- here is where we set the scaling factor for the raster -> y values
-- if things are weird, set it to 0 and try small multiplications or divisions
-- to see what happens.
-- for metric systems you will want to multiply
-- for geographic coordinates you will want to divide
)*10 -- user-defined factor for VERTICAL EXAGGERATION
)
)
)
)
)
)
) -- wee
If you don’t have your raster data on a SSD this can be a bit slow.
Yes, this works if you change your CRS!
Pingback: Dynamic elevation profile lines as @QGIS geometry generator – GeoNe.ws
Really nice !
thanks for the share !
Amazing work!
I would like to hear more explanation since for some reason, the code does not work for me, and input “collect_geometries” does not exist in qgis 3.4.4
See the note at the very top. This only works in the current development version until the next version is released.
I used QGIS 3.8.3, I tried to put the “expression” in the expression inside the scratch layer properties, but it does not do anything, and it says the expression is wrong. Can you help me by explaining a little bit more on how to use the expression
“Development version” means one that you compile yourself from the latest source code. ;)
You will have to wait until 3.10. Which will be released in a week!
Hi,
First off this is really great! Second, i have the code to work but it is just giving back flat lines and not taking into account the raster layer. I have the raster_layer as the file path for the raster layer and then the layer id as the polygon scratch layer, could this be why?
Got it working! once again this is great!
Hi, I have the same problem. What was your solution here?
Only the raster layer needs to be explicitly referenced in the expression if I remember correctly, so make sure you did not mix up that with the scratch layer.
If that is all fine and the problem persists, play with the “VERTICAL EXAGGERATION” value.
Pingback: #30DayMapChallenge: Day 3 – Polygons OR Lego® style brick raster in QGIS using Geometry Generator expressions | Hannes ihm sein Blog
Hello, and thanks for the tutorial, very interesting!
In my case, there is a displacement of the curves towards the north, of an approximate 1 kilometers. But I can’t understand what I can modify to match .. thank you very much!
Hm, not sure. You can try lowering the exaggeration to 1 (= no exaggeration) at the bottom of the script. Are the lines still offset then?
Hi. Yes. decreasing the value you mention, the offset also decreases. But there is always a northward movement. Annex images. Thank you
https://drive.google.com/drive/folders/1OMaHstV4rJf3ugrRfBXz0F8N4d8E96ca?usp=sharing
Out of curiosity did you find a solution to this? I’m experiencing the same issue.
Pingback: Johannes Kröger to GeoHipster: “$existing_free_software can do that already.” | GeoHipster
Pingback: Johannes Kröger to GeoHipster: “$existing_free_software can do that already.” – GeoHipster
Pingback: Joy Plots with Geo Data – COOL BLUE DATA
Pingback: Joy Plot on the Map in Tableau – COOL BLUE DATA