Category Archives: Programmazione

OSMQuake

A quasi tre mesi dalla presentazione ufficiale ad OSMit, pubblico finalmente il codice di OSMQuake purtroppo ancora incompleto e con il codice ancora molto sporco e incasinato (l’ho scritto in tre ritagli di tempo la sera tardi).

Ho aspettato così tanto perché mi sarebbe piaciuto completare alcune parti del software che avevo implementato soltanto in parte purtroppo però in questo periodo non ho molto tempo e preferisco pubblicare il codice in modo che chiunque voglia contribuire (anche per disegnare un logo ad esempio) possa farlo.

Il codice sorgente si trova attualmente qui, se qualcuno volesse collaborare posso metterlo su google code e usare svn per la gestione della versione.

Questo è il risultato dell’elaborazione di stamattina sull’Italia centrale.

mappa terremoti luglio 2009 Italia centrale

mappa terremoti luglio 2009 Italia centrale

Già dalla mappa è possibile vedere cosa manca:

  • Il raggio del marker è direttamente proporzionale alla magnitudo ma il colore dovrebbe essere inversamente proporzionale al tempo, cosicchè i terremoti più recenti siano di un rosos più intenso.
  • Sarebbe bello avere una didascalia con qualche indicazione riguardo i range di dimensioni e di colori e delle statistiche generate automaticamente

Per generare la mappa precedente basta avviare OSMQuake e poi premere sul tasto “Scarica” per effettuare il parsing della pagina e salvare gli eventi in un database sqlite (notare in basso a sinistra il numero degli eventi scaricati):

Interfaccia grafica OSMQuake

Interfaccia grafica OSMQuake

A questo punto si possono scegliere i parametri di filtraggio, lo zoom della mappa e il tipo di mappa (Mapnik, Osmarender e OpenArial) e si clicca su Genera mappa. A questo punto il software mostra le tile da scaricare e le dimensioni della mappa in pixel e inizia a scaricare le tile necessarie. Dopo di che le unisce e disegna sopra la mappa i marker calcolando dinamicamente il raggio.

Il risultato finale è una nuova finestra con la mappa:

Mappa finale

Mappa finale

Mappa finale2

Mappa finale2

Cosa funziona in OSMQuake:

  • Parsing della pagina
  • Riempimento del database con gli eventi
  • Filtraggio per magnitudo
  • Filtraggio per profondità
  • Scelta dello zoom
  • Scelta del server
  • Calcolo delle tile da scaricare
  • Calcolo delle dimensioni della mappa in pixel

Cosa non funziona (ancora!) in OSMQuake:

  • Filtraggio degli eventi in base alla distanza da un punto geografico
  • Calcolo dell’area coperta dalla mappa
  • Filtraggio in base alla regione (ho già i bbox delle regioni italiane che mi ha dato Niccolò Rigacci ma non ho avuto il tempo di creare un dizionario con i bbox)
  • Per generare una nuova mappa con la stessa istanza è necessario cancellare a mano le tile (io uso uno script in bash)
  • Prima di scaricare di nuovo gli eventi è necessario cancellare il file del database (il file prova)

Cosa sarebbe mi piacerebbe implementare in OSMQuake:

  • Riscrivere il codice ad oggetti
  • Implementare il threading per lo scaricamento delle tile (la policy del tile server di OpenStreetMap permette solo due thread)
  • Permettere di mantenere un database storico degli eventi e di filtrarli anche per periodo per creare delle mappe mensili o settimanali di una determinata zona
  • Permettere l’esportazione deglio eventi sismici in KML

Qualsiasi contributo è benaccetto!

Trasformare in massa tracce igc e nmea in tracce gpx

Durante l’openstreecamping2008 abbiamo avuto la necessità di trasformare, con gpsbable, le decine di tracce igc, il formato di tracking che utilizza il cellulare di Fradeve, raccolte durante i giri in bici in formato gpx che è il formato utilizzato da josm.

Dopo qualche giorno ci siamo resi conto che era noioso ridigitare ogni volta il comando dal terminale (ovviamente non tutto, ma modificando semplicemente il nome del file nel comando precedente) e potevamo perdere tempo prezioso in questo modo? Ovviamente no!

Mentre Fradeve leggeva la biografia di Torvalds (ve la consiglio) e il caldo era insopportabile, ho scritto un piccolo script in python per convertire in massa file igc e nmea in file gpx.

Credo sia possibile farlo anche in bash, ma non conoscendo il bash ho preferito usare il python e in particolare il modulo os, contenuto nella libreria standard, che permette al programma di interfacciarsi con il sistema operativo.

Clic qui per scaricare lo script

Qualche commento al codice:


if formato in ListaFormati :
    ListaFile = CercaFile(os.listdir('.') , formato)
else :
    print "Formato inesistente o non ancora implementato, esco dal programma."
exit()

Controlla il formato passato come argomento al programma e, se corretto (i formati accettati sono igc e nmea), restituisce una lista, attraverso la funzione os.listdir(cartella), con tutti i file contenuti nella cartella passata come argomento.


def CercaFile(lista, flag):
    for i in lista:
        if flag in i:
            gpx.append(i)
return gpx

La funzione CercaFile restituisce una nuova lista contenente soltanto i file con l’estensione interessata (igc o nmea), eliminando tutti gli altri file inutili.


if ListaFile != []:
    c = 0
    for i in ListaFile:
        stringa = "gpsbabel -i " + formato + " -f '" + i + "' -o gpx -F '" + i[0:-3] + "'gpx"
        os.system(stringa)
        c = c + 1
    print "Ho trasformato " +str(c)+ " file in gpx ed ho cancellato i file " + formato + ""
else:
    print "Non ci sono file da convertire, ciao!"

Controlla che ci siano file da convertire, in caso positivo passa al sistema, attraverso il la funzione os.system, il comando gpsbabel necessario alla conversione dei file. La stringa che può sembrare complicata serve a trasformare i file mantenendo il nome originale.

Per eseguire lo script basta copiare i file da trasformare nella stessa cartella dove è presente lo script e poi da terminale digitare:

$: python trasforma.py formato

dove formato deve essere sostituito con igc o con nmea a seconda del formato di partenza dei file.

Semplice, veloce ed efficace a patto di aver gpsbabel installato, ovviamente!

Estrapolare dati dai file gpx

Dopo l’avventurosa e faticosissima biciclettata di sabato scorso sulla strada che porta a Castel del Monte (foto), che ovviamente abbiamo mappato (permalink osm), mi sono chiesto quale fosse la variazione di pendenza che le nostre povere gambe hanno dovuto sopportare e mi sono subito messo all’opera per scrivere un rudimentale parser in Python sfruttando il modulo BeautifulSoup (installabile dai repository di Ubuntu)

Avendo più tempo a disposizione mi piacerebbe scrivere l’interfaccia grafica del programmino e far disegnare il grafico ad uno dei potenti widget di wxPython, ma purtroppo adesso devo accontentarmi di questo script molto semplice ma al tempo stesso efficace.

Clic qui per scaricare lo script.

Anche se lo script è semplicissimo aggiungo qualche commento:

</code>

try:
NomeFile = sys.argv[1]
except:
print "Argomento mancante o non valido"
exit()

Controlla che il nome del file sia stato passato come argomento.

</code>

try:
gpx = open(NomeFile,'r')
except:
print "Impossibile leggere il file, controllare che lo stesso esista e che sia leggibile"
exit()

Tenta di aprire il file gpx passato come argomento.

</code>

xml = gpx.read()
gpx.close()
soup = BeautifulStoneSoup(xml)
dati = open('dati.txt','w')
n = 0
for i in soup.findAll('ele'):
dati.write(i.string + '\n')
n = n + 1
dati.close()

Il file viene letto e il suo contenuto, salvato nella variabile xml, viene passato al parser xml di BeautifulSoup, a questo punto viene invocata la funzione findAll che restituisce una lista contenente tutti i tag <ele> (compreso il contenuto dei tag).

L'istanza string, richiamata sui singoli elementi della lista, restituisce solo il contenuto dei tag <ele> senza il tag stesso, infine i contenuti vengono salvati su un file txt separati da un carriage return.

Per eseguire correttamente lo script è sufficiente eseguire lo script digitando da terminale:

$: python altitudine.py nomefile.gpx

e poi ricopiare i valori del file dati.txt in un foglio di calcolo e far elaborare il grafico dal software (ovviamente consiglio sempre di utilizzare OpenOffice.org - Calc).

Questo è il grafico elaborato dai gpx del percorso verso Castel del Monte (clic per ingrandire):

Salvare la banca dati Inran in un file sqlite3

Giocherellando con i moduli di python per la gestione dei database sqlite3, per il parsing delle pagine web e con le espressioni regolari ho scritto un piccolo programmino che permette di effettuare l’html screen scraping delle pagine componenti la banca dati dell’Inran e di salvare i dati riguardanti la composizione nutrizionale di 790 alimenti in un database ordinato sqlite3.

Ho pensato di pubblicare il programma, con licenza GPL3, pensando che possa essere utile a qualcuno, comunque ho già cominciato a scrivere l’interfaccia grafica per accedere ed elaborare i dati (una specie di calcolatore di calorie) sperando che possa tra qualche tempo entrare a far parte del programma per la gestione e l’archiviazione delle ricette che ho intenzione di scrivere.

</p>

<p style="text-align: left;">#! /usr/bin/python
#-*- coding: utf-8 -*-
# Script per effetuare il parsing delle pagine dati INRAN e per
# salvare i dati in maniera ordinata in un database SQlite3
# Copyright (C) 2008  Alessandro De Noia <alessandro .denoia@gmail.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

import re, sqlite3, string
from BeautifulSoup import BeautifulSoup
from time import time
from urllib import urlopen

def NormalizeStr(FoodStr):
"""Restituisce la stringa senza il commento tra parentesi quadre e senza apici
Return a new string without the comment in the square brackets and without the apices  """
if string.find(FoodStr, "[") == -1:
NewFoodStr = FoodStr
else:
NewFoodStr = FoodStr[0:(string.find(FoodStr, "[")-1)]
return string.join(string.split(NewFoodStr,'\''),"\\''")

def NormalizeNum(DataNum):
"""Restituisce un numero float cambiando la virgola in punto o altrimenti cambia la stringa None nel valore NULL
Return a float number turning the comma into a dot or else change the string None into the value NULL"""
if string.find(DataNum, ",") != -1:
NewDataNum = round(float(string.join(string.split(DataNum,","),".")),2)
elif (DataNum == "None") or (DataNum == "tr") or (DataNum == " "):
NewDataNum = -1.00
else:
NewDataNum = round(float(DataNum),2)
return NewDataNum

def Database():
"""Crea, popola e riempie il database con i dati acquisiti
Create, populate and fill the database with the acquired data"""
data = ['']*22
rows = ('inran_id', 'pe', 'acqua', 'proteine', 'lipidi', 'carboidrati', 'amido', 'zucchero', 'fibra', 'energia_c', 'energia_j', 'sodio', 'potassio', 'ferro', 'calcio', 'fosforo', 'tiamina', 'riboflavina', 'niacina', 'vit_a', 'vit_c', 'vit_e')
categories = ('cereali', 'legumi', 'verdure', 'frutta', 'carni_fresche', 'carni_trasformate', 'fast_food', 'frattaglie', 'pesca', 'latte', 'formaggi', 'uova', 'olii', 'dolci', 'vari', 'alcooliche')
Nid = 0
conn = sqlite3.connect("inran")
cur = conn.cursor()
cur.execute("""CREATE table inran (id INTEGER PRIMARY KEY,
inran_id FLOAT,
categoria VARCHAR NOT NULL,
alimento VARCHAR NOT NULL,
pe FLOAT DEFAULT 100,
acqua FLOAT DEFAULT NULL,
proteine FLOAT DEFAULT NULL,
lipidi FLOAT DEFAULT NULL,
carboidrati FLOAT DEFAULT NULL,
amido FLOAT DEFAULT NULL,
zucchero FLOAT DEFAULT NULL,
fibra FLOAT DEFAULT NULL,
energia_c FLOAT DEFAULT NULL,
energia_j FLOAT DEFAULT NULL,
sodio FLOAT DEFAULT NULL,
potassio FLOAT DEFAULT NULL,
ferro FLOAT DEFAULT NULL,
calcio FLOAT DEFAULT NULL,
fosforo FLOAT DEFAULT NULL,
tiamina FLOAT DEFAULT NULL,
riboflavina FLOAT DEFAULT NULL,
niacina FLOAT DEFAULT NULL,
vit_a FLOAT DEFAULT NULL,
vit_c FLOAT DEFAULT NULL,
vit_e FLOAT DEFAULT NULL)""")
for category in categories:
try:
socket = urlopen('http://www.inran.it/servizi_cittadino/per_saperne_di_piu/tabelle_composizione_alimenti/composizione/'+category)
except:
print("Impossible to resolve the host, please check internet connection")
exit()
page = BeautifulSoup(socket.read())
socket.close()
food = page.findAll('td', {"class":re.compile("descrizione_[1-2]")})
FoodData = page.findAll('td', {"class":re.compile("dato_[1-2]")})
n = 0
for i in food:
StrSql = ("""INSERT INTO inran (id, categoria, alimento)
VALUES (%d,'%s','%s')""") % (Nid, category, NormalizeStr(i.string))
cur.execute(StrSql)
data = FoodData[(22*n):(22*(n+1))]
m = 0
for k in data:
StrSql2 = ("UPDATE inran SET %s=%f WHERE id=%d") % (rows[m], NormalizeNum(str(k.string)), Nid)
cur.execute(StrSql2)
m = m + 1
n= n + 1
Nid = Nid + 1
cur.close()
conn.commit()
conn.close()

time1 = time()
print("-------------------------------------------------------------")
print("Sto creando il database, attendere")
print("-------------------------------------------------------------")
Database()
time2 = time()
print("-------------------------------------------------------------")
print("Database creato in %f secondi") % (time2 - time1)
print("-------------------------------------------------------------")
<p style="text-align: left;">

Scaricate il file da qui e poi eseguitelo da un terminale semplicemente digitando (è necessario avere installato il modulo BeautifulSoup dai repository di Ubuntu):

$: python iran.py

Essendo scritto in python funziona su qualsiasi sistema operativo con python 2.5 e i relativi moduli installati.

Hello World!

Mi sono lasciato trascinare anche io dalla blog-mania e penso che non ci sia modo migliore di cominciare questa impresa se non con il classico

Hello World!