Quante evidenze archeologiche di epoca romana sono presenti in Italia?

Curiosando sul Catalogo generale dei Beni Culturali mi aspettavo di trovare una risposta ma non è stato così. Già solo accedendo al portale, senza applicare nessun tipo di filtro, effettuando uno zoom sull'area dei Campi Flegrei mi ritrovo nella situazione che segue.

No description has been provided for this image

E' presente il solo Castello di Baia in questa area, secondo il catalogo, ma nella realtà in quest'area possiamo trovare:

  • la Piscina Mirabilis
  • la Casina Vanvitelliana
  • Baia sommersa
  • il Tempio di Serapide
  • il Parco archeologico del Pausilypon

Solo per citare i luoghi che conosco per averli visitati direttamente, ma ce ne sono tanti altri.

Così ho deciso di usare i superpoteri di Python e OpenStreetMap per darmi una risposta.

Prima di iniziare¶

Librerie¶

Per raggiungere l'obiettivo userò le librerie che seguono.

In [1]:
from pathlib import Path
import geopandas as gpd
import pandas as pd
from matplotlib import pyplot as plt
import contextily as cx
import osmnx as ox

Fonti dati¶

Oltre ai dati di OpenStreetMap userò i confini comunali generalizzati 2023 rilasciati da ISTAT.

In [2]:
main_folder = Path.cwd().parent.parent.parent.parent.joinpath('sample_data')
municipalities = main_folder.joinpath('Com01012023_g').joinpath('Com01012023_g_WGS84.shp')
regions = main_folder.joinpath('Reg01012023_g').joinpath('Reg01012023_g_WGS84.shp')

osm_crs = 4326

municipalities_gdf = gpd.read_file(municipalities).to_crs(osm_crs)
regions_gdf = gpd.read_file(regions).to_crs(osm_crs)

Come vedremo in seguito tornerà molto utile conoscere la tassonomia di OpenStreetMap, tassonomia disponibile qui.

Rimozione dei warnings¶

Il codice che segue serve solo per eliminare i messaggi di warning che renderebbero antiestetico l'articolo. Attenzione ad ignorarli però! Vanno ben approfonditi e non ignorati alla leggera. Io lo faccio solo perchè questo è un articolo dimostrativo.

In [3]:
import warnings
warnings.filterwarnings('ignore')
warnings.simplefilter('ignore')

Contenuti¶

  • 1. Lavoriamo in piccolo: Bacoli
  • 2. Ricerca a scala regionale: Campania
  • 3. Ricerca a scala nazionale
  • Conclusione

1. Lavoriamo in piccolo: Bacoli¶

Partiremo con l'analizzare l'area di Bacoli.

In [4]:
bacoli = municipalities_gdf[municipalities_gdf['COMUNE']=='Bacoli'].squeeze()
bacoli
Out[4]:
COD_RIP                                                       4
COD_REG                                                      15
COD_PROV                                                     63
COD_CM                                                      263
COD_UTS                                                     263
PRO_COM                                                   63006
PRO_COM_T                                                063006
COMUNE                                                   Bacoli
COMUNE_A                                                    NaN
CC_UTS                                                        0
Shape_Leng                                         20303.054123
geometry      POLYGON ((14.06724657892957 40.842943679557926...
Name: 5138, dtype: object

Interrogheremo il database di OpenStreetMap usando OSMnx libreria che (cito dal sito del progetto) is a Python package to download, model, analyze, and visualize street networks and other geospatial features from OpenStreetMap. Andremo in particolare ad usare il TAG historic con alcune eccezioni che vedremo.

In [5]:
%%time

bacoli_data = ox.features_from_polygon(
    polygon=bacoli.geometry,
    tags={'historic': True}
)

bacoli_data
CPU times: user 266 ms, sys: 3.82 ms, total: 270 ms
Wall time: 734 ms
Out[5]:
historic name wikidata wikipedia geometry tourism historic:civilization length natural nodes ... name:ru opening_hours opening_hours:url operator phone reservation start_date dataset description data
element_type osmid
node 1045290525 archaeological_site Piscina Mirabilis Q222410 en:Piscina Mirabilis POINT (14.08028 40.79519) NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1104926219 archaeological_site Grotte dell'Acqua - Lago Fusaro NaN NaN POINT (14.05955 40.82506) NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1139094827 archaeological_site Grotta della Dragonara Q55673920 NaN POINT (14.08506 40.78477) attraction NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1139094838 archaeological_site Sacello degli Augustali Q3944423 it:Sacello degli Augustali POINT (14.08460 40.78747) NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1706624371 archaeological_site Grotta di Cocceio Q518104 NaN POINT (14.06211 40.84534) NaN ancient_roman_-_Augustus_Emperator_period 1 km cave_entrance NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2235447677 ruins NaN NaN NaN POINT (14.06509 40.82330) NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2235447711 memorial Bunker NaN NaN POINT (14.06457 40.82321) NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2235447893 memorial Bunker NaN NaN POINT (14.06555 40.82358) NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
8755033944 ruins Tempo di Iside NaN NaN POINT (14.05002 40.84415) NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
9060732167 ruins NaN NaN NaN POINT (14.06845 40.81674) NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
way 124092891 archaeological_site Parco Archeologico Terme di Baia Q3685188 it:Complesso archeologico di Baia POLYGON ((14.07084 40.81923, 14.07072 40.81929... NaN ancient_roman NaN NaN [1382052835, 4083235857, 1382052825, 408323585... ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
124093354 archaeological_site Anfiteatro di Cuma Q93976746 NaN POLYGON ((14.05636 40.84248, 14.05598 40.84255... NaN ancient_roman NaN NaN [1382055624, 1382055618, 1382055628, 138205562... ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
144917231 castle Castello Aragonese di Baia Q3662303 it:Castello Aragonese (Baia) POLYGON ((14.08025 40.81003, 14.08046 40.81018... NaN NaN NaN NaN [1583990045, 1583990048, 1583990061, 158399006... ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
240100401 archaeological_site Tomba di Agrippina NaN NaN POLYGON ((14.08145 40.80291, 14.08133 40.80294... attraction NaN NaN NaN [2478723947, 2478723948, 2478723949, 247872395... ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
323122081 building Casina Vanvitelliana Q958152 it:Casina Vanvitelliana POLYGON ((14.05844 40.81979, 14.05847 40.81983... NaN NaN NaN NaN [3299164580, 6897303092, 6897328941, 689731239... ... Домик Ванвителли Sa,Su 10:00-14:00,16:00-19:00 http://www.prolococittadibacoli.it/casina-vanv... Pro Loco Città di Bacoli +39 379 1030885 recommended 1782 NaN NaN NaN
406222066 archaeological_site Tempio di Diana NaN NaN POLYGON ((14.07065 40.81926, 14.07043 40.81923... NaN NaN NaN NaN [4083235856, 4083235855, 4083235852, 408323584... ... NaN NaN NaN NaN NaN NaN NaN primo quarto del III secolo d.C. antica aula termale NaN
429218964 archaeological_site Columbari NaN NaN POLYGON ((14.06482 40.81952, 14.06543 40.81914... NaN NaN NaN NaN [4283467129, 4283467130, 4283467131, 428346713... ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
429324871 archaeological_site Monumental Park of Baia NaN NaN POLYGON ((14.07125 40.81337, 14.07098 40.81320... NaN NaN NaN NaN [4284413253, 4284413254, 4284413255, 428441325... ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
429338160 archaeological_site Tempio di Mercurio NaN NaN POLYGON ((14.06978 40.81790, 14.06982 40.81792... NaN NaN NaN NaN [4284599234, 4284599235, 4284599236, 428459923... ... NaN NaN NaN NaN NaN NaN NaN NaN l'edificio era un frigidarium. La volta circol... prima metà del I sec. d.C.
429339087 archaeological_site Tempio di Venere Q96694237 NaN POLYGON ((14.07139 40.81624, 14.07152 40.81627... NaN NaN NaN NaN [4284611823, 4284611824, 4284611825, 428461182... ... NaN NaN NaN NaN NaN NaN NaN NaN edificio termale NaN
429340403 archaeological_site NaN NaN NaN POLYGON ((14.06974 40.81769, 14.06978 40.81770... NaN NaN NaN NaN [4284609514, 4284609515, 4284609516, 428460951... ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
429341185 archaeological_site NaN NaN NaN POLYGON ((14.06991 40.81750, 14.06992 40.81745... NaN NaN NaN NaN [4284609519, 4284631813, 4284631814, 428463181... ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
429341186 archaeological_site NaN NaN NaN POLYGON ((14.06997 40.81712, 14.07006 40.81679... NaN NaN NaN NaN [4284631827, 4284631828, 4284631829, 428463183... ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
429341188 archaeological_site NaN NaN NaN POLYGON ((14.07011 40.81672, 14.07006 40.81670... NaN NaN NaN NaN [4284631843, 4284631844, 4284631845, 428463184... ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
429341189 archaeological_site NaN NaN NaN POLYGON ((14.06979 40.81670, 14.06990 40.81672... NaN NaN NaN NaN [4083235569, 4284631859, 4284631860, 428463186... ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
429341190 archaeological_site NaN NaN NaN POLYGON ((14.06992 40.81624, 14.06989 40.81630... NaN NaN NaN NaN [4284631863, 4284631864, 4284631865, 906085113... ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
736686146 building NaN NaN NaN POLYGON ((14.07068 40.82155, 14.07062 40.82149... NaN NaN NaN NaN [6897279565, 6897310515, 6897272664, 689731985... ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
736686737 archaeological_site NaN NaN NaN POLYGON ((14.06929 40.81767, 14.06939 40.81727... NaN NaN NaN NaN [6897334201, 6897298978, 6897296141, 689732206... ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
736690821 archaeological_site NaN NaN NaN POLYGON ((14.06999 40.81713, 14.07037 40.81721... NaN NaN NaN NaN [6897281438, 6897326113, 6897290885, 689733550... ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1154634667 archaeological_site Teatro romano di Misenum Q55685837 NaN POLYGON ((14.08315 40.78788, 14.08303 40.78776... NaN ancient_roman NaN NaN [10738232596, 10738232597, 10738232598, 107382... ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN

30 rows × 35 columns

In [6]:
bacoli_site_count = len(bacoli_data.index)

bacoli_site_count
Out[6]:
30

Come si può vedere in quest'area ci sono ben 30 siti di interesse archeologico, molti più dei tre che conosco che fanno parte dell'elenco di inizio articolo.

Ma veniamo ai TAG di nostro interesse. Analizzando l'elenco delle chiavi ce ne sono alcune che non mi interessano e le inserirò nella viriabile che segue perchè a me interessano solo le strutture o i resti di strutture.

In [7]:
excluded_keys = ['aircraft', 'aircraft; memorial', 'anchor', 'battlefield', 'bomb_crater', 'boundary_stone', 'cannon', 'cattle_crush', 'district', 'highwater_mark', 'hotel', 'locomotive', 'memorial', 'ogham_stone', 'railway', 'railway_car', 'railway_station', 'road', 'shieling', 'ship', 'tank', 'vehicle', 'wayside_cross', 'wayside_shrine', 'wreck', 'yes']

excluded_keys
Out[7]:
['aircraft',
 'aircraft; memorial',
 'anchor',
 'battlefield',
 'bomb_crater',
 'boundary_stone',
 'cannon',
 'cattle_crush',
 'district',
 'highwater_mark',
 'hotel',
 'locomotive',
 'memorial',
 'ogham_stone',
 'railway',
 'railway_car',
 'railway_station',
 'road',
 'shieling',
 'ship',
 'tank',
 'vehicle',
 'wayside_cross',
 'wayside_shrine',
 'wreck',
 'yes']

Inoltre escluderò anche alcune colonne dal dataset primario in modo da restringere ulteriormente il campo.

In [8]:
bacoli_data = bacoli_data[['historic', 'name', 'historic:civilization', 'geometry']]
bacoli_data = bacoli_data[~bacoli_data['historic'].isin(excluded_keys)]
bacoli_data = bacoli_data[bacoli_data['name'].notna()]
bacoli_data.reset_index(inplace=True)

bacoli_data
Out[8]:
element_type osmid historic name historic:civilization geometry
0 node 1045290525 archaeological_site Piscina Mirabilis NaN POINT (14.08028 40.79519)
1 node 1104926219 archaeological_site Grotte dell'Acqua - Lago Fusaro NaN POINT (14.05955 40.82506)
2 node 1139094827 archaeological_site Grotta della Dragonara NaN POINT (14.08506 40.78477)
3 node 1139094838 archaeological_site Sacello degli Augustali NaN POINT (14.08460 40.78747)
4 node 1706624371 archaeological_site Grotta di Cocceio ancient_roman_-_Augustus_Emperator_period POINT (14.06211 40.84534)
5 node 8755033944 ruins Tempo di Iside NaN POINT (14.05002 40.84415)
6 way 124092891 archaeological_site Parco Archeologico Terme di Baia ancient_roman POLYGON ((14.07084 40.81923, 14.07072 40.81929...
7 way 124093354 archaeological_site Anfiteatro di Cuma ancient_roman POLYGON ((14.05636 40.84248, 14.05598 40.84255...
8 way 144917231 castle Castello Aragonese di Baia NaN POLYGON ((14.08025 40.81003, 14.08046 40.81018...
9 way 240100401 archaeological_site Tomba di Agrippina NaN POLYGON ((14.08145 40.80291, 14.08133 40.80294...
10 way 323122081 building Casina Vanvitelliana NaN POLYGON ((14.05844 40.81979, 14.05847 40.81983...
11 way 406222066 archaeological_site Tempio di Diana NaN POLYGON ((14.07065 40.81926, 14.07043 40.81923...
12 way 429218964 archaeological_site Columbari NaN POLYGON ((14.06482 40.81952, 14.06543 40.81914...
13 way 429324871 archaeological_site Monumental Park of Baia NaN POLYGON ((14.07125 40.81337, 14.07098 40.81320...
14 way 429338160 archaeological_site Tempio di Mercurio NaN POLYGON ((14.06978 40.81790, 14.06982 40.81792...
15 way 429339087 archaeological_site Tempio di Venere NaN POLYGON ((14.07139 40.81624, 14.07152 40.81627...
16 way 1154634667 archaeological_site Teatro romano di Misenum ancient_roman POLYGON ((14.08315 40.78788, 14.08303 40.78776...

Purtroppo a causa del fatto che la colonna historic:civilization non è corrattamente campita non riuscirò a sfruttare correttamente i dati a disposizione per rispondere alla mia domanda iniziale, ma meglio di niente. Alcuni siti come la Piscina Mirabilis sono di epoca romana ma questo non viene indicato nella colonna in questione per cui se pure volessi filtrare i dati cercando roman con la funzione str.contains di Pandas otterei meno dati del previsto. E' un peccato perchè sotto Rome OpenStreetMap ha un bel po' di possibilità di ricerca potendo filtrare i dati in base ai vari periodi in cui si è sviluppata la civiltà romana antica.

Come avrete sicuramente notato, il dataset ha geometrie miste. Di seguito lo normalizzerò per fare in modo da avere solo punti.

In [9]:
bacoli_polygons = bacoli_data[bacoli_data['element_type']=='way']

bacoli_polygons
Out[9]:
element_type osmid historic name historic:civilization geometry
6 way 124092891 archaeological_site Parco Archeologico Terme di Baia ancient_roman POLYGON ((14.07084 40.81923, 14.07072 40.81929...
7 way 124093354 archaeological_site Anfiteatro di Cuma ancient_roman POLYGON ((14.05636 40.84248, 14.05598 40.84255...
8 way 144917231 castle Castello Aragonese di Baia NaN POLYGON ((14.08025 40.81003, 14.08046 40.81018...
9 way 240100401 archaeological_site Tomba di Agrippina NaN POLYGON ((14.08145 40.80291, 14.08133 40.80294...
10 way 323122081 building Casina Vanvitelliana NaN POLYGON ((14.05844 40.81979, 14.05847 40.81983...
11 way 406222066 archaeological_site Tempio di Diana NaN POLYGON ((14.07065 40.81926, 14.07043 40.81923...
12 way 429218964 archaeological_site Columbari NaN POLYGON ((14.06482 40.81952, 14.06543 40.81914...
13 way 429324871 archaeological_site Monumental Park of Baia NaN POLYGON ((14.07125 40.81337, 14.07098 40.81320...
14 way 429338160 archaeological_site Tempio di Mercurio NaN POLYGON ((14.06978 40.81790, 14.06982 40.81792...
15 way 429339087 archaeological_site Tempio di Venere NaN POLYGON ((14.07139 40.81624, 14.07152 40.81627...
16 way 1154634667 archaeological_site Teatro romano di Misenum ancient_roman POLYGON ((14.08315 40.78788, 14.08303 40.78776...
In [10]:
bacoli_polygons['centroid'] = bacoli_polygons.geometry.centroid
bacoli_polygons.drop(columns={'geometry'}, inplace=True)
bacoli_polygons.rename(columns={'centroid': 'geometry'}, inplace=True)

bacoli_polygons
/tmp/ipykernel_6801/311082464.py:1: UserWarning: Geometry is in a geographic CRS. Results from 'centroid' are likely incorrect. Use 'GeoSeries.to_crs()' to re-project geometries to a projected CRS before this operation.

  bacoli_polygons['centroid'] = bacoli_polygons.geometry.centroid
/home/max/.cache/pypoetry/virtualenvs/pygis_blog-iPs2SW5R-py3.10/lib/python3.10/site-packages/geopandas/geodataframe.py:1538: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  super().__setitem__(key, value)
/tmp/ipykernel_6801/311082464.py:2: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  bacoli_polygons.drop(columns={'geometry'}, inplace=True)
/tmp/ipykernel_6801/311082464.py:3: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  bacoli_polygons.rename(columns={'centroid': 'geometry'}, inplace=True)
Out[10]:
element_type osmid historic name historic:civilization geometry
6 way 124092891 archaeological_site Parco Archeologico Terme di Baia ancient_roman POINT (14.07024 40.81724)
7 way 124093354 archaeological_site Anfiteatro di Cuma ancient_roman POINT (14.05604 40.84199)
8 way 144917231 castle Castello Aragonese di Baia NaN POINT (14.08032 40.81106)
9 way 240100401 archaeological_site Tomba di Agrippina NaN POINT (14.08128 40.80285)
10 way 323122081 building Casina Vanvitelliana NaN POINT (14.05842 40.81971)
11 way 406222066 archaeological_site Tempio di Diana NaN POINT (14.07056 40.81914)
12 way 429218964 archaeological_site Columbari NaN POINT (14.06500 40.81928)
13 way 429324871 archaeological_site Monumental Park of Baia NaN POINT (14.07141 40.81283)
14 way 429338160 archaeological_site Tempio di Mercurio NaN POINT (14.06987 40.81782)
15 way 429339087 archaeological_site Tempio di Venere NaN POINT (14.07152 40.81612)
16 way 1154634667 archaeological_site Teatro romano di Misenum ancient_roman POINT (14.08313 40.78778)
In [11]:
bacoli_final = pd.concat([bacoli_polygons, bacoli_data[bacoli_data['element_type']=='node']])
bacoli_final.drop(columns={'element_type'}, inplace=True)
bacoli_final.sort_values(by='name', inplace=True)
bacoli_final = gpd.GeoDataFrame(bacoli_final, geometry='geometry')

bacoli_final
Out[11]:
osmid historic name historic:civilization geometry
7 124093354 archaeological_site Anfiteatro di Cuma ancient_roman POINT (14.05604 40.84199)
10 323122081 building Casina Vanvitelliana NaN POINT (14.05842 40.81971)
8 144917231 castle Castello Aragonese di Baia NaN POINT (14.08032 40.81106)
12 429218964 archaeological_site Columbari NaN POINT (14.06500 40.81928)
2 1139094827 archaeological_site Grotta della Dragonara NaN POINT (14.08506 40.78477)
4 1706624371 archaeological_site Grotta di Cocceio ancient_roman_-_Augustus_Emperator_period POINT (14.06211 40.84534)
1 1104926219 archaeological_site Grotte dell'Acqua - Lago Fusaro NaN POINT (14.05955 40.82506)
13 429324871 archaeological_site Monumental Park of Baia NaN POINT (14.07141 40.81283)
6 124092891 archaeological_site Parco Archeologico Terme di Baia ancient_roman POINT (14.07024 40.81724)
0 1045290525 archaeological_site Piscina Mirabilis NaN POINT (14.08028 40.79519)
3 1139094838 archaeological_site Sacello degli Augustali NaN POINT (14.08460 40.78747)
16 1154634667 archaeological_site Teatro romano di Misenum ancient_roman POINT (14.08313 40.78778)
11 406222066 archaeological_site Tempio di Diana NaN POINT (14.07056 40.81914)
14 429338160 archaeological_site Tempio di Mercurio NaN POINT (14.06987 40.81782)
15 429339087 archaeological_site Tempio di Venere NaN POINT (14.07152 40.81612)
5 8755033944 ruins Tempo di Iside NaN POINT (14.05002 40.84415)
9 240100401 archaeological_site Tomba di Agrippina NaN POINT (14.08128 40.80285)

Ora che il dataset è di soli punti cerchiamo di rispondere a qualche domanda.

1.1. Come sono raggruppati i siti?¶

In [12]:
bacoli_group = bacoli_final.groupby(by='historic').count()
bacoli_group.drop(columns={'name', 'historic:civilization', 'geometry'}, inplace=True)
bacoli_group.rename(columns={'osmid': 'count'}, inplace=True)
bacoli_group.sort_values(by='count', ascending=False, inplace=True)

bacoli_group
Out[12]:
count
historic
archaeological_site 14
building 1
castle 1
ruins 1

1.2. Dove sono localizzati i soli siti archeologici?¶

In [13]:
contextily_tile_crs = 3857
target_data = 'archaeological_site'
bacoli_archaeological_site = bacoli_final[bacoli_final['historic']==target_data]

bacoli_polygon = gpd.GeoDataFrame(geometry=gpd.GeoSeries(bacoli.geometry), crs=osm_crs).to_crs(contextily_tile_crs)


b_minx, b_miny, b_maxx, b_maxy = bacoli_polygon.squeeze().bounds

bacoli_img, bacoli_ext = cx.bounds2img(w=b_minx, s=b_miny, e=b_maxx, n=b_maxy, ll=False)

fig, ax = plt.subplots(figsize=(10, 10))
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
plt.title(f'Siti archeologici nel Comune di Bacoli: {len(bacoli_archaeological_site.index)}')

ax.imshow(bacoli_img, extent=bacoli_ext, zorder=0)
bacoli_polygon.boundary.plot(ax=ax, edgecolor='black', zorder=1)
bacoli_archaeological_site.to_crs(contextily_tile_crs).plot(ax=ax, marker="o", facecolor='red', edgecolor='white', markersize=50, zorder=2)
Out[13]:
<Axes: title={'center': 'Siti archeologici nel Comune di Bacoli: 14'}>
No description has been provided for this image

2. Ricerca a scala regionale: Campania¶

Ripetiamo l'analisi ma a scala regionale in modo da ottenere i dati che ci consentiranno di dare le risposte alle stesse domande fatte per Bacoli.

In [14]:
campania = regions_gdf[regions_gdf['DEN_REG']=='Campania'].squeeze()

campania
Out[14]:
COD_RIP                                                       4
COD_REG                                                      15
DEN_REG                                                Campania
Shape_Leng                                         888166.70685
Shape_Area                                   13663252600.799999
geometry      MULTIPOLYGON (((15.294678222474477 40.02369364...
Name: 14, dtype: object
In [15]:
%%time

campania_data = ox.features_from_polygon(
    polygon=campania.geometry,
    tags={'historic': True}
)

campania_data
CPU times: user 6.98 s, sys: 36 ms, total: 7.02 s
Wall time: 15.8 s
Out[15]:
historic geometry name religion access name:bg name:it alt_name archaeological_site addr:city ... old_name operator:type disused pump defensive description:de description:en disused:railway hazard trail_visibility
element_type osmid
node 1233738646 ruins POINT (15.51893 40.07559) NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1234013962 castle POINT (15.55494 40.13962) NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1278425106 ruins POINT (15.42702 40.27348) NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1456773590 ruins POINT (15.36115 39.99905) Torre dell'Isola NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1601204543 monument POINT (15.32197 40.15126) Chiesa di San Marco Evangelista NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
way 1105039541 ruins POLYGON ((13.88314 41.12800, 13.88307 41.12790... NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1109860259 castle POLYGON ((14.25132 41.36490, 14.25159 41.36487... Rupecanina NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1119447938 building POLYGON ((14.15338 41.26210, 14.15339 41.26206... Torre dell'orologio NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1120991526 building POLYGON ((14.22349 41.27448, 14.22348 41.27437... Scuola Municipale Storica di Roccaromana NaN NaN NaN NaN NaN NaN Roccaromana ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
relation 10557325 castle POLYGON ((13.93373 41.23848, 13.93372 41.23847... Castello ducale NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN

3480 rows × 215 columns

In [16]:
campania_data = campania_data[['historic', 'name', 'historic:civilization', 'geometry']]
campania_data = campania_data[~campania_data['historic'].isin(excluded_keys)]
campania_data = campania_data[campania_data['name'].notna()]
campania_data.reset_index(inplace=True)

campania_data
Out[16]:
element_type osmid historic name historic:civilization geometry
0 node 1456773590 ruins Torre dell'Isola NaN POINT (15.36115 39.99905)
1 node 1601204543 monument Chiesa di San Marco Evangelista NaN POINT (15.32197 40.15126)
2 node 1704137785 monument Casa del Canonico Antonio Maria De Luca NaN POINT (15.40496 40.09458)
3 node 1711457809 ruins Cappella S. Michele NaN POINT (15.37871 40.09500)
4 node 1967471831 monument Christo NaN POINT (15.35784 40.06201)
... ... ... ... ... ... ...
1803 way 1090715537 ruins Rovine del Castello di Caianello NaN POLYGON ((14.08538 41.29496, 14.08553 41.29500...
1804 way 1109860259 castle Rupecanina NaN POLYGON ((14.25132 41.36490, 14.25159 41.36487...
1805 way 1119447938 building Torre dell'orologio NaN POLYGON ((14.15338 41.26210, 14.15339 41.26206...
1806 way 1120991526 building Scuola Municipale Storica di Roccaromana NaN POLYGON ((14.22349 41.27448, 14.22348 41.27437...
1807 relation 10557325 castle Castello ducale NaN POLYGON ((13.93373 41.23848, 13.93372 41.23847...

1808 rows × 6 columns

In [17]:
campania_polygons = campania_data[campania_data['element_type']=='way']

campania_polygons
Out[17]:
element_type osmid historic name historic:civilization geometry
18 way 103970321 castle Torre (Castello degli Antichi) NaN POLYGON ((15.67241 40.33869, 15.67253 40.33868...
19 way 109673812 castle Castello di Policastro NaN POLYGON ((15.52128 40.07844, 15.52157 40.07790...
20 way 111289472 archaeological_site Sito archeologico di Molpa NaN POLYGON ((15.30344 40.03226, 15.30374 40.03207...
21 way 144525571 castle Palazzo Baronale NaN POLYGON ((15.67943 40.21478, 15.67957 40.21472...
22 way 232953215 building Palazzo Ducale NaN POLYGON ((15.33727 40.33529, 15.33720 40.33496...
... ... ... ... ... ... ...
1802 way 1034620667 ruins rocca Dragonis NaN POLYGON ((13.89958 41.13091, 13.89942 41.13064...
1803 way 1090715537 ruins Rovine del Castello di Caianello NaN POLYGON ((14.08538 41.29496, 14.08553 41.29500...
1804 way 1109860259 castle Rupecanina NaN POLYGON ((14.25132 41.36490, 14.25159 41.36487...
1805 way 1119447938 building Torre dell'orologio NaN POLYGON ((14.15338 41.26210, 14.15339 41.26206...
1806 way 1120991526 building Scuola Municipale Storica di Roccaromana NaN POLYGON ((14.22349 41.27448, 14.22348 41.27437...

1127 rows × 6 columns

In [18]:
campania_polygons['centroid'] = campania_polygons.geometry.centroid
campania_polygons.drop(columns={'geometry'}, inplace=True)
campania_polygons.rename(columns={'centroid': 'geometry'}, inplace=True)

campania_polygons
/tmp/ipykernel_6801/3675524279.py:1: UserWarning: Geometry is in a geographic CRS. Results from 'centroid' are likely incorrect. Use 'GeoSeries.to_crs()' to re-project geometries to a projected CRS before this operation.

  campania_polygons['centroid'] = campania_polygons.geometry.centroid
/home/max/.cache/pypoetry/virtualenvs/pygis_blog-iPs2SW5R-py3.10/lib/python3.10/site-packages/geopandas/geodataframe.py:1538: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  super().__setitem__(key, value)
/tmp/ipykernel_6801/3675524279.py:2: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  campania_polygons.drop(columns={'geometry'}, inplace=True)
/tmp/ipykernel_6801/3675524279.py:3: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  campania_polygons.rename(columns={'centroid': 'geometry'}, inplace=True)
Out[18]:
element_type osmid historic name historic:civilization geometry
18 way 103970321 castle Torre (Castello degli Antichi) NaN POINT (15.67246 40.33864)
19 way 109673812 castle Castello di Policastro NaN POINT (15.52158 40.07822)
20 way 111289472 archaeological_site Sito archeologico di Molpa NaN POINT (15.30370 40.03271)
21 way 144525571 castle Palazzo Baronale NaN POINT (15.67941 40.21455)
22 way 232953215 building Palazzo Ducale NaN POINT (15.33695 40.33505)
... ... ... ... ... ... ...
1802 way 1034620667 ruins rocca Dragonis NaN POINT (13.89960 41.13073)
1803 way 1090715537 ruins Rovine del Castello di Caianello NaN POINT (14.08543 41.29480)
1804 way 1109860259 castle Rupecanina NaN POINT (14.25164 41.36472)
1805 way 1119447938 building Torre dell'orologio NaN POINT (14.15341 41.26209)
1806 way 1120991526 building Scuola Municipale Storica di Roccaromana NaN POINT (14.22353 41.27442)

1127 rows × 6 columns

In [19]:
campania_final = pd.concat([campania_polygons, campania_data[campania_data['element_type']=='node']])
campania_final.drop(columns={'element_type'}, inplace=True)
campania_final.sort_values(by='name', inplace=True)
campania_final = gpd.GeoDataFrame(campania_final, geometry='geometry')

campania_final
Out[19]:
osmid historic name historic:civilization geometry
745 2119655941 monument 150° Anni d'Italia NaN POINT (14.34131 41.07334)
292 435717995 monastery Abbazia del Goleto NaN POINT (15.14352 40.90592)
94 4947822441 ruins Abitato di acropoli - edificio arcaico NaN POINT (15.27648 40.25771)
123 222321463 monument Acquedotto NaN POINT (15.26815 40.24818)
1707 845154928 bridge Acquedotto NaN POINT (14.26074 40.87512)
... ... ... ... ... ...
1099 505054347 tomb unknown tomb NaN POINT (14.48051 40.75207)
1097 505054345 tomb unknown tomb NaN POINT (14.48061 40.75202)
433 7036790307 ruins vecchia calcara NaN POINT (14.74056 40.68214)
1703 802580354 archaeological_site via Domitiana ancient_roman POINT (14.05667 40.85108)
1746 5378404295 ruins villa romana NaN POINT (14.21883 41.18651)

1733 rows × 5 columns

In [20]:
campania_site_count = len(campania_final.index)

campania_site_count
Out[20]:
1733

Sulla base dei dati contenuti in OpenStreetMap e dei TAG di ricerca inseriti, risulta che in Campania ci sono 1733 siti di interesse storico-archeologico.

2.1. Come sono raggruppati i siti?¶

In [21]:
campania_group = campania_final.groupby(by='historic').count()
campania_group.drop(columns={'name', 'historic:civilization', 'geometry'}, inplace=True)
campania_group.rename(columns={'osmid': 'count'}, inplace=True)
campania_group.sort_values(by='count', ascending=False, inplace=True)

campania_group
Out[21]:
count
historic
archaeological_site 577
ruins 365
monument 229
castle 205
tomb 100
heritage 78
building 74
city_gate 39
citywalls 11
tower 10
bridge 10
church 9
monastery 6
fort 4
farm 3
aqueduct 3
roman_road 2
village 1
acqueduct 1
gate 1
prison 1
milestone 1
lavoir 1
archaelogical_site;mine;aqueduct 1
windmill 1

2.2. Dove sono localizzati i soli siti archeologici?¶

In [22]:
campania_polygon = gpd.GeoDataFrame(geometry=gpd.GeoSeries(campania.geometry), crs=osm_crs).to_crs(contextily_tile_crs)
campania_archaeological_site = campania_final[campania_final['historic']==target_data]

c_minx, c_miny, c_maxx, c_maxy = campania_polygon.squeeze().bounds

campania_img, campania_ext = cx.bounds2img(w=c_minx, s=c_miny, e=c_maxx, n=c_maxy, ll=False)

fig2, ax2 = plt.subplots(figsize=(10, 10))
ax2.get_xaxis().set_visible(False)
ax2.get_yaxis().set_visible(False)
plt.title(f'Siti archeologici in Campania: {len(campania_archaeological_site.index)}')

ax2.imshow(campania_img, extent=campania_ext, zorder=0)
campania_polygon.boundary.plot(ax=ax2, edgecolor='black', zorder=1)
campania_archaeological_site.to_crs(contextily_tile_crs).plot(ax=ax2, marker="o", facecolor='red', edgecolor='white', markersize=50, zorder=2)
Out[22]:
<Axes: title={'center': 'Siti archeologici in Campania: 577'}>
No description has been provided for this image

3. Ricerca a scala nazionale¶

Tutto come al punto 2 ma a scala nazionale.

In [23]:
italia = regions_gdf.dissolve().squeeze()

italia
Out[23]:
geometry      MULTIPOLYGON (((8.41239408066858 38.8612742703...
COD_RIP                                                       1
COD_REG                                                       1
DEN_REG                                                Piemonte
Shape_Leng                                        1236799.83183
Shape_Area                                   25393881930.299999
Name: 0, dtype: object
In [24]:
%%time

italia_data = ox.features_from_polygon(
    polygon=italia.geometry,
    tags={'historic': True}
)

italia_data
CPU times: user 4min 12s, sys: 8.48 s, total: 4min 20s
Wall time: 8min 13s
Out[24]:
historic name geometry access barrier bicycle foot motorcar motorcycle tourism ... lanes:emergency:conditional bridge:name:fr name:oc source:name:oc source:prominence name:frp parking:both trailblazed:visibility mtb:note handrail:left
element_type osmid
node 7868747286 memorial Memoriale vittime del naufragio del 3 ottobre ... POINT (12.60751 35.50267) NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
465242664 memorial Monumento all'olivicultore Il Sicano POINT (12.81015 37.66188) NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
910358621 wayside_cross NaN POINT (12.59370 37.66452) NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
910561763 wayside_cross NaN POINT (12.60369 37.65963) NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1149564353 ruins Torre Granatelli POINT (12.62953 37.69836) NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
way 792170382 yes NaN POLYGON ((6.88599 45.68088, 6.88605 45.68092, ... NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
792170989 yes NaN POLYGON ((6.88611 45.68022, 6.88612 45.68026, ... NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
889030470 ruins NaN LINESTRING (7.14040 45.68853, 7.14047 45.68853... NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
889257442 wayside_shrine NaN POLYGON ((7.13543 45.71861, 7.13546 45.71862, ... NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1080515646 ruins Capanna Gamba POLYGON ((6.88259 45.80152, 6.88264 45.80153, ... NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN

117984 rows × 1254 columns

In [25]:
italia_data = italia_data[['historic', 'name', 'historic:civilization', 'geometry']]
italia_data = italia_data[~italia_data['historic'].isin(excluded_keys)]
italia_data = italia_data[italia_data['name'].notna()]
italia_data.reset_index(inplace=True)

italia_data
Out[25]:
element_type osmid historic name historic:civilization geometry
0 node 1149564353 ruins Torre Granatelli NaN POINT (12.62953 37.69836)
1 node 1149564682 ruins Torre Grimesi NaN POINT (12.72536 37.71378)
2 node 3878637404 archaeological_site Necropoli, Castelvetrano NaN POINT (12.78983 37.59280)
3 node 4479113496 ruins Santuario di Hera Matrimoniale NaN POINT (12.81771 37.58643)
4 node 5965009778 archaeological_site Selinunte ingresso Triscina Ancient_Greek POINT (12.81288 37.58463)
... ... ... ... ... ... ...
28114 way 445667229 watermill Mulino del Grand-Haury NaN POLYGON ((7.13874 45.68356, 7.13875 45.68353, ...
28115 way 652952909 ruins Casermette modern POLYGON ((6.90022 45.68080, 6.90025 45.68075, ...
28116 way 652952910 ruins Casermette modern POLYGON ((6.89994 45.68062, 6.89994 45.68056, ...
28117 way 768670460 ruins Ricovero Adami NaN POLYGON ((6.99024 45.61458, 6.99030 45.61462, ...
28118 way 1080515646 ruins Capanna Gamba NaN POLYGON ((6.88259 45.80152, 6.88264 45.80153, ...

28119 rows × 6 columns

In [26]:
italia_polygons = italia_data[italia_data['element_type']=='way']

italia_polygons
Out[26]:
element_type osmid historic name historic:civilization geometry
7 way 34943416 ruins Arco Normanno NaN POLYGON ((12.59113 37.65041, 12.59112 37.65036...
8 way 38785368 ruins Tempio di Hera NaN POLYGON ((12.83445 37.58675, 12.83527 37.58670...
9 way 58606782 ruins Patrantonio NaN POLYGON ((12.65663 37.61588, 12.65687 37.61558...
10 way 58606783 ruins Baglio Don Federico NaN POLYGON ((12.51577 37.69994, 12.51596 37.69984...
11 way 58606785 ruins Baglio Riolo NaN POLYGON ((12.56747 37.67633, 12.56798 37.67623...
... ... ... ... ... ... ...
28114 way 445667229 watermill Mulino del Grand-Haury NaN POLYGON ((7.13874 45.68356, 7.13875 45.68353, ...
28115 way 652952909 ruins Casermette modern POLYGON ((6.90022 45.68080, 6.90025 45.68075, ...
28116 way 652952910 ruins Casermette modern POLYGON ((6.89994 45.68062, 6.89994 45.68056, ...
28117 way 768670460 ruins Ricovero Adami NaN POLYGON ((6.99024 45.61458, 6.99030 45.61462, ...
28118 way 1080515646 ruins Capanna Gamba NaN POLYGON ((6.88259 45.80152, 6.88264 45.80153, ...

15596 rows × 6 columns

In [27]:
italia_final = pd.concat([italia_polygons, italia_data[italia_data['element_type']=='node']])
italia_final.drop(columns={'element_type'}, inplace=True)
italia_final.sort_values(by='name', inplace=True)
italia_final = gpd.GeoDataFrame(italia_final, geometry='geometry')

italia_final
Out[27]:
osmid historic name historic:civilization geometry
21854 10934220626 monument "Abbraccio" di Walter Mutton NaN POINT (9.06102 45.69856)
3544 5284179170 monument "Aia" NaN POINT (13.14895 43.50022)
10516 4119157392 monument "Albero inginocchiato" - luogo in cui San Brun... NaN POINT (16.31276 38.55455)
25308 6825324511 archaeological_site "Campanile" prehistoric POINT (8.84725 40.42183)
25671 485182848 ruins "Ciappa" NaN POLYGON ((8.31572 44.16803, 8.31571 44.16802, ...
... ... ... ... ... ...
9970 2661451129 archaeological_site zona archeologica NaN POINT (15.95379 37.92615)
9984 321561427 ruins Àfrico Vecchio modern POLYGON ((15.97584 38.06419, 15.97706 38.06399...
4924 8344362252 technical_monument Áncora di Molo Sartorio NaN POINT (13.76053 45.64642)
22775 225138405 ruins Òsini Betzu/Osini Vecchio NaN POLYGON ((9.49217 39.82852, 9.49175 39.82864, ...
5941 3548335004 archaeological_site Ακράγας ancient_greek POINT (13.58857 37.29203)

26555 rows × 5 columns

In [28]:
italia_site_count = len(italia_final.index)

italia_site_count
Out[28]:
26555

Sulla base dei dati contenuti in OpenStreetMap e dei TAG di ricerca inseriti, risulta che in Italia ci sono 26554 siti di interesse storico-archeologico.

3.1. Come sono raggruppati i siti?¶

In [29]:
italia_group = italia_final.groupby(by='historic').count()
italia_group.drop(columns={'name', 'historic:civilization', 'geometry'}, inplace=True)
italia_group.rename(columns={'osmid': 'count'}, inplace=True)
italia_group.sort_values(by='count', ascending=False, inplace=True)

italia_group
Out[29]:
count
historic
archaeological_site 5472
ruins 4814
monument 4024
castle 3055
building 1566
... ...
former_convent 1
footway 1
etrusca 1
edificio_storico_neoclassico 1
millstone 1

202 rows × 1 columns

3.2. Dove sono localizzati i soli siti archeologici?¶

In [30]:
italia_polygon = gpd.GeoDataFrame(geometry=gpd.GeoSeries(italia.geometry), crs=osm_crs).to_crs(contextily_tile_crs)
italia_archaeological_site = italia_final[italia_final['historic']==target_data]

minx, miny, maxx, maxy = italia_polygon.squeeze().bounds

italia_img, italia_ext = cx.bounds2img(w=minx, s=miny, e=maxx, n=maxy, ll=False)

fig3, ax3 = plt.subplots(figsize=(10, 10))
ax3.get_xaxis().set_visible(False)
ax3.get_yaxis().set_visible(False)
plt.title(f'Siti archeologici in Italia: {len(italia_archaeological_site.index)}')

ax3.imshow(italia_img, extent=italia_ext, zorder=0)
italia_polygon.boundary.plot(ax=ax3, edgecolor='black', zorder=1)
italia_archaeological_site.to_crs(contextily_tile_crs).plot(ax=ax3, marker="o", facecolor='red', edgecolor='white', markersize=20, zorder=2)
Out[30]:
<Axes: title={'center': 'Siti archeologici in Italia: 5472'}>
No description has been provided for this image

Conclusione¶

L'analisi appena condotta può dare solo una stima parziale per patrimonio storico-archeologico italiano. Solo i dati ufficiali del Ministero della Cultura possono dare una informazione esatta. Purtroppo i dati ufficiali al momento risultano molto carenti per cui si fa di necessità virtù. Immaginate cosa potrebbe essere realizzato per incentivare, migliorare ed equamente distribuire il turismo in Italia se i dati ufficiali fossero liberamente disponibili. Le metodologie di analisi, come quella appena condotta, esistono ma manca il dato! Manca il dato OPEN!