3

I want to load a WMS with PyQGIS. I know this is possible on version 2.18 If it is done with the graphical Interface by checking on the Use contextual WMS legend

Load WMS and its legend from QGIS Graphical Interface

Now I manage to load a WMS with PyQGIS but I can not figure how to load the WMS and its legend.

Below there is partial working code snippet:

urlWithParams = "url=http://www.geoportaligm.gob.ec/50k/wms&format=image/png&layers=igm:acequia_l&styles=&crs=EPSG:32717"
rlayer = QgsRasterLayer(urlWithParams, 'testing', 'wms')
rlayer.isValid() 
QgsMapLayerRegistry.instance().addMapLayer(rlayer)
4
  • I this a geoserver specific question as per tag, or is it a generic WMS question? Normally I would expect that you would need to parse the GetCapabilities response to find the URL for the legend (normally a GetLegendGraphic request) relevant to the style you have selected for the specific layer.
    – nmtoken
    Commented Mar 1, 2018 at 16:48
  • Hi, indeed you can do it with a specific GetLegendGraphic request from geoserver, nevertheless I am looking a way of doing it using PyQGIS. The way It is shown on the code above only adds the wms but it dismiss the legend. In the end my objective is to load a WMS with its legend with the PyQGIS API. Hope it helps to clarify the question.
    – George
    Commented Mar 1, 2018 at 17:53
  • 1
    A WMS may have multiple layers and each layer may have multiple styles each with it's own legend. So do you want to request the appropriate legend using PyQGIS (in which case I can't see any other way than parse the GetCapabilities in PyQGIS as a first step), or if not, what is it you want PyQGIS to do? Construct your own legend based on the pixel values of the image??
    – nmtoken
    Commented Mar 1, 2018 at 18:50
  • Thanks for your comment but I think I am not making myself clear. For example if I add this layer using the GUI, QGIS shows automatically the legend on the left side. On the other hand if I go into the python console and type the lines of code updated above. Legend is never shown. Thanks for your help
    – George
    Commented Mar 2, 2018 at 15:55

2 Answers 2

4

When you use QGIS to Add a WMS Layer through the GUI, when you have selected the service URL and click connect, in the background QGIS runs a WMS GetCapabilities request.

GetCapabilities request when connecting to a WMS

If you don't click the Use Contextual WMS Legend option then the legend that appears is a GetLegendGraphic request like below:

http://ogc.bgs.ac.uk/cgi-bin/BGS_BGS-HPA_Radon_Potential/wms?language=eng&version=1.3.0&service=WMS&request=GetLegendGraphic&sld_version=1.1.0&layer=GBR_BGS-HPA_625K_RADON_POTENTIAL&format=image/png&STYLE=default&&TRANSPARENT=true

This URL is parsed from the GetCapabilities response for the selected layer/style. The legend generated has no context, it shows all the classes for the map.

GetLegendGraphic (non contextual)

If you do click the Use Contextual WMS Legend option, you still have a GetLegendGraphic request, but this time the request has additional parameters added to the parsed GetLegendGraphic URL to add context.

The contextual GetLegendGraphic request should append CRS/SRS depending on the WMS version, BBOX (in the coordinates of the CRS/SRS), and the width and height (of the GetMap image providing the context), so if your GetMap request is like:

http://ogc.bgs.ac.uk/cgi-bin/BGS_BGS-HPA_Radon_Potential/wms?language=eng&&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&BBOX=55.02958881675145619,-4.984571910596027777,57.17968296470549205,-2.783458579470199368&CRS=EPSG:4326&WIDTH=906&HEIGHT=885&LAYERS=GBR_BGS-HPA_625K_RADON_POTENTIAL&STYLES=default&FORMAT=image/png&DPI=96&MAP_RESOLUTION=96&FORMAT_OPTIONS=dpi:96&TRANSPARENT=TRUE

Your contextual GetLegendGraphic request should be like:

http://ogc.bgs.ac.uk/cgi-bin/BGS_BGS-HPA_Radon_Potential/wms?language=eng&version=1.3.0&service=WMS&request=GetLegendGraphic&sld_version=1.1.0&layer=GBR_BGS-HPA_625K_RADON_POTENTIAL&format=image/png&STYLE=default&&TRANSPARENT=true&BBOX=55.02958881675145619,-4.984571910596027777,57.17968296470549205,-2.783458579470199368&CRS=EPSG:4326&WIDTH=906&HEIGHT=885&

The legend returned is contextual, it only shows classes that appear in the associated GetMap request. So as there are no areas > 499.99 Bqm3 in the map, the contextual legend doesn't have this class (red in the non-contextual legend).

GetMap image

GetLegendGraphic (contextual)

In your example the service has an endpoint like:

http://www.geoportaligm.gob.ec/50k/wms?

A GetCapabilities request can be:

http://www.geoportaligm.gob.ec/50k/wms?service=WMS&request=GetCapabilities&

Your example layer igm:acequia_l has two styles (though they look the same to me, so perhaps not the best example)

<Style>
    <Name>acequia_l_escala</Name>
    <Title>acequia</Title>
    <LegendURL width="67" height="40">
        <Format>image/png</Format>
        <OnlineResource
         xmlns:xlink="http://www.w3.org/1999/xlink"
         xlink:type="simple"
         xlink:href="http://www.geoportaligm.gob.ec:80/50k/ows?service=WMS&request=GetLegendGraphic&format=image%2Fpng&width=20&height=20&layer=igm%3Aacequia_l"/>
    </LegendURL>
</Style>
<Style>
    <Name>acequia_l</Name>
    <Title>acequia</Title>
    <LegendURL width="67" height="40">
        <Format>image/png</Format>
        <OnlineResource
         xmlns:xlink="http://www.w3.org/1999/xlink"
         xlink:type="simple"
         xlink:href="http://www.geoportaligm.gob.ec:80/50k/ows?service=WMS&request=GetLegendGraphic&format=image%2Fpng&width=20&height=20&layer=igm%3Aacequia_l&style=acequia_l"/>
    </LegendURL>
</Style>

GetLegendGraphic (non contextual) for style acequia_l_escala for layer igm:acequia_l:

GetLegendGraphic (non contextual) for style acequia_l_escala

GetLegendGraphic (non contextual) for style acequia_l for layer igm:acequia_l:

GetLegendGraphic (non contextual) for style acequia_l

At the moment you have urlWithParams = "url=http://www.geoportaligm.gob.ec/50k/wms&format=image/png&layers=igm:acequia_l&styles=&crs=EPSG:32717" if this is intended to a test URL that generates the legend you will need to change that to be an appropriate contextual GetLegendGraphic request.

In your live code, you will need to work out how to split up the contextual and non-contextual components of the URL, because the contextual component changes every time you move/zoom the map.

In your live code you will probably need to work out which named style to use per selected layer, though you may be able to miss it out and go with the default by using style&

3
  • Thanks for taking your time and give such a nice explanation. Nevertheless I am looking for doing it by means of python code. If you try to run the code provided within the python console, you will find that this method loads the data but there is no legend. Could you give me a hand with that?
    – George
    Commented Mar 4, 2018 at 4:07
  • I understand you're trying to do it with Python, I know what PyQGIS is. The it in question though is as I have described, that is what you will need to do programmatically. If your urlWithParams = "url=http://www.geoportaligm.gob.ec/50k/wms&format=image/png&layers=igm:acequia_l&styles=&crs=EPSG:32717" is meant to be the URL that generates the contextual legend then you will need replace that with an appropriate GetLegendGraphic request. You will need to split the contextual and noncontextual components, as the contextual part changes as your zoom/move the map.
    – nmtoken
    Commented Mar 4, 2018 at 4:42
  • Note, GIS.SE, is not a code writing service, my answer is to help you understand you need a GetLegendGraphic request.
    – nmtoken
    Commented Mar 4, 2018 at 4:45
2

You need to set the contextualWMSLegend=1 and don't forget to set the style property in the URL of the layer.

For example:

    quri = QgsDataSourceURI()
    quri.setParam("layers", ’usa:states’)
    quri.setParam("styles", ’xxx’)
    quri.setParam("format", ’image/png’)
    quri.setParam("crs", ’EPSG:4326’)
    quri.setParam("contextualWMSLegend", ’1’) # <---- here 
    quri.setParam("url", ’https://my_auth_enabled_server_ip/wms’)
    rlayer = QgsRasterLayer(quri.encodedUri(), ’states’, ’wms’)

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.