2

I am working with OWSLib in Python and I am trying to read a WMS of the Corine land cover in Ireland for the year 2000. Below you can see the request of the WMS.

from owslib.wms import WebMapService
ireland_wms = WebMapService('https://gis-test.epa.ie/geoserver/ows?SERVICE=WMS&')

Then I print some general info about the layer of interest.

def layer_report(service, layer_name):
  print(f"WMS general info:\n")
  print(f"WMS version: {service.identification.version}")
  print(f"WMS title: {service.identification.title}")
  print(f"WMS abstract: {service.identification.abstract}")
  print(f"Provider name: {service.provider.name}")
  print(f"Provider address: {service.provider.contact.address}")
  print(f"\nLayer info:\n")
  print('- Title: ', service.contents[layer_name].title)
  print('- BoundingBox: ', service.contents[layer_name].boundingBox)
  print('- BoundingBoxWGS84: ', service.contents[layer_name].boundingBoxWGS84)
  print('- CrsOptions: ', service[layer_name].crsOptions)
  print('- Format Options: ', service.getOperationByName('GetMap').formatOptions)
  print('- Layer styles: ', service[layer_name].styles)
  print('- Operations ', [op.name for op in service.operations])

layer_report(ireland_wms, 'EPA:LAND_CLC00Rev')

and I get the following output

enter image description here

Now I have the legend that corresponds to type of Land cover, If I click on link shown in the above picture I get the following legend.

enter image description here

Now I would like to know if there is any way to gain more information about the legend. In particular, I would like to get, if it is possible, the color codes of the legend in order to use them for plotting. Is there any way to do this using OWSLib or any other library which is compatible with Python?

3
  • 1
    I doubt that the color-codes are somewhere stored in the wms-specs... why not use a image-editing software to determine the codes from the legend? (it's maybe a 10 min work but it'll still be faster than setting up an automated approach...) ... also... i didn't check but those codes might be just the ones you're searching for: gis.stackexchange.com/questions/243940/…
    – raphael
    Commented Apr 19, 2022 at 13:09
  • Some WMS servers give access to the colours used in the map/legend through a GetStyles request
    – nmtoken
    Commented Apr 19, 2022 at 15:41
  • 1
    But if you just want CORINE then perhaps just see: collections.sentinel-hub.com/corine-land-cover/readme.html
    – nmtoken
    Commented Apr 19, 2022 at 16:20

2 Answers 2

1

I found a rather nasty solution 😅

... with the official EEA DiscoMap WMS there's the possibility of getting the legend as a json-dict!
While the colors are still not directly available in the dictionary, there are base64 strings of the legend color-images... from which the actual rgba values can be extracted as follows (all imports are native python3!):

(I really don't get why they don't just provide a rgba tuple for the colors directly... but this is at least a working (python) method to extract the colors from the legend images)

import json
import requests
import base64
import io
import PIL

def most_common_color(base64_string):
    """
    extract the most common color from a base64 encoded png image
    as rgba tuple (with values in the range [0-1])
    
    Parameters
    ----------
    base64_string : str
        the base64 string.

    Returns
    -------
    most_common_color : tuple
        a rgba tuple of the most common color in the image.

    """
    img = base64.b64decode(base64_string)
    img = io.BytesIO(img)
    img = PIL.PngImagePlugin.PngImageFile(img)
    colors = img.getcolors()
    
    _, most_common_color = max(colors, key=lambda x: x[0])
    return tuple(i/255 for i in most_common_color)


url = "https://image.discomap.eea.europa.eu/arcgis/rest/services/Corine/CLC2018_LAEA/MapServer/legend?dynamicLayers=%5B0%5D&f=pjson"
leg = json.loads(requests.get(url).content.decode())

# select the first layer
layer = leg["layers"][0]

# check the name of the layer
layer_name = layer["layerName"]

# extract legend colors from legend-image data
legend = {i["label"] : most_common_color(i["imageData"]) for i in layer["legend"]}

... and here's the proof of concept that it actually works:

import matplotlib.pyplot as plt
f, ax = plt.subplots(figsize=(12,7))
ax.grid(axis="x")

ax.scatter(legend.keys(), [1]*len(legend), c=list(legend.values()),
           s=200, zorder=5)
ax.tick_params(rotation=90, left=False, labelleft=False)
f.subplots_adjust(top=.99, bottom=0.93, left=0, right=1)

enter image description here



update

Since it was mentioned in the comments that this does not work with the actual WMS service... here's how you could "decode" the given legend image to get the color-codes:

Since for your WMS only a png of the full legend is available, the only possibility I see is to chop the legend into the individual entries and then do the same procedure as above, e.g.:

from owslib.wms import WebMapService
import requests
import io
import PIL
import numpy as np


ireland_wms = WebMapService('https://gis-test.epa.ie/geoserver/ows?SERVICE=WMS&')
imgurl = ireland_wms["EPA:LAND_CLC00Rev"].styles["EPA:LAND_CLC00Rev"]["legend"]

# the pixel size of the entries (to split the legend into individual rows)
entry_width, entry_height = 20, 20

img = requests.get(imgurl)
img = img.content

img = io.BytesIO(img)
img = PIL.PngImagePlugin.PngImageFile(img)

# split the legend into the individual entries
imgarray = np.array(img)
entries = np.split(imgarray[:,:entry_width,:], imgarray.shape[0]/entry_height)

colors = []
for i in entries:
    entry_img = PIL.Image.fromarray(i)
    # extract most common color that is NOT white
    _, mcc = max((i for i in entry_img.getcolors() if i[1] != (255, 255, 255)), 
                 key=lambda x: x[0])
    # append the color as rgb tuple with values in the range [0, 1]
    colors.append(tuple(i/255 for i in mcc))

which then gives you something like:

enter image description here

4
  • Neat, but you aren't calling the WMS, with https://image.discomap.eea.europa.eu/arcgis/rest/services/Corine/CLC2018_LAEA/MapServer/legend?
    – nmtoken
    Commented Apr 19, 2022 at 15:45
  • that's true... I've updated the answer to show how one could use the procedure to "decode" the legend-image from the wms-service.... (it's even nastier than the initial approach :-D)
    – raphael
    Commented Apr 19, 2022 at 16:46
  • @raphael Really nice, it does really work! In the meanwhile I just got the colors codes from the links in the comments and created a dictionary mapping the Corine codes of the various land covers to the color codes. Now I am trying to use them for categorical plotting with geopandas and I am getting some annoying errors. Maybe I'll post another Q if I don't find a solution. I'll let you know. Thanks again, really nice! Commented Apr 20, 2022 at 8:10
  • 1
    @dem0nakos glad I could help! ...It's not a very general solution but at least it provides a way to get the colors from the available data... and it was a fun exercise :-)
    – raphael
    Commented Apr 20, 2022 at 10:02
1

The information you require is encoded in the SLD document that represents the style of the layer you are looking at.

Your service object suggests that GetStyles is available but I can't see any reference to it in the GetCapabilities document.

As a fall back if you have a registered user on that server then you could use the REST API to request the style matching the layer.

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.