import streamlit as st
import geopandas as gpd
import folium
from streamlit_folium import folium_static
from dotenv import load_dotenv
from utils import get_provider_data
import os
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
from folium.features import CustomIcon
# Load environment variables
load_dotenv()
# Set page config for dark theme
st.set_page_config(
page_title="Europeana Data Explorer",
page_icon="🌍",
layout="wide",
initial_sidebar_state="expanded",
)
# Load CSS file
def load_css(file_name):
with open(file_name) as f:
st.markdown(f'', unsafe_allow_html=True)
# Load the CSS
load_css("style.css")
# Ensure that the API key is set
if 'EUROPEANA_API_KEY' not in os.environ:
st.error("EUROPEANA_API_KEY is not set in the environment variables. Please set it and restart the app.")
st.stop()
# Load world map dataset
world = gpd.read_file("lowres_world.geojson")
# Set up the Streamlit app
st.title('🌍 Europeana Data Explorer')
# Sidebar
st.sidebar.header("About")
st.sidebar.info("This app allows you to explore data from Europeana providers. Enter a provider name to fetch and visualize their data across different countries.")
# Add Europeana logo below the "About" section
logo_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/0/02/Europeana_logo_2015_basic.svg/800px-Europeana_logo_2015_basic.svg.png"
st.sidebar.image(logo_url, width=50)
# Input for provider name
provider_name = st.text_input('Enter the name of the data provider:', help="e.g., 'Rijksmuseum'")
# Button to trigger data fetch
if st.button('🔍 Fetch Data'):
if provider_name:
# Show loading message
with st.spinner('Fetching data...'):
# Get the data
df, world_counts = get_provider_data(provider_name, world)
# Display the data
st.subheader(f'📊 Data from {provider_name}')
st.write(f'Number of items retrieved: {len(df):,}')
# Display the first few rows
st.subheader('🔎 Sample Data:')
st.dataframe(df.head(), use_container_width=True)
# Create and display the choropleth map
with st.expander('Object Counts by Country'):
choropleth_map = folium.Map(location=[20, 0], zoom_start=2, tiles="cartodbpositron")
# Apply log transformation to object_count
world_counts['log_count'] = np.log1p(world_counts['object_count'])
# Use a custom colormap
colormap = plt.colormaps['Blues'] # Access the 'Blues' colormap
norm = mcolors.Normalize(
vmin=world_counts['log_count'].min(),
vmax=world_counts['log_count'].max())
# Function to map log_count to a color using the colormap
def get_color(log_count):
return mcolors.to_hex(colormap(norm(log_count)))
# Add the choropleth layer
choropleth = folium.Choropleth(
geo_data=world_counts,
name='choropleth',
data=world_counts,
columns=['name', 'log_count'],
key_on='feature.properties.name',
fill_opacity=0.7,
line_opacity=0.2,
legend_name=None
)
# Remove the existing color map from the choropleth object
for key in choropleth._children:
if key.startswith('color_map'):
del (choropleth._children[key])
choropleth.add_to(choropleth_map)
# Manually set the colors for each feature based on log_count using the
# custom function
for feature in choropleth.geojson.data['features']:
log_count = feature['properties']['log_count']
feature['properties']['style'] = {
'fillColor': get_color(log_count)}
# Add hover functionality
def style_function(x): return {'fillColor': '#ffffff',
'color': '#000000',
'fillOpacity': 0.1,
'weight': 0.1}
def highlight_function(x): return {'fillColor': '#ffffff',
'color': '#000000',
'fillOpacity': 0.50,
'weight': 0.1}
info = folium.features.GeoJson(
world_counts,
style_function=style_function,
control=False,
highlight_function=highlight_function,
tooltip=folium.features.GeoJsonTooltip(
fields=['name', 'object_count'],
aliases=['Country:', 'Number of Objects:'],
style=(
"background-color: #FFFFFF; color: #333333; font-family: arial; font-size: 12px; padding: 10px;")
)
)
choropleth_map.add_child(info)
choropleth_map.keep_in_front(info)
folium_static(choropleth_map, width=500, height=500)
# Sample the DataFrame to get 20 random entries
sample_df = df.sample(n=min(20, len(df)), random_state=1)
# Create and display the marker map
with st.expander('Collection Objects on the Map'):
marker_map = folium.Map(location=[20, 0], zoom_start=2, tiles="cartodbpositron")
# Function to create a marker with an image
def add_marker(row):
image_url = row['edmPreview'] # URL to the image
popup_html = f'
'
folium.Marker(
location=[row['edmPlaceLatitude'], row['edmPlaceLongitude']],
icon=CustomIcon(icon_image=image_url, icon_size=(50, 50)),
popup=folium.Popup(popup_html, max_width=250)
).add_to(marker_map)
# Apply the function to each row in the sampled DataFrame
sample_df.apply(add_marker, axis=1)
folium_static(marker_map, width=500, height=500)
# Option to download the full dataset
csv = df.to_csv(index=False)
st.download_button(
label="📥 Download full dataset as CSV",
data=csv,
file_name=f"{provider_name}_data.csv",
mime="text/csv",
)
else:
st.warning('⚠️ Please enter a provider name.')
# Run this app with: streamlit run app.py