Interactive Visualizations#
Up to this point, we have created several plots for vector data, raster data, and data frames. However, Python also supports interactive visualizations through powerful libraries such as: plotly
, bokeh
, altair
, dash
, ipywidgets
among others. Interactive visualizations allow users to explore data dynamically, providing an intuitive way to identify patterns, trends, and outliers. Python offers several powerful libraries for creating such visualizations, enabling interactivity with features like zooming, panning, tooltips, and filtering.
Interactive Maps with Vector Data#
Ipywidgets
Creating interactive maps with combination of Geopandas
and ipywidgets
in Python is a great way to visualize geospatial data dynamically. Below is an example of how you can create interactive maps using plotly with vector data.
import geopandas as gpd
import matplotlib.pyplot as plt
import ipywidgets as widgets
from IPython.display import display
# Load Kanchanpur GPKG
vector_data = gpd.read_file("data/vector/kanchanpur.gpkg")
# Reproject vector data to a projected CRS (e.g., UTM zone 45N for this area)
vector_data = vector_data.to_crs(epsg=32645)
# Add few more columns
# Population
vector_data['Population'] = [
37900, 46565, 72813, 49223, 52221, 64436, 40823,
97216, 36368, 277108, 51835, 38199, 46773, 44571,
48838, 11581, 131, 19211, 56755, 58257, 37573
]
# Calculate the area of each district (in square meters)
vector_data['area_m2'] = vector_data.geometry.area
# Convert the area from square meters to square kilometers
vector_data['Area'] = vector_data['area_m2'] / 1e6
# Add a new column with density (population/area)
vector_data['Density'] = vector_data['Population'] / vector_data['Area']
# Column names
print(vector_data.columns)
Index(['NAME', 'geometry', 'Population', 'area_m2', 'Area', 'Density'], dtype='object')
# Widget: Dropdown to select visualization type
viz_type = widgets.Dropdown(
options=["Population", "Area", 'Density'],
value="Population",
description="Visualize:",
)
# Widget: Slider for adjusting edge line width
line_width = widgets.IntSlider(
value=1, min=1, max=5, step=1, description="Line Width:"
)
# Function to update the map
def update_map(viz_type, line_width):
fig, ax = plt.subplots(figsize=(10, 8))
vector_data.plot(
column=viz_type,
cmap="viridis",
edgecolor="black",
linewidth=line_width,
legend=True,
ax=ax,
)
ax.set_title(f"Kanchanpur District Map: {viz_type}", fontsize=16)
plt.show()
# Link the widgets with the function
widgets.interactive(update_map, viz_type=viz_type, line_width=line_width)
Why Use Ipywidgets?
Interactive
: Enables user-driven exploration with widgets like sliders, dropdowns, and text inputs.Lightweight
: Does not rely heavily on external JavaScript libraries.Compatible
: Integrates seamlessly into Jupyter Book, JupyterLab, and Jupyter Notebook.Customizable
: You can build your own tailored widgets for any workflow.
Interactive Maps with Raster Data#
Plotly
can visualize raster data as heatmaps or images on a geographic projection.
import plotly.express as px
import rasterio
import numpy as np
# Path to your raster file
raster_path = "data/raster/landcover_2019.tif"
# Open the raster file
with rasterio.open(raster_path) as src:
raster_data = src.read(1) # Single-band raster
bounds = src.bounds # Get raster bounds
# Create a 2D heatmap
fig = px.imshow(
raster_data,
color_continuous_scale="Viridis",
title="ESA Land Cover Data 2019",
origin="upper",
)
fig.update_layout(
xaxis_title="Longitude",
yaxis_title="Latitude",
)
fig.show()
Why use Plotly
Advanced interactivity
Hover/click events
Supports large raster arrays
Interactive Maps with Combined Data#
Combining vector
and raster
data in a single interactive map can provide a more comprehensive visualization. You can display both types of data (e.g., vector boundaries or polygons on top of a raster base map) using libraries like Folium
combined with Ipywidgets
for interaction. Below is how you can achieve this with a raster layer (for example, a landcover map) and vector data (such as the Kanchanpur polygon) in a single interactive map.
import folium
import geopandas as gpd
from folium import raster_layers
from ipywidgets import widgets
# Load the vector data (Kanchanpur polygon as GeoDataFrame)
gdf = gpd.read_file("data/vector/kanchanpur.gpkg")
# Load the raster data
import rasterio
from rasterio.plot import show
# Open the raster data
raster_file = "data/raster/landcover_2019.tif"
raster = rasterio.open(raster_file)
# Get the bounds of the raster
bounds = raster.bounds
# Create a base map
m = folium.Map(location=[28.7755, 80.2656], zoom_start=8)
# Add the raster data to the map
raster_layer = raster_layers.ImageOverlay(
image=raster.read(1), # Get the first band
bounds=[[bounds.bottom, bounds.left], [bounds.top, bounds.right]], # Coordinates for the extent of the raster data
colormap=lambda x: [x / 255, 0.5, 0], # Example colormap
opacity=0.6,
)
raster_layer.add_to(m)
# Add vector data (Kanchanpur polygon) to the map
folium.GeoJson(gdf).add_to(m)
# Create an interactive control (checkbox) to toggle the visibility of the raster layer
raster_control = widgets.Checkbox(value=True, description="Show Raster")
def toggle_raster(change):
if change['new']:
raster_layer.add_to(m)
else:
m.remove_child(raster_layer)
raster_control.observe(toggle_raster, names='value')
# Show the map
m
The Kanchanpur polygon is loaded using GeoPandas (
gpd.read_file
), and it’s added to the Folium map usingfolium.GeoJson
.The raster data is read using
Rasterio
and displayed on the map as anImageOverlay
object. Thebounds
attribute defines the geographic extent of the raster.A custom colormap function (
lambda x: [x / 255, 0.5, 0]
) is applied to the raster layer to provide a red-green color scale (you can adjust this based on your needs).An
ipywidgets.Checkbox
is used to control the visibility of the raster layer on the map.The
toggle_raster
function handles showing or hiding the raster layer based on the checkbox status.
For this tutorial, this concludes the coverage of Interactive Visualizations in Python. If you would like to explore additional packages for interactive maps, examples, or need clarification on any of the steps covered, please visit the GitHub repository: Python_tutorial and feel free to open an issue.