QGIS – How Geometry by Expression Works with Layers without Geometry

distance matrixgeojsongeometry-generatorqgisvector

There is distance matrix with 9.455 features without geometries in GeoJSON format. It was created outside of QGIS with a tool similar to QGIS's "Distance matrix".

The matrix looks like this:

input

Now I am trying to connect these features with points from/to that have geometries and stored in other layers.

I am doing it with "Geometry by expression", where I take my matrix as an 'Input layer'

window

and I am using this expression to create a line:

make_line(
    geometry(
        get_feature(
            'layer_from',
            'fid',
            "FROM_ID"
            )
        ), 
    geometry(
        get_feature(
            'layer_to',
            'fid',
            "TO_ID"
            )
        )
    )

When I press Run I receive an empty output. Why?

I wrapped the above expression into is_empty_or_null(...) and I got false -> means that geometries are not NULL, they exist somewhere.

When I read the documentation it says that input layer is a vector layer:

INPUT: Input layer

Parameter type: QgsProcessingParameterFeatureSource

Accepted data types:
    - str: layer ID
    - str: layer name
    - str: layer source
    - QgsProcessingFeatureSourceDefinition
    - QgsProperty
    - QgsVectorLayer

This is logical. Moreover, when I checked the 'Matrix' layer with some PyQGIS:

layer = QgsProject.instance().mapLayersByName('Matrix')[0]

print(layer.type()) # QgsMapLayerType.VectorLayer
print(layer.LayerType) # <enum 'QgsMapLayerType'>
print(layer.PropertyType) # <class 'qgis._core.QgsMapLayer.PropertyType'>
print(layer.geometryType()) # 4
print(layer.providerType()) # ogr
print(layer.storageType()) # GeoJSON

it looks also promising to me, looks like a Vector, is not it?

Are there any workarounds available? Maybe it is not possible at all. And simply saying "Geometry by expression" in QGIS does not except layer without geometry as an input.

The one that I found is to refer to layer with destination-points via 'Matrix' layer, taking origin-points as an 'Input' in the "Geometry by expression".

Perhaps it is again the same story, that:

QGIS does not support GeometryCollection as a valid geometry type.

which is inside of my GeoJSON:

geojson

BTW, this is a piece of GeoJSON that I am working on:

{
"type": "FeatureCollection",
"name": "Matrix",
"features": [
{ "type": "Feature", "properties": { "FROM_ID": 1, "TO_ID": 1, "DURATION_H": 0.92035555555555559, "DIST_KM": 4.60184 }, "geometry": null },
{ "type": "Feature", "properties": { "FROM_ID": 1, "TO_ID": 2, "DURATION_H": 1.1758277777777777, "DIST_KM": 5.87926 }, "geometry": null },
{ "type": "Feature", "properties": { "FROM_ID": 1, "TO_ID": 3, "DURATION_H": 1.5567583333333332, "DIST_KM": 7.7839 }, "geometry": null },
{ "type": "Feature", "properties": { "FROM_ID": 1, "TO_ID": 4, "DURATION_H": 1.5678055555555557, "DIST_KM": 7.83914 }, "geometry": null },
{ "type": "Feature", "properties": { "FROM_ID": 1, "TO_ID": 5, "DURATION_H": 0.44944166666666668, "DIST_KM": 2.24724 }, "geometry": null },
{ "type": "Feature", "properties": { "FROM_ID": 1, "TO_ID": 6, "DURATION_H": 0.41768055555555555, "DIST_KM": 2.08844 }, "geometry": null },
{ "type": "Feature", "properties": { "FROM_ID": 1, "TO_ID": 7, "DURATION_H": 1.156236111111111, "DIST_KM": 5.78126 }, "geometry": null },
{ "type": "Feature", "properties": { "FROM_ID": 1, "TO_ID": 8, "DURATION_H": 1.2599444444444445, "DIST_KM": 6.2998 }, "geometry": null },
{ "type": "Feature", "properties": { "FROM_ID": 1, "TO_ID": 9, "DURATION_H": 1.1397833333333334, "DIST_KM": 5.69899 }, "geometry": null },
{ "type": "Feature", "properties": { "FROM_ID": 1, "TO_ID": 10, "DURATION_H": 0.60408888888888879, "DIST_KM": 3.02048 }, "geometry": null }
]
}

Best Answer

The problem

The problem with your expression is that you apply it on the Matrix layer, but this is a layer without geometry. Creating geometries works only on layers that contain geomtries. It does not even work on a geometry layer that does not contain any features (empty layer).

I think Geometry generator (and by extension Geometry by expression) is a way to style (visualize) geometries - however, when you do not have any geometries, you can't style anything. In your case, you have an "attribute only" layer. I don't know why this is considered to be a vector, maybe vector in the sense that it's not a raster layer. It's data structure (a layer with an attribute table) is closer to a vector then a raster layer.

How to solve it

So the expression must be based on one of the point layers that you want to connect. Here I used the layer_from.

Use this expression:

collect_geometries( 
    array_foreach (
        generate_series (0,  aggregate( 'matrix', 'count', $id)-1),
        make_line(
            geometry(
                get_feature(
                    'layer_from',
                    'fid',
                    attribute (
                        get_feature_by_id (
                            'matrix',
                            @element
                        ),
                    'FROM_ID'
                    )
                )
            ), 
            geometry(
                get_feature(
                    'layer_to',
                    'fid',
                    attribute (
                        get_feature_by_id (
                            'matrix',
                            @element
                        ),
                    'TO_ID'
                    )
                )
            )
        )
    )
)

enter image description here

Related Question