Zmieniasz alternatywną etykietę, jeśli pierwsza etykieta nie pasuje do QGIS?

10

Próbuję utworzyć mapę do wydrukowania, a wielkość moich wielokątów jest bardzo różna. Ponieważ będzie to mapa odniesienia, muszę opisać każdy wielokąt, ale niektóre nazwy nie będą pasować do wielokąta. W takich przypadkach chciałbym zamiast tego użyć identyfikatora funkcji, a następnie mieć tabelę atrybutów łączącą identyfikator z nazwą.

Chciałbym mieć jakieś wyrażenie, którego mogę użyć, aby wybrać, która etykieta ma być użyta na mapie i które wiersze uwzględnić w tabeli atrybutów. Coś takiego isLabelledmogłoby uwzględniać skalę mapy, długość etykiety, rozmiar czcionki itp.

Ian Turton
źródło
2
Pamiętaj, że dla użytkownika mapy może być mylące, gdy wielokąty tej samej klasy obiektów są oznaczone na różne sposoby i dodatkowo tylko niektóre z nich pojawiają się w tabeli atrybutów.
tallistroan
Myślę o mapie hrabstwa GB
Ian Turton
A co z dynamicznym zmienianiem czcionki w celu dopasowania? Możesz wziąć najdłuższy z wymiarów elementów, podzielić przez liczbę znaków w łańcuchu etykiety i albo wykonać matematykę ze skalą, albo po prostu użyć tego, aby zmienić już ustawiony rozmiar czcionki ... Alternatywnie możesz użyć tej miary (najdłuższy wymiar wymiaru / długość łańcucha) i jeśli jest za długa etykieta z id.
Jesse McMillan,
głównie martwię się o czytelność, więc nie chcę zadzierać z czcionką
Ian Turton
1
Można użyć niestandardowego wyrażenia w języku Python, biorąc etykietę, rozmiar czcionki i skalę oraz zwracając wartość prawda lub fałsz, jeśli będzie pasować. Następnie w silniku wyrażeń użyj klauzuli if do przełączania etykiet. Później opracuję dla ciebie odpowiedź z przykładami.
Jesse McMillan

Odpowiedzi:

8

Oto nieco przybliżony (ale miejmy nadzieję skuteczny) sposób na zrobienie tego.

Najpierw trochę matematyki. Musimy dowiedzieć się, ile znaków przy określonym rozmiarze czcionki może zawierać funkcja. Oto rzeczy / założenia, które należy wiedzieć:

  • przy założeniu jednostek metrycznych (dodana niewielka zmiana poniżej, która może sprawić, że będzie to dla nas działaniem crs.)
  • rozmiar czcionki jest miarą wysokości czcionki. Większość czcionek ma około połowy szerokości i wysokości.
  • przy użyciu pt dla wysokości czcionki, 1pt to z grubsza 0,035 cm
  • zakładając, że twoje paczki są w przybliżeniu prostokątne / regularne

Aby dowiedzieć się, jak długi jest element na ekranie / wydruku, możemy użyć jego najdłuższego wymiaru (długość lub wysokość lub tylko długość, jeśli twoje etykiety są tylko poziome) / skala * 100 (aby przejść z M do CM)

Następnie możemy sprawdzić, czy nasza etykieta będzie pasować.

Można to zrobić w silniku wyrażeń, ale niestandardowe wyrażenie w języku Python byłoby bardziej wydajne. Oto samouczek, jak go utworzyć.

Moje niestandardowe wyrażenie:

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

Następnie użyj tego wyrażenia na etykiecie:

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

Musisz oczywiście podłączyć dowolny atrybut, którego faktycznie używasz, i zmienić rozmiar czcionki z 8 na cokolwiek, którego używasz. Ponadto, ponieważ czcionki różnią się nieco, być może trzeba będzie je nieco poprawić, aby wyglądało poprawnie.

Możesz także użyć tego wyrażenia, aby zmienić kolor na podstawie tego, czy etykieta pasuje, czy nie.


Aby użyć tego wyrażenia poza obszarem mapy (tj. W etykiecie kompozytora lub tabeli atrybutów), potrzebujemy sposobu, aby programowo uzyskać skalę danego elementu mapy. Umieściłem kod, aby to osiągnąć w innej odpowiedzi tutaj . Metoda daje nam wyrażenie getScale („nazwa kompozytora”, „nazwa mapy”), aby włączyć go do naszego wyrażenia:

if(
    labelFits( "yourAttribute" , 8 , getScale('composername','mapname')),
    "yourAttribute",$id)
Jesse McMillan
źródło
1
Myślałem też o czymś podobnym. Zwłaszcza jeśli używasz jednostek mapy i projekcji w metrach. Nowi (ish) operatorzy geometrii również mogą tu pomóc, zakładając, że etykiety są wyśrodkowane na środku ciężkości. Będzie to działać lepiej z czcionką o stałej szerokości (monospaced) niż czcionką proporcjonalną (na przykład, gdy „W” jest znacznie szersze niż „i”). Coś tu jest, ale podejrzewam, że czcionki proporcjonalne i kerning dodadzą złożoności.
Steven Kay,
Możesz użyć pil's imagefont.getsize (). To dałoby ci dokładną szerokość łańcucha renderowanego w wybranej czcionce, ale myślę, że miałoby to duży wpływ na wydajność. Szorstka matematyka powyżej jest znacznie prostsza, zwłaszcza jeśli masz na ekranie setki etykiet
Jesse McMillan
Jedynym drobnym problemem jest to, że funkcja nie działa jak filtr w tabelach atrybutów w kompozytorze wydruku.
Ian Turton
Czy skala mapy różni się w zależności od strony? Spróbuj ręcznie wprowadzić skalę zamiast zmiennej @map_scale. zgaduję, że tabela atrybutów nie ma możliwości poznania skali mapy. (Ponieważ na przykład możesz mieć wiele elementów mapy w kompozytorze w różnych skalach)
Jesse McMillan
1
@iant Zamieściłem link do innego niestandardowego wyrażenia, które programowo uzyska skalę mapy kompozytora.
Jesse McMillan
3

Zduplikuj warstwę, jedną bez symboli, i ustaw różne poziomy powiększenia / ustawienia przeszkód dla etykiet dla każdej z nich.

Tom Chadwin
źródło
1

Miałem podobną sytuację z obowiązkiem oznakowania każdej drogi warstwą drogi. Moim rozwiązaniem było utworzenie płótna w większym rozmiarze, wyeksportowanie do pliku PDF, a następnie wydrukowanie pliku PDF do wymaganego rozmiaru.

Na przykład gotowy produkt musiał mieć format A3. Na płótnie w A3 nie mogłem zmieścić wszystkich etykiet. Zrobiłem więc płótno A2, dzięki czemu wszystkie etykiety były widoczne. Utwórz plik PDF mapy formatu A2 i wydrukuj go w formacie A3.

Johanna
źródło