Mudando para etiqueta alternativa se a primeira etiqueta não couber no QGIS?

10

Estou tentando criar um mapa para imprimir e o tamanho dos meus polígonos varia muito. Como esse será um mapa de referência, preciso rotular todos os polígonos, mas alguns dos nomes não cabem no polígono. Nesses casos, eu gostaria de usar o ID do recurso e, em seguida, fazer com que uma tabela de atributos vincule o ID ao nome.

O que eu gostaria de fazer é ter algum tipo de expressão que eu possa usar para selecionar qual rótulo usar no mapa e quais linhas incluir na tabela de atributos. Algo assim isLabelledseria capaz de levar em consideração a escala do mapa, o tamanho da etiqueta, o tamanho da fonte etc.

Ian Turton
fonte
2
Lembre-se de que pode ser confuso para o usuário do mapa, quando polígonos da mesma classe de recurso são rotulados de maneiras diferentes e, além disso, apenas alguns deles aparecem em uma tabela de atributos.
tallistroan
Estou pensando em um mapa do condado de GB
Ian Turton
Que tal mudar dinamicamente a fonte para caber? Você pode ter a maior dimensão das feições, dividir por quantos caracteres na sequência de caracteres do rótulo e fazer algumas contas com a escala ou apenas usá-la para alterar o tamanho da fonte já definido ... Como alternativa, você pode usar essa medida (a mais longa dimensão do recurso / len da string) e, se for um rótulo muito longo com o ID.
Jesse McMillan
principalmente eu estou preocupado com a legibilidade, então eu não quero mexer com o tamanho da fonte
Ian Turton
1
Você pode usar uma expressão personalizada do Python pegando o rótulo, o tamanho da fonte e a escala e retornando verdadeiro ou falso, se for adequado. Em seguida, no mecanismo de expressão, use uma cláusula if para alternar rótulos. Mais tarde, elaborarei uma resposta para você com exemplos.
Jesse McMillan

Respostas:

8

Aqui está uma maneira aproximada (mas espero que eficaz) de fazer isso.

Primeiro um pouco de matemática. Precisamos descobrir quantos caracteres em um determinado tamanho de fonte um recurso pode conter. Aqui, coisas / suposições a saber:

  • assumindo unidades métricas (adicionou uma pequena alteração abaixo, o que pode fazer com que isso funcione para nós pés crs.)
  • tamanho da fonte é uma medida da altura da fonte. A maioria das fontes tem metade da largura e é alta.
  • usando pt para altura da fonte, 1pt é aproximadamente 0.035CM
  • assumindo que suas encomendas são aproximadamente retangulares / regulares

Para descobrir quanto tempo um item está na tela / impressão, podemos usar a sua dimensão mais longa (comprimento ou altura, ou apenas se as etiquetas forem horizontais) / escala * 100 (para passar de M para CM)

Então podemos ver se nosso rótulo se encaixaria.

Você pode fazer tudo isso no mecanismo de expressão, mas uma expressão python personalizada seria mais eficiente. Aqui está um tutorial sobre como criar um.

Minha expressão personalizada:

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

Em seguida, basta usar essa expressão no rótulo:

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

Você precisará conectar qualquer atributo que esteja usando, é claro, e alterar o tamanho da fonte de 8 para o que estiver usando. Além disso, como as fontes variam bastante, talvez você precise ajustá-las um pouco até que pareça correta.

Você também pode usar essa expressão para fazer coisas como mudar a cor com base se o rótulo se encaixa ou não.


Para usar essa expressão fora da tela do mapa (ou seja, em um rótulo do compositor ou em uma tabela de atributos), precisamos de uma maneira de obter programaticamente a escala de um determinado item do mapa. Eu publiquei o código para fazer isso em outra resposta aqui. O método nos fornece uma expressão getScale ('composername', 'mapname') para incorporá-lo à nossa expressão:

if(
    labelFits( "yourAttribute" , 8 , getScale('composername','mapname')),
    "yourAttribute",$id)
Jesse McMillan
fonte
1
Eu estava pensando em algo semelhante também. Especialmente se estiver usando unidades de mapa e uma projeção em metros. Os novos operadores de geometria (ish) também podem ajudar aqui, assumindo que os rótulos estejam centralizados no centróide. Isso funcionará melhor com uma fonte de largura fixa (monoespaçada) do que uma fonte proporcional (onde um 'W' é muito mais amplo que um 'i', por exemplo). Você está interessado em algo aqui, mas eu suspeito que fontes proporcionais e kerning irão adicionar complexidade.
Steven Kay
Você pode usar imagefont.getsize () de pil. Isso daria uma largura exata de uma sequência renderizada na fonte escolhida, mas acho que isso teria um grande impacto no desempenho. A matemática áspera acima é muito mais simples, especialmente se você tem centenas de rótulos na tela
Jesse McMillan
O único problema menor é que a função parece não funcionar como um filtro nas tabelas de atributos no compositor de impressão.
Ian Turton
A escala do seu mapa varia de página para página? Tente colocar manualmente a escala em vez da variável @map_scale. meu palpite seria que a tabela de atributos não tem como saber a escala do seu mapa. (Porque, por exemplo, você poderia ter vários itens de mapa no compositor em diferentes escalas)
Jesse McMillan
1
@iant Publiquei um link para outra expressão personalizada que obterá a escala do seu mapa do compositor programaticamente.
precisa saber é o seguinte
3

Duplique a camada, uma sem simbologia, e defina diferentes níveis de zoom / configurações de obstáculos para os rótulos de cada uma.

Tom Chadwin
fonte
1

Eu tive uma situação semelhante com a obrigação de rotular todas as estradas em uma camada de estrada. Minha solução foi criar a tela em um tamanho maior, exportar para PDF e depois imprimi-lo no tamanho necessário.

Por exemplo, era necessário que o produto final fosse A3. Na tela do A3, eu não conseguia encaixar todas as etiquetas. Então eu fiz a tela A2 e isso permitiu que todos os rótulos fossem vistos. Crie um PDF do mapa de tamanho A2 e imprima-o como A3.

Johanna
fonte