1

I have a polygon layer published in GeoServer through PostgreSQL (PostGIS) and I am trying to build a legend to use with GetLegendGraphich. The layer is requested as WMS layer in client with Leaflet on an Angular project.

My goal is to build a legend with properties 'fill' and 'fill-opacity' coming from the database (and not hard-coded in the style).

The layer is composed of following data:

  • id (Integer)
  • id_class (Integer)
  • fill_color (String). It is a hexadecimal color code.
  • fill_opacity (BigDecimal)
  • geom (MultiPolygon)

The primary key is {id, id_class}. 'id' is used as a filter:

SELECT id, id_class, fill_color, fill_opacity, geom
FROM table
WHERE id = %id%

So far, I am using fields 'fill_color' and 'fill_opacity' to set the symbology in the layer's SLD style (but without any legend). Like this:

  <NamedLayer>
    <Name>layer_name</Name>
    <UserStyle>
      <Title>layer_title</Title>
      <FeatureTypeStyle>
        
        <Rule>
          <Name>rule_name</Name>
          <Title>rule_title</Title>
          <PolygonSymbolizer>
             <Fill>
               <CssParameter name="fill-opacity">
                    <ogc:PropertyName>fill_opacity</ogc:PropertyName>
               </CssParameter>
               <CssParameter name="fill">
                   <ogc:PropertyName>fill_color</ogc:PropertyName>
               </CssParameter>
             </Fill>
             <Stroke>
                <CssParameter name="stroke">#000000</CssParameter>
                <CssParameter name="stroke-width">0.2</CssParameter>
             </Stroke>
          </PolygonSymbolizer>
        </Rule>

      </FeatureTypeStyle>
    </UserStyle>
  </NamedLayer>

My goal is to build a legend like this one:

My goal is to build a legend like this one:

enter image description here

which I have built using the following SLD style:

  <NamedLayer>
    <Name>layer_name</Name>
    <UserStyle>
      <Title>legend</Title>
      <FeatureTypeStyle>
        
        <Rule>
          <RasterSymbolizer>
            <ChannelSelection>
              <GrayChannel>
                <SourceChannelName>1</SourceChannelName>
              </GrayChannel>
            </ChannelSelection>
            <ColorMap type="values">
              <ColorMapEntry label=" [a - b]" quantity="1" color="#32ce80"/>
              <ColorMapEntry label=" (b - c]" quantity="2" color="#e3e926"/>
              <ColorMapEntry label=" (c - d]" quantity="3" color="#e8ad15"/>
              <ColorMapEntry label=" (d - e]" quantity="4" color="#ec0037"/>
              <ColorMapEntry label=" > e" quantity="5" color="#a0009d"/>
            </ColorMap>
          </RasterSymbolizer>
        </Rule>

      </FeatureTypeStyle>
    </UserStyle>
  </NamedLayer>

So, I could use the first one (which uses PolygonSymbolizer properly) for symbology and the latter for producing a legend image (which would be a hack).

However, I would like to have one style: color + opacity coming from data fields (not hard-coded), and the legend.

I tried to separate each 'id_class' into a different rule, but could not make it work. The fill colors are not used in the legend:

enter image description here

  <NamedLayer>
    <Name>layer_name</Name>
    <UserStyle>
      <Title>layer_title</Title>
      <FeatureTypeStyle>
        
        <Rule>
          <Name>class_1</Name>
          <Title>[a - b]</Title>          
          <ogc:Filter>              
              <ogc:PropertyIsEqualTo>
                  <ogc:PropertyName>id_class</ogc:PropertyName>
                  <ogc:Literal>1</ogc:Literal>                
               </ogc:PropertyIsEqualTo>                                
          </ogc:Filter>          
          <PolygonSymbolizer>
             <Fill>
               <CssParameter name="fill-opacity">
                    <ogc:PropertyName>fill_opacity</ogc:PropertyName>
               </CssParameter>
               <CssParameter name="fill">
                   <ogc:PropertyName>fill_color</ogc:PropertyName>
               </CssParameter>
             </Fill>
             <Stroke>
                <CssParameter name="stroke">#000000</CssParameter>
                <CssParameter name="stroke-width">0.2</CssParameter>
             </Stroke>
          </PolygonSymbolizer>
        </Rule>
        
        <Rule>
          <Name>class_2</Name>
          <Title>(b - c]</Title>          
          <ogc:Filter>              
              <ogc:PropertyIsEqualTo>
                  <ogc:PropertyName>id_class</ogc:PropertyName>
                  <ogc:Literal>2</ogc:Literal>                
               </ogc:PropertyIsEqualTo>                                
          </ogc:Filter>          
          <PolygonSymbolizer>
             <Fill>
               <CssParameter name="fill-opacity">
                    <ogc:PropertyName>fill_opacity</ogc:PropertyName>
               </CssParameter>
               <CssParameter name="fill">
                   <ogc:PropertyName>fill_color</ogc:PropertyName>
               </CssParameter>
             </Fill>
             <Stroke>
                <CssParameter name="stroke">#000000</CssParameter>
                <CssParameter name="stroke-width">0.2</CssParameter>
             </Stroke>
          </PolygonSymbolizer>
        </Rule>
       
        <Rule>
          <Name>class_3</Name>
          <Title>(c - d]</Title>          
          <ogc:Filter>              
              <ogc:PropertyIsEqualTo>
                  <ogc:PropertyName>id_class</ogc:PropertyName>
                  <ogc:Literal>3</ogc:Literal>                
               </ogc:PropertyIsEqualTo>                                
          </ogc:Filter>          
          <PolygonSymbolizer>
             <Fill>
               <CssParameter name="fill-opacity">
                    <ogc:PropertyName>fill_opacity</ogc:PropertyName>
               </CssParameter>
               <CssParameter name="fill">
                   <ogc:PropertyName>fill_color</ogc:PropertyName>
               </CssParameter>
             </Fill>
             <Stroke>
                <CssParameter name="stroke">#000000</CssParameter>
                <CssParameter name="stroke-width">0.2</CssParameter>
             </Stroke>
          </PolygonSymbolizer>
        </Rule>
        
        <Rule>
          <Name>class_4</Name>
          <Title>(d - e]</Title>          
          <ogc:Filter>              
              <ogc:PropertyIsEqualTo>
                  <ogc:PropertyName>id_class</ogc:PropertyName>
                  <ogc:Literal>4</ogc:Literal>                
               </ogc:PropertyIsEqualTo>                                
          </ogc:Filter>          
          <PolygonSymbolizer>
             <Fill>
               <CssParameter name="fill-opacity">
                    <ogc:PropertyName>fill_opacity</ogc:PropertyName>
               </CssParameter>
               <CssParameter name="fill">
                   <ogc:PropertyName>fill_color</ogc:PropertyName>
               </CssParameter>
             </Fill>
             <Stroke>
                <CssParameter name="stroke">#000000</CssParameter>
                <CssParameter name="stroke-width">0.2</CssParameter>
             </Stroke>
          </PolygonSymbolizer>
        </Rule>        

        <Rule>
          <Name>class_5</Name>
          <Title>> e</Title>          
          <ogc:Filter>              
              <ogc:PropertyIsEqualTo>
                  <ogc:PropertyName>id_class</ogc:PropertyName>
                  <ogc:Literal>5</ogc:Literal>                
               </ogc:PropertyIsEqualTo>                                
          </ogc:Filter>          
          <PolygonSymbolizer>
             <Fill>
               <CssParameter name="fill-opacity">
                    <ogc:PropertyName>fill_opacity</ogc:PropertyName>
               </CssParameter>
               <CssParameter name="fill">
                   <ogc:PropertyName>fill_color</ogc:PropertyName>
               </CssParameter>
             </Fill>
             <Stroke>
                <CssParameter name="stroke">#000000</CssParameter>
                <CssParameter name="stroke-width">0.2</CssParameter>
             </Stroke>
          </PolygonSymbolizer>
        </Rule>        
      
      </FeatureTypeStyle>
    </UserStyle>
  </NamedLayer>

https://my_server/geoserver/wms?REQUEST=GetLegendGraphic&VERSION=1.0.0&FORMAT=image/png&LAYER=my_layer

Is there a way or I must use hard-coded fill color values?

4
  • You can create a PNG of the required legend graphic and add that to the layer.
    – Ian Turton
    Mar 8, 2023 at 13:39
  • Tks Ian. The whole point is to change the hex color code directly in the database and have symbology and legend altered. Would your suggestion work like that? Mar 8, 2023 at 13:46
  • Then GeoServer would need to read the entire table for each legend display
    – Ian Turton
    Mar 8, 2023 at 18:57
  • For each id (used in the filter) there are up to five features (rows) (one for each 'id_class'). Would that be a problem? Mar 8, 2023 at 19:12

1 Answer 1

1

You can prepare a style with sections that are meant just legend production, and section just for rendering (or for both). See here:

https://docs.geoserver.org/stable/en/user/styling/sld/extensions/rendering-selection.html#rendering-selection

3
  • 1
    Don't stop at the validation results (it's a formal check only) and try to actually save and use the style. May 10, 2023 at 7:02
  • The answer was helpful. Solves half of my problem, because I can make the polygon's fill colors come from the database like I wanted. However, the legend part still needs hard-coded color values to work with <VendorOption name="inclusion">legendOnly</VendorOption>. Thank you Oct 31, 2023 at 19:50
  • 1
    Yes, there is currently no way to generate such a legend. That would require performing a dataset scan, to find out all unique values (and if you have multiple attributes used in the style, all the unique combinations of values across the different attributes). If this is important to you, see this guide on how to get it included in GeoServer: github.com/geoserver/geoserver/wiki/… Nov 2, 2023 at 13:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.