dati territoriali socio economici pronti per la stampa in 3D

SHP2STL
Doug McCune, ha creato l’interessante libreria “shp2stl” che trasforma un file in formato .shp (usato per i dati geografici vettoriali) in formato stl (usato nella prototipazione 3D per i CAD). Il formato stl è comunemente usato nella stampa 3D. Questo formato può essere visualizzato con diversi software, fra cui l’italianissimo Meshalb. GitHub offre un visualizzatore online di stl se il file caricato in un repository.
L’idea geniale di Doug è stata quella di creare mappe 3D fisiche che rappresentino dati di tipo socio-economico. L’esempio più affascinante viene dalle stampe del crimine a San Francisco.
Un esempio con dati.trentino.it
Affascinato dal tutto ho provato ad elaborare qualcosa partendo da dagli indicatori statistici per comunità di valle del Trentino scaricabili dal portale open data dati.trentino.it. Come esempio ho preso il dataset del tasso di turisticità (espresso in percentuale) incrociato con le geometrie delle comunità di valle filtrato all’anno 2013.
Ho così ottenuto un file csv con le 16 Comunità di Valle e relativi indicatore di turisticità del 2013. L’indicatore è calcolato come “le presenze medie giornaliere in strutture alberghiere. complementari e alloggi privati su popolazione residente per 100” (fonte: servizio statistica Provincia Autonoma di Trento)
[csv src=https://raw.githubusercontent.com/napo/shp2stl_experiments/master/3dmaps/tasso_turistico_2013_comunita_valle_trentino/tasso_turistico_comunita_valle_2013.csv] (fare clic sulla colonna “valore” per ordinare la tabella)
Apparentemente la tabella sembra presentare un errore in quanto il valore della comunità di valle Rotaliana-Königsberg è ripetuto due volte. Il file è stato generato incrociando i dati del servizio statistica con il file con le geometrie delle comunità di valle prodotto dal servizio servizio urbanistica e tutela del paesaggio. Il dato geografico delle comunità di valle presenta 17 geometrie in quanto, il comune di Zambana, appartenente alla comunità di valle in questione si estende su un’enclave che si trova a cavallo fra altre comunità di valle.
L’associazione fra indicatori e geometrie permette di creare una mappa coropletica colorando le aree con una scala dall’arancio (minimo) al rosso (massimo) in relazione al valore dell’indicatore. ma la conversione in .stl genera poi quel fascino del 3D che fa poi venire voglia di stampare il risultato
angolo dello spippolatore
La struttura dei dati
Come già visto precedentemente gli ingredienti base sono: un file di tipo tabellare con un indicatore associabile ad una geometria o attraverso la stessa oppure tramite un identificatore univoco comune un file contenente dati geografici in formato vettoriale a cui poter associare, per ogni geometria, un attributo nell’esempio riportato si è scelto pertanto il tasso di turisticità delle comunità di valle in formato .csv e il vettoriale dei confini delle comunità di valle del Trentino. Purtroppo le due risorse, così come sono, richiedono prima di qualche accorgimento: Il file .csv, che usa come separatore il punto e virgola, si presenta su 494 righe e 3 colonne. La prima riga contiene l’intestazione e descrive tre variabili: anno, codEnte e valore. Di queste quella leggermente sibillina suona la seconda che espansa sta per “codice ente” e rappresenta il codice univoco con cui si distinguono le comunità di valle. I metadati sono descritti all’indirizzo http://www.statweb.provincia.tn.it/INDICATORISTRUTTURALISubPro/selezione.aspx?idind=48 da cui è anche possibile fare estrazioni mirate per anno e per unità territoriali. I valori contenuti da “codEnte” vanno da 1001 a 1016 oltre al valore 9999. Ad esclusione dell’ultimo (che rappresenta il valore per l’intero territorio della Provincia Autonoma di Trento) ciascuno riferisce ad una precisa comunità di valle. Il file con le geometrie delle comunità di valle, invece, si presenta con un file .zip che contiene al suo interno il numero minimo di file con cui distribuire uno shapefile. Si tratta del file delle geometrie (ammcva.shp), degli attributi (ammcva.dbf) e degli indici fra attributi e geometrie (ammcva.shx). Manca, purtroppo, il file che descrive la proiezione usata per rappresentare i dati. La scheda informativa del dataset riporta ETRS89, andando a controllare poi ulteriore documentazione allegata si scopre che si tratta della ETRS89 / UTM zone 32N codice EPSG:25832. Al sito spatialreference.org è disponibile la sua codifica in formato .prj (il quarto file necessario per distribuire shapefile riusabili). Scaricando il file e rinominadolo in ammcva.prj si risolve il problema. Lo shapefile può essere così visualizzato in un software come QGIS e, da lì investigarlo.
creare il file .stl manualmente
Gli attributi associati alle geometrie sono 7: AREA (area della geometria), PERIMETER (perimetro della geometria), COMUNITA (identificativo univoco delle geometrie associate ad una singola comunità di valle), PROV (codice istat per la provincia autonoma di trento), DESC_ (nome della comunità di valle) e SEDE (nome del comune dove si trova la sede della relativa comunità di valle).
I campi utili per associare i dati del file .csv alle geometrie sono codEnte e COMUNITA. Con la differenza che il primo si presenza con sequenza da 1001 a 1016 e il secondo da 1 a 16.
Inoltre, il file .csv, va filtrato per l’anno che si vuole rappresentare.
A questo punto attraverso un foglio di calcolo (es. LibreOffice) vanno modificati i valori di “codEnte” in modo d’averli nella sequenza da 1 a 16 e si estrae una copia dei dati filtrando per l’anno di interesse (es. 2013).
Ottenuto il nuovo file si segue la procedura di QGIS attraverso cui estendere gli attributi di uno shapefile attraverso un file tabellare in formato csv e si genera il nuovo file .shp.
Per la creazione del file .stl serve:
- installare node.js (le istruzioni sono al sito ufficiale)
- installare shp2stl
npm install shp2stl - creare un file .js con i comandi di conversioneQuesta operazione richiede la creazione di un file di testo, qui un esempio per il file
var fs = require('fs'); var shp2stl = require('shp2stl'); var file = 'tasso_turistico_comunita_valle_2013.shp'; shp2stl.shp2stl(file, { width: 100, //le unità in STL sono arbitrarie, ma tipicamente le stampanti 3D usano mm height: 10, extraBaseHeight: 0, extrudeBy: "valore", simplification: 0.2, binary: true, cutoutHoles: false, verbose: true, extrusionMode: 'straight' }, function(err, stl) { fs.writeFileSync('tasso_turistico_comunita_valle_2013.stl', stl); } );le informazioni importanti da conoscere sono:- riga 2: nome del file .shp da trasformare
- riga 10: valore (da 0 a 1) per semplificare le geometrie (utile per generare file più piccoli)
- riga 17: nome del file .stl da generare
- eseguire il file .js con il comando
nodejs crea_stl.js
automatizzare il tutto con uno script
Quanto descritto sopra è automatizzabile con un po’ di bash scripting e appoggiandosi a tool come wget, spatialite e ogr2ogr. È richiesta un po’ di conoscenza di SQL, ma non è così complesso come si può immaginare.
wget -c "http://www.statweb.provincia.tn.it/indicatoristrutturalisubpro/exp.aspx?idind=48&info=d&fmt=csv" -O tasso_turistico_comunita_valle.csv
wget -c http://www.territorio.provincia.tn.it/geodati/813_Comunit__di_valle_12_12_2011.zip
unzip 813_Comunit__di_valle_12_12_2011.zip
wget http://spatialreference.org/ref/epsg/25832/prj/ -O ammcva.prj
cat > cmd.sql << EOF
CREATE VIRTUAL TABLE "ammcva" USING VirtualShape('ammcva','UTF-8', 25832);
CREATE VIRTUAL TABLE "tasso_turistico_comunita_valle" USING VirtualText('tasso_turistico_comunita_valle.csv',
'UTF-8', 1, POINT, NONE, ';');
create table "tasso_turistico_comunita_valle_2013" as SELECT DISTINCT(cast("b"."COMUNITA" as integer)) AS "id", lower("b"."DESC_") AS "comunita", lower("b"."SEDE") AS "sede","a"."valore" AS "valore","b"."Geometry" AS "geometry"
FROM "tasso_turistico_comunita_valle" AS "a"
JOIN "ammcva" AS "b" ON ("a"."codEnte"-1000 = "b"."COMUNITA") WHERE "a"."anno"=2013;
SELECT RecoverGeometryColumn('tasso_turistico_comunita_valle_2013','geometry',25832,'POLYGON','XY');
.dumpshp tasso_turistico_comunita_valle_2013 geometry "tasso_turistico_comunita_valle_2013" "utf-8"
EOF
spatialite ammcva.sqlite < cmd.sql
ogr2ogr -f "geojson" -t_srs epsg:4326 tasso_turistico_comunita_valle_2013.geojson tasso_turistico_comunita_valle_2013.shp
spatialite -header -csv ammcva.sqlite "select id, comunita, sede,valore from tasso_turistico_comunita_valle_2013" > tasso_turistico_comunita_valle_2013.csv
mkdir -p ../3dmaps/tasso_turistico_2013_comunita_valle_trentino
rm *.zip
rm ammcva*
rm *.sql
nodejs shp2stl_tasso_turistico_comunita_valle_2013.js
mv tasso_turistico_comunita_valle_2013* ../3dmaps/tasso_turistico_2013_comunita_valle_trentino
Le righe dalla 1 alla 4 servono a scaricare i dati. Dalla 5 alla 14 invece ad incrociare i dati delle tue tabelle. Interessante l’uso dei comandi “CREATE VIRTUAL TABLE […]” i quali permettono di accedere ai file .csv e .shp senza importarli in spatialite ma astraendoli come se fossero tabelle. Nel comando successivo la query SQL necessaria per unire le tabelle si occupa anche di sistemare i nomi delle colonne e di conciliare i due indici (codEnte e COMUNITA) E, infine, quella per generare il file .shp. Il nuovo file csv viene creato da un comando spatialite (riga 15) mentre ogr2ogr si occupa di creare un file .geojson utile allo script per nodejs con cui si genera il file .topojson necessari alla creazione del file .stl La riga 22 esegue il file shp2stl_tasso_turistico_comunita_valle_2013.js Qui riportato
var shapefile = require('shapefile'),
geocolor = require('geocolor'),
shp2stl = require('shp2stl'),
fs = require('fs'),
topojson = require('topojson'),
ogr2ogr = require('ogr2ogr'),
brewer = require('colorbrewer');
geodata = require('geojson');
var fileRoot = "tasso_turistico_comunita_valle_2013",
shpFile = fileRoot + ".shp",
attribute = "valore",
numBreaks = 9,
colorScheme = "Oranges"
var sourceProjection = fileRoot + ".prj";
var obj = JSON.parse(fs.readFileSync(fileRoot + ".geojson", 'utf8'));
geojson = geocolor.jenks(obj, attribute, numBreaks, brewer[colorScheme][numBreaks], {'stroke-width':.3})
fs.writeFileSync(fileRoot + ".geojson", JSON.stringify(geojson));
var topology = topojson.topology(geojson.features, {"property-transform": function(feature) { return feature.properties; }});
fs.writeFileSync(fileRoot + ".topojson", JSON.stringify(topology));
shp2stl.shp2stl(shpFile,
{
width: 100, //le unità in STL sono arbitrarie, ma tipicamente le stampanti 3D usano mm
height: 10,
extrudeBy: attribute,
sourceSRS: sourceProjection,
extraBaseHeight: 0,
simplification: 0.2,
//trasformazione secondo la proiezione di Google Mercatore
//semplicemente per una visualizzazione meno sferica
destSRS: 'EPSG:900913'
},
function(err, stl) {
fs.writeFileSync(fileRoot + '.stl', stl);
}
);
Questo si distingue rispetto al precedente solo perchè risolve la questione di generare un file .topojson completo della rappresentazione come mappa coropletica facendo uso dell’algoritmo jenks breaks che definisce i colori rispetto all’indicatore scelto e alle dimensioni della geoemtria a cui si applica rispetto alle altre per evitare confusioni di valutazioni quando l’area è piccola rispetto alle altre ma ha un indicatore alto. Il codice è rilasciato su github
