IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Afficher sur un graph zoomable une grande quantité de données


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre extrêmement actif Avatar de petitours
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Février 2003
    Messages
    2 037
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 2 037
    Par défaut Afficher sur un graph zoomable une grande quantité de données
    Bonjour

    Besoin de base
    Je cherche à afficher sur un chart des séries de données de type Line avec possibilité de zoomer dans tous les sens très facilement (vue globale, vue de détail, vue d'un peu moins ensemble...)

    Problème de base
    Mon soucis vient de la grande quantité de points à afficher qui rend à la fois le chargement du chart très long et ensuite le zoom et autre sur le chart très lourd, inutilisable en pratique.
    J'ai jusqu'à une 12n de séries de plusieurs 100n de milliers de points à afficher.

    Pour le moment je travaille sur des CSV, dans l'avenir je pourrai optimiser un peu (j'espère) en passant par des fichiers binaires (donc moins gros)

    Quel code aujourd'hui ?
    J'arrive à afficher de 2 manières aujourd'hui
    solution avec lecture du CSV et ajout des points dans les séries au fil de l'eau
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
                System.IO.StreamReader file = new System.IO.StreamReader(@"C:\0-PROJ\201306-220-11-MiniCoreV1\SOFT\WindowsFormsApplication3\WindowsFormsApplication3\ddd.csv");
     
                while (!file.EndOfStream) //tant que je ne suis pas à la fin du fichier
                {
                    string ligne = file.ReadLine(); //je lis une ligne
                    string[] tabCSV = ligne.Split(';'); //on recupère un tableau de string avec chaque contenu entre ;
                    //remplissage de la série
     
                    double date = DateTime.ParseExact(tabCSV[0], "dd/MM/yyyy HH:mm:ss", null).ToOADate();
                    double LaValeur1 = Convert.ToDouble(tabCSV[1]);
                    double LaValeur2 = Convert.ToDouble(tabCSV[2]);
     
                    chart2.Series["Series1"].Points.AddXY(date, LaValeur1);
                    chart2.Series["Series2"].Points.AddXY(date, LaValeur2);                
                }
    Ce code me permet d'afficher en 14secondes les 2 series de 200 000 points de mon CSV de test

    Autre solution en passant par une base de donnée SQL CE. On m'a consillié de faire avec ca, j'en ai bavé et le résultat est pas terrible :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
                string cn = @"Data Source=C:\0-PROJ\201306-220-11-MiniCoreV1\SOFT\WindowsFormsApplication3\WindowsFormsApplication3\mesdata.sdf";
     
                SqlCeConnection connexion = new SqlCeConnection(cn);
     
                //vidage de la table
                string MaRequeteVidage = "DELETE FROM table1";
     
                SqlCeCommand cdeEffacement = new SqlCeCommand(MaRequeteVidage, connexion);
     
                cdeEffacement.Connection.Open();
                try
                {
                    cdeEffacement.ExecuteNonQuery();  //Execution de la requête 
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
                cdeEffacement.Connection.Close();
     
     
                //  connexion.Open();
                string MaRequeteInsert = "INSERT INTO table1 ";
                MaRequeteInsert += " (DATE, Valeur1, Valeur2)";
                MaRequeteInsert += "VALUES(@ma_DATE, @ma_VALEUR1, @ma_VALEUR2)";
     
                //SqlCeCommand commande = connexion.CreateCommand();
                SqlCeCommand commande = new SqlCeCommand(MaRequeteInsert, connexion);
                int counter = 0;
                string line;
     
                // Read the file and display it line by line.
                System.IO.StreamReader file = new System.IO.StreamReader(@"C:\0-PROJ\201306-220-11-MiniCoreV1\SOFT\WindowsFormsApplication3\WindowsFormsApplication3\ccc.csv");
                line = file.ReadLine();
     
                commande.Parameters.Add("@ma_DATE", SqlDbType .BigInt);
                commande.Parameters.Add("@ma_VALEUR1", SqlDbType.BigInt);
                commande.Parameters.Add("@ma_VALEUR2", SqlDbType.BigInt);
     
     
                commande.Connection.Open();
                while ((line = file.ReadLine()) != null)
                {
                    string[] data = line.Split(';');
     
                    commande.Parameters["@ma_DATE"].Value = data[0];
                    commande.Parameters["@ma_VALEUR1"].Value = data[1];
                    commande.Parameters["@ma_VALEUR2"].Value = data[2];
     
                    int a = 0;
                    a++;
     
                    try
                    {
                        commande.ExecuteNonQuery();  //Execution de la requête 
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                    counter++;
                }
     
                commande.Connection.Close();
                file.Close();
     
                // TODO: cette ligne de code charge les données dans la table 'mesdataDataSet.table1'. Vous pouvez la déplacer ou la supprimer selon vos besoins.
                this.table1TableAdapter.Fill(this.mesdataDataSet.table1);
                chart1.DataBind();
    Avec ce passage par une base de donnée le temps de chargement et d'affichage passe à 30s.

    2 questions
    1) Est il possible d'optimiser fortement mon code, avec ou sans BDD de manière à révolutionner les temps de chargement ?
    2) Sinon, comment puis je envisager l'affichage de mes données avec un zoom facile et fluide ?
    J'ai le sentiment qu'il est débile d'afficher autant de points sur un graph qui n'a pas autant de pixels à l’écran... mais en même temps, je ne vois pas comment afficher moins de points ('genre un point sur 1000) sans que ma vue perde tout son sens (que se passe t-il dans les 999 points que je n'aurais pas affiché!!???.

    Merci par avance pour vos critiques et vos idées

  2. #2
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Par défaut
    Il faudrait déjà savoir si c'est la lecture du fichier (I/O), son analyse (parsing) ou l'affichage qui prend du temps. A mon avis c'est la lecture du fichier, sauf si le composant utilisé pour le graphe est très mal foutu (création de 200k objets WPF par exemple).

    Citation Envoyé par petitours Voir le message
    J'ai le sentiment qu'il est débile d'afficher autant de points sur un graph qui n'a pas autant de pixels à l’écran... mais en même temps, je ne vois pas comment afficher moins de points ('genre un point sur 1000) sans que ma vue perde tout son sens (que se passe t-il dans les 999 points que je n'aurais pas affiché!!???.
    En utilisant un index spatial tel qu'un quadtree : on divise l'espace en quatre. Chaque carré contient un booléen indiquant s'il y a ou non des points, et chaque carré contient à son tour quatre sous-carrés, et ainsi de suite.

    Avec ça tu as une structure de données capable de te dire en o(log(numObjets)) si tu dois afficher un point aux coordonnées (x, y), et très efficace pour déterminer la liste des pixels à peindre dans une région donnée. C'est ce qui est par exemple utilisé dans les jeux pour savoir quels objets de la scène dessiner à l'écran (version 3D : l'octree) .

    La construction prend du temps cependant, ce n'est rentable que si l'on n'affiche qu'une partie de l'espace et à nouveau il faudrait déjà savoir quel est le problème. Enfin et surtout c'est totalement superflu pour 200k points : un parcours direct pour créer un bitmap à la force brute serait simple et rapide (un CPU peut mouliner environ un milliard de points par seconde).

  3. #3
    Membre extrêmement actif Avatar de petitours
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Février 2003
    Messages
    2 037
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 2 037
    Par défaut
    Bonjour et un grand merci de mettre les pieds dans le plat.

    Est ce le chargement du CSV ou l'affichage sur le chart qui pose soucis ?
    A priori, d’après mes essais c'est très largement à cause du chart, que ce soit via le dataBing() ou via les points.Add

    Au delà du problème de chargement, il y a de toute manière problème avec le chart une fois rempli, il est très lent à réagir une fois rempli, les zooms prennent une éternité. L'application finale doit être archi fluent sur ces opérations là

    Pour illustrer au mieux le problème, voici le projet :
    www.68hc08.net/WindowsFormsApplication3.zip
    il y a tout dedans, y compris les csv de test.

    savoir "si le composant utilisé pour le graphe est très mal foutu " ?
    J'avais essayé il y a deux ans avec le composant Zedgraph. Ca allait un chouillia plus vite qu'avec le chart de MS intégré à Visual studio mais c'était plus difficile à utiliser.
    Aujourd'hui j'utilise chart de MS. Est il mal foutu avec la création de nombreux objets WPF ????? Il est très complet donc surement pas très léger de nature, mais je suis incompétent pour juger de son éventuelle état mal fichu.

    Faut il que je me crée mon propre composant ?, un truc tout léger qui fabrique à la force brute un bitmap ? (là il faut voir mon visage blanchir face à l'ampleur de la tâche bien que très excité à l'idée )

    Merci

  4. #4
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Par défaut
    Bon ben le problème est donc que le contrôle n'a pas été prévu pour ça : MS a ciblé l'apparence et laissé de côté les scénarios avec un grand nombre de données. Pour un composant standard on ne peut pas leur en vouloir : ça répond aux besoins les plus communs.

    Du coup il faut avoir recours à la technique du bitmap, soit pour créer soi-même son graphe (ou en trichant avec un graphe sans points derrière lequel on mettra une image), soit pour éliminer les points redondants (en générant une vraie "bit map" : un booléen par pixel) voire carrément les points voisins en simpllifiant le graphe (un nuage de points je présume ?). Enfin il existe sans doute des composants optimisés pour de larges jeux de données.

  5. #5
    Membre extrêmement actif Avatar de petitours
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Février 2003
    Messages
    2 037
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 2 037
    Par défaut
    Citation Envoyé par DonQuiche Voir le message
    Bon ben le problème est donc que le contrôle n'a pas été prévu pour ça : MS a ciblé l'apparence et laissé de côté les scénarios avec un grand nombre de données. Pour un composant standard on ne peut pas leur en vouloir : ça répond aux besoins les plus communs.
    Je ne leur en veut pas, c'est un peu le sentiment que j'avais.
    Citation Envoyé par DonQuiche Voir le message
    Du coup il faut avoir recours à la technique du bitmap, soit pour créer soi-même son graphe (ou en trichant avec un graphe sans points derrière lequel on mettra une image), soit pour éliminer les points redondants (en générant une vraie "bit map" : un booléen par pixel) voire carrément les points voisins en simplifiant le graphe (un nuage de points je présume ?).
    Je n'ai pas tout compris sur ces 3 techniques envisageables.
    Simplifier le graph c'est la solution "compliquée" que j'avais en tête jusque là ; charger un chart MS avec beaucoup moins de points. Points sélectionnés, voir recalculés, en fonction du niveau de zoom. Mais ça fait de sacrés algos à monter ça ! Afficher pas tout,ok , mais quoi (le min ? le max ? une moyenne...) ???
    Ci joint une image d'un graph tel que j'ai besoin (des courbes, toutes sur le même axe X au format date, un ou plusieurs axes Y, un zoom ultra facile, un marquer qui indique le point de data, possibilité d'avoir une info bulle sur le point pour avoir la valeur, un curseur pour comparer plus facilement les courbes)
    Citation Envoyé par DonQuiche Voir le message
    Enfin il existe sans doute des composants optimisés pour de larges jeux de données.
    Des idées de où je peux trouver ca ? une idée de quoi ou dans quel domaine chercher ?

    Merci
    Images attachées Images attachées  

  6. #6
    Membre Expert Avatar de callo
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Février 2004
    Messages
    887
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Togo

    Informations professionnelles :
    Activité : Administrateur systèmes et réseaux
    Secteur : Service public

    Informations forums :
    Inscription : Février 2004
    Messages : 887
    Par défaut
    Citation Envoyé par petitours Voir le message
    Ci joint une image d'un graph tel que j'ai besoin (des courbes, toutes sur le même axe X au format date ...
    Merci
    Pour ça, tu peux utiliser les séries de MS Chart.

  7. #7
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Par défaut
    Citation Envoyé par petitours Voir le message
    Je n'ai pas tout compris sur ces 3 techniques envisageables.
    Simplifier le graph c'est la solution "compliquée" que j'avais en tête jusque là ; charger un chart MS avec beaucoup moins de points. Points sélectionnés, voir recalculés, en fonction du niveau de zoom. Mais ça fait de sacrés algos à monter ça ! Afficher pas tout,ok , mais quoi (le min ? le max ? une moyenne...) ???
    Mais non, c'est super simple : mesure la largeur du composant "graph" et crée un tableau de booléens de même taille. Puis tu scannes tes points, tu convertis l'abscisse en index du tableau et si l'élément est "faux", tu le passes à vrai et tu ajoutes un point au graph. Dix lignes de code et tu t'en tirerais déjà avec moins de mille points affichés par série. Et si c'est toujours trop élevé et bien il faudra ensuite lisser la courbe, ce qui n'est pas si compliqué une fois que tu as ce tableau (en remplaçant les booléens par les ordonnées correspondantes).

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Envoyer une grande quantité de données dans un xml via http
    Par qdaemon_fr dans le forum Format d'échange (XML, JSON...)
    Réponses: 2
    Dernier message: 03/03/2009, 09h51
  2. Manipulation d'une grande quantité de données
    Par sebastyen dans le forum Langage
    Réponses: 1
    Dernier message: 10/11/2008, 15h54
  3. Réponses: 11
    Dernier message: 23/09/2008, 15h39
  4. Une grande quantité de données sur Oracle 8i?
    Par bliml dans le forum Oracle
    Réponses: 13
    Dernier message: 01/03/2007, 11h45
  5. Réponses: 1
    Dernier message: 10/01/2007, 15h52

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo