From df4010a2cf927473666299b8b56b93277b033b28 Mon Sep 17 00:00:00 2001 From: putro Date: Sun, 12 Apr 2020 14:08:38 +0200 Subject: [PATCH] updated openlamb to read data online or from csv files --- README | 18 ++++++-- openlamb.py | 130 ++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 105 insertions(+), 43 deletions(-) diff --git a/README b/README index 3815085..42fa447 100644 --- a/README +++ b/README @@ -1,6 +1,6 @@ Software per il recupero delle informazioni dei dati dei sensori ambientali pubblicati dall'arpa sul portale opendata della regione lombardia -la lista delle stazioni e dai sensori si trova qui': +la lista delle stazioni e dai sensori si trova qui': https://www.dati.lombardia.it/Ambiente/Stazioni-qualit-dell-aria/ib47-atvt lo script stazioni.py stampa la lista delle stazioni e dei sensori recuperando i dati da link qui' sopra, se si salva invece il contenuto di quel link come stazioni.csv la ricerca viene fatta offline in questo file. @@ -26,9 +26,19 @@ sensori_aria_2017.zip - 13M sensori_aria_2018.zip - 13M sensori_aria_2019.zip - 13M -per visualizzarne i dati e' necessario scaricare l'intero file e processarlo. +per visualizzarne i dati e' necessario scaricare l'intero file. Quindi per l'analisi dei dati recenti e' piu' comodo lavorare con i dataset, per analisi storiche invece bisogna usare i csv -openlamb usa i dataset, -in futuro ci sara' una versione che lavorera' con i csv +i csv vanno scaricati manualmente (per ora) e messi nella cartella csv o in una cartella a scelta modificando il percorso specificato nel file openlamb.py + +sintassi: + + python openlamb.py --dataset 2018 2019 --sensori 6956 10320 + mostra i grafico per il dataset degli anni 2018 e 2019 per i sensori indicati + + python openlamb.py --csv 2018.csv 2019.csv --sensori 6956 10320 + mostra i grafico dei dati contenuti nei file 2018.csv e 2019.csv per i sensori indicati + + python openlamb.py --dataset 2019 --csv 2019.csv --sensori 6956 + mostra il grafico del confronto dei dati nel dataset e nel file csv per il sensore indicato diff --git a/openlamb.py b/openlamb.py index 14e6f26..a79602e 100755 --- a/openlamb.py +++ b/openlamb.py @@ -1,19 +1,21 @@ #!/usr/bin/env python -# pylint: skip-file import argparse import traceback import sys -import subprocess import pandas as pd import numpy as np from sodapy import Socrata import matplotlib.pyplot as plt +import glob +import os +from os import getcwd, chdir +path_to_csv_files = "csv/" -datasets_ambiente = {"2020": "nicp-bhqi", - "2019": "kujm-kavy", - "2018": "bgqm-yq56", +datasets_ambiente = {"2020": "nicp-bhqi", + "2019": "kujm-kavy", + "2018": "bgqm-yq56", "2017": "j8j8-qsb2"} @@ -21,77 +23,126 @@ def _connect(): client = Socrata("www.dati.lombardia.it", None) return client -def process_dataset(dataset, sensore): + +def read_data_online(dataset, sensore): client = _connect() - results = client.get(dataset, IdSensore=sensore) + return client.get(dataset, IdSensore=sensore) + + +def read_data_from_csv(datafile): + return pd.read_csv("csv/" + datafile, usecols=['IdSensore', 'Data', 'Valore', 'Stato', 'idOperatore']) + + +def process(dati, sensore, csv): + """ processa i dati per un sensore da un dataset o un file csv e restituisce un dataframe """ + print('Sto processando i dati del sensore %s per l\'origine dati %s...' % (sensore, dati)) + if csv: + results = read_data_from_csv(dati) + else: + results = read_data_online(dati, sensore) results_df = pd.DataFrame.from_records(results) + results_df.columns = [x.lower() for x in results_df.columns] try: + results_df = results_df.astype({'idsensore': 'int64'}) + results_df = results_df[results_df['idsensore'] == int(sensore)] results_df = results_df.astype({'valore': 'float64'}) + results_df["data"] = pd.to_datetime(results_df["data"]) + results_df = results_df.replace(-9999, np.nan) except: - print('\nspiacente, dati non disponibili per il sensore %s') % sensore + print('\nERRORE: dati non disponibili per il sensore %s\n') % sensore + traceback.print_exc() sys.exit(-1) - results_df["data"] = pd.to_datetime(results_df["data"]) - results_df = results_df.replace(-9999, np.nan) results_df.sort_values(by=['data'], inplace=True) - results_df.rename(columns = {'valore':sensore}, inplace = True) - results_df.drop(columns=['idoperatore', 'idsensore', 'stato'], inplace = True) + results_df.rename(columns={'valore': sensore}, inplace=True) + results_df.drop(columns=['idoperatore', 'idsensore', 'stato'], + inplace=True) return results_df def merge_df(dataframes, sensori): + """ fonde diversi dataframes in un dataframe unico con un sensore per colonna """ df = dataframes[sensori[0]] for sensore in sensori[1:]: df = pd.merge(df, dataframes[sensore]) return df -def get_dataframes(datasets, sensori): +def get_dataframes(dati_csv, dati, sensori): + """ salva in un dict i dataframes dei vari sensori richiesti """ dataframes = {} for sensore in sensori: - df = process_dataset(datasets[0], sensore) - for dataset in datasets[1:]: - df = pd.concat([df, process_dataset(dataset, sensore)], axis=0) - dataframes[sensore] = df + if dati_csv: + df = process(dati_csv[0], sensore, True) + for d in dati_csv[1:]: + df = pd.concat([df, process(d, sensore, True)], axis=0) + df.rename(columns={sensore: sensore + "-csv"}, inplace=True) + dataframes[sensore + "-csv"] = df + if dati: + df = process(dati[0], sensore, False) + for d in dati[1:]: + df = pd.concat([df, process(d, sensore, False)], axis=0) + dataframes[sensore] = df return dataframes def plot_dataframe(dataframe): dataframe.plot(x='data') - plt.axhline(y=50, color='black', linestyle='-', label='24-hour average EU limit') + plt.axhline(y=50, color='black', linestyle='-', label='EU limit') plt.show() -def main(): +def list_of_csv_files(dir_name): + saved = getcwd() + os.chdir(dir_name) + filelist = glob.glob('*.csv') + chdir(saved) + return filelist + +def main(): parser = argparse.ArgumentParser() - parser.add_argument("--dataset", nargs='+', required=True, help="ricerca dei datasets") - parser.add_argument('--sensori', nargs='+', required=True, help="specifica i sensori") + parser.add_argument("--dataset", nargs='+', required=False, + help="ricerca dei datasets") + parser.add_argument("--csv", nargs='+', required=False, + help="ricerca nei files csv") + parser.add_argument('--sensori', nargs='+', required=True, + help="cerca i dati di questi sensori") args = parser.parse_args() try: - datasets = [] - if "all" in args.dataset: - for k in datasets_ambiente.keys(): - datasets.append(datasets_ambiente[k]) - else: - for d in args.dataset: - datasets.append(datasets_ambiente[d]) - sensori = args.sensori - dataframes = get_dataframes(datasets, sensori) - datamerged = merge_df(dataframes, sensori) + dati_csv = [] + csv_files = list_of_csv_files(path_to_csv_files) + if args.csv: + if "all" in args.csv: + dati_csv = csv_files + else: + for d in args.csv: + if d in csv_files: + dati_csv.append(d) + else: + print("spiacente, ma il file csv %s non e' disponibile nel " + "percorso indicato: %s" % (d, path_to_csv_files)) + sys.exit(-1) + dati = [] + if args.dataset: + if "all" in args.dataset: + for k in datasets_ambiente.keys(): + dati.append(datasets_ambiente[k]) + else: + for d in args.dataset: + dati.append(datasets_ambiente[d]) + dataframes = get_dataframes(dati_csv, dati, args.sensori) + datamerged = merge_df(dataframes, dataframes.keys()) import stazioni s = stazioni.get_stazioni() - for sensore in sensori: - location = s.loc[s['idsensore'] == sensore, 'nomestazione'].iloc[0] + for sensore in datamerged.columns[1:]: + print(sensore) + location = s.loc[s['idsensore'] == sensore.split("-")[0], 'nomestazione'].iloc[0] print('Valore medio per il sensore %s %s: %s' % (sensore, location, datamerged[sensore].mean().round(1))) plot_dataframe(datamerged) - - except KeyError: - print("\nErrore:") - #print("Datasets disponibili:") - #print('\n'.join([str(lst) for lst in sorted(datasets_ambiente.keys())])) - traceback.print_exc() + print("\nKeyError: forse hai specificato un dataset che non esiste ?") + traceback.print_exc() except KeyboardInterrupt: print("program terminated by user") except SystemExit: @@ -102,5 +153,6 @@ def main(): print("\nReport this to putro@autistici.org") sys.exit() + if __name__ == '__main__': main()