mirror of
https://github.com/tomasriveral/ReSSPublica.git
synced 2026-08-11 18:28:38 +02:00
feeds: add places of worship per Religion in Bern
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 296 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 299 KiB |
@@ -16,6 +16,11 @@ on:
|
|||||||
required: false
|
required: false
|
||||||
default: "false"
|
default: "false"
|
||||||
type: boolean
|
type: boolean
|
||||||
|
forceGenerationBernPlacesOfWorship:
|
||||||
|
description: "force feed generation of places of worship per religion in Bern"
|
||||||
|
required: false
|
||||||
|
default: "false"
|
||||||
|
type: boolean
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@@ -92,6 +97,31 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
git commit -m "feeds: asian hornets sighting in Bern update $(date -u +%Y-%m-%d)"
|
git commit -m "feeds: asian hornets sighting in Bern update $(date -u +%Y-%m-%d)"
|
||||||
|
|
||||||
|
- name: Generate feeds for places of worship per religion in Bern
|
||||||
|
run: |
|
||||||
|
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ inputs.verbose }}" = "true" ]; then
|
||||||
|
echo "Running in VERBOSE mode"
|
||||||
|
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ inputs.forceGenerationBernPlacesOfWorship }}" = "true" ]; then
|
||||||
|
resspublica --force_gen_bernReligionMap --verbose
|
||||||
|
else
|
||||||
|
resspublica --gen_bernReligionMap --verbose
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ inputs.forceGenerationBernPlacesOfWorship }}" = "true" ]; then
|
||||||
|
resspublica --force_gen_bernReligionMap
|
||||||
|
else
|
||||||
|
resspublica --gen_bernReligionMap
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
git add feed/ .cache/ assets/
|
||||||
|
|
||||||
|
if git diff --cached --quiet; then
|
||||||
|
echo "No changes to commit"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
git commit -m "feeds: places of worship per Religion in Bern update $(date -u +%Y-%m-%d)"
|
||||||
|
|
||||||
|
|
||||||
- name: Push changes
|
- name: Push changes
|
||||||
run: |
|
run: |
|
||||||
git push origin main
|
git push origin main
|
||||||
|
|||||||
@@ -25,7 +25,9 @@ AI (ChatGPT 5.5 and Deepl) was used in this project for :
|
|||||||
* crafting the SPARQL requests (a language I had never heard of before this project)
|
* crafting the SPARQL requests (a language I had never heard of before this project)
|
||||||
* minor debugging when alternative methods did not solve the problems.
|
* minor debugging when alternative methods did not solve the problems.
|
||||||
* German, Italian and Romansh translations.
|
* German, Italian and Romansh translations.
|
||||||
* counselling the right python libraries to use
|
* help with Python libraries
|
||||||
|
|
||||||
|
All code was reviewed by a human.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
|
||||||
|
<id>https://raw.githubusercontent.com/tomasriveral/ReSSPublica/refs/heads/main/feed/atom/de/gotteshauserNachReligionImKantonBern</id>
|
||||||
|
<title>Gotteshäuser nach Religion im Kanton Bern</title>
|
||||||
|
<updated>2026-06-17T21:51:13.499795+02:00</updated>
|
||||||
|
<author>
|
||||||
|
<name>ReSSPublica</name>
|
||||||
|
</author>
|
||||||
|
<link href="https://raw.githubusercontent.com/tomasriveral/ReSSPublica/refs/heads/main/feed/atom/de/gotteshauserNachReligionImKantonBern.atom" rel="self"/>
|
||||||
|
<generator uri="https://lkiesow.github.io/python-feedgen" version="1.0.0">python-feedgen</generator>
|
||||||
|
<subtitle>RSS-Feed der Gotteshäuser nach Religion im Kanton Bern</subtitle>
|
||||||
|
</feed>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="fr">
|
||||||
|
<id>https://raw.githubusercontent.com/tomasriveral/ReSSPublica/refs/heads/main/feed/atom/fr/lieuDeCulteParReligionDansLeCantonDeBerne</id>
|
||||||
|
<title>Lieu de culte par religion dans le canton de Berne</title>
|
||||||
|
<updated>2026-06-17T21:51:13.497469+02:00</updated>
|
||||||
|
<author>
|
||||||
|
<name>ReSSPublica</name>
|
||||||
|
</author>
|
||||||
|
<link href="https://raw.githubusercontent.com/tomasriveral/ReSSPublica/refs/heads/main/feed/atom/fr/lieuDeCulteParReligionDansLeCantonDeBerne.atom" rel="self"/>
|
||||||
|
<generator uri="https://lkiesow.github.io/python-feedgen" version="1.0.0">python-feedgen</generator>
|
||||||
|
<subtitle>Flux RSS des Lieu de culte par religion dans le canton de Berne</subtitle>
|
||||||
|
</feed>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
|
||||||
|
<channel>
|
||||||
|
<title>Gotteshäuser nach Religion im Kanton Bern</title>
|
||||||
|
<link>https://raw.githubusercontent.com/tomasriveral/ReSSPublica/refs/heads/main/feed/atom/de/gotteshauserNachReligionImKantonBern.atom</link>
|
||||||
|
<description>RSS-Feed der Gotteshäuser nach Religion im Kanton Bern</description>
|
||||||
|
<atom:link href="https://raw.githubusercontent.com/tomasriveral/ReSSPublica/refs/heads/main/feed/atom/de/gotteshauserNachReligionImKantonBern.atom" rel="self"/>
|
||||||
|
<docs>https://github.com/tomasriveral/ReSSPublica</docs>
|
||||||
|
<generator>python-feedgen</generator>
|
||||||
|
<language>de</language>
|
||||||
|
<lastBuildDate>Wed, 17 Jun 2026 21:51:13 +0200</lastBuildDate>
|
||||||
|
</channel>
|
||||||
|
</rss>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
|
||||||
|
<channel>
|
||||||
|
<title>Lieu de culte par religion dans le canton de Berne</title>
|
||||||
|
<link>https://raw.githubusercontent.com/tomasriveral/ReSSPublica/refs/heads/main/feed/atom/fr/lieuDeCulteParReligionDansLeCantonDeBerne.atom</link>
|
||||||
|
<description>Flux RSS des Lieu de culte par religion dans le canton de Berne</description>
|
||||||
|
<atom:link href="https://raw.githubusercontent.com/tomasriveral/ReSSPublica/refs/heads/main/feed/atom/fr/lieuDeCulteParReligionDansLeCantonDeBerne.atom" rel="self"/>
|
||||||
|
<docs>https://github.com/tomasriveral/ReSSPublica</docs>
|
||||||
|
<generator>python-feedgen</generator>
|
||||||
|
<language>fr</language>
|
||||||
|
<lastBuildDate>Wed, 17 Jun 2026 21:51:13 +0200</lastBuildDate>
|
||||||
|
</channel>
|
||||||
|
</rss>
|
||||||
@@ -31,6 +31,7 @@
|
|||||||
matplotlib
|
matplotlib
|
||||||
pycurl
|
pycurl
|
||||||
beautifulsoup4
|
beautifulsoup4
|
||||||
|
seaborn
|
||||||
];
|
];
|
||||||
|
|
||||||
# you will need to point to your local git clone
|
# you will need to point to your local git clone
|
||||||
@@ -59,6 +60,7 @@
|
|||||||
matplotlib
|
matplotlib
|
||||||
beautifulsoup4
|
beautifulsoup4
|
||||||
pycurl
|
pycurl
|
||||||
|
seaborn
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
+2
-1
@@ -18,7 +18,8 @@ dependencies = [
|
|||||||
"pyarrow", #dep for parquet
|
"pyarrow", #dep for parquet
|
||||||
"matplotlib",
|
"matplotlib",
|
||||||
"beautifulsoup4",
|
"beautifulsoup4",
|
||||||
"pycurl"
|
"pycurl",
|
||||||
|
"seaborn"
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ def generateBernAsianHornetFeed(ASSETS, CACHE):
|
|||||||
else:
|
else:
|
||||||
weeklyEntry["url"] = f"https://opendata.swiss/{lang}/dataset/asiatische-hornisse"
|
weeklyEntry["url"] = f"https://opendata.swiss/{lang}/dataset/asiatische-hornisse"
|
||||||
weeklyEntry["title"] = translatedBernAsianHornetSightings[lang] + f" {start.isoformat()}-{end.isoformat()}"
|
weeklyEntry["title"] = translatedBernAsianHornetSightings[lang] + f" {start.isoformat()}-{end.isoformat()}"
|
||||||
weeklyEntry["text"] = f"<img src=\"https://raw.githubusercontent.com/tomasriveral/ReSSPublica/refs/heads/main/.cache/bernAsianHornets-{lang}-{start.isoformat()}-{end.isoformat()}.png\" alt=\"{translatedBernAsianHornetSightings[lang]} {start.isoformat()}-{end.isoformat()}\">" # yes there is an error in filename. the s in asian is capitalized. I don't really want to regenerate all the images...
|
weeklyEntry["text"] = f"<img src=\"https://raw.githubusercontent.com/tomasriveral/ReSSPublica/refs/heads/main/.cache/bernAsianHornets-{lang}-{start.isoformat()}-{end.isoformat()}.png\" alt=\"{translatedBernAsianHornetSightings[lang]} {start.isoformat()}-{end.isoformat()}\">"
|
||||||
feeds[lang].append(copy.deepcopy(weeklyEntry))
|
feeds[lang].append(copy.deepcopy(weeklyEntry))
|
||||||
|
|
||||||
generateFeed(
|
generateFeed(
|
||||||
|
|||||||
@@ -0,0 +1,272 @@
|
|||||||
|
import pandas as pd
|
||||||
|
import copy
|
||||||
|
import geopandas as gpd
|
||||||
|
from shapely import wkb
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import datetime
|
||||||
|
from datetime import date, time
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
from tinydb import TinyDB, Query
|
||||||
|
from time import sleep
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
from pathlib import Path
|
||||||
|
from seaborn import color_palette
|
||||||
|
|
||||||
|
|
||||||
|
import logging
|
||||||
|
logger = logging.getLogger("resspublica")
|
||||||
|
|
||||||
|
from .translations import *
|
||||||
|
from .utils import *
|
||||||
|
|
||||||
|
# We don't have a date fields in this dataset.
|
||||||
|
# What we do i create a snapshot (an image) each trimester to see the evolution
|
||||||
|
|
||||||
|
def generateBernReligionMap(ASSETS, CACHE):
|
||||||
|
|
||||||
|
arbitraryStartDate = date.fromisoformat("2026-01-01") # start date for weekly image generation. The data source starts at 2021-05-22, but as there is no date information, we must start at today
|
||||||
|
|
||||||
|
logger.info("Generating Religion map in Bern feed...")
|
||||||
|
logger.info("Preparing data...")
|
||||||
|
#ASIAN_HORNETS_DB_PATH = CACHE / "bernAsianHornet.json"
|
||||||
|
#global db
|
||||||
|
#global q
|
||||||
|
#db = TinyDB(ASIAN_HORNETS_DB_PATH)
|
||||||
|
#q = Query()
|
||||||
|
|
||||||
|
|
||||||
|
# 1. Load data
|
||||||
|
url = "https://geofiles.be.ch/geoportal/pub/download/RELIGION/religion_relstaet.parquet"
|
||||||
|
dataframe = pd.read_parquet(url)
|
||||||
|
|
||||||
|
# 2. Convert WKB geometry safely
|
||||||
|
def safe_load(x):
|
||||||
|
try:
|
||||||
|
return wkb.loads(x)
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
dataframe["geometry"] = dataframe["geometry"].apply(safe_load)
|
||||||
|
dataframe = dataframe.dropna(subset=["geometry"])
|
||||||
|
|
||||||
|
religionGeoDataFrame = gpd.GeoDataFrame(dataframe, geometry="geometry", crs="EPSG:2056")
|
||||||
|
|
||||||
|
# We create a trimesterly image
|
||||||
|
# We just need to check if we haven't already created it
|
||||||
|
|
||||||
|
# Each row is of the form Pandas(Index=127, objectid=23, uuid='D7CF8B83-4CD0-4F9E-9126-603BCCC0A42D', e_koord=2585316, n_koord=1221326, adresse='Rue de la Source 27', plz_ort='2502 Biel/Bienne', name_staet='Christkatholische Kirchgemeinde Biel', bez_staet='Christkatholische Kirchgemeinde Biel', symbol=8, reltra_id=1, reltrat_reltra_de='christlich', reltrat_reltra_fr='Christianisme', nkenn_id=6.0, nkennt_nkenn_de='christkatholisch', nkennt_nkenn_fr='catholique chrétien', kontakt_id=1, kontaktt_kontakt_de='offiziell', kontaktt_kontakt_fr='officiel', url='https://christkatholisch.ch/biel', adresse_k='Sekretariat und Pfarramt, General-Dufourstrasse 105', plz_ort_k='2502 Biel/Bienne', telefon='032 341 21 16', email='sekretariat.biel@christkatholisch.ch', jur_id=1, jurt_jur_de='öffentlich-rechtlich anerkannte Körperschaft', jurt_jur_fr='Collectivité reconnue de droit public', geometry=<POINT (2585316 1221326)>, bbox={'min_x': 2585316.0, 'min_y': 1221326.0, 'max_x': 2585316.0, 'max_y': 1221326.0})
|
||||||
|
|
||||||
|
# Note : some religion don't have subdivision in this dataset (ex: Judaisme) and as such don't have nkennt_* keys for them we set nkenn_id to 0
|
||||||
|
|
||||||
|
# Generate a dictionary that contains all (available) religions :
|
||||||
|
logger.info("Gathering information on the religions...")
|
||||||
|
df = religionGeoDataFrame.copy()
|
||||||
|
|
||||||
|
# ensure nkenn_id exists even when NaN
|
||||||
|
df['nkenn_id_filled'] = df['nkenn_id'].fillna(0).astype(int)
|
||||||
|
|
||||||
|
# build composite key "reltra-nkenn"
|
||||||
|
df['key'] = df['reltra_id'].astype(int).astype(str) + "-" + df['nkenn_id_filled'].astype(str)
|
||||||
|
|
||||||
|
# keep only relevant columns
|
||||||
|
cols = [
|
||||||
|
'key',
|
||||||
|
'reltra_id',
|
||||||
|
'nkenn_id',
|
||||||
|
'nkennt_nkenn_fr',
|
||||||
|
'nkennt_nkenn_de',
|
||||||
|
'reltrat_reltra_fr',
|
||||||
|
'reltrat_reltra_de'
|
||||||
|
]
|
||||||
|
|
||||||
|
df = df[cols].drop_duplicates(subset=['key'])
|
||||||
|
|
||||||
|
# sort by reltra_id so that religion groups are contiguous
|
||||||
|
df = df.sort_values(by=["reltra_id", "nkenn_id"], na_position="last")
|
||||||
|
# build dictionary
|
||||||
|
religions = (
|
||||||
|
df.set_index('key')
|
||||||
|
.apply(lambda row: {
|
||||||
|
k: v for k, v in {
|
||||||
|
"nkenn_id": row["nkenn_id"],
|
||||||
|
"nkennt_nkenn_fr": row["nkennt_nkenn_fr"],
|
||||||
|
"nkennt_nkenn_de": row["nkennt_nkenn_de"],
|
||||||
|
"reltra_id": row["reltra_id"],
|
||||||
|
"reltrat_reltra_fr": row["reltrat_reltra_fr"],
|
||||||
|
"reltrat_reltra_de": row["reltrat_reltra_de"],
|
||||||
|
}.items()
|
||||||
|
if pd.notna(v)
|
||||||
|
}, axis=1)
|
||||||
|
.to_dict()
|
||||||
|
)
|
||||||
|
logger.debug(religions)
|
||||||
|
|
||||||
|
# generate color palette (1 color by religion with similar religion similar color)
|
||||||
|
palette = color_palette("husl", len(religions.keys()))
|
||||||
|
color_map = {
|
||||||
|
key: palette[i]
|
||||||
|
for i, key in enumerate(religions.keys())
|
||||||
|
}
|
||||||
|
|
||||||
|
# as the canton borders do not change (frequently), we just download once the data
|
||||||
|
gdbPathToCantonBoundariesDirectory = ASSETS / "swissBOUNDARIES3D_1_5_LV95_LN02.gdb"
|
||||||
|
|
||||||
|
cantonsBoundariesData = gpd.read_file(
|
||||||
|
gdbPathToCantonBoundariesDirectory,
|
||||||
|
layer="TLM_KANTONSGEBIET"
|
||||||
|
)
|
||||||
|
|
||||||
|
bernCantonBoundaries = cantonsBoundariesData[
|
||||||
|
cantonsBoundariesData["KANTONSNUMMER"] == 2
|
||||||
|
].to_crs(religionGeoDataFrame.crs)
|
||||||
|
|
||||||
|
religionGeoDataFrame = religionGeoDataFrame[religionGeoDataFrame.geometry.notnull()].copy()
|
||||||
|
|
||||||
|
municipialitiesBoundaries = gpd.read_file(
|
||||||
|
gdbPathToCantonBoundariesDirectory,
|
||||||
|
layer="TLM_HOHEITSGEBIET"
|
||||||
|
)
|
||||||
|
|
||||||
|
bernCityBoundaries = municipialitiesBoundaries[
|
||||||
|
municipialitiesBoundaries["NAME"] == "Bern"
|
||||||
|
].to_crs(religionGeoDataFrame.crs)
|
||||||
|
|
||||||
|
bernCityPolygon = bernCityBoundaries.geometry.iloc[0]
|
||||||
|
|
||||||
|
# subset of the scatter points of religion within the boundaries of the city of Bern
|
||||||
|
religionGeoDataFrameSubsetInBernCity = religionGeoDataFrame[religionGeoDataFrame.within(bernCityPolygon)].copy()
|
||||||
|
|
||||||
|
for start, end in trimesterRangesFrom(arbitraryStartDate):
|
||||||
|
if Path( CACHE / f"bernReligionMap-fr-{start.isoformat()}-{end.isoformat()}.png").exists(): # we only check french, but if one language exists the other ones should also exist
|
||||||
|
logger.debug(f"Trimester {start.isoformat()}-{end.isoformat()} was already cached. Skipping...")
|
||||||
|
continue
|
||||||
|
logger.debug(f"Handling trimester {start.isoformat()}-{end.isoformat()}...")
|
||||||
|
|
||||||
|
for lang in ["fr", "de"]:
|
||||||
|
fig, (pltAxBernCanton, pltAxBernCity) = plt.subplots(
|
||||||
|
2, 1,
|
||||||
|
figsize=(12, 16),
|
||||||
|
gridspec_kw={"height_ratios": [1.2, 1]}
|
||||||
|
)
|
||||||
|
bernCantonBoundaries.plot(
|
||||||
|
ax=pltAxBernCanton,
|
||||||
|
facecolor="none",
|
||||||
|
edgecolor="black",
|
||||||
|
linewidth=2
|
||||||
|
)
|
||||||
|
|
||||||
|
for religion_key in religions.keys():
|
||||||
|
logger.info(f"Handling religion {religion_key}")
|
||||||
|
reltra_id_str, nkenn_id_str = religion_key.split("-")
|
||||||
|
|
||||||
|
reltra_id = int(reltra_id_str)
|
||||||
|
nkenn_id = int(nkenn_id_str)
|
||||||
|
|
||||||
|
subset = religionGeoDataFrame[religionGeoDataFrame["reltra_id"] == reltra_id]
|
||||||
|
|
||||||
|
if nkenn_id == 0:
|
||||||
|
subset.plot(
|
||||||
|
ax=pltAxBernCanton,
|
||||||
|
color=color_map[religion_key],
|
||||||
|
markersize=5,
|
||||||
|
alpha=0.6,
|
||||||
|
label=religions[religion_key][f"reltrat_reltra_{lang}"]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
subset = subset[subset["nkenn_id"] == nkenn_id]
|
||||||
|
|
||||||
|
subset.plot(
|
||||||
|
ax=pltAxBernCanton,
|
||||||
|
color=color_map[religion_key],
|
||||||
|
markersize=5,
|
||||||
|
alpha=0.6,
|
||||||
|
label=religions[religion_key][f"nkennt_nkenn_{lang}"]
|
||||||
|
+ f" ({religions[religion_key][f'reltrat_reltra_{lang}'].strip(" ")})"
|
||||||
|
) # for some reason the reltrat_reltra_fr for bouddisme has a final " " so we need to strip it
|
||||||
|
handles, labels = pltAxBernCanton.get_legend_handles_labels()
|
||||||
|
|
||||||
|
fig.legend(
|
||||||
|
handles,
|
||||||
|
labels,
|
||||||
|
loc="upper right",
|
||||||
|
ncol=1,
|
||||||
|
fontsize=10,
|
||||||
|
title=translatedPlacesOfWorshipInBern[lang]
|
||||||
|
)
|
||||||
|
fig.subplots_adjust(right=0.8)
|
||||||
|
|
||||||
|
pltAxBernCanton.set_title("")
|
||||||
|
pltAxBernCanton.set_axis_off()
|
||||||
|
|
||||||
|
bernCantonBoundaries.plot(
|
||||||
|
ax=pltAxBernCity,
|
||||||
|
facecolor="none",
|
||||||
|
edgecolor="black",
|
||||||
|
linewidth=2
|
||||||
|
)
|
||||||
|
|
||||||
|
bernCityBoundaries.boundary.plot(ax=pltAxBernCity, color="black", linewidth=1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for religion_key in religions.keys():
|
||||||
|
reltra_id_str, nkenn_id_str = religion_key.split("-")
|
||||||
|
|
||||||
|
reltra_id = int(reltra_id_str)
|
||||||
|
nkenn_id = int(nkenn_id_str)
|
||||||
|
|
||||||
|
subset = religionGeoDataFrameSubsetInBernCity[religionGeoDataFrameSubsetInBernCity["reltra_id"] == reltra_id]
|
||||||
|
|
||||||
|
if nkenn_id != 0:
|
||||||
|
subset = subset[subset["nkenn_id"] == nkenn_id]
|
||||||
|
|
||||||
|
subset.plot(
|
||||||
|
ax=pltAxBernCity,
|
||||||
|
color=color_map[religion_key],
|
||||||
|
markersize=5,
|
||||||
|
alpha=0.7
|
||||||
|
)
|
||||||
|
xmin, ymin, xmax, ymax = bernCityBoundaries.total_bounds
|
||||||
|
|
||||||
|
pltAxBernCity.set_xlim(xmin, xmax)
|
||||||
|
pltAxBernCity.set_ylim(ymin, ymax)
|
||||||
|
pltAxBernCity.set_title(translatedCityOfBern[lang])
|
||||||
|
pltAxBernCity.set_axis_off()
|
||||||
|
|
||||||
|
plt.tight_layout()
|
||||||
|
plt.savefig(CACHE / f"bernReligionMap-{lang}-{start.isoformat()}-{end.isoformat()}.png", dpi=120, bbox_inches="tight")
|
||||||
|
logger.debug(f"Generated bernReligionMap-{lang}-{start.isoformat()}-{end.isoformat()}.png")
|
||||||
|
plt.close()
|
||||||
|
feeds = {
|
||||||
|
"fr": [],
|
||||||
|
"de": []
|
||||||
|
}
|
||||||
|
for start, end in trimesterRangesFrom(arbitraryStartDate):
|
||||||
|
trimestrialEntry = {}
|
||||||
|
trimestrialEntry["id"] = datetime.combine(start, time(12, 0)).timestamp() # we use timestamp as ids
|
||||||
|
trimestrialEntry["creationDate"] = start.isoformat()
|
||||||
|
trimestrialEntry["date"] = start.isoformat() # there is no point have them different. On other feeds it's used for update date
|
||||||
|
trimestrialEntry["source"] = "opendata.swiss"
|
||||||
|
|
||||||
|
for lang in ["fr", "de"]:
|
||||||
|
trimestrialEntry["url"] = f"https://opendata.swiss/{lang}/dataset/religionslandkarte"
|
||||||
|
trimestrialEntry["title"] = f"{translatedPlacesOfWorshipInBern[lang]}-{start.isoformat()}"
|
||||||
|
trimestrialEntry["text"] = f"<img src=\"https://raw.githubusercontent.com/tomasriveral/ReSSPublica/refs/heads/main/.cache/bernReligionMap-{lang}-{start.isoformat()}-{end.isoformat()}.png\" alt=\"{translatedPlacesOfWorshipInBern[lang]} {start.isoformat()}\">"
|
||||||
|
generateFeed(
|
||||||
|
translatedPlacesOfWorshipInBern["fr"],
|
||||||
|
f"Flux RSS des {translatedPlacesOfWorshipInBern["fr"]}",
|
||||||
|
translatedPlacesOfWorshipInBernCamelCase["fr"],
|
||||||
|
"fr",
|
||||||
|
["rss", "atom"],
|
||||||
|
datetime.now().replace(tzinfo=ZoneInfo("Europe/Zurich")),
|
||||||
|
feeds["fr"]
|
||||||
|
)
|
||||||
|
generateFeed(
|
||||||
|
translatedPlacesOfWorshipInBern["de"],
|
||||||
|
f"RSS-Feed der {translatedPlacesOfWorshipInBern["de"]}",
|
||||||
|
translatedPlacesOfWorshipInBernCamelCase["de"],
|
||||||
|
"de",
|
||||||
|
["rss", "atom"],
|
||||||
|
datetime.now().replace(tzinfo=ZoneInfo("Europe/Zurich")),
|
||||||
|
feeds["de"]
|
||||||
|
)
|
||||||
@@ -9,6 +9,7 @@ from .utils import *
|
|||||||
from .federalInitiativesFeeds import *
|
from .federalInitiativesFeeds import *
|
||||||
from .translations import *
|
from .translations import *
|
||||||
from .bernAsianHornet import *
|
from .bernAsianHornet import *
|
||||||
|
from .bernReligionMap import *
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
@@ -16,6 +17,8 @@ def main():
|
|||||||
parser.add_argument("--gen_federalInitiatives", action="store_true", help="Generate federal popular initiatives feed")
|
parser.add_argument("--gen_federalInitiatives", action="store_true", help="Generate federal popular initiatives feed")
|
||||||
parser.add_argument("--gen_bernAsianHornets", action="store_true", help="Generate Asian hornets sightings in Bern feed (only Mondays)")
|
parser.add_argument("--gen_bernAsianHornets", action="store_true", help="Generate Asian hornets sightings in Bern feed (only Mondays)")
|
||||||
parser.add_argument("--force_gen_bernAsianHornets", action="store_true", help="Generate Asian hornets sightings in Bern feed even when not Monday")
|
parser.add_argument("--force_gen_bernAsianHornets", action="store_true", help="Generate Asian hornets sightings in Bern feed even when not Monday")
|
||||||
|
parser.add_argument("--gen_bernReligionMap", action="store_true", help="Generate map of religions in Bern (only start of trimesters)")
|
||||||
|
parser.add_argument("--force_gen_bernReligionMap", action="store_true", help="Generate map of religions in Bern even when not start of trimester")
|
||||||
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
@@ -35,4 +38,6 @@ def main():
|
|||||||
generateFederalFeed(CACHE)
|
generateFederalFeed(CACHE)
|
||||||
if (date.today().weekday() == 0 and args.gen_bernAsianHornets) or args.force_gen_bernAsianHornets:
|
if (date.today().weekday() == 0 and args.gen_bernAsianHornets) or args.force_gen_bernAsianHornets:
|
||||||
generateBernAsianHornetFeed(ASSETS, CACHE)
|
generateBernAsianHornetFeed(ASSETS, CACHE)
|
||||||
|
if ( args.gen_bernReligionMap and date.today().day == 1 and date.today().month in [1, 5, 9]) or args.force_gen_bernReligionMap:
|
||||||
|
generateBernReligionMap(ASSETS, CACHE)
|
||||||
logging.info("Done")
|
logging.info("Done")
|
||||||
|
|||||||
@@ -76,3 +76,15 @@ translatedBernAsianHornetSightings = {
|
|||||||
"it": ("Avvistamenti di calabroni asiatici a Berna"),
|
"it": ("Avvistamenti di calabroni asiatici a Berna"),
|
||||||
"rm": ("Observaziuns da vespras asiaticas a Berna"),
|
"rm": ("Observaziuns da vespras asiaticas a Berna"),
|
||||||
}
|
}
|
||||||
|
translatedPlacesOfWorshipInBern = {
|
||||||
|
"de": "Gotteshäuser nach Religion im Kanton Bern",
|
||||||
|
"fr": "Lieu de culte par religion dans le canton de Berne"
|
||||||
|
}
|
||||||
|
translatedPlacesOfWorshipInBernCamelCase = {
|
||||||
|
"de": "gotteshauserNachReligionImKantonBern",
|
||||||
|
"fr": "lieuDeCulteParReligionDansLeCantonDeBerne"
|
||||||
|
}
|
||||||
|
translatedCityOfBern = {
|
||||||
|
"de": "Stadt Bern",
|
||||||
|
"fr": "Ville de Bern"
|
||||||
|
}
|
||||||
|
|||||||
@@ -117,3 +117,35 @@ def weeklyRangesFrom(start_date: date):
|
|||||||
start += timedelta(days=7)
|
start += timedelta(days=7)
|
||||||
|
|
||||||
return weeks
|
return weeks
|
||||||
|
|
||||||
|
|
||||||
|
def trimester_start(d: date) -> date:
|
||||||
|
if d.month <= 4:
|
||||||
|
return date(d.year, 1, 1)
|
||||||
|
elif d.month <= 8:
|
||||||
|
return date(d.year, 5, 1)
|
||||||
|
else:
|
||||||
|
return date(d.year, 9, 1)
|
||||||
|
def next_trimester_start(d: date) -> date:
|
||||||
|
if d.month <= 4:
|
||||||
|
return date(d.year, 5, 1)
|
||||||
|
elif d.month <= 8:
|
||||||
|
return date(d.year, 9, 1)
|
||||||
|
else:
|
||||||
|
return date(d.year + 1, 1, 1)
|
||||||
|
def trimesterRangesFrom(start_date: date):
|
||||||
|
today = date.today()
|
||||||
|
|
||||||
|
current_trimester_start = trimester_start(today)
|
||||||
|
start = trimester_start(start_date)
|
||||||
|
|
||||||
|
trimesters = []
|
||||||
|
|
||||||
|
while start < current_trimester_start:
|
||||||
|
next_start = next_trimester_start(start)
|
||||||
|
end = next_start - timedelta(days=1)
|
||||||
|
|
||||||
|
trimesters.append((start, end))
|
||||||
|
start = next_start
|
||||||
|
|
||||||
|
return trimesters
|
||||||
|
|||||||
Reference in New Issue
Block a user