Comment créer un Atlas basé sur des attributs de point?

9

Essentiellement, je veux produire un atlas basé sur un champ catégoriel dans une couche de points.

c'est-à-dire que j'ai une couche de points de gardiennes d'enfants avec le champ catégorique «Provision». J'ai classé chaque fonctionnalité dans ce domaine avec "After School Club", "Breakfast Club" etc. Une carte des clubs parascolaires, une carte des clubs de petit-déjeuner, etc. Les étendues peuvent être subtilement différentes.

Je pourrais le faire un par un, mais il semble qu'il devrait y avoir un moyen de produire un atlas basé sur l'étendue de chaque catégorie? (Je sens que je manque quelque chose d'évident :))

Ou bien existe-t-il un moyen d'automatiser la création d'une couche polygonale et de l'utiliser comme couverture cachée pour l'atlas?

EDIT: J'ai fait un petit progrès avec cela - vous pouvez utiliser un style basé sur des règles pour activer et désactiver des fonctionnalités pertinentes pour la fonctionnalité de couverture de l'atlas actuelle. cela fonctionne très bien si tout ce que vous voulez faire est d'afficher un ensemble différent de points. Je cherche maintenant à relier cela à un schéma de couleurs et à une légende réactive.

JonoPatterson
la source
1
Il s'agit essentiellement d'un doublon de gis.stackexchange.com/questions/155143
Chris W
Merci Chris - mais je ne sais pas si c'est le cas. Que l'on cherche à demander si vous pouvez faire un sous-atlas pour chaque zone dans un atlas original? par exemple, 4 zones de 4 pages chacune? (Même si j'ai eu du mal à suivre ce qui était demandé)
JonoPatterson
1
Non, vous voulez tous deux créer une série de cartes. La série montre la même étendue de carte et les mêmes informations de base, mais des caractéristiques différentes dans chacune. Mon commentaire là-bas parle et liens pour le faire dans ArcGIS via ce qu'on appelle des requêtes de définition de page - c'est-à-dire que chaque page de l'atlas / du livre de cartes a une requête de définition qui détermine quelles couches / entités sont affichées sur cette page. Il veut une série de séries, où vous voulez juste une seule série. Cependant, je ne sais pas si QGIS offre encore une telle fonctionnalité (je pensais avoir lu une réponse / un commentaire contraire, mais je ne peux pas le trouver maintenant).
Chris W
De plus, dans votre cas, vous pouvez générer des cadres de délimitation en fonction de l'étendue de chaque point partageant les mêmes attributs, puis les utiliser comme fonctionnalités d'index, mais vous avez toujours le problème d'activer et de désactiver automatiquement les différents groupes de points . Même si vous les divisez en calques séparés, sans aucune sorte de requête de définition, il n'y a aucun moyen de désactiver ces points sur une page donnée.
Chris W
Oui, tu es mort. C'est aussi une répétition de celui-ci gis.stackexchange.com/questions/121802/… - donc je pourrais avoir à recourir à le faire manuellement.
JonoPatterson

Réponses:

9

J'ai finalement résolu cela à mes fins, alors voici la solution que j'ai trouvée si cela aide quelqu'un:

Écrivez un script python (le mien à la fin de ceci) qui fait essentiellement ceci:

  1. identifier les catégories uniques dans le champ d'intérêt de la couche de points
  2. pour chaque catégorie, sélectionnez tous les points correspondants et établissez l'étendue de cet ensemble
  3. pour chaque étendue, générez un nouveau polygone dans une couche de couverture d'atlas vierge avec un attribut clé "NomCatégorie"

Cela m'a donné la couche de couverture de l'atlas avec un polygone pour chaque catégorie d'intérêt ressemblant à ceci: Couche de couverture Atlas

Configurez l'atlas et le compositeur d'impression comme d'habitude - ne laissant que le problème de désactiver et d'activer les fonctionnalités.

Pour cela, c'est un peu d'essais et d'erreurs pour déterminer l'ensemble exact d'options:

  1. L'expression ci-dessous vous permet d'obtenir la valeur actuellement conservée dans le champ Nom de catégorie pour la fonction d'atlas actuelle

    attribute ($atlasfeature, 'CategoryName') 
    
  2. Utilisez-le pour créer un style basé sur des règles pour le calque de points le long des lignes de

    attribute ($atlasfeature, 'CategoryName') = PointCategory AND PointCategory = "RedDots"
    
  3. J'avais aussi une règle pour garantir que tous les autres devenaient transparents

    attribute ($atlasfeature, 'CategoryName') IS NOT PointCategory
    

Règles affichées

Tester cela avec l'atlas fonctionne très bien. Enfin, utilisez simplement la même approche pour manipuler les étiquettes affichées, rendre les étiquettes dynamiques et filtrer les tableaux de manière appropriée. Cochez la case «filtrer la légende par le contenu de la carte» est également très efficace si vous ne voulez pas que tous les éléments de légende sur toutes les cartes.

Ensemble d'atlas final:

Atlas basé sur les fonctionnalités

Modifier - comme cela a été demandé, voici mon script:

    from PyQt4.QtCore import *

#main script----------------------------------------------
    #set up the layer references - you will need to change this
targetlayer=QgsMapLayerRegistry.instance().mapLayer("AtlasExtents20150727154732521")
eylayer = QgsMapLayerRegistry.instance().mapLayer("Early_Years_Providers20150727152919862")

#establish the unique categories 
names = getUniqueAttributes(eylayer, 'Mapping_La')

#get a set of boxes
boxset = getBoundings(eylayer, names)

#ensure layer is emptied, then add bounding boxes
deleteBoxes(targetlayer)
createBoxes(targetlayer, boxset)
 #end main script----------------------------------------------   


 #------functions-------#
#gets unique set of attributes - returns a set()
def getUniqueAttributes(layer, fieldname):
    values = set()
    for feature in layer.getFeatures():
        values.add(feature[fieldname])
    return values

#quickly selects all points on a layer, given a query 
def selectionQuick(layer, queryitem):
    layer.removeSelection ()

    #hardcoded field name
    expr = QgsExpression( "\"Mapping_La\" = '" + queryitem +"'")
    it = layer.getFeatures( QgsFeatureRequest( expr ) )
    ids = [i.id() for i in it]
    layer.setSelectedFeatures( ids )

#for a set of unique items, get bounding boxes 
def getBoundings(layer, itemset):
    bboxes = {}
    for itemname in itemset:
        selectionQuick(layer,itemname)
        box = layer.boundingBoxOfSelected()
        bboxes[itemname] = box
    return bboxes

#for a layer create a bunch of boxes
def createBoxes(layer, boxes):
    id=0
    for boxkey in boxes:
        id = id +1
        box=boxes[boxkey]
        feat = QgsFeature(layer.pendingFields())
        geom = QgsGeometry.fromRect(box)
        feat.setAttribute('id', id)
        #hardcoded field name
        feat.setAttribute('CareType', boxkey)
        feat.setGeometry(geom)
        (res, outFeats) = layer.dataProvider().addFeatures([feat])

def deleteBoxes(layer):
        ids = [f.id() for f in layer.getFeatures()]
        layer.dataProvider().deleteFeatures( ids )
JonoPatterson
la source
3
@JonoPatterson si vous partagez maintenant également votre script python mentionné dans le début, ce serait la meilleure réponse de tous les temps;)
Bernd V.
Ok va le faire - bien que son brut soit prêt, il aura donc besoin de quelques ajustements (je n'ai pas fait de codage depuis des années!). Quelle est la meilleure façon de le faire - il suffit de coller dans une boîte à code?
JonoPatterson
@JonoPatterson Merci beaucoup pour le script. Pour moi en tant que débutant, cela semble déjà très bien :). Je suis sûr que j'en aurai besoin bientôt.
Bernd V.
Vos exemples d'expressions sont un peu faux - ce devrait être "$ atlasfeature", pas "$ atlasfeatureid"
ndawson