JavaFX (8) - Amélioration des performances du diagramme de dispersion


Question:

De quelles manières puis-je améliorer le temps de rendu dans le scénario décrit ci-dessous?

Description:

La tâche à laquelle je suis confronté est de tracer pas mal de points sur un graphique en nuage de points dans JavaFX. Je reçois les données d'une base de données Oracle.

Je pense que mon goulot d'étranglement actuel est scatterChart.getData().add(series);

Le series contient tous les points de données nécessaires dans le graphique.

L'exécution et le rendu du graphique à l'écran peuvent prendre de plusieurs secondes à plusieurs minutes. Pendant ce temps, l'interface graphique se fige.

Nous exécutons des Thinkpad Lenovo avec 4 Cœurs 4 Threads, des graphiques Intel HD4000.

Quelques exemples de graphiques finis sont ci-dessous. Ce dernier étant le pire cas actuel, mais à mesure que plus de données sont collectées, plus de données seront affichées.

(en raison de la taille peu pratique des images, seuls les liens)

Graphique avec ~5.5 K points
Graphique avec ~75 points

Plus info

J'ai suivi ce tutoriel parce que je suis nouveau sur JavaFX, donc je ne sais pas exactement comment le rendu se produit.

Exemple de Code

Ce n'est pas le code réel que j'utilise, c'est juste pour illustrer comment je fais les choses.

//Reference to the chart in the fxml file.
@FXML
private ScatterChart<Date, Number> scatterChart
= new ScatterChart<>(new DateAxis(), new NumberAxis());

private void handleSelectionUpdate(PerfResultSet newValue){
    //newValue is an object containing all the data from the database
    XYChart.Series<Date, Number> series = new XYChart.Series<>();
    /**
    *   adding all the data from newValue to series as 
    *   XYChart.Data<Date, Number>
    *
    *   this is handled by multiple threads and does not take long
    */

    series.setName("myName");


    //this statement is where the gui freezes
    //can I optimize this in any way?
    scatterChart.getData().add(series);
}
Author: Marius Schär, 2015-10-02

1 answers

J'ai rencontré un problème similaire - je dessinais un itinéraire composé de nombreux points sur Google map avec Javascript. J'ai éliminé les points en tenant compte du barème actuel. J'ai vu vos fichiers png, il semble vous avez vraiment besoin de ~30-50 points pour exprimer le message suivant - hé, ce segment vertical/horizontal contient tellement de points que vous pouvez le supposer ligne continue!

Le problème suivant est l'échelle maximale - je pense que chaque ligne continue dans le graphique 75K n'est en fait pas solide. Je veux dire, à petite échelle, je vois un les points de lot comme la ligne continue ____ mais dans l'échelle maximale, je les vois comme . . . ... . ..Mais généralement, l'échelle maximale requise uniquement pour un petit morceau de graphique et vous pouvez éliminer non pas par échelle mais par frontières. Encore une fois référence à Google map-lorsque vous zoomez sur la carte, vous ne voyez pas le globe entier en résolution cool mais un petit morceau de carte. Autres frontières éliminées automatiquement.

Postez ici votre code, quelques informations sur l'échelle ,le zoom (avez-vous une telle fonctionnalité?). Si vous ne l'avez pas fait et que votre graphique est toujours comme dans les fichiers png dans link, vous devez parcourir chaque ligne verticale ou horizontale, rechercher des points séquentiels et remplacer, par exemple, 100 points séquentiels par le point médian de ces 100 points. Au lieu de 100 trouver expérimentalement un tel X, que le remplacement de sequental X pointe vers un point de valeur moyenne n'affecte pas le graphique résultant.

Je répète l'idée principale - Il existe un certain X, tel que le dessin X sequental points égaux à dessin 1 point dans certains échelle fixe-de nombreux points ne donnent pas de précision, mais se "écrasent" simplement en raison des limites de l'échelle et de l'œil humain.

Un pseudocode pour trouver X si votre échelle est constante;

int MAGIC = 50; //change it on each run of your program! You have to find the best value
int counter=1; // points[0] taken as included in accumulating solid segment
int startIndex=0,endIndex;
ArrayList<Integer> compressedDatesArray = new ArrayList<Integer>();
for(int i=1;i<datesArray.length;i++){
  if(deltaBetweenDates(datesArray[i]-datesArray[i-1])==1){
     counter++;
     endIndex=i;
     if(counter==MAGIC){
       counter=0;
       compressedDatesArray.add(datesArray[{endIndex-startIndex)/2]);
       startIndex=endIndex+1;
     }
  }

}

Render compressedArray, voir png. Si le résultat est mauvais-chnage MAGIC et répétez

MISE À JOUR

Vous pouvez recherche binaire MAGIC - essayez 5000, si toujours solide après comperssing 5000 points à un, essayez une valeur plus grande sinon, essayez 2500 et ainsi de suite... Les humains peuvent également recherche binaire quelque chose=)))

Aussi, n'oubliez pas de vous rappeler la valeur Y du point représentant le grand segment. Je veux dire, déclarez également {[3] } et ajoutez correspinding Y de datesArray[(endIndex-startIndex/2)]

 3
Author: Baurzhan, 2015-10-02 09:09:58