2

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")
 )
PolyGeo
65.5k29 gold badges115 silver badges350 bronze badges
asked Jun 14 at 7:48
2
  • 1
    Apart 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? Commented Jun 14 at 12:15
  • 2
    Can you provide sample data and a screenshot of successful lines with Geometry generator to see what you expect as result? Commented Jun 15 at 7:37

2 Answers 2

1

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" OR
  • order_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.

PolyGeo
65.5k29 gold badges115 silver badges350 bronze badges
answered Jun 14 at 12:28
0
0

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.

answered Jun 15 at 10:25

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.