Se trata de un mapa completo que muestra seis tipos de datos en dos dimensiones: el número de tropas de Napoleón; la distancia recorrida; la temperatura; la latitud y la longitud; la dirección del viaje; y la ubicación en relación con fechas concretas, sin hacer mención a Napoleón; el interés de Minard radica en las fatigas y los sacrificios de los soldados.
“La Carta figurativa de las sucesivas pérdidas de hombres de la armada francesa en la campaña de Rusia de Napoleón en 1812” (Carte figurative des pertes successives en hommes de l’Armée Française dans la campagne de Russie 1812-1813)
Activamos el entorno virtual
use_virtualenv("r-reticulate")
py_available(TRUE)
## [1] TRUE
Instalamos las librerias de Python necesarias
Cargamos las librerias
import pandas as pd
import altair as alt
import numpy as np
from vega_datasets import data
Cargamos el dataset de las ciudades
cities = pd.read_csv("data/minard_cities.txt", sep=" ", names=["lon", "lat", "city"])
cities
## lon lat city
## 0 24.0 55.0 Kowno
## 1 25.3 54.7 Wilna
## 2 26.4 54.4 Smorgoni
## 3 26.8 54.3 Molodexno
## 4 27.7 55.2 Gloubokoe
## 5 27.6 53.9 Minsk
## 6 28.5 54.3 Studienska
## 7 28.7 55.5 Polotzk
## 8 29.2 54.4 Bobr
## 9 30.2 55.3 Witebsk
## 10 30.4 54.5 Orscha
## 11 30.4 53.9 Mohilow
## 12 32.0 54.8 Smolensk
## 13 33.2 54.9 Dorogobouge
## 14 34.3 55.2 Wixma
## 15 34.4 55.5 Chjat
## 16 36.0 55.5 Mojaisk
## 17 37.6 55.8 Moscou
## 18 36.6 55.3 Tarantino
## 19 36.5 55.0 Malo-Jarosewli
Cargamos el dataset de las temperaturas
temperatures = pd.read_csv("data/minard_temperature.txt", sep=" ", names=["lon", "temp", "days", "day"])
temperatures
## lon temp days day
## 0 37.6 0 6 Oct-18
## 1 36.0 0 6 Oct-24
## 2 33.2 -9 16 Nov-9
## 3 32.0 -21 5 Nov-14
## 4 29.2 -11 10 NaN
## 5 28.5 -20 4 Nov-28
## 6 27.2 -24 3 Dec-1
## 7 26.7 -30 5 Dec-6
## 8 25.3 -26 1 Dec-7
Cargamos el dataset de las tropas
troops = pd.read_csv("data/minard_troops.txt", sep=" ", names=["lon", "lat", "survivors" , "direction", "division"])
troops.head()
## lon lat survivors direction division
## 0 24.0 54.9 340000 A 1
## 1 24.5 55.0 340000 A 1
## 2 25.5 54.5 340000 A 1
## 3 26.0 54.7 320000 A 1
## 4 27.0 54.8 300000 A 1
ETL del dataset temperaturas
temperatures["label"] = temperatures.fillna("").apply(
axis=1, func=lambda row: "{}° {}".format(row[1], row[3].replace("-", " "))
)
temperatures.head()
## lon temp days day label
## 0 37.6 0 6 Oct-18 0° Oct 18
## 1 36.0 0 6 Oct-24 0° Oct 24
## 2 33.2 -9 16 Nov-9 -9° Nov 9
## 3 32.0 -21 5 Nov-14 -21° Nov 14
## 4 29.2 -11 10 NaN -11°
ETL del dataset tropas
troops = troops.sort_values(by=["division", "survivors"], ascending=False)
troops.head()
## lon lat survivors direction division
## 45 24.0 55.2 22000 A 3
## 46 24.5 55.3 22000 A 3
## 47 24.6 55.8 6000 A 3
## 48 24.6 55.8 6000 R 3
## 49 24.2 54.4 6000 R 3
Generamos el gráfico del volumen de tropoas
troops_chart = alt.Chart(troops).mark_trail().encode(
x='lon:Q',
y='lat:Q',
size=alt.Size('survivors', scale=alt.Scale(range=[1, 75]), legend=None),
color=alt.Color('direction')
)
troops_chart.save("data/troops_first_try.html")
htmltools::includeHTML("data/troops_first_try.html")
En este apartado se muestra la dirección de ataque y retirada del ejercito napoleonico.
troops_chart = alt.Chart(troops).mark_trail().encode(
longitude='lon:Q',
latitude='lat:Q',
size=alt.Size(
'survivors',
scale=alt.Scale(range=[1, 75]),
legend=None
),
detail='division',
color=alt.Color(
'direction',
scale=alt.Scale(
domain=['A', 'R'],
range=['#EBD2A8', '#888888']
),
legend=None
),
).project(
type="mercator"
)
troops_chart.save("data/troops.html")
htmltools::includeHTML("data/troops.html")
Aquí se muestran el volukmen de efectivos de las tropas.
ETL del dataset Tropas
# Small manipulation to scatter the troop size text a bit
troops_text = troops.iloc[::2, :].copy()
troops_text["lon"] += 0.13 * (troops_text["division"])
troops_text["lat"] += troops_text["direction"].replace({"A": 0.35, "R": -0.21})
troops_text.head()
## lon lat survivors direction division
## 45 24.39 55.55 22000 A 3
## 47 24.99 56.15 6000 A 3
## 49 24.59 54.19 6000 R 3
## 28 24.26 55.45 60000 A 2
## 30 25.76 55.05 60000 A 2
Generamos gráfica de número de tropas por ubicación
troops_text_chart = alt.Chart(troops_text).mark_text(
font='Cardo',
fontSize=7,
fontStyle='italic',
angle=280
).encode(
longitude='lon:Q',
latitude='lat:Q',
text='survivors'
).project(
type="mercator"
)
Grabamos en html
troops_text_chart.save("data/troops_text.html")
htmltools::includeHTML("data/troops_text.html")
Aquí se muestran el número de efectivos de las tropas.
Generamos la gráfica de las localidades donde atraviesa la ruta.
cities_chart = alt.Chart(cities).mark_text(
font='Cardo',
fontSize=11,
fontStyle='italic',
dx=-3
).encode(
longitude='lon:Q',
latitude='lat:Q',
text='city',
).project(
type="mercator"
)
Grabamos en html
cities_chart.save("data/cities.html")
htmltools::includeHTML("data/cities.html")
En este apartado se muestran las ciudades por las que recorrió el ejercito entre la frontera polaca y Moscú.
x_encode = alt.X(
'lon:Q',
scale=alt.Scale(
domain=[cities["lon"].min(), cities["lon"].max()]
),
axis=None
)
y_encode = alt.Y(
'temp',
axis=alt.Axis(
title="Temperatura durante la Retirada",
grid=True,
orient='right'
)
)
y_encode
## Y({
## axis: Axis({
## grid: True,
## orient: 'right',
## title: 'Temperatura durante la Retirada'
## }),
## shorthand: 'temp'
## })
Generamos las gráficas de la temperatura
temperatures_chart = alt.Chart(temperatures).mark_line(
color="#888888"
).encode(
x=x_encode,
y=y_encode
) + alt.Chart(temperatures).mark_text(
dx=5,
dy=20,
font='Cardo',
fontSize=10
).encode(
x=x_encode,
y=y_encode,
text='label'
)
Grabamos en html
temperatures_chart.save("data/temperature.html")
htmltools::includeHTML("data/temperature.html")
Muestra la temperatura en cada momento de paso de las tropas.
temperatures_chart = temperatures_chart.properties(
height=100
)
temperatures_chart
## alt.LayerChart(...)
Sumamos los mapas
# sumamos los mapas
map_chart = troops_chart + cities_chart + troops_text_chart
# Resultado final
final_chart = alt.vconcat(map_chart, temperatures_chart).configure_view(
width=900,
height=400,
strokeWidth=0
).configure_axis(
grid=False,
labelFont="Cardo",
titleFont="Cardo"
)
Grabamos en html
final_chart.save("data/minard_chart.html")
htmltools::includeHTML("data/minard_chart.html")
Resultado final juntando todos los mapas