Skip to content

Commit

Permalink
Merge branch 'main' of github.com:geo-engine/geoengine-python into re…
Browse files Browse the repository at this point in the history
…sultdescriptor-with-time
  • Loading branch information
jdroenner committed Oct 28, 2024
2 parents de13ccb + 66cb76b commit d9627e9
Show file tree
Hide file tree
Showing 21 changed files with 2,052 additions and 71 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
fail-fast: false
matrix:
# use all supported versions from https://devguide.python.org/versions/
python-version: ["3.8", "3.9", "3.10", "3.11"]
python-version: ["3.9", "3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v3
Expand Down Expand Up @@ -61,7 +61,7 @@ jobs:

env:
# use minimum supported versions from https://devguide.python.org/versions/
python-version: "3.8"
python-version: "3.9"
# lowest compatible versions for all direct dependencies
# cf., https://github.com/astral-sh/uv#resolution-strategy
resolution: "lowest-direct"
Expand Down
38 changes: 9 additions & 29 deletions examples/ml_pipeline.ipynb

Large diffs are not rendered by default.

201 changes: 201 additions & 0 deletions examples/ml_water_bodies/labeling.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
'''
Labeling tools for smaller ML use cases.
'''

import os
from typing import Tuple, Callable, Optional, Mapping, TypedDict, List
import matplotlib.pyplot as plt
from matplotlib.backend_bases import MouseButton, MouseEvent
from matplotlib.backend_tools import Cursors
from matplotlib.patches import Circle
import ipywidgets as widgets
from IPython.display import display
import geopandas as gpd
from shapely.geometry import Point
import pandas as pd


class ClassValue(TypedDict):
value: int
color: str


class PointLabelingTool(widgets.VBox):
'''
Create points labels by overlaying them over a background.
Select a class and click to add one.
'''

points: gpd.GeoDataFrame
crs: str
filename: str
class_column: str
selected_class_value: int
classes: Mapping[str, ClassValue]
color_map: Mapping[int, str]

fig: plt.Figure
ax: plt.Axes
plt_fg: Optional[pd.plotting.PlotAccessor]
legend_handles: List[Circle]

def __init__(self,
*,
filename: str,
class_column: str,
classes: Mapping[str, ClassValue],
crs: str,
background: Callable[[plt.Axes], None],
figsize: Optional[Tuple[int, int]] = None) -> None:
super().__init__()

self.filename = filename
self.crs = crs

self.class_column = class_column
self.classes = classes

self.color_map = {c['value']: c['color'] for c in self.classes.values()}
self.selected_class_value = next(iter(self.classes.values()))['value']

self.points = self.__make_gdf(None)

if os.path.exists(filename):
self.points = pd.concat(
[
self.points,
gpd.read_file(filename).set_crs(self.crs, allow_override=True),
],
ignore_index=True,
)

self.children = [
self.__create_selection(background),
self.__create_plot(background, figsize),
]

self.__plot_and_save(background)

def __make_gdf(self, entry: Optional[Tuple[Point, int]]) -> gpd.GeoDataFrame:
'''
Create a GeoDataFrame from a given entry.
If `entry` is None, an empty GeoDataFrame is created.
'''

data: dict[str, list] = {'geometry': [], self.class_column: []}

if entry:
geom, class_value = entry
data['geometry'].append(geom)
data[self.class_column].append(class_value)

return gpd.GeoDataFrame(
data=data,
crs=self.crs,
geometry='geometry',
)

def __create_plot(self,
background: Callable[[plt.Axes], None],
figsize: Optional[Tuple[int, int]]) -> widgets.Output:
"""
Creates a plot with a specified background and figure size,
and sets up an interactive widget for labeling points.
"""

output = widgets.Output()

with output, plt.ioff():
self.fig, self.ax = plt.subplots(figsize=figsize, constrained_layout=True)

self.fig.canvas.toolbar_visible = False
self.fig.canvas.header_visible = False
self.fig.canvas.footer_visible = False

display(self.fig.canvas)

background(self.ax)

def on_click(event: MouseEvent):
if self.fig.canvas.widgetlock.locked():
return # Don't do anything if the zoom/pan tools have been enabled.
if event.button is not MouseButton.LEFT:
return
if not event.inaxes:
return

self.points.loc[len(self.points)] = [
Point(event.xdata, event.ydata),
self.selected_class_value,
]
self.points.set_geometry(col='geometry', inplace=True)

self.__plot_and_save(background)

self.fig.canvas.mpl_connect('button_press_event', on_click)

self.legend_handles = [
Circle((0.5, 0.5), 1, label=name, facecolor=v['color']) for (name, v) in self.classes.items()
]

return output

def __create_selection(self, background: Callable[[plt.Axes], None]) -> widgets.HBox:
"""
Creates a selection interface for labeling water bodies.
This method generates a horizontal box layout containing toggle buttons for class selection
and an undo button. The class buttons allow the user to select a class from the available
options, while the undo button removes the last point added to the selection.
"""

class_buttons = widgets.ToggleButtons(
options=[(c, v['value']) for (c, v) in self.classes.items()],
description='Class:',
button_style='info',
)

undo_button = widgets.Button(
icon='undo',
button_style="warning",
)

def on_undo(_event):
self.points.drop(self.points.tail(1).index, inplace=True)

self.__plot_and_save(background)

undo_button.on_click(on_undo)

def set_selected_class_value(change) -> None:
self.selected_class_value = change['new']

class_buttons.observe(set_selected_class_value, names=["value"])

return widgets.HBox([class_buttons, undo_button])

def __plot_and_save(self,
background: Callable[[plt.Axes], None]) -> None:
"""
Plots the points on the given background and saves the plot to a file.
"""

self.ax.clear()

background(self.ax)

if len(self.points) == 0:
return

colors = self.points[self.class_column].map(self.color_map)
self.plt_fg = self.points.plot(ax=self.ax, c=colors)

self.points.to_file(self.filename)

self.ax.cursor_to_use = Cursors.POINTER

self.ax.legend(
handles=self.legend_handles,
loc='center left',
bbox_to_anchor=(1, 0.5),
)
62 changes: 62 additions & 0 deletions examples/ml_water_bodies/training_data.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"type": "FeatureCollection",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::32632" } },
"features": [
{ "type": "Feature", "properties": { "water": 1.0 }, "geometry": { "type": "Point", "coordinates": [ 359492.047223033325281, 5649059.958522516302764 ] } },
{ "type": "Feature", "properties": { "water": 1.0 }, "geometry": { "type": "Point", "coordinates": [ 359436.58185506798327, 5648255.710687017999589 ] } },
{ "type": "Feature", "properties": { "water": 1.0 }, "geometry": { "type": "Point", "coordinates": [ 361045.077526063658297, 5639935.90549221355468 ] } },
{ "type": "Feature", "properties": { "water": 1.0 }, "geometry": { "type": "Point", "coordinates": [ 359381.116487102583051, 5640102.301596108824015 ] } },
{ "type": "Feature", "properties": { "water": 1.0 }, "geometry": { "type": "Point", "coordinates": [ 357966.749603985692374, 5641599.866531174629927 ] } },
{ "type": "Feature", "properties": { "water": 1.0 }, "geometry": { "type": "Point", "coordinates": [ 357328.89787238399731, 5643374.758306065574288 ] } },
{ "type": "Feature", "properties": { "water": 1.0 }, "geometry": { "type": "Point", "coordinates": [ 357134.769084505212959, 5644983.253977061249316 ] } },
{ "type": "Feature", "properties": { "water": 1.0 }, "geometry": { "type": "Point", "coordinates": [ 357134.769084505212959, 5645676.571076628752053 ] } },
{ "type": "Feature", "properties": { "water": 1.0 }, "geometry": { "type": "Point", "coordinates": [ 357606.224712210823782, 5646453.086228143423796 ] } },
{ "type": "Feature", "properties": { "water": 1.0 }, "geometry": { "type": "Point", "coordinates": [ 358382.739863725961186, 5647118.670643728226423 ] } },
{ "type": "Feature", "properties": { "water": 1.0 }, "geometry": { "type": "Point", "coordinates": [ 358992.858911345014349, 5647395.997483555227518 ] } },
{ "type": "Feature", "properties": { "water": 1.0 }, "geometry": { "type": "Point", "coordinates": [ 357467.561292297381442, 5642903.30267836060375 ] } },
{ "type": "Feature", "properties": { "water": 1.0 }, "geometry": { "type": "Point", "coordinates": [ 357245.699820435955189, 5643763.015881823375821 ] } },
{ "type": "Feature", "properties": { "water": 1.0 }, "geometry": { "type": "Point", "coordinates": [ 359076.056963293056469, 5649531.414150222204626 ] } },
{ "type": "Feature", "properties": { "water": 1.0 }, "geometry": { "type": "Point", "coordinates": [ 358770.997439483529888, 5649753.275622082874179 ] } },
{ "type": "Feature", "properties": { "water": 1.0 }, "geometry": { "type": "Point", "coordinates": [ 360213.097006583120674, 5639963.63817619625479 ] } },
{ "type": "Feature", "properties": { "water": 1.0 }, "geometry": { "type": "Point", "coordinates": [ 358465.937915674003307, 5640851.084063641726971 ] } },
{ "type": "Feature", "properties": { "water": 1.0 }, "geometry": { "type": "Point", "coordinates": [ 358650.151550401293207, 5648719.950428013689816 ] } },
{ "type": "Feature", "properties": { "water": 1.0 }, "geometry": { "type": "Point", "coordinates": [ 358511.599955826473888, 5648917.881277405656874 ] } },
{ "type": "Feature", "properties": { "water": 1.0 }, "geometry": { "type": "Point", "coordinates": [ 358326.864496393478476, 5649425.903790846467018 ] } },
{ "type": "Feature", "properties": { "water": 1.0 }, "geometry": { "type": "Point", "coordinates": [ 358128.933647000929341, 5649089.421346879564226 ] } },
{ "type": "Feature", "properties": { "water": 1.0 }, "geometry": { "type": "Point", "coordinates": [ 357858.428152831096668, 5649683.213895057328045 ] } },
{ "type": "Feature", "properties": { "water": 1.0 }, "geometry": { "type": "Point", "coordinates": [ 357614.313438580313232, 5649815.167794652283192 ] } },
{ "type": "Feature", "properties": { "water": 1.0 }, "geometry": { "type": "Point", "coordinates": [ 358148.726731940172613, 5649531.466910522431135 ] } },
{ "type": "Feature", "properties": { "water": 1.0 }, "geometry": { "type": "Point", "coordinates": [ 359488.058812829724047, 5648667.168868175707757 ] } },
{ "type": "Feature", "properties": { "water": 1.0 }, "geometry": { "type": "Point", "coordinates": [ 359138.380978902918287, 5647651.123841293156147 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 358905.963186536508147, 5648231.670999898575246 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 356869.274874848197214, 5647952.125545353628695 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 353501.417731991037726, 5647779.073597301729023 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 354632.911238484550267, 5648457.96970119792968 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 355365.05409562739078, 5649389.787883015349507 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 358866.028121601440944, 5646168.359311587177217 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 361421.872277445625514, 5646514.46320769097656 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 359771.222926796239335, 5642787.190480418503284 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 358067.326822900155094, 5645396.28138950932771 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 355404.989160562457982, 5645076.800870028324425 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 356682.911238484550267, 5645782.320350548252463 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 356043.950199523533229, 5647512.839831067249179 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 353914.080069653398823, 5646155.047623275779188 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 352316.677472250768915, 5645662.515155742876232 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 352662.781368354684673, 5646115.112558340653777 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 352369.924225497525185, 5647952.125545353628695 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 352263.430719004012644, 5649363.164506392553449 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 352103.69045926380204, 5640524.203467431478202 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 353754.339809913130011, 5641003.424246652051806 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 354872.521628094953485, 5640670.632038859650493 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 354979.015134588466026, 5641229.722947950474918 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 353967.326822900155094, 5642733.943727171979845 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 353661.157991731306538, 5645023.554116781800985 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 353315.05409562739078, 5643958.619051846675575 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 355751.093056666373741, 5643905.372298600152135 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 357215.378770952112973, 5640883.619051846675575 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 356416.677472250768915, 5641708.943727171979845 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 359678.041108614415862, 5644943.683986911550164 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 361155.638511211844161, 5644730.696973924525082 ] } },
{ "type": "Feature", "properties": { "water": 0.0 }, "geometry": { "type": "Point", "coordinates": [ 359039.080069653398823, 5643279.722947950474918 ] } }
]
}
Loading

0 comments on commit d9627e9

Please sign in to comment.