This page last changed on Nov 29, 2005 by dblasby.

Controlling Label Placement

Controlling where the WMS server places labels with SLD is bit complex. The SLD specification only defines the most basic way of controlling placement explictly says that defining more control is "a real can of worms". Geoserver fully supports the SLD specification plus adds a few extra parameters so you can make pretty maps.

The Future

Labeling improvements are an ongoing process. Please leave suggestions on the geotools-devel or geoserver-devel list.

Basic SLD Placement

The SLD specification indicates two types of LabelPlacement:

  • for Point Geometries ("PointPlacement")
  • for Linear (line) geometries ("LinePlacement")
Relative to Where?

See below for the actual algorithm details, but:
Polygons are intersected with the viewport and the centroid is used.
Lines are intersected with the viewport and the middle of the line is used.

<xsd:element name="PointPlacement">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element ref="sld:AnchorPoint" minOccurs="0"/>
        <xsd:element ref="sld:Displacement" minOccurs="0"/>
        <xsd:element ref="sld:Rotation" minOccurs="0"/>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
  ...
  <xsd:element name="LinePlacement">    
      <xsd:complexType>
        <xsd:sequence>
          <xsd:element ref="sld:PerpendicularOffset" minOccurs="0"/>
        </xsd:sequence>
      </xsd:complexType>
  </xsd:element>

PointPlacement

When you use a <PointPlacement> element, the geometry you are labeling will be reduced to a single point (usually the "middle" of the geometry - see algorithm below for details). You can control where the label is relative to this point using the options:

Option Meaning
AnchorPoint This is relative to the LABEL. Using this you can do things such as center the label on top of the point, have the label to the left of the point, or have the label centered under the point.
Displacement This is in PIXELS and lets you fine-tune the location of the label.
Rotation This is the clockwise rotation of the label in degrees.

The best way to understand these is with examples:

AnchorPoint

The anchor point determines where the label is placed relative to the label point. These measurements are relative to the bounding box of the label. The (x,y) location inside the label's bounding box (specified by the AnchorPoint) is placed at the label point.


The anchor point is defined relative to the label's bounding box. The bottom left is (0,0), the top left is (1,1), and the middle is (0.5,0.5).

<PointPlacement>
	<AnchorPoint>
	  <AnchorPointX>
	  0.5
	  </AnchorPointX>
	  <AnchorPointY>
	  0.5
	  </AnchorPointY>
	</AnchorPoint>
</PointPlacement>

By changing the values, you can control where the label is placed.

(x=0,y=0.5) DEFAULT - place the label to the right of the label point (x=0.5,y=0.5) - place the centre of the label at the label point
(x=1,y=0.5) - place the label to the left of the label point (x=0.5,y=0) - place the label centered above the label point

Displacement

Displacement allows fine control of the placement of the label. The displacement values are in pixels and simply move the location of the label on the resulting image.

<PointPlacement>
 <Displacement>
   <DisplacementX>
      10
   </DisplacementX>
   <DisplacementY>
       0
   </DisplacementY>
 </Displacement>
</PointPlacement>
displacement of x=10 pixels
compare with anchor point (x=0,y=0.5) above
displacement of y=-10 pixels
compare with anchor point (x=0.5,y=1.0) not shown

Rotation

Rotation is simple - it rotates the label clockwise the number of degrees you specify. See the examples below for how it interacts with AnchorPoints and displacements.

<Rotation>
  45
</Rotation>
simple 45 degrees rotation 45 degrees rotation with anchor point (x=0.5,y=0.5)
45 degrees with 40 pixel X displacement 45 degrees rotation with 40 pixel Y displacement
with anchor point (x=0.5,y=0.5)

LinePlacement

When you are labeling a line (i.e. a road or river), you can specify a <LinePlacement> element. This tells the labeling system two things:
(a) that you want Geoserver to determine the best rotation and placement for the label (b) a minor option to control how the label is placed relative to the line.

The line placement option is very simple - it only allows you to move a label up-and-down from a line.

<xs:elementname="LinePlacement">
 <xs:complexType>
   <xs:sequence>
     <xs:element ref="sld:PerpendicularOffset" minOccurs="0"/>
   </xs:sequence>
 </xs:complexType>
</xs:element>
...
<xs:element name="PerpendicularOffset" type="sld:ParameterValueType"/>

This is very similiar to the DisplacementY option (see above).

<LabelPlacement>
  <LinePlacement>
    <PerpendicularOffset>
       10
    </PerpendicularOffset>	       
  </LinePlacement>
</LabelPlacement>
PerpendicularOffset=0 PerpendicularOffset=10 pixels

Summary of SLD options

Geoserver Specific Enhanced Options

These specific enhancements could change

The labeling process is an on going task, and new options can be added in the future. Check back here or visit the geotools-devel or geoserver-devel mailing list.

Priority Labeling (<Priority>)

Geoserver has extended the standard SLD to also include priority labeling. This allows you to control which labels are rendered in preference to other labels.

For example, lets assume you have a dataset like this:

City Name   | population
-------------+------------
 Yonkers     |     197,818
 Jersey City |     237,681
 Newark      |     280,123
 New York    |   8,107,916

Most people don't know where "Yonkers" city is, but do know where "New York" city is. On our map, we want to give "New York" priority so its more likely to be labeled when its in conflict (overlapping) "Yonkers".

Standard SLD Behavior

If you do not have a <Priority> tag in your SLD then you get the default SLD labeling behavior. This basically means that if there's a conflict between two labels, there is no 'dispute' mechanism and its random which label will be displayed.

In our TextSymbolizer we can put an Expression to retreive or calculate the priority for each feature:

<Priority>
    <PropertyName>population</PropertyName>
</Priority>


Location of the cities (see population data above)


New York is labeled in preference to the less populated cities. Without priority labeling, "Yonkers" could be labeled in preference to New York, making a difficult to interpret map.


Notice that larger cities are more readily named than smaller cities.

Grouping Geometries (<VendorOption name="group">)

Sometime you will have a set of related features that you only want a single label. The grouping option groups all features with the same label text, then finds a representative geometry for the group.

Roads datasets are an obvious example - you only want a single label for all of "main street", not a label for every piece of "main street."


When the grouping option is off (default), grouping is not performed and each geometry is labeled (space permitting).


With the grouping option on, all the geometries with the same label are grouped together and the label position is determined from ALL the geometries.

Geometry Representative Geometry
Point Set first point inside the view rectangle is used.
Line Set lines are (a) networked together (b) clipped to the view rectangle (c) middle of the longest network path is used.
Polygon Set polygons are (a) clipped to the view rectangle (b) the centroid of the largest polygon is used.
<VendorOption name="group">yes</VendorOption>
Warning

Watch out - you could group together two sets of features by accident. For example, you could create a single group for "Paris" which contains features for Paris (France) and Paris (Texas).

Overlapping and Separating Labels (<VendorOption name="spaceAround">)

By default geoserver will not put labels "on top of each other". By using the spaceAround option you can allow overlaps to overlap and you can also add extra space around a label.

<VendorOption name="spaceAround">10</VendorOption>


Default behavior ("0") - the bounding box of a label cannot overlap the bounding box of another label.


With a negative spaceAround value, overlapping is allowed.


With a spaceAround value of 10 for all TextSymbolizers, each label will be 20 pixels apart from each other (see below).

NOTE: the value you specify (an integer in pixels) actually provides twice the space that you might expect. This is because you can specify a spaceAround for one label as 5, and for another label (in another TextSymbolizer) as 3. The distance between them will be 8. For two labels in the first symbolizer ("5") they will each be 5 pixels apart from each other, for a total of 10 pixels!

Interaction with different values in different TextSymbolizers

You can have multiple TextSymbolizers in your SLD file, each with a different spaceAround option. This will normally do what you would think if all your spaceAround options are >=0. If you have negative values ('allow overlap') then these labels can overlap labels that you've said should not be overlapping. If you dont like this behavior, its not too difficult to change - feel free to submit a patch!

Goodness of Fit

Geoserver will remove labels if they are a particularly bad fit for the geometry they are labeling.

Currently, there's no way to easily change this values (MIN_GOODNESS_FIT = 0.7).

Geometry Goodness of Fit Algorithm
Point Always returns 1.0 since the label is at the point
Line Always returns 1.0 since the label is always placed on the line.
Polygon The label is sampled approximately at every letter. The distance from these points to the polygon is determined and each sample votes based on how close it is to the polygon. (see LabelCacheDefault#goodnessOfFit())

Geoserver/Geotools Labeling Algorithm Summary


point_x15y0_5.gif (image/gif)
point_x0y0_5.gif (image/gif)
point_x0_5y0_5.gif (image/gif)
point_x0_5y0.gif (image/gif)
label_bbox.gif (image/gif)
point_x0y1_displacey10.gif (image/gif)
point_x0y0_5_displacex10.gif (image/gif)
rot3.gif (image/gif)
rot2.gif (image/gif)
rot1.gif (image/gif)
rot4.gif (image/gif)
lp_2.gif (image/gif)
lp_1.gif (image/gif)
priority_some.gif (image/gif)
priority_all.gif (image/gif)
priority_lots.gif (image/gif)
priority_lots.gif (image/gif)
group_yes.gif (image/gif)
group_not.gif (image/gif)
space_neg.gif (image/gif)
space_neg.gif (image/gif)
space_10.gif (image/gif)
space_10.gif (image/gif)
space_0.gif (image/gif)
space_0.gif (image/gif)
Document generated by Confluence on Jan 16, 2008 23:27