sabato 28 gennaio 2012

[C#] Dati Controllo Chart

Descrizione :
Esempio pratico di associazione dati e loro rappresentazione con il controllo Chart.

+ Articolo :

Anzitutto, dal momento che di "controlli chart" in giro ce ne sono davvero tanti, voglio precisare che l'argomento in esame riguarda esclusivamente il controllo incluso in Visual Studio ( in questo caso : 2010 ), e per l'esattezza quello in Forms :
System.Windows.Forms.DataVisualization.Charting.Chart().

Ho creato questo articolo per un duplice scopo :
1. Mostrare una tecnica valida per collegare un Chart con le sue varie Serie, ad una unica fonte dati, come un DataTable.
2. Illustrare 4 diversi modi per evidenziare ciascun dato, una volta che è rappresentato graficamente nel Chart.

Oltre a questo, si noterà come diversi controlli, come le ComboBox per la scelta di ciascun Punto-Dati, vengano automaticamente messe in relazione all'atto della loro associazione con una fonte dati comune.

Per replicare l'articolo occorre una semplice Form "FormMain", con i seguenti controlli essenziali :
--> Chart : chart1
--> ComboBox : cmb_x
--> ComboBox : cmb_serie2
--> ComboBox : cmb_serie3
Le Label sono a scopo descrittivo.

Un'immagine rende bene l'idea della struttura desiderata e del funzionamento ottenuto :


--> Codice completo FormMain :
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;

namespace DatiControlloChart
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private Font fontLab = new Font(FontFamily.GenericSansSerif, 14, FontStyle.Regular);
        private DataTable DT = new DataTable("TabellaDati");
        private string percorsoBmp = Application.StartupPath + "\\";
        private string nomeBmp = "arrow.bmp";

        private int RandomInteger(int min, int max, int seed)
        {
            return (new Random(seed)).Next(min, max);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //Formattazione DataTable Tabella Dati per contenere due serie
            //Asse X comune alle Serie Dati
            DT.Columns.Add("X", typeof(System.Int32));
            DT.PrimaryKey = new DataColumn[] {DT.Columns["X"]};
            //Asse Y Serie1
            DT.Columns.Add("YSerie1", typeof(System.Single));
            //Asse Y Serie2
            DT.Columns.Add("YSerie2", typeof(System.Int32));
            //Asse Y Serie3
            DT.Columns.Add("YSerie3", typeof(System.Int32));
            //Asse Y Serie4
            DT.Columns.Add("YSerie4", typeof(System.Int32));

            //Creazione Dati ( Pseudo-Random )
            for (int i = 1; i <= 20; i++)
            {
                DT.Rows.Add( new object[] { i, RandomInteger(10, 25, Convert.ToInt32((Math.Pow(i, 2)))) * 1.2, 
                                               RandomInteger(25, 50, Convert.ToInt32((Math.Pow(i, 3)))), 
                                               RandomInteger(50, 75, Convert.ToInt32((Math.Pow(i, 4)))), 
                                               RandomInteger(75, 100, Convert.ToInt32((Math.Pow(i, 5))))});
            }

            //Creazione Serie
            chart1.Series.Clear();
            chart1.DataSource = DT;
            //Serie1
            Series serie1 = new Series("Serie1");
            serie1.ChartType = SeriesChartType.Column;
            serie1.Color = Color.Goldenrod;
            serie1.BorderWidth = 1;
            serie1.BorderColor = Color.Black;
            serie1.XValueMember = DT.Columns["X"].ToString();
            serie1.YValueMembers = DT.Columns["YSerie1"].ToString();
            chart1.Series.Add(serie1);
            serie1.ToolTip = serie1.Name + " [ #VALX{F0} | #VALY{F2} ]";
            //Serie2
            Series serie2 = new Series("Serie2");
            serie2.ChartType = SeriesChartType.Line;
            serie2.Color = Color.Red;
            serie2.BorderWidth = 2;
            serie2.MarkerSize = 12;
            serie2.MarkerBorderColor = Color.Black;
            serie2.MarkerBorderWidth = 2;
            serie2.MarkerStyle = MarkerStyle.Diamond;
            serie2.XValueMember = DT.Columns["X"].ToString();
            serie2.YValueMembers = DT.Columns["YSerie2"].ToString();
            chart1.Series.Add(serie2);
            //Serie3
            Series serie3 = new Series("Serie3");
            serie3.ChartType = SeriesChartType.Line;
            serie3.Color = Color.SlateBlue;
            serie3.BorderWidth = 2;
            serie3.MarkerSize = 10;
            serie3.MarkerBorderColor = Color.Blue;
            serie3.MarkerBorderWidth = 2;
            serie3.MarkerStyle = MarkerStyle.Circle;
            serie3.XValueMember = DT.Columns["X"].ToString();
            serie3.YValueMembers = DT.Columns["YSerie3"].ToString();
            chart1.Series.Add(serie3);
            //Serie4
            Series serie4 = new Series("Serie4");
            serie4.ChartType = SeriesChartType.Line;
            serie4.Color = Color.Green;
            serie4.BorderWidth = 2;
            serie4.MarkerSize = 8;
            serie4.MarkerBorderColor = Color.DarkGreen;
            serie4.MarkerBorderWidth = 2;
            serie4.MarkerStyle = MarkerStyle.Square;
            serie4.XValueMember = DT.Columns["X"].ToString();
            serie4.YValueMembers = DT.Columns["YSerie4"].ToString();
            chart1.Series.Add(serie4);

            cmb_x.DropDownStyle = ComboBoxStyle.DropDownList;
            cmb_x.DataSource = DT;
            cmb_x.ValueMember = DT.Columns["X"].ToString();
            cmb_x.DisplayMember = DT.Columns["X"].ToString();

            cmb_serie2.DropDownStyle = ComboBoxStyle.DropDownList;
            cmb_serie2.DataSource = DT;
            cmb_serie2.ValueMember = DT.Columns["X"].ToString();
            cmb_serie2.DisplayMember = DT.Columns["YSerie2"].ToString();

            cmb_serie3.DropDownStyle = ComboBoxStyle.DropDownList;
            cmb_serie3.DataSource = DT;
            cmb_serie3.ValueMember = DT.Columns["X"].ToString();
            cmb_serie3.DisplayMember = DT.Columns["YSerie3"].ToString();

        }

        private void cmb_serie2_SelectedIndexChanged(object sender, EventArgs e)
        {
            var s2 = chart1.Series["Serie2"];
            if (s2.Points.Count == 0)
            {
                return;
            }
            for (int i = 0; i < s2.Points.Count; i++)
            {
                s2.Points[i].Label = string.Empty;
                s2.Points[i].MarkerStyle = MarkerStyle.Diamond;
            }

            var pts2 = chart1.Series["Serie2"].Points[cmb_serie2.SelectedIndex];
            pts2.Font = fontLab;
            pts2.Label = "Serie2 - " + "X = " + cmb_serie2.SelectedValue + " | Y = " + cmb_serie2.Text;
            pts2.LabelBackColor = Color.Gold;
            pts2.LabelBorderColor = Color.Black;
            pts2.LabelBorderWidth = 1;
            pts2.LabelForeColor = Color.Black;
            pts2.MarkerStyle = MarkerStyle.Star10;
        }

        private void cmb_serie3_SelectedIndexChanged(object sender, EventArgs e)
        {
            var s3 = chart1.Series["Serie3"];
            if (s3.Points.Count == 0)
            {
                return;
            }
            for (int i = 0; i < s3.Points.Count; i++)
            {
                s3.Points[i].MarkerImage = string.Empty;
            }

            var pts3 = chart1.Series["Serie3"].Points[cmb_serie3.SelectedIndex];
            pts3.MarkerImage = percorsoBmp + nomeBmp;
            pts3.MarkerImageTransparentColor = Color.White;
        }

        private void chart1_MouseMove(object sender, MouseEventArgs e)
        {
            HitTestResult HTR = chart1.HitTest(e.X, e.Y);
            //Controllo sul fatto che sia un DataPoint valido
            if (!(HTR.ChartElementType == ChartElementType.DataPoint))
            {
                return;
            }
            //Controllo sul fatto che sia la Serie desiderata ( Serie4 )
            if (!(HTR.Series.Name == "Serie4"))
            {
                return;
            }

            var s4 = chart1.Series["Serie4"];
            for (int i = 0; i < s4.Points.Count; i++)
            {
                s4.Points[i].Label = string.Empty;
                s4.Points[i].MarkerStyle = MarkerStyle.Square;
            }
            var pts4 = chart1.Series["Serie4"].Points[HTR.PointIndex];
            pts4.Font = fontLab;
            pts4.Label = "Serie4 - " + "X = " + pts4.XValue + " | Y = " + pts4.YValues[0];
            pts4.LabelBackColor = Color.YellowGreen;
            pts4.LabelBorderColor = Color.Black;
            pts4.LabelBorderWidth = 1;
            pts4.LabelForeColor = Color.Black;
            pts4.MarkerStyle = MarkerStyle.Star10;
        }
    }
}

NOTE :

--> Il Chart, le Serie e anche le ComboBox puntano al medesimo DataTable, chiaramente ciascuno al suo o suoi campi di pertinenza.

--> Serie1 : evidenzia il dato al passaggio del Mouse come semplice ToolTip.

--> Serie2 : evidenzia il dato ( scelto in cmb_serie2 ) con una Label. A mio avviso la scelta più completa e flessibile.

--> Serie3 : evidenzia il dato ( scelto in cmb_serie3 ) con una bitmap caricata da disco. In questo caso sarà necessario predisporre un'immagine che abbia al suo centro il Marker, e uno o più indicatori esterni. La figura seguente mostra come ho creato la mia "arrow.bmp" in 3 semplici passi, aiutandomi semplicemente con le Forme di Word 2007 :


--> Serie4 : evidenzia il dato al passaggio del Mouse con una Label. Comportamento molto simile al ToolTip della Serie1, ma molto più flessibile nella gestione.

--> Come già accennato, una selezione su ciascuna delle 3 ComboBox si propaga alle altre in automatico e senza che sia necessario estendere gli Handles nelle routine di evento, o scrivere alcun codice aggiuntivo, perchè ciò accade solo grazie alle associazioni fatte in precedenza con i Campi del DataTable.

+ Fine Articolo.

Un Click su "Mi Piace" è il modo migliore per ringraziare l'autore di questo articolo.



0 commenti:

Posta un commento

 
Design by Free WordPress Themes Modificato da MarcoGG