I am trying to create lines from a point layer using the Geometry by expression tool. I can get the code to work in geometry generator but not this tool. I have several groups of points (in one layer) and each group needs to be converted into separate line features in a single layer. The problem relates to aggregate functions and grouping.
This was as far as I got:
Make_line(
array_agg(
make_point(x(@geometry),y(@geometry)),"ID")
)
Evaluation error: Cannot use aggregate function in this context
To clarify, I have a point file that has an attribute field ID that identifies several groups and a distance field. The make line component is to create a line for each group of points ordered by a numeric field. The result is a layer containing several line features. Now I can do this in the point to path tool but hoping to do it here so that eventually I will build on the code to create polygons, something I got the geometry generator to do. I tried the sample code provided but struggled to get past the red invalid code message in the expression builder.
In particular, how can I insert a group_by command in the example you provided as array_agg supports this?
make_line(
aggregate(
'My_layer_name', -- change layer name here
'array_agg',
make_point (x (@geometry),y (@geometry)),
group_by:="ID",
order_by:="Distance"
)
)
This code below does not report an error but does not create any features;
make_line(
array_agg( @geometry,group_by:="C_ID",order_by:="Depth_m")
)
-
1Apart rom the expression, you should also tell us your data structure. If I have a point layer, the expression you poste does not produce anything, not even with Geomtery Generator. So what is your intention (drawing a line from each point to.... where exactly?) and how is your data structured?Babel– Babel2025年06月14日 12:15:42 +00:00Commented Jun 14 at 12:15
-
2Can you provide sample data and a screenshot of successful lines with Geometry generator to see what you expect as result?Babel– Babel2025年06月15日 07:37:16 +00:00Commented Jun 15 at 7:37
2 Answers 2
The algorithm Geometry by expression
is almost identical to Geometry Generator
. However, geometry generator has an easier way to reference to the current layer. With Geometry by expression, this is not possible. So e.g. the varibale @layer
to reference the current layer can be used with Geometry Generator, but not with Geometry by expression. Here, you always have to state the layer's name explicitely instead in single quotes: 'my_layer_name'
.
The same is true with simplified aggregate functions like array_agg()
: These work by default work on the current layer, so in this case, no argument specifying the layer is needed. Geometry by expression, however, can't deal with this. It needs a function that explicitely specifies which layer to use.
For this reason, with Geometry by expression, you have to use the generic aggregate()
function. You can use it in the same way as the array_agg()
function, but have to tell QGIS which layer it should call and what kind off aggregate (here: array_agg
) to create. Change the layer name (in single quotes '
) in line 3:
make_line(
aggregate(
'your_layer_name', -- change layer name here
'array_agg',
make_point (x (@geometry),y (@geometry)),
"ID"
)
)
By the way: in your expression, "ID"
seems to be a condition for a filter
or order_by
argument. I am not sure what your data structure looks like and what exactly you want to achieve, but depending on your goal, you should make explicit how the optional "ID" should be treated, thus either:
filter:="ID"
ORorder_by:="ID"
After your update, it seems you must modify your expression a bit. As mentioned before, aggregate()
function has no group_by
argument, but a filter
arugument. To make a separate line for each group with the same ID
and then connect these points, ordered by the value from the field Distance
, use this expression.
To be able to use the ID of the current feature inside the aggregate function, you must first create a variable (I call it current_id
) based on this ID value. Like this, you can call it in the filter
condition: "ID"=@current_id
. So the expression looks like this - you could enclose the whole expression inside a make_polygon()
function to convert the lines to polygons in one step.:
with_variable(
'current_id',
"ID",
make_line(
aggregate(
'my_layer_name', -- change layer name here
'array_agg',
make_point (x (@geometry),y (@geometry)),
filter:="ID"=@current_id,
order_by:="Distance"
)
))
Be aware, however, that this is inefficient as Geometry by expression (as well as Geometry generator) works on a per-feature basis. So the same line is created repeatedly for each feature with the same ID. When finished, you can run Delete duplicate geometries.
You can avoid creating duplicate geometries if you create a geometry only for one of the features of each ID
group, see the following expression how to achieve that. You still get an output layer with the same number of features as the input (point) layer, but with many empty or NULL geometries that you may want to delete from the result with Remove NULL geometries:
with_variable(
'current_id',
"ID",
with_variable(
'output',
case
when
@id = aggregate('my_layer_name', 'min', @id, filter:="ID"=@current_id) -- change layer name
then
make_line(
aggregate(
'my_layer_name', -- change layer name here
'array_agg',
make_point (x (@geometry),y (@geometry)),
filter:="ID"=@current_id,
order_by:="Distance"
)
)
end,
case
when NOT is_empty_or_null (@output)
then @output
end
))
So I am not sure about your workflow and final goal. Depending on that, there might be better approaches.
If I understood you correctly, you want to connect points, grouped by field ID
and ordered by field Distance
and then convert the lines to polygons. You want to do this in one step and thus tried Geometry by expression. This can work (see my other solution), but has the disadvantage of working on a per-feature basis and thus the output contains more features than geometries.
An alternative is to use Points to paths and then Lines to polygons. You can create a model for this simple combination of algorithms to run it at once. This produces just one feature for each separate geometry.
Explore related questions
See similar questions with these tags.