Changer d'étiquette alternative si la première étiquette ne tient pas dans QGIS?


10

J'essaie de créer une carte à imprimer et la taille de mes polygones varie considérablement. Comme ce sera une carte de référence, j'ai besoin d'étiqueter chaque polygone, mais certains noms ne rentreront pas dans le polygone. Dans ces cas, j'aimerais utiliser l'ID de fonctionnalité à la place, puis avoir une table d'attributs reliant l'ID au nom.

Ce que je voudrais faire, c'est avoir une sorte d'expression que je peux utiliser pour sélectionner quelle étiquette utiliser sur la carte et quelles lignes inclure dans la table attributaire. Quelque chose comme isLabelledça pourrait prendre en compte l'échelle de la carte, la longueur de l'étiquette, la taille de la police, etc.


2
Gardez à l'esprit que cela peut prêter à confusion pour l'utilisateur de la carte, lorsque les polygones de la même classe d'entités sont étiquetés de différentes manières et en plus seuls certains d'entre eux apparaissent dans une table attributaire.
tallistroan

Je pense à une carte du comté de GB
Ian Turton

Qu'en est-il de la modification dynamique de la police pour l'adapter? Vous pouvez prendre la plus longue des dimensions des fonctionnalités, diviser par le nombre de caractères dans la chaîne d'étiquette, et soit faire un peu de calcul avec l'échelle ou simplement l'utiliser pour modifier la taille de police déjà définie ... Alternativement, vous pouvez utiliser cette mesure (la plus longue dimension / len de la chaîne) et s'il est trop long, étiquetez avec l'id.
Jesse McMillan

la plupart du temps, je suis préoccupé par la lisibilité, donc je ne veux pas jouer avec la taille de la police
Ian Turton

1
Vous pouvez utiliser une expression personnalisée Python prenant l'étiquette, la taille de la police et l'échelle et renvoyant true ou false si cela convient. Ensuite, dans le moteur d'expression, utilisez une clause if pour changer d'étiquette. Je vais trouver une réponse pour vous plus tard avec des exemples.
Jesse McMillan

Réponses:


8

Voici une façon quelque peu approximative (mais si tout va bien efficace) de le faire.

D'abord un peu de maths. Nous devons déterminer combien de caractères à une certaine taille de police une fonctionnalité peut contenir. Voici les choses / hypothèses à savoir:

  • en supposant des unités métriques, (ajout d'un léger changement ci-dessous qui peut faire que cela fonctionne pour nous pieds crs.)
  • la taille de police est une mesure de la hauteur de police. La plupart des polices sont environ deux fois plus larges que hautes.
  • en utilisant pt pour la hauteur de police, 1pt est approximativement 0,035 cm
  • en supposant que vos colis sont à peu près rectangulaires / réguliers

Pour savoir combien de temps un élément est affiché à l'écran / imprimé, nous pouvons utiliser sa dimension la plus longue (longueur ou hauteur, ou simplement la longueur si vos étiquettes sont horizontales uniquement) / échelle * 100 (pour passer de M à CM)

Ensuite, nous pouvons voir si notre étiquette conviendrait.

Vous pouvez tout faire dans le moteur d'expression, mais une expression python personnalisée serait plus efficace. Voici un tutoriel sur la façon d'en créer un.

Mon expression personnalisée:

from qgis.core import *
from qgis.gui import *

@qgsfunction(args='auto', group='Custom')
def labelFits(labelStr, fontPt, scaleM, feature, parent):
    # returns true if a label will fit in the feature at a given
    # font size and scale

    bbox = feature.geometry().boundingBox()

    # for CRS in us foot
    # fontWidth = fontPt * 0.0875

    # for CRS in metric
    # 1pt = 0.035CM
    fontWidth = fontPt * 0.035 * 0.5

    # length of maximum dimension on-screen/print in CM
    labelRoom =  max(bbox.width(),bbox.height()) / scaleM * 100

    # approx length of our label in CM based on font height * 0.5
    labelLen = len(labelStr) * fontWidth

    if labelRoom > labelLen:
        return True
    else:
        return False

Ensuite, utilisez simplement cette expression dans l'étiquette:

if(labelFits( "yourAttribute" , 8 , @map_scale ), "yourAttribute",$id)

Vous devrez bien sûr brancher l'attribut que vous utilisez réellement, et changer la taille de police de 8 à celle que vous utilisez. De plus, comme les polices varient beaucoup, vous devrez peut-être les modifier un peu jusqu'à ce qu'elles semblent correctes.

Vous pouvez également utiliser cette expression pour faire des choses comme changer la couleur en fonction de l'adéquation ou non de l'étiquette.


Pour utiliser cette expression en dehors du canevas de carte (c'est-à-dire dans une étiquette de compositeur ou une table d'attributs), nous avons besoin d'un moyen d'obtenir par programme l'échelle d'un élément de carte donné. J'ai posté du code pour accomplir cela dans une autre réponse ici La méthode ici nous donne une expression getScale ('composername', 'mapname') afin de l'intégrer dans notre expression:

if(
    labelFits( "yourAttribute" , 8 , getScale('composername','mapname')),
    "yourAttribute",$id)

1
Je pensais aussi à quelque chose de similaire. Surtout si vous utilisez des unités de carte et une projection en mètres. Les nouveaux opérateurs de géométrie (ish) pourraient également aider ici, en supposant que les étiquettes sont centrées sur le centroïde. Cela fonctionnera mieux avec une police à largeur fixe (à espacement fixe) qu'une police proportionnelle (où un «W» est beaucoup plus large qu'un «i», par exemple). Vous êtes sur quelque chose ici, mais je pense que les polices proportionnelles et le crénage ajouteront de la complexité.
Steven Kay

Vous pouvez utiliser l'imagefont.getsize () de pil. Cela vous donnerait une largeur exacte d'une chaîne rendue dans la police choisie, mais je pense que cela aurait un impact majeur sur les performances. Le calcul approximatif ci-dessus est beaucoup plus simple, surtout si vous avez des centaines d'étiquettes à l'écran
Jesse McMillan

Le seul problème mineur est que la fonction ne semble pas fonctionner comme un filtre dans les tables d'attributs du compositeur d'impression.
Ian Turton

L'échelle de votre carte varie-t-elle d'une page à l'autre? Essayez de mettre manuellement l'échelle au lieu de la variable @map_scale. je suppose que la table attributaire n'a aucun moyen de connaître l'échelle de votre carte. (Parce que par exemple, vous pouvez avoir plusieurs éléments de carte dans le compositeur à différentes échelles)
Jesse McMillan

1
@iant J'ai publié un lien vers une autre expression personnalisée qui obtiendra l'échelle de votre carte de compositeur par programmation.
Jesse McMillan

3

Dupliquez le calque, un sans symbologie, et définissez différents niveaux de zoom / paramètres d'obstacles pour les étiquettes pour chacun.


1

J'ai eu une situation similaire avec l'obligation d'étiqueter chaque route dans une couche de route. Ma solution était de créer le canevas à une plus grande taille, d'exporter au format PDF puis d'imprimer le PDF à la taille requise.

Par exemple, le produit fini devait être A3. Sur la toile en A3, je ne pouvais pas tenir toutes les étiquettes. J'ai donc réalisé la toile A2 et cela a permis de voir toutes les étiquettes. Créez un PDF de la carte de taille A2 et imprimez-le au format A3.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.