diff --git a/.gitignore b/.gitignore index d6e362e..04dd9ef 100644 --- a/.gitignore +++ b/.gitignore @@ -257,3 +257,4 @@ python_pkg/music_gen/output/ # Screen locker state files python_pkg/screen_locker/sick_day_state.json python_pkg/screen_locker/workout_log.json.bak +preview_images diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9a61a76..c524d7e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -36,7 +36,7 @@ repos: - id: check-toml - id: check-xml - id: check-added-large-files - args: [--maxkb=1000] + args: [--maxkb=2000] - id: check-merge-conflict - id: check-case-conflict - id: check-symlinks diff --git a/python_pkg/warsaw_districts/run.sh b/python_pkg/warsaw_districts/run.sh new file mode 100755 index 0000000..cf60e60 --- /dev/null +++ b/python_pkg/warsaw_districts/run.sh @@ -0,0 +1,56 @@ +#!/bin/bash +# Script to set up environment, install dependencies, and generate Warsaw Districts Anki deck + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +VENV_DIR="$SCRIPT_DIR/.venv" +PREVIEW_DIR="$SCRIPT_DIR/preview_images" + +echo "=== Warsaw Districts Anki Generator ===" +echo + +# Create virtual environment if it doesn't exist +if [ ! -d "$VENV_DIR" ]; then + echo "Creating virtual environment..." + python3 -m venv "$VENV_DIR" +fi + +# Activate virtual environment +echo "Activating virtual environment..." +source "$VENV_DIR/bin/activate" + +# Install dependencies +echo "Installing dependencies..." +pip install --quiet --upgrade pip +pip install --quiet matplotlib genanki geopandas + +# Export preview images +echo +echo "Exporting preview images to $PREVIEW_DIR..." +mkdir -p "$PREVIEW_DIR" +cd "$SCRIPT_DIR" +python -c " +from warsaw_districts_anki import WARSAW_DISTRICTS, generate_district_image_bytes +from pathlib import Path + +preview_dir = Path('$PREVIEW_DIR') +for district in WARSAW_DISTRICTS: + filename = district.replace(' ', '_').replace('-', '_') + '.png' + filepath = preview_dir / filename + filepath.write_bytes(generate_district_image_bytes(district)) + print(f' Exported: {filename}') +" + +echo +echo "Preview images exported! Check: $PREVIEW_DIR" + +# Generate Anki deck +echo +echo "Generating Anki flashcards..." +python -m warsaw_districts_anki --output warsaw_districts.apkg + +echo +echo "Done!" +echo " - Preview images: $PREVIEW_DIR" +echo " - Anki deck: $SCRIPT_DIR/warsaw_districts.apkg" diff --git a/python_pkg/warsaw_districts/warsaw_districts.apkg b/python_pkg/warsaw_districts/warsaw_districts.apkg new file mode 100644 index 0000000..843434a Binary files /dev/null and b/python_pkg/warsaw_districts/warsaw_districts.apkg differ diff --git a/python_pkg/warsaw_districts/warsaw_districts_anki.py b/python_pkg/warsaw_districts/warsaw_districts_anki.py index ad447a2..ef1f07f 100755 --- a/python_pkg/warsaw_districts/warsaw_districts_anki.py +++ b/python_pkg/warsaw_districts/warsaw_districts_anki.py @@ -70,8 +70,36 @@ def get_district_names() -> list[str]: WARSAW_DISTRICTS = get_district_names() +# 18 unique distinct colors for all Warsaw districts +# Chosen to be visually distinct from each other in both light and dark modes +DISTRICT_COLORS = [ + "#E74C3C", # Red + "#3498DB", # Blue + "#2ECC71", # Emerald green + "#9B59B6", # Purple + "#F39C12", # Orange + "#1ABC9C", # Turquoise + "#E91E63", # Pink + "#00BCD4", # Cyan + "#8BC34A", # Light green + "#FF5722", # Deep orange + "#673AB7", # Deep purple + "#FFEB3B", # Yellow + "#795548", # Brown + "#607D8B", # Blue grey + "#CDDC39", # Lime + "#FF9800", # Amber + "#4CAF50", # Green + "#03A9F4", # Light blue +] + + def create_district_map(district_name: str) -> Figure: - """Create a map showing Warsaw districts with one district highlighted. + """Create a map showing Warsaw with one district highlighted. + + The map shows Warsaw as a plain shape (no internal district borders) + with only the target district highlighted in color with a bold border. + This makes it harder to guess the district using contextual cues. Args: district_name: Name of the district to highlight. @@ -82,22 +110,38 @@ def create_district_map(district_name: str) -> Figure: # Load all district data gdf = load_district_data() - # Create figure + # Create figure with transparent background fig, ax = plt.subplots(figsize=(10, 10)) ax.set_aspect("equal") ax.axis("off") + fig.patch.set_alpha(0) + ax.patch.set_alpha(0) - # Plot all districts with light gray borders - gdf.boundary.plot(ax=ax, color="lightgray", linewidth=0.5, alpha=0.5) - - # Find and highlight the target district + # Find the target district target = gdf[gdf["name"] == district_name] if len(target) == 0: msg = f"District {district_name} not found in data" raise ValueError(msg) - # Plot the highlighted district with bold black border - target.boundary.plot(ax=ax, color="black", linewidth=3) + # Create unified Warsaw shape by dissolving all districts + warsaw_unified = gdf.union_all() + + # Plot Warsaw as a plain gray shape (no internal borders) + warsaw_gdf = gpd.GeoDataFrame(geometry=[warsaw_unified], crs=gdf.crs) + warsaw_gdf.plot(ax=ax, color="#D5D8DC", alpha=0.6) + warsaw_gdf.boundary.plot(ax=ax, color="#2C3E50", linewidth=2) + + # Assign colors to districts based on sorted names for consistency + sorted_names = sorted(gdf["name"].tolist()) + color_map = { + name: DISTRICT_COLORS[i % len(DISTRICT_COLORS)] + for i, name in enumerate(sorted_names) + } + + # Highlight only the target district with bright color and bold border + fill_color = color_map[district_name] + target.plot(ax=ax, color=fill_color, alpha=0.9) + target.boundary.plot(ax=ax, color="#1A1A1A", linewidth=4) # Set tight layout ax.set_xlim(gdf.total_bounds[0], gdf.total_bounds[2]) @@ -143,7 +187,41 @@ def generate_anki_package( ) model_id = int(model_id_hash.hexdigest()[:8], 16) - # Define the note model (card template) + # Define the note model (card template) with centered styling + card_css = """ +.card { + font-family: Arial, sans-serif; + font-size: 24px; + text-align: center; + color: #333; + background-color: #fff; +} +.card.night_mode { + color: #eee; + background-color: #2f2f2f; +} +.map-container { + display: flex; + justify-content: center; + align-items: center; + min-height: 80vh; +} +.map-container img { + max-width: 100%; + max-height: 80vh; + object-fit: contain; +} +.answer-text { + font-size: 32px; + font-weight: bold; + margin-top: 20px; + color: #2C3E50; +} +.card.night_mode .answer-text { + color: #ECF0F1; +} +""" + my_model = genanki.Model( model_id, "Warsaw District Model", @@ -154,10 +232,13 @@ def generate_anki_package( templates=[ { "name": "Card 1", - "qfmt": "{{DistrictMap}}", - "afmt": '{{FrontSide}}