7

I want to create bird species location maps for a single area (and there are multiple areas). There are a lot of species, every one needs an individual map, so I'm facing 100+ maps per area. Is there any way beyond manually creating the same map extent per every species? I imagine i can deal with visibility of specific species with style based on $id = @atlasfeatureid, but I'd hate to copy-paste the same rectangle over 100 times for each area.

  • 2
    Can you load all the range polygons into the same table? Then you could simply drive each map from each polygon feature in a single table. – DPSSpatial May 4 at 15:22
  • 2
    Maybe you can do this with a "field group section" in a print report (not a print layout). It's like a print atlas, but more versatile, I think. I haven't actually used this feature myself. north-road.com/2018/01/23/… – csk May 4 at 20:54
  • 1
    Report is not the solution for this problem but cool function though! – Dawid Zyskowski May 7 at 17:04
2

Finally, I figured out workflow for this and improved my answer.

Initial data: area (polygons with id); sp (points with id)

enter image description here

Do spatial join of both layers with Join attributes by location for creating new species layer with area_id (I set for this example optional prefix area_)

enter image description here

Use Field Calculator and create new field (e.g. atlas_fiel) that combines the id of species and id of area like:

    id || '_' || area_id

enter image description here

Create a table with list of unique values of atlas_fiel. For this you can use this python script in console (set path fot csv and name of field). This is intended to work on active layer.

csv_path = "/your/path/table.csv"
field_name = "atlas_fiel"

layer = iface.activeLayer() 

l = []
for feature in layer.getFeatures():
    l.append(feature[field_name])

uniq_val = list(set(l))

with open(csv_path, "w") as f:
    for item in uniq_val.sort():
        f.write("%s\n" % item)

uri = (
    'file://{}?type=csv&useHeader=No&geomType=none'
).format(csv_path)

layer = iface.addVectorLayer(
    uri, "table_"+field_name, "delimitedtext"
)    

enter image description here

Now get the atlas work. Select generated table as Coverage layer and set the symbology of Joined layer to rule-based

 @atlas_pagename  = atlas_fiel

Additional tips:

For retrieving values from joined layer (for example for textbox) you can use expression like this:

attribute(get_feature('Joined layer', 'atlas_fiel', @atlas_pagename ), 'area_id')

Example in textbox:

area: [%attribute(get_feature('Joined layer', 'atlas_fiel', @atlas_pagename ), 'area_id') %] 
species: [%attribute(get_feature('Joined layer', 'atlas_fiel', @atlas_pagename ), 'id') %]

You can even center the view for features from layer area. In Map item properties set Data defined override for paritcular extent values, like this:

x_min(geometry(get_feature('area', 'id', attribute(get_feature('Joined layer', 'atlas_fiel', @atlas_pagename ), 'area_id'))))

repeat this for y_min, x_max, y_max, for increase the bounding box you can multiply the value in expression (e.g add *1.1 and so on)

enter image description here

... or style area layer for highlight the polygon (or hide other polygons) by rule-based symbology:

to_int(substr(@atlas_pagename,0,1))  = id  

Now you can generate hundreds of maps :)

enter image description here


Original answer (works only for species in seperate layers for one area):

I had same problem before. I solved it by this steps:

  • create a table with list of layers id (layer_id)
  • use this table as a atlas covarage layer
  • set the rule based symbology of layers: @layer_id = @atlas_pagename
  • preview atlas

For automate this process I wrote a python script which takes group of layers, create a .csv table with layer id of each layer in the group, set them the proper symbology, and load table to project. You have to only manually group your species layers and define your group_name and csv_path input in script and run it in python console. Then use the created table as atlas covarage layer.

Grouped layers:

enter image description here Script for Python console:

group_name = "group1"
csv_path = "output/csv/path/table.csv"

root = QgsProject.instance().layerTreeRoot()

group_layers = []
for i in root.findGroup(group_name).findLayers():
    group_layers.append(i.layerId())
    layer = i.layer()
    symbol = QgsSymbol.defaultSymbol(layer.geometryType())
    renderer = QgsRuleBasedRenderer(symbol)
    root_rule = renderer.rootRule()
    rule = root_rule.children()[0]
    rule.setLabel("Atlas")
    rule.setFilterExpression('@layer_id = @atlas_pagename')
    layer.setRenderer(renderer)

with open(csv_path, "w") as f:
    for item in group_layers:
        f.write("%s\n" % item)

uri = (
    'file://{}?type=csv&useHeader=No&geomType=none'
).format(csv_path)

layer = iface.addVectorLayer(
    uri, group_name + "_list", "delimitedtext"
)

https://github.com/kalab-oto/QGIS-Microtools/blob/master/console_scripts/layer_list_csv.py

Generated table:

enter image description here Atlas preview: enter image description here

  • 1
    damn that's impressive... but my method is still way faster – Dawid Zyskowski May 7 at 16:56
  • You're right, I missed that you have more areas, so this is pretty useless for you :). How your species data are stored? In single layer, or as in my answer (one species for layer)? – Oto Kaláb May 9 at 6:54
  • All data in one layer. I figured out I can filter visibility by atlas feature ID, but still haven't found fast way to generate an atlas sheet per every species automatically – Dawid Zyskowski May 13 at 7:55
  • @DawidZyskowski I updated my answer, maybe this helps you. – Oto Kaláb May 15 at 21:50
0

one idea if you have the species occurrence in a grid. create a single table with the list of all species. Them in the Layout, configure Atlas feature with that table. Then go to Layer properties of the species and in Symbology define your type of legend and then for the Column an expression something like this

eval( '"' || attribute( @atlas_feature , 'specie') || '"')
0

Ok, thank you all, it seems that as for now there is no fast automatic "click here and there" way to do this and it requires some manual tweaking with layers one way or another. As for now fastest workflow is: 1. assign individual ID to every species in a layer 2. assign visibility basing on current atlas feature number 3. create atlas extend layer with single polygon copy-pasted in the same spot as many times, as there are species

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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