Manipulate projections (Halieutic dataset)¶

In [1]:
import gstlearn as gl
import gstlearn.plot as gp
import gstlearn.proj as prj
import gstlearn.document as gdoc
import matplotlib.pyplot as plt
import numpy as np

The ICES Working Group WGACEGG dataset: Acoustic Noise Scale (NASC) densities of anchovies and sardines per 1 nautical mile sampling unit, observed in spring 2018 and 2021.

Column descriptions:

  • survey: campaign
  • year: year
  • time: date/time of data recording x: longitude in decimal degrees (WGS84)
  • y: latitude in decimal degrees (WGS84)
  • NASC: acoustic density in m².MN⁻²
  • sp: species (anchovy = "ENGR-ENC"
  • sardine = "SARD-PIL")

For more information on the origin of these data: Doray, M., Van Der Kooij, J., Boyra, G. (Eds.), 2021. ICES Survey Protocols - Manual for acoustic surveys coordinated under the ICES Working Group on Acoustic and Egg Surveys for Small Pelagic Fish (WGACEGG). https://doi.org/10.17895/ICES.PUB.7462.

Load the data in long/lat (alias WGS84 or EPSG:4326)

In [2]:
# Read the data
csv = csv = gl.CSVformat.create(True, charSep=";")
file_csv = gdoc.loadData("halieutic", "AC-SPRING-IBBB-NASC_ANE-PIL_2018-2021.csv")
data = gl.Db.createFromCSV(file_csv, csv=csv)
data.setLocators(["x", "y"], gl.ELoc.X)
data.setLocator("NASC", gl.ELoc.Z)

# Read the polygon
file_csv = gdoc.loadData("halieutic", "WGACEGGspringPolygon.csv")
poly = gl.Polygons.createFromCSV(file_csv, csv)
print("Polygon extension:", poly.getExtensionAsVD(), " degrees")

# Read the boundaries
name = gdoc.loadData("boundaries", "world.poly")
world = gl.Polygons.createFromNF(name)
print("Boundaries extension:", np.round(world.getExtensionAsVD(), 0), " degrees")

# Plot
fig, ax = gp.init(flagEqual=True)
ax.set_xlim([-15, 10])
ax.set_ylim([35, 52])
ax.symbol(data, s=1)
ax.polygon(poly)
ax.polygon(
    world, edgecolor="black", facecolor="lightblue", flagFace=True, flagLabels=True
)
plt.show()
Polygon extension: [-9.94955409 -1.23270531 35.99409516 48.02438771]  degrees
Boundaries extension: [-180.  180.  -90.   84.]  degrees
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
File ~/work/gstlearn/gstlearn/.venv/lib/python3.14/site-packages/matplotlib/backend_bases.py:2281, in FigureCanvasBase.print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
   2277 try:
   2278     # _get_renderer may change the figure dpi (as vector formats
   2279     # force the figure dpi to 72), so we need to set it again here.
   2280     with cbook._setattr_cm(self.figure, dpi=dpi):
-> 2281         result = print_method(
   2282             filename,
   2283             facecolor=facecolor,
   2284             edgecolor=edgecolor,
   2285             orientation=orientation,
   2286             bbox_inches_restore=_bbox_inches_restore,
   2287             **kwargs)
   2288 finally:
   2289     if bbox_inches and restore_bbox:

File ~/work/gstlearn/gstlearn/.venv/lib/python3.14/site-packages/matplotlib/backend_bases.py:2138, in FigureCanvasBase._switch_canvas_and_return_print_method.<locals>.<lambda>(*args, **kwargs)
   2134     optional_kws = {  # Passed by print_figure for other renderers.
   2135         "dpi", "facecolor", "edgecolor", "orientation",
   2136         "bbox_inches_restore"}
   2137     skip = optional_kws - {*inspect.signature(meth).parameters}
-> 2138     print_method = functools.wraps(meth)(lambda *args, **kwargs: meth(
   2139         *args, **{k: v for k, v in kwargs.items() if k not in skip}))
   2140 else:  # Let third-parties do as they see fit.
   2141     print_method = meth

File ~/work/gstlearn/gstlearn/.venv/lib/python3.14/site-packages/matplotlib/backends/backend_agg.py:537, in FigureCanvasAgg.print_png(self, filename_or_obj, metadata, pil_kwargs)
    490 def print_png(self, filename_or_obj, *, metadata=None, pil_kwargs=None):
    491     """
    492     Write the figure to a PNG file.
    493 
   (...)    535         *metadata*, including the default 'Software' key.
    536     """
--> 537     self._print_pil(filename_or_obj, "png", pil_kwargs, metadata)

File ~/work/gstlearn/gstlearn/.venv/lib/python3.14/site-packages/matplotlib/backends/backend_agg.py:485, in FigureCanvasAgg._print_pil(self, filename_or_obj, fmt, pil_kwargs, metadata)
    480 def _print_pil(self, filename_or_obj, fmt, pil_kwargs, metadata=None):
    481     """
    482     Draw the canvas, then save it using `.image.imsave` (to which
    483     *pil_kwargs* and *metadata* are forwarded).
    484     """
--> 485     FigureCanvasAgg.draw(self)
    486     mpl.image.imsave(
    487         filename_or_obj, self.buffer_rgba(), format=fmt, origin="upper",
    488         dpi=self.figure.dpi, metadata=metadata, pil_kwargs=pil_kwargs)

File ~/work/gstlearn/gstlearn/.venv/lib/python3.14/site-packages/matplotlib/backends/backend_agg.py:438, in FigureCanvasAgg.draw(self)
    435 # Acquire a lock on the shared font cache.
    436 with (self.toolbar._wait_cursor_for_draw_cm() if self.toolbar
    437       else nullcontext()):
--> 438     self.figure.draw(self.renderer)
    439     # A GUI class may be need to update a window using this draw, so
    440     # don't forget to call the superclass.
    441     super().draw()

File ~/work/gstlearn/gstlearn/.venv/lib/python3.14/site-packages/matplotlib/artist.py:94, in _finalize_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
     92 @wraps(draw)
     93 def draw_wrapper(artist, renderer, *args, **kwargs):
---> 94     result = draw(artist, renderer, *args, **kwargs)
     95     if renderer._rasterizing:
     96         renderer.stop_rasterizing()

File ~/work/gstlearn/gstlearn/.venv/lib/python3.14/site-packages/matplotlib/artist.py:71, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     68     if artist.get_agg_filter() is not None:
     69         renderer.start_filter()
---> 71     return draw(artist, renderer)
     72 finally:
     73     if artist.get_agg_filter() is not None:

File ~/work/gstlearn/gstlearn/.venv/lib/python3.14/site-packages/matplotlib/figure.py:3282, in Figure.draw(self, renderer)
   3279             # ValueError can occur when resizing a window.
   3281     self.patch.draw(renderer)
-> 3282     mimage._draw_list_compositing_images(
   3283         renderer, self, artists, self.suppressComposite)
   3285     renderer.close_group('figure')
   3286 finally:

File ~/work/gstlearn/gstlearn/.venv/lib/python3.14/site-packages/matplotlib/image.py:133, in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    131 if not_composite or not has_images:
    132     for a in artists:
--> 133         a.draw(renderer)
    134 else:
    135     # Composite any adjacent images together
    136     image_group = []

File ~/work/gstlearn/gstlearn/.venv/lib/python3.14/site-packages/matplotlib/artist.py:71, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     68     if artist.get_agg_filter() is not None:
     69         renderer.start_filter()
---> 71     return draw(artist, renderer)
     72 finally:
     73     if artist.get_agg_filter() is not None:

File ~/work/gstlearn/gstlearn/.venv/lib/python3.14/site-packages/matplotlib/axes/_base.py:3350, in _AxesBase.draw(self, renderer)
   3347 if artists_rasterized:
   3348     _draw_rasterized(self.get_figure(root=True), artists_rasterized, renderer)
-> 3350 mimage._draw_list_compositing_images(
   3351     renderer, self, artists, self.get_figure(root=True).suppressComposite)
   3353 renderer.close_group('axes')
   3354 self.stale = False

File ~/work/gstlearn/gstlearn/.venv/lib/python3.14/site-packages/matplotlib/image.py:133, in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    131 if not_composite or not has_images:
    132     for a in artists:
--> 133         a.draw(renderer)
    134 else:
    135     # Composite any adjacent images together
    136     image_group = []

File ~/work/gstlearn/gstlearn/.venv/lib/python3.14/site-packages/matplotlib/artist.py:71, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     68     if artist.get_agg_filter() is not None:
     69         renderer.start_filter()
---> 71     return draw(artist, renderer)
     72 finally:
     73     if artist.get_agg_filter() is not None:

File ~/work/gstlearn/gstlearn/.venv/lib/python3.14/site-packages/matplotlib/text.py:909, in Text.draw(self, renderer)
    905         textrenderer.draw_tex(gc, x, y, clean_line,
    906                               self._fontproperties, angle,
    907                               mtext=mtext)
    908     else:
--> 909         textrenderer.draw_text(gc, x, y, clean_line,
    910                                self._fontproperties, angle,
    911                                ismath=ismath, mtext=mtext)
    913 gc.restore()
    914 renderer.close_group('text')

File ~/work/gstlearn/gstlearn/.venv/lib/python3.14/site-packages/matplotlib/backends/backend_agg.py:245, in RendererAgg.draw_text(self, gc, x, y, s, prop, angle, ismath, mtext)
    240 items = font._layout(
    241     s, flags=get_hinting_flag(),
    242     features=mtext.get_fontfeatures() if mtext is not None else None,
    243     language=mtext.get_language() if mtext is not None else None)
    244 size = prop.get_size_in_points()
--> 245 self._draw_text_glyphs_and_boxes(
    246     gc, x, y, angle,
    247     ((item.ft_object, size, item.glyph_index, 0, 1, item.x, item.y)
    248      for item in items),
    249     [])

File ~/work/gstlearn/gstlearn/.venv/lib/python3.14/site-packages/matplotlib/backends/backend_agg.py:182, in RendererAgg._draw_text_glyphs_and_boxes(self, gc, x, y, angle, glyphs, boxes)
    180 for font, size, glyph_index, slant, extend, dx, dy in glyphs:  # dy is upwards.
    181     font.set_size(size, self.dpi)
--> 182     font._set_transform(
    183         (0x10000 * np.array([[cos, -sin], [sin, cos]])
    184          @ [[extend, extend * slant], [0, 1]]).round().astype(int),
    185         [round(0x40 * (x + dx * cos - dy * sin)),
    186          # FreeType's y is upwards.
    187          round(0x40 * (self.height - y + dx * sin + dy * cos))]
    188     )
    189     bitmap = font._render_glyph(
    190         glyph_index, load_flags,
    191         RenderMode.NORMAL if gc.get_antialiased() else RenderMode.MONO)
    192     buffer = bitmap.buffer

TypeError: _set_transform(): incompatible function arguments. The following argument types are supported:
    1. (self: matplotlib.ft2font.FT2Font, matrix: typing.Annotated[collections.abc.Sequence[typing.Annotated[collections.abc.Sequence[typing.SupportsInt | typing.SupportsIndex], "FixedSize(2)"]], "FixedSize(2)"], delta: typing.Annotated[collections.abc.Sequence[typing.SupportsInt | typing.SupportsIndex], "FixedSize(2)"]) -> None

Invoked with: <matplotlib.ft2font.FT2Font object at 0x7f5cf17c8670>, array([[65536,     0],
       [    0, 65536]]), [522294613333328265084365694828544, -78766]
<Figure size 640x480 with 1 Axes>

Transform all coordinates to EPSG:2154 and display only some countries

In [3]:
crsFrom = "EPSG:4326"  # WGS84 (lat/lon)
crsTo = "EPSG:2154"

# Transform the data coordinates
datat = data.clone()
x, y = prj.proj(datat["x"], datat["y"], crsFrom, crsTo)
datat["x"] = x
datat["y"] = y

# Transform polygon coordinates
polyt = poly.clone()
x, y = prj.proj(polyt.getX(0), polyt.getY(0), crsFrom, crsTo)
polyt.setX(0, x)
polyt.setY(0, y)
ext = polyt.getExtensionAsVD()
print("Polygon extension:", np.round(ext, 0), " meters")

# Transform boundaries coordinates (only for France, Portugal and Spain)
ids = [119, 214, 215]
worldt = gl.Polygons()
nid = 0
for id in ids:
    worldt.addPolyElem(world.getPolyElem(id))
    x, y = prj.proj(worldt.getX(nid), worldt.getY(nid), crsFrom, crsTo)
    worldt.setX(nid, x)
    worldt.setY(nid, y)
    nid += 1
print("Boundaries extension:", np.round(worldt.getExtensionAsVD(), 0), " meters")

# Plot
fig, ax = gp.init(flagEqual=True)
ax.symbol(datat, s=1)
ax.polygon(polyt)
ax.polygon(
    worldt,
    edgecolor="black",
    facecolor="lightblue",
    flagFace=True,
    flagLabels=True,
    labels=["France", "Portugal", "Spain"],
)
plt.show()
Polygon extension: [-427232.  368841. 5479556. 6797888.]  meters
Boundaries extension: [-393135. 1072736. 5463375. 7117128.]  meters
No description has been provided for this image
In [4]:
# Plot the two basemaps together from the initial data
fig, axs = gp.init(ny=2)
axs[0].baseMap(data, size=0.5)
axs[1].baseMap(data, size=0.5, flagProj=True, crsFrom=crsFrom, crsTo=crsTo)
plt.show()
No description has been provided for this image
In [ ]: