In questo breve tutorial vedremo come realizzare un grafico in Android Studio per i nostri dispositivi Ltouch, utilizzando la libreria esterna jjoe64/GraphView in pochi e semplici passaggi. L’esempio da noi proposto andrà a realizzare un grafico avente come asse delle ascisse il tempo trascorso e come asse delle ordinate l’andamento della temperatura. Quest’ultima data da una sonda di temperatura PT100 collegata al dispositivo tramite ingresso analogico ( nulla vieta che la comunicazione possa avvenire in Modbus RTU ). I dati vengono letti e scritti su di una tabella ( temperature_table ) all’interno di un database locale ( DB_CHART.db ) ma in questa guida ci occuperemo solo della lettura quindi consiglio la visione del seguente articolo .
Nel caso in cui un passaggio dovesse essere poco chiaro oppure abbiate bisogno di maggiori informazioni ( per quanto riguarda la realizzazione del grafico ) tutto il materiale da cui attingere è reperibile al seguente indirizzo.
Detto ciò, il primo passaggio prevede di implementare la dipendenza nel build.gradle tramite il seguente comando:
implementation 'com.jjoe64:graphview:4.2.2'
Nel secondo passaggio invece si dovrà aprire il file xml dell’attività ( Es. layout/activity_main.xml ) e aggiungere il tag per creare il grafico vero e proprio ( disporlo all’interno a piacimento ):
Nel terzo passaggio:
-Per prima cosa inizializziamo le variabli…
LineGraphSeries dataseries = new LineGraphSeries<>(new DataPoint[0]); SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy\nHH:mm:ss"); //Nell'onCreate() mioGrafico = (GraphView) findViewById(R.id.TempChart);
-Dopo di che dando per scontato che il database si già popolato, utilizzo il metodo getAllData() contenuto nella classe DatabaseHelper in questo modo:
//Ottengo i vari DataPoint ( valoreX, valoreY ) da applicare in seguito al grafico dataseries.resetData(mioDBHelper.getAllData());
Il metodo getAllData() non fa altro che un SELECT di tutti i dati all’interno della tabella ( temperature_table ) e crea un vettore DataPoint ( che è quello che poi restituisce ). Quest’ultimo contiene i vari punti del grafico ovvero l’associazione ( asseX / asseY ) dove per asseX si intende prendere il valore della riga la cui corrispondente colonna è rappresentata da Time ( in Unix timestamp ) mentre per asseY si intende prendere il valore della riga per cui la corrispondente colonna è rappresentata da Temperature:
/** * Metodo per ottenere tutti i dati presenti all'interno della tabella temperature_table * ( anche se alla fine tengo conto solo delle colonne Time e Temperature * @return : DataPoint[] */ public DataPoint[] getAllData(){ //Ottengo il DB in modalità lettura SQLiteDatabase mioDB = this.getReadableDatabase(); //Creo un oggetto Cursor per selezionare tutti i dati all'interno della tabella Cursor mioCursor = mioDB.rawQuery("SELECT * FROM "+TABLE_name,null); //Istanzio DataPoint di dimensione pari a mioCursore.getCount() ( ovvero pari al numero di // righe ) DataPoint[] mieiDataPoint = new DataPoint[mioCursor.getCount()]; //Con questo ciclo creo i vari datapoint (x,y) e prendo min e max di entrambi gli assi for(int i = 0; i < mioCursor.getCount(); i++){ mioCursor.moveToNext(); if (i == 0){ MinX = mioCursor.getInt(mioCursor.getColumnIndex("Time")); MinY = mioCursor.getDouble(mioCursor.getColumnIndex("Temperature")); } if(i == (mioCursor.getCount()-1)){ MaxX = mioCursor.getInt(mioCursor.getColumnIndex("Time")); MaxY = mioCursor.getDouble(mioCursor.getColumnIndex("Temperature")); } mieiDataPoint[i] = new DataPoint(mioCursor.getInt(mioCursor.getColumnIndex("Time")),mioCursor.getDouble(mioCursor.getColumnIndex("Temperature"))); } //Chiudo il db ( aperto in modalità lettura ) mioDB.close(); return mieiDataPoint; }
A questo punto non rimane altro da fare che il seguente comando per caricare DataPoint[] all’interno del grafico
mioGrafico.addSeries(dataseries);
Nel caso in cui si voglia ottenere un qualcosa di più elaborato propongo di seguito un’altro esempio
//Imposto colore della linea del grafico dataseries.setColor(Color.GREEN); //Imposto se mettere o meno i punti ( in questo caso si ) dataseries.setDrawDataPoints(true); //Imposto il raggio dei punti dataseries.setDataPointsRadius(5); //Imposto la grossezza della linea dataseries.setThickness(3); /* Per settare maualmente l'asse y... mioGrafico.getViewport().setYAxisBoundsManual(true); mioGrafico.getViewport().setMinY(mioDBHelper.getMinY()); mioGrafico.getViewport().setMaxY(mioDBHelper.getMaxY()) */ //Setto manualmente l'asse x mioGrafico.getViewport().setXAxisBoundsManual(true); //Specifico valore minimo asse x mioGrafico.getViewport().setMinX(mioDBHelper.getMinX()); //Specifico valore massimo asse x mioGrafico.getViewport().setMaxX(mioDBHelper.getMaxX()); //Do la possibilità di fare lo zoom e lo scroll mioGrafico.getViewport().setScalable(true); mioGrafico.getGridLabelRenderer().setHumanRounding(false); //In quanto uso data e ora come asse delle x //Aggiungo al grafico i DataPoint mioGrafico.addSeries(dataseries);
Il risultato ottenuto dovrebbe essere simile a quello in figura:
Come potrete notare manca solo un’ultimo passaggio ovvero la conversione Unix timestamp in data e ora comprensibili. La libreria ci viene in contro fornendoci gli strumenti per cambiare manualmente le label degli assi quindi basterà utilizzare quelli per raggiungere il nostro scopo.
mioGrafico.getGridLabelRenderer().setLabelFormatter(new DefaultLabelFormatter(){ @Override public String formatLabel(double value, boolean isValueX) { if(isValueX){ //Come mostrare i valori dell'asse x //Ora legale europa centrale sdf.setTimeZone(TimeZone.getTimeZone("GMT+2")); return sdf.format(new Date((long) value * 1000L)); }else{ //Come mostrare i valori dell'asse y return super.formatLabel(value,isValueX); } } });
Da non dimenticare la creazione dell’oggetto sdf ( SimpleDataFormat ):
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy\nHH:mm:ss");
Con questa guida è tutto, se l’articolo vi è piaciuto condividete e restate sintonizzati per non perdervi alti tutorial sul mondo Android.