Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
SimStadt
Germany Open-Data CityGML
Commits
cea14af4
Commit
cea14af4
authored
Nov 10, 2025
by
Eric Duminil
Browse files
Trying to download BW zips
parent
33c6ec83
Changes
1
Hide whitespace changes
Inline
Side-by-side
01_baden_wuerttemberg.py
View file @
cea14af4
from
citygml_download
import
Bundesland
,
TMP_DIR
,
download_file
import
json
import
json
import
zipfile
from
datetime
import
datetime
from
pathlib
import
Path
from
citygml_download
import
TMP_DIR
,
Bundesland
,
CityGMLWithDate
,
download_file
,
download_all_files
# Data are available as WFS
# Data are available as WFS
# NOTE: Use geopandas or specific WFS lib?
# NOTE: Use geopandas or specific WFS lib?
# TODO: Try to find data with QGIS or Geopandas
# TODO: Try to find data with QGIS or Geopandas
BW_WFS
=
"https://owsproxy.lgl-bw.de/owsproxy/wfs/WFS_LGL-BW_LoD2_Aktualitaet?SERVICE=WFS&VERSION=1.1.0&REQUEST=GetFeature&TYPENAME=verm:v_lod2_aktualitaet&MAXFEATURES=50000&OUTPUTFORMAT=application/json"
BW_WFS
=
"https://owsproxy.lgl-bw.de/owsproxy/wfs/WFS_LGL-BW_LoD2_Aktualitaet?SERVICE=WFS&VERSION=1.1.0&REQUEST=GetFeature&TYPENAME=verm:v_lod2_aktualitaet&MAXFEATURES=50000&OUTPUTFORMAT=application/json"
ZIP_URL_FORMAT
=
"https://opengeodata.lgl-bw.de/data/lod2/LoD2_32_%s_%s_2_bw.zip"
BADEN_WUERTTEMBERG
=
Bundesland
(
BADEN_WUERTTEMBERG
=
Bundesland
(
"Baden-Württemberg"
,
"Baden-Württemberg"
,
source
=
"https://opengeodata.lgl-bw.de/#/(sidenav:product/lod2)"
,
source
=
"https://opengeodata.lgl-bw.de/#/(sidenav:product/lod2)"
,
...
@@ -13,98 +19,54 @@ BADEN_WUERTTEMBERG = Bundesland(
...
@@ -13,98 +19,54 @@ BADEN_WUERTTEMBERG = Bundesland(
license
=
"dl-de/by-2-0"
,
license
=
"dl-de/by-2-0"
,
)
)
if
__name__
==
"__main__"
:
# bw_json = TMP_DIR / "bw_lod2.json"
# download_file(
# BW_WFS,
# bw_json
# )
#
# with open(bw_json) as json_file:
# data = json.load(json_file)
# xs, ys = [], []
# import matplotlib.pyplot as plt
# for feature in data["features"]:
# x, y = feature['bbox'][:2]
# date = feature['properties']['produktionsdatum'] or '1970-01-01'
# xs.append(x)
# ys.append(y)
# # citygmls.append(
# # CityGMLWithDate(
# # url=feature["properties"]["xml"],
# # bundesland=NIEDERSACHSEN,
# # source_date=datetime.strptime(feature["properties"]["Aktualitaet"], "%Y-%m-%d %H:%M:%S"),
# # # coordinate_reference_system ?
# # )
# # )
# # TODO: Show dates too?
# plt.scatter(xs, ys, s=0.1)
# plt.show()
from
owslib.wfs
import
WebFeatureService
import
geopandas
as
gpd
import
io
from
citygml_download
import
TMP_DIR
# 1. Define the WFS URL and Feature Type
WFS_URL
=
"https://owsproxy.lgl-bw.de/owsproxy/wfs/WFS_LGL-BW_LoD2_Aktualitaet?"
FEATURE_TYPE
=
"verm:v_lod2_aktualitaet"
# 2. Connect to the WFS
try
:
# Use version 2.0.0 as it's the modern standard
wfs
=
WebFeatureService
(
url
=
WFS_URL
,
version
=
"2.0.0"
)
except
Exception
as
e
:
print
(
f
"Error connecting to WFS:
{
e
}
"
)
# Handle error or exit
# 3. Request all features in GeoJSON format
# We specify a large 'count' (MAXIMUM=1000000) to request all tiles.
# Since the server handles streaming large files, this should work without manual pagination.
print
(
f
"Requesting features for
{
FEATURE_TYPE
}
..."
)
try
:
# Get the raw response content (GeoJSON string)
response
=
wfs
.
getfeature
(
typename
=
FEATURE_TYPE
,
outputFormat
=
"application/json"
,
# count=1000000, # Request a large number to ensure all tiles are returned
).
read
()
# 4. Convert the GeoJSON response to a GeoPandas GeoDataFrame
# NOTE: Slightly different than in 07_hessen.py
# Use io.BytesIO to treat the response string as a file for geopandas
class
ZipFile
(
CityGMLWithDate
):
gdf
=
gpd
.
read_file
(
io
.
BytesIO
(
response
),
driver
=
"GeoJSON"
)
def
download
(
self
,
tmp_dir
:
Path
=
TMP_DIR
,
max_retries
:
int
=
3
,
sleep
:
int
=
0
)
->
bool
:
result
=
super
().
download
(
tmp_dir
,
max_retries
,
sleep
)
if
result
:
output_folder
=
self
.
download_folder
try
:
print
(
f
" Extracting
{
self
.
filename
}
"
)
with
zipfile
.
ZipFile
(
self
.
path
,
"r"
)
as
main_zip
:
main_zip
.
extractall
(
output_folder
)
except
zipfile
.
BadZipfile
:
print
(
f
"🛑
{
self
.
path
}
is corrupt. Deleting"
)
self
.
path
.
unlink
()
return
False
# 5. Review and Save the Data
return
result
# Print the total number of tiles successfully loaded
print
(
f
"
\n
✅ Download complete. Total tiles loaded:
{
len
(
gdf
)
}
"
)
# Save the GeoDataFrame to a file
if
__name__
==
"__main__"
:
file_path
=
"bw_lod2_aktualitaet_tiles.geojson"
bw_json
=
TMP_DIR
/
"bw_lod2.json"
gdf
.
to_file
(
TMP_DIR
/
file_path
,
driver
=
"GeoJSON"
)
download_file
(
BW_WFS
,
bw_json
)
print
(
f
"Data saved to:
{
file_path
}
"
)
with
open
(
bw_json
)
as
json_file
:
print
(
gdf
.
columns
)
data
=
json
.
load
(
json_file
)
# Inspect the key columns
zip_files
=
[]
print
(
"
\n
First 5 tiles and their Kachelnamen:"
)
print
(
gdf
[[
"kachelname"
,
"produktionsdatum"
,
"dgm_datum"
]].
head
())
for
feature
in
data
[
"features"
]:
print
(
gdf
[
"dgm_datum"
].
describe
())
date
=
feature
[
"properties"
][
"produktionsdatum"
]
or
"1970-01-01"
print
(
gdf
[
"produktionsdatum"
].
describe
())
name
=
feature
[
"properties"
][
"kachelname"
]
# Assuming your GeoDataFrame is named 'gdf'
x
,
y
=
name
.
split
(
"-"
)
import
pandas
as
pd
# Zip contains 4 GMLs. X odd, Y even.
# 1. Ensure 'produktionsdatum' is in datetime format
# example: https://opengeodata.lgl-bw.de/data/lod2/LoD2_32_403_5312_2_bw.zip
gdf
[
'produktionsdatum'
]
=
pd
.
to_datetime
(
gdf
[
'produktionsdatum'
])
if
int
(
x
)
%
2
==
0
:
continue
# 2. Sort the GeoDataFrame by the more recent 'produktionsdatum'
if
int
(
y
)
%
2
==
1
:
# This column effectively captures the latest update that led to file re-packaging.
continue
most_recent_tiles
=
gdf
.
sort_values
(
by
=
'produktionsdatum'
,
ascending
=
False
)
url
=
ZIP_URL_FORMAT
%
(
x
,
y
)
# 3. Display the top 10 most recently updated tiles
zip_files
.
append
(
print
(
"Top 10 most recently updated tiles, sorted by 'produktionsdatum':"
)
ZipFile
(
print
(
most_recent_tiles
[[
'kachelname'
,
'produktionsdatum'
,
'dgm_datum'
]].
head
(
10
))
url
=
url
,
bundesland
=
BADEN_WUERTTEMBERG
,
except
Exception
as
e
:
source_date
=
datetime
.
strptime
(
date
,
"%Y-%m-%d"
),
print
(
f
"
\n
❌ An error occurred during the GetFeature request or processing:
{
e
}
"
)
# coordinate_reference_system ?
print
(
"If the error is related to size, consider manually paginating the requests."
)
)
)
download_all_files
(
zip_files
)
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment