I'm looking for a better labeling-solution for my projects. It seems to be difficult - but maybe I'm just blind?

My projects: I build printed bike-hike-books. The main scale is 1:75k and there are a city scale of 10k and a overview scale of 200k. Because I like to have a "cartographic" quality of labels placements, I touch every single label and move it to it's best position. I have to do this for every single scale so my labeling columns for 3 scales look like this ('scale 1' stands for 10k 'scale 2' for 75k and 'scale 3' for 200k):

enter image description here

But before I try to explain in detail, I build this simple Example-Project where you can see and test my (old) labeling solution for 3 scales: http://www.map-site.de/tmp/LabelingExample.zip

Well, it is working but:

  • You need labeling columns for every scale
  • You need a layer for every scale

I'm looking for a much better solution without duplicate layers and tons of columns. I count on your creative minds!

EDIT: I added this two very dense map as examples:

enter image description here

There is only one single possible position for "St. Paulus Dom" and it's not any quadrant: enter image description here

Every label has to be moved manually. Some of the labels are not in a quadrant.

  • Do the labels need to accomplish some specific criteria? I don't understand what you mean with "best position". – mgri Feb 23 '17 at 20:22
  • 1
    With "best position" I mean a position according to cartographic claims. It's more subjective. – MAP Feb 24 '17 at 9:26
  • 2
    I found that your example uses a font, 'Noto Sans', that I do not have, and I'm guessing that will be the case for others as well. You can download the font here google.com/get/noto After installing the fonts you have to restart QGIS. – TJ Rockefeller Feb 27 '17 at 19:43
  • Thanks for adding that link - it's the standard font of my Mint installation. – MAP Feb 28 '17 at 13:42

I have to say that what you are requesting is complicated a little bit because you want the labeling to be visible at small scale clearly as well as at large scale (best fit). So, the idea here is how to place the point that can be visible at different scales.

After several testing, I found that instead of creating several columns for each scale range and put coordinates for x and y at fixed points, you can create only one column for priority positions for each point for best location, as you can see below (I followed the locations in your file):

enter image description here

Then, you go to Layer propoerties -> Labels -> Placement -> Offset from point or Around point, both are OK, but I chose Offset from point.

  1. At Quadrant Select Data defined override -> Edit, and enter the following formula:

    enter image description here

    WHEN  $scale >= 200000 THEN  "priority"  
    WHEN  $scale < 200000 and $scale >= 75000 THEN  "priority"   
    WHEN  $scale < 75000 and $scale >=10000 THEN  5
    WHEN  $scale < 10000 THEN 2 

    Here, "Priority" is the location of points defined in the field name Priority

  2. You need to use offset to shift the points for better visibility, and I used the following formula:

    WHEN  $scale >= 200000 THEN '0.001,0'
    WHEN  $scale < 200000 and $scale >= 75000 THEN '0.001,0'
    WHEN  $scale < 75000 and $scale >=10000 THEN '0.0005,0'
    WHEN  $scale < 10000 THEN '0.0001,0'

Here is the output at different scales:

enter image description here

enter image description here

enter image description here

enter image description here

In order to see what each number [0-8] represents in which location, please have a look at following image:

enter image description here

You can control the position of the labels by adding the value corresponding with each position. But unfortunately, you cannot do it by 'click-and-move' approach. You need to do it in the attribute table.


Based on your requirement that 9 quadrant positions are not enough, I found if you select Cartography instead of Offset from point, and select priority, as in the image below, you will have 12 priority positions instead of 9. You need to create a field of Text type, then put only the abbreviation that you want for the best position 'TL', 'TSL', 'T'...etc. Also, you can enter a distance to avoid the label from covering the point.

enter image description here

  • Thats a approach I did not try until now. Do you see any way, to place the label in the quadrant by 'click-and-move'? – MAP Feb 28 '17 at 7:30
  • Unfortunately, you cannot do it by 'click-and-move' approach. You need to do it in the attribute table. But adding 1 column is better than 6 columns for each x,y scale levels. I updated my answer. – ahmadhanb Feb 28 '17 at 7:59
  • 1
    In the last days, I also tried to give a solution but I gave up because I thought the problem was too subjective for offering a more general solution. Instead, the solution by @ahmadhanb seems creative enough for doing it (I didn't test it, though). +1 for me. – mgri Feb 28 '17 at 8:22
  • I agree with you. The subjectivity here is high. It is mainly a personal opinion on how you can judge the locations of labels if they are suitable or not. – ahmadhanb Feb 28 '17 at 8:39
  • 1
    Do not use identify tool to edit the priority locations, it is better to use select tool. Open the attribute table, and choose only to show selected points. Start editing session, and update the location and save edits. The priority location will be updated directly, if you already added the expression in the Data defined override. – ahmadhanb Mar 2 '17 at 7:26

You can get rid of the multiple layers by using expressions.

From what I could see in your example the main difference between the layers is the Data defined Coordinate X Y definitions pointing to the different scale x,y values.

You can accomplish this in a single layer by selecting the dropdowns next to X and Y and selecting edit... which will bring up an expression string builder.

For X you can use something like

if(@map_scale <=10000, "scale1-x", if(@map_scale <=75000, "scale2-x", "scale3-x"))

And for Y you can use something like

if(@map_scale <=10000,  "scale1-y" , if(@map_scale <=75000, "scale2-y", "scale3-y"))

This should use scale1 x,y values if the map scale is less than or equal to 1:10,000 and scale 2 x,y if the map scale is less than or equal to 1:75,000 and scale 3 x,y for anything above that.

If you have to manually position for each scale I don't see how you can get away from scale#-x and scale#-y columns for each level you have defined.

  • I have a high destiny of labels with different weight. I have to place them manually since no automatism is able to do it in a 'real' cartographic way. And the maps will be printed and updated every year so the labeling have to be somewhat static. en.wikipedia.org/wiki/Cartographic_labeling#Placement – MAP Feb 27 '17 at 18:10
  • @MAP OK, so you know you have to manually position items, you just want less layers and columns. – TJ Rockefeller Feb 27 '17 at 19:33
  • This helps for displaying the labels of 3 scales with just one layer. But QGIS is not able to "write back" coordinates via expression. So If I use the scale-expression as you mentioned, I can not move the labels any more. – MAP Feb 28 '17 at 7:25

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.