3

I have a map of the districts of a city. The districts are in a single layer having the properties [fid, name, long, lat]. The values of long and lat are the centroids of the shapes which I calculated with QGIS.

What I really would like to have is drawing a graph where the nodes are the districts, being positioned at the GPS coordinates of the centroids, having the name as a label. The edges should be active between two nodes if they share a border. The latter one might be a bit harder, but since I used the snapping tool when drawing the polygons, I guess that the data is existing.

I know this is a bigger project, but does anyone know if there is a standard procedure, maybe an already existing function in QGIS?

Might there be a different tool or website existing for that purpose? In theory, I only need the table of properties and an addition list which ids are adjacent to each other.

enter image description here

0

3 Answers 3

3

You can use a Virtual Layer to join the layer to itself by intersecting polygons, where their fids are different. Then create a line between the centroids. Execute the query and tick "Load as new layer"

The layer is temporary, to save it right-click - Export - Save As.

select  row_number() over() as id, a.name as name_a, b.name as name_b,
        SetSRID(makeline(st_point(a.long, a.lat), st_point(b.long, b.lat)), 4326) as geometry
from district a
left join district b
on st_intersects(a.geometry, b.geometry) and a.fid<b.fid
order by a.fid, b.fid

enter image description here enter image description here

1
  • Very neat code and explanation, thank you
    – Hemmelig
    Commented Jan 20 at 11:50
2

Not in QGIS but in R:

First of all let's get some polygons (municipality boundaries around Åsane) using osmdata package. If you have the data already in form of geopackage or other shapefile, use st_read() function from sf package.

b <- osmdata::getbb("Åsane", format_out = "sf_polygon") |>
  sf::st_buffer(dist = 20000) |>
  sf::st_bbox() |>
  osmdata::opq() |>
  osmdata::add_osm_feature(key = "boundary", value = "administrative") |>
  osmdata::osmdata_sf()

m <- b$osm_multipolygons |>
  subset(b$osm_multipolygons$admin_level == 7)

And visualize it:

tmap::tm_shape(m) +
  tmap::tm_polygons(col = "name") +
  tmap::tm_legend(legend.position = c(0.82,0.0))

Now let's use spdep package and 2 functions: poly2nb() to construct neighbors list form polygons and `nb2lines() to create the lines between polygons centroids:

nb <- spdep::poly2nb(m)
l <- spdep::nb2lines(nb, coords = sf::st_centroid(sf::st_geometry(m)))

tmap::tm_shape(m) +
  tmap::tm_polygons(col = "name") +
  tmap::tm_shape(l) +
  tmap::tm_lines() +
  tmap::tm_legend(legend.position = c(0.82,0.0))

Created on 2024-01-02 with reprex v2.0.2

1
  • Very nice idea and good code, thank you!
    – Hemmelig
    Commented Jan 20 at 11:50
2

Use Geometry Generator with the following expression. Instead of centroids, I used the function point_on_surface() because depending on the polygon's shape, sometimes its centroid falls outside the polygon. If you want centroids, use centroid() instead:

collect_geometries (
    array_foreach(
        overlay_touches (
            @layer,  -- replace this with your layer name in single quotes
            point_on_surface ($geometry)
        ),
        make_line(
            point_on_surface ($geometry),
            @element
        )
    )
)

If you want to create actual lines, use Geometry by Expression and change @layer in line 4 with the actual layer name in single quotes, e.g. 'polygon'.

Red lines, based on the blue polygons with black outline, created with the expression: enter image description here

1
  • Very nice idea and good code, thank you!
    – Hemmelig
    Commented Jan 20 at 11:50

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.