Interaction with LifeWatch WMS server

In the framework of LifeWatch, the Wallonia-Brussels Federation is financing a research program as a partnership between the Earth and Life Institute (UCL) and the Unit for Biodiversity and Landscape (Ulg-Gbx). The LifeWatch Wallonia-Brussels (LW-WB) team combines a strong experience in land cover mapping through with biodiversity modeling expertise.

WMS : https://maps.elie.ucl.ac.be/cgi-bin/mapserv72?map=/maps_server/lifewatch/mapfiles/LW_Ecotopes/latest/LW_ecotopes_lc_hr_raster_2022.map&SERVICE=wms&REQUEST=GetCapabilities

[2]:

from wolfhece.wolf_array import WolfArray from wolfhece.lifewatch import LifeWatch_Legend, get_LifeWatch_Wallonia, get_LifeWatch_center_width_height, get_LifeWatch_bounds, count_pixels, get_areas from wolfhece.PyWMS import getLifeWatch from PIL import Image import matplotlib.pyplot as plt import numpy as np

Legend and reference

[3]:
# Plot the legend for the LifeWatch -- Not available in the WMS but encoded in WOLFHECE
fig, ax = LifeWatch_Legend.plot_legend()

LifeWatch_Legend.reference()
[3]:
'https://www.mdpi.com/2306-5729/8/1/13'
../_images/tutorials_lifewatch_4_1.png

Get Data from the WMS server

  • Image

  • WolfArray

[4]:
# Get the LifeWatch IMAGE for Wallonia
wallonia_image:Image.Image
wallonia_image, bounds= get_LifeWatch_Wallonia(2022, 'Palette')
xmin, ymin, xmax, ymax = bounds

# Info on the image
print(f"Image size: {wallonia_image.size}") # (width, height) --> Similar to (nbx, nby) in WolfArray
print(f"Image mode: {wallonia_image.mode}")

# Plot the image using matplotlib imshow - no parameters
fig, ax = plt.subplots(figsize=(10, 10), dpi=300)
ax.imshow(wallonia_image)
# In this case, the image is not georeferenced, so the extent is not set.
# The first pixel is at (0,0) on le upper-left corner of the image.

# One can also set the extent of the image using the bounds of the area
# The image is now "georeferenced" in the sense that the axes represent the right coordinates.
fig, ax = plt.subplots(figsize=(10, 10), dpi=300)
ax.imshow(wallonia_image, extent=(xmin, xmax, ymin, ymax))

# Get the LifeWatch WOLFARRAY for Wallonia
wallonia_wolf:WolfArray
wallonia_wolf, bounds = get_LifeWatch_Wallonia(2022, 'WolfArray')

#Info on the WolfArray
print(wallonia_wolf)

# One can use the WolfArray to plot the image using matplotlib
# No need to set the extent, it is already set in the WolfArray object
fig, ax = wallonia_wolf.plot_matplotlib()
# One can use the fig, ax returned by the plot function to set the title, labels, etc.
ax.set_title('LifeWatch WOLFARRAY for Wallonia')
fig.set_size_inches(15, 10)
fig.tight_layout()
Image size: (2048, 1299)
Image mode: P
Shape  : 2048 x 1299
Resolution  : 126.953125 x 127.02078521939954
Spatial extent :
   - Origin : (40000 ; 10000)
   - End : (300000.0 ; 175000.0)
   - Width x Height : 260000.0 x 165000.0
   - Translation : (0.0 ; 0.0)
Null value : 0.0


../_images/tutorials_lifewatch_6_1.png
../_images/tutorials_lifewatch_6_2.png
../_images/tutorials_lifewatch_6_3.png
  • Numpy

[5]:
# Get the LifeWatch NUMPY for Wallonia
wallonia_numpy:np.ndarray
wallonia_numpy, bounds= get_LifeWatch_Wallonia(2022, 'NUMPY')
xmin, ymin, xmax, ymax = bounds

# Info on the image
print(f"Array shape: {wallonia_numpy.shape}") # (rows, columns) --> Not similar to (nbx, nby) in WolfArray but (nby, nbx)
print(f"Data type: {wallonia_numpy.dtype}") # Data type of the array

# Pay attention to the fact that the numpy array is not georeferenced, so the extent is not set.
# The shape of the array is (height, width) and not (width, height)
# The first pixel is at (0,0) on the upper-left of the array.

fig, ax = plt.subplots(2, 1, figsize=(20, 10), dpi=300)
ax[0].imshow(wallonia_numpy, extent=(xmin, xmax, ymin, ymax)) # No need to set the origin to 'lower' to have the same orientation as the image

# As it is a numpy array, it does not contains a palette, so we need to set the colormap manually.
ax[1].imshow(wallonia_numpy, extent=(xmin, xmax, ymin, ymax), cmap=LifeWatch_Legend.cmap(), norm=LifeWatch_Legend.norm())
Array shape: (1299, 2048)
Data type: uint8
[5]:
<matplotlib.image.AxesImage at 0x24d2dca4a30>
../_images/tutorials_lifewatch_8_2.png

Searching values in differnt formats

As format can be :

- Image
- Numpy
- WolfArray

Ara data stored at the same location in memory?

[6]:
# searching code == '10'

ij_image_bad = np.argwhere(wallonia_image == 10) # Cannot be used, the image does not contain code but colors !!

code_from_image = LifeWatch_Legend.colors2codes(wallonia_image) # This is the right way to get the codes from the image
ij_image = np.argwhere(code_from_image == 10) # This is the right way to get the codes from the image
ij_wolf = np.argwhere(wallonia_wolf.array == 10)
ij_numpy = np.argwhere(wallonia_numpy == 10)

print(f'Number of selected pixels in image: {ij_image_bad.shape[0]}, {ij_image_bad.shape[1]}')
print(f'Number of selected pixels in image: {ij_image.shape[0]}, {ij_image.shape[1]}')
print(f'Number of selected pixels in wolf: {ij_wolf.shape[0]}, {ij_wolf.shape[1]}')
print(f'Number of selected pixels in numpy: {ij_numpy.shape[0]}, {ij_numpy.shape[1]}')

# all counters are the same, except for the image which is not a code but a color
Number of selected pixels in image: 0, 0
Number of selected pixels in image: 7496, 2
Number of selected pixels in wolf: 7496, 2
Number of selected pixels in numpy: 7496, 2
[7]:
print('First pixel in image:', ij_image[0][0], ij_image[0][1]) # First pixel with code 10 in the image
print('First pixel in wolf:', ij_wolf[0][0], ij_wolf[0][1]) # First pixel with code 10 in the wolf array
print('First pixel in numpy:', ij_numpy[0][0], ij_numpy[0][1]) # First pixel with code 10 in the numpy array

print(code_from_image[ij_image[0][0], ij_image[0][1]]) # First pixel with code 10 in the image
print(wallonia_wolf.array[ij_wolf[0][0], ij_wolf[0][1]]) # First pixel with code 10 in the wolf array
print(wallonia_numpy[ij_numpy[0][0], ij_numpy[0][1]]) # First pixel with code 10 in the numpy array

# CAUTION : indices in the numpy are not the same
# For memory:
print('Image shape', code_from_image.shape)
print('Wolf shape', wallonia_wolf.array.shape)
print('Numpy shape', wallonia_numpy.shape)

# 'C' or 'F' order
print('Image order is C :', code_from_image.flags['C_CONTIGUOUS'])
print('Wolf order is C :', wallonia_wolf.array.flags['C_CONTIGUOUS'])
print('Numpy order is C :', wallonia_numpy.flags['C_CONTIGUOUS'])

# For more information  : https://numpy.org/doc/stable/reference/generated/numpy.array.html

# compare arrays
print('Image == Wolf', np.array_equal(code_from_image, wallonia_wolf.array))
print('Image == Numpy', np.array_equal(code_from_image, wallonia_numpy))
print('Wolf == Numpy', np.array_equal(wallonia_wolf.array, wallonia_numpy))

code_from_image_np = LifeWatch_Legend.colors2codes(wallonia_image, aswolf=False) # By default, it is aswolf=True -- we can force it to False

print('Image_np shape', code_from_image_np.shape)
print('Image_np order is C :', code_from_image_np.flags['C_CONTIGUOUS'])
print('Image_np == Numpy', np.array_equal(code_from_image_np, wallonia_numpy))

# In this case, the image is equivalent to the numpy array.
First pixel in image: 40 1170
First pixel in wolf: 40 1170
First pixel in numpy: 58 1601
10
10
10
Image shape (2048, 1299)
Wolf shape (2048, 1299)
Numpy shape (1299, 2048)
Image order is C : False
Wolf order is C : False
Numpy order is C : True
Image == Wolf True
Image == Numpy False
Wolf == Numpy False
Image_np shape (1299, 2048)
Image_np order is C : True
Image_np == Numpy True

Only a part of the Region

[8]:
# Part Wallonia
xmin = 200_000
xmax = 202_000
ymin = 150_000
ymax = 152_000

year = 2022

image, b = get_LifeWatch_bounds(year, xmin, ymin, xmax, ymax, 'Palette')
fig, ax = plt.subplots(figsize=(10, 10), dpi=300)
ax.imshow(image, extent=(xmin, xmax, ymin, ymax))
[8]:
<matplotlib.image.AxesImage at 0x24d33bcbc70>
../_images/tutorials_lifewatch_13_1.png
[9]:
# Part Wallonia
x_center = 201_000
y_center = 151_000
width = 2_000
height = 2_000

year = 2022

image2, b = get_LifeWatch_center_width_height(year, x_center, y_center, width, height, 'Palette')
fig, ax = plt.subplots(figsize=(10, 10), dpi=300)
ax.imshow(image2, extent=(xmin, xmax, ymin, ymax))
[9]:
<matplotlib.image.AxesImage at 0x24d33c58910>
../_images/tutorials_lifewatch_14_1.png

Count the codes in the array

[10]:
# Based on Numpy array
x_center = 201_000
y_center = 151_000
width = 2_000
height = 2_000

year = 2022

array_np, b = get_LifeWatch_center_width_height(year, x_center, y_center, width, height, 'NUMPY')

out_np = count_pixels(array_np)
print(out_np)
{0: 5, 10: 1341, 15: 5182, 20: 610373, 21: 368113, 30: 1800613, 35: 783269, 40: 12, 48: 8958, 50: 15119, 51: 4826, 55: 412652, 56: 183841}
[11]:
# Based on Wolf array
array_wolf:WolfArray

x_center = 201_000
y_center = 151_000
width = 2_000
height = 2_000

year = 2022

array_wolf, b = get_LifeWatch_center_width_height(year, x_center, y_center, width, height, 'WolfArray')

out_wolf = count_pixels(array_wolf)
print(out_wolf)
# No 0 here, because 0 are MASKED cells in the WolfArray
{10: 1341, 15: 5182, 20: 610373, 21: 368113, 30: 1800613, 35: 783269, 40: 12, 48: 8958, 50: 15119, 51: 4826, 55: 412652, 56: 183841}
[12]:
# Based on Wolf array
x_center = 201_000
y_center = 151_000
width = 2_000
height = 2_000

year = 2022

array_wolf, b = get_LifeWatch_center_width_height(year, x_center, y_center, width, height, 'WolfArray')

out_wolf = get_areas(array_wolf) # in m²
print(out_wolf)
# No 0 here, because 0 are MASKED cells in the WolfArray
{10: 5364.0, 15: 20728.0, 20: 2441492.0, 21: 1472452.0, 30: 7202452.0, 35: 3133076.0, 40: 48.0, 48: 35832.0, 50: 60476.0, 51: 19304.0, 55: 1650608.0, 56: 735364.0}
[13]:
array_wolf:WolfArray
# or ...
print(array_wolf.count_unique_pixels()) # in pixels
# or ...
print(array_wolf.get_unique_areas()) # in m²
# or ...
print(array_wolf.get_unique_areas('ha')) # in ha
# or ...
print(array_wolf.get_unique_areas('km²')) # in km²
{10: 1341, 15: 5182, 20: 610373, 21: 368113, 30: 1800613, 35: 783269, 40: 12, 48: 8958, 50: 15119, 51: 4826, 55: 412652, 56: 183841}
{10: 1278.8772583007812, 15: 4941.9403076171875, 20: 582097.053527832, 21: 351059.9136352539, 30: 1717198.371887207, 35: 746983.528137207, 40: 11.444091796875, 48: 8543.014526367188, 50: 14418.601989746094, 51: 4602.4322509765625, 55: 393535.6140136719, 56: 175324.4400024414}
{10: 0.12788772583007812, 15: 0.49419403076171875, 20: 58.2097053527832, 21: 35.10599136352539, 30: 171.7198371887207, 35: 74.6983528137207, 40: 0.0011444091796875, 48: 0.8543014526367188, 50: 1.4418601989746094, 51: 0.46024322509765625, 55: 39.35356140136719, 56: 17.53244400024414}
{10: 0.0012788772583007812, 15: 0.0049419403076171875, 20: 0.582097053527832, 21: 0.3510599136352539, 30: 1.717198371887207, 35: 0.746983528137207, 40: 1.1444091796875e-05, 48: 0.008543014526367188, 50: 0.014418601989746094, 51: 0.0046024322509765625, 55: 0.3935356140136719, 56: 0.1753244400024414}