Requisito: crea un AreaChart animato con dati di streaming in tempo reale. Forse trama 300 punti dati ogni 1 s.Come tracciare i dati di streaming in tempo reale utilizzando AreaChart in JAVAFX 2 - Concurrency, Animation, Charting
Dettagli- Quindi ho bisogno di leggere i dati di streaming in tempo reale da un dispositivo medico, del modello di respirazione di un paziente e visualizzarlo in forma d'onda utilizzando AreaChart in JavaFX. Sono nuovo di JavaFX e così ho costruito un piccolo POC, per vedere come la concorrenza e le opere di animazione in JavaFX.
Il concetto funziona e sono felice con il test di base, per quanto riguarda l'attuazione della funzionalità. Ma non sono contento della prestazione che ottengo dal codice qui sotto.
Nel codice di lavoro seguente, creo un thread separato per simulare il recupero dei dati dal dispositivo medico. Il thread genera solo un numero casuale e lo aggiunge a ConcurrentLinkedQueue.
Il thread JavaFX Application estrae questi dati dalla coda, tramite la linea temporale, e li aggiunge a una serie AreaChart.
Questo tipo di animazione mi serve e i dati vengono aggiunti in fase di esecuzione. Puoi copiare e incollare questo codice e testarlo. Dovrebbe funzionare.
MA le prestazioni non sono impressionanti - la CPU raggiunge il 56% di utilizzo - Ho un processore Intel Core 2 Duo @ 2.53 GHZ e 4 GB ram sul mio laptop. La mia scheda grafica è Mobile Intel serie 4 Express con driver di ultima generazione.
Come è possibile migliorare questa animazione o il tracciamento dei dati in tempo reale, al fine di ottenere prestazioni migliori?
NOTA: io sono disposto a compromettere l'animazione, se il collo della bottiglia. Sono aperto a un'implementazione come mostrato qui http://smoothiecharts.org/ in cui la forma d'onda è solo precompilati e solo lo streaming da destra a sinistra.
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.SequentialTransition;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.chart.AreaChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart.Series;
import javafx.stage.Stage;
import javafx.util.Duration;
/**
* A chart that fills in the area between a line of data points and the axes.
* Good for comparing accumulated totals over time.
*
* @see javafx.scene.chart.Chart
* @see javafx.scene.chart.Axis
* @see javafx.scene.chart.NumberAxis
* @related charts/line/LineChart
* @related charts/scatter/ScatterChart
*/
public class AreaChartSample extends Application {
private Series series;
private int xSeriesData=0;
private ConcurrentLinkedQueue<Number> dataQ = new ConcurrentLinkedQueue<Number>();
private ExecutorService executor;
private AddToQueue addToQueue;
private Timeline timeline2;
private SequentialTransition animation;
private void init(Stage primaryStage) {
Group root = new Group();
primaryStage.setScene(new Scene(root));
NumberAxis xAxis = new NumberAxis();
xAxis.setAutoRanging(true);
NumberAxis yAxis = new NumberAxis();
yAxis.setAutoRanging(true);
//-- Chart
final AreaChart<Number,Number> sc = new AreaChart<Number,Number>(xAxis,yAxis);
sc.setId("liveAreaChart");
sc.setTitle("Animated Area Chart");
//-- Chart Series
series=new AreaChart.Series<Number,Number>();
series.setName("Area Chart Series");
series.getData().add(new AreaChart.Data<Number, Number>(5d, 5d));
sc.getData().add(series);
root.getChildren().add(sc);
}
@Override public void start(Stage primaryStage) throws Exception {
init(primaryStage);
primaryStage.show();
//-- Prepare Executor Services
executor = Executors.newCachedThreadPool();
addToQueue=new AddToQueue();
executor.execute(addToQueue);
//-- Prepare Timeline
prepareTimeline();
}
public static void main(String[] args) { launch(args); }
private class AddToQueue extends Thread {
public void run(){
try {
Thread.currentThread().setName(Thread.currentThread().getId()+"-DataAdder");
//-- Add Random numbers to Q
dataQ.add(Math.random());
Thread.sleep(50);
executor.execute(addToQueue);
} catch (InterruptedException ex) {
Logger.getLogger(AreaChartSample.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
//-- Timeline gets called in the JavaFX Main thread
private void prepareTimeline(){
//-- Second slower timeline
timeline2 = new Timeline();
//-- This timeline is indefinite.
timeline2.setCycleCount(Animation.INDEFINITE);
timeline2.getKeyFrames().add(
new KeyFrame(Duration.millis(100), new EventHandler<ActionEvent>() {
@Override public void handle(ActionEvent actionEvent) {
addDataToSeries();
}
})
);
//-- Set Animation- Timeline is created now.
animation = new SequentialTransition();
animation.getChildren().addAll(timeline2);
animation.play();
}
private void addDataToSeries(){
for(int i=0;i<20;i++){ //-- add 20 numbers to the plot
if(dataQ.isEmpty()==false) {
series.getData().add(new AreaChart.Data(xSeriesData++,dataQ.remove()));
//-- Get rid of a bunch from the chart
if (series.getData().size() > 1000) {
series.getData().remove(0,999);
}
}
else{
return;
}
}
}
}
Questa domanda è stata incrociata (e ha risposto correttamente) su un [thread del forum JavaFX Oracle] (https://forums.oracle.com/forums/thread.jspa?threadID=2411087). – jewelsea