Data Binding Microsoft Chart Control
Overview
When you add a new visualization in your application, the very first thing you do, is bind it to the data. Microsoft Chart control allows many different ways of populating data in the chart and it is important to understand the differences between them and being able to choose the best approach. I put together all the possible data binding options and the scenarios when they should be used.
Data Sources
Before jumping into the binding methods I want to quickly list all the supportable data sources which can be used in chart binding methods. Keep in mind that not all methods accept all source types.
- SqlCommand
- OleDbCommand
- SqlDataAdapter
- OleDbDataAdapter
- DataView
- DataSet
- DataReader
- List
- Array
- IList
- IListSource
- IEnumerable
Data Point X and Y values
When you bind chart you create series and series data points. Each data point in the series should have it's Y value set and in addition to the Y value you can also bind or set other data point properties:
- X Value - Defines location of the data point along X axis. If not specified, data point index in the series will be used.
- Additional Y Values - Chart types like Bubble or Stock require multiple Y values. You can also bind additional Y values in the regular chart types, if you want to use those values for labels or tooltips.
- Category - When you displaying categories on the X axis, they are stored in the AxisLabel property of the data point. All data binding methods will automatically detect the type of the data and you should not worry about it.
- Other Properties - Some of the binding methods allow you to set additional properties like data point labels, tooltips and others.
Binding Options Overview
This table lists data binding techniques, starting from the most basic methods proceeding to more advanced.
Chart.DataBindTable |
|
|
Chart.DataSource and Chart.DataBind |
|
|
Points.DataBind(X)Y |
|
|
Points.DataBind |
|
|
Chart.DataBindCrossTab |
|
|
Binding Options Details
Chart.DataBindTable method
The Chart.DataBindTable method is the simplest way to bind chart to a table with several columns. New series will be automatically created for each of the columns and you can optionally use one column for the X value for all series.
Example
Imagine you have a data source containing these columns: Prod A, Prod B, Prod C, Prod D, Prod E, Other and SalesName, you can easily create chart below with a single line of code:
Chart1.DataBindTable(myReader, "SalesName");
Chart.DataSource property
Chart DataSource property is the only way to bind chart at design-time. In addition to specifying the DataSource property you also need to create series and set their YValueMembers and optionally XValueMember properties. Multiple Y values can be bound if you specify comma separated list of members in the YValueMembers property.
Chart will automatically bind itself to specified data source and members just before rendering. You can force chart to bind at any moment by calling Chart.DataBind() method.
// Set chart data source chart1.DataSource = myCommand; // Set series members names for the X and Y values chart1.Series["Series 1"].XValueMember = "Name"; chart1.Series["Series 1"].YValueMembers = "Sales"; // Data bind to the selected data source chart1.DataBind();
DataBindCrossTab
The Chart.DataBindCrossTab is different compared to all other binding methods, in that it allows for the grouping of unique values in a column. Each unique value in the specified grouped column results in the creation of a data series. In addition, extended data point properties other than X and Y values can be bound.
These other properties are bound using the otherFields parameter using this syntax:
PointProperty=Field[{Format}] [,PointProperty= Field[{Format}]].
A list of these properties are as follows: AxisLabel, Tooltip, Label, LegendText, LegendTooltip and CustomPropertyName (the name of a custom property). For more information on possible formats see the Formatting Types topic in the MSDN library.
Example
In the sample below we have a table that has the sales and commissions of sales people for three years. We group by the "Name" column, thereby creating one data series per sales person. The X values are bound to the "Year" column, the Y values are bound to the "Sales" column, the Label property of the resulting data points (one per record) is bound to the "Commissions" column, and the LegendText property is bound to the "Name" column.
// Group by "Name" column, bind X values to "Year", Y values to "Sales", // and Label property to "Commissions. chart1.DataBindCrossTab(myReader, "Name", "Year", "Sales", "Label=Commissions");
Points.DataBind
This method allows for data point properties other than X and Y values to be bound to data columns. For example, you want to set data point label to a value in one of the data source columns. These other properties are bound using the otherFields parameter using this syntax:
PointProperty=FieldName[{Format}][,PointProperty= FieldName[{Format}]]
A list of these properties includes: AxisLabel, Tooltip, Label, LegendText, LegendTooltip and CustomPropertyName (the name of a custom property).
This method does not allow you to specify separate data sources for the X and Y values of a series (for this functionality use the DataBind(X)Y methods described in the section above).
Example
Code below demonstrates how to bind X and Y values of the series to columns "Name" and "Sales" respectively. The Label and Tooltip properties of the resulting data points are also bound to the "Commissions" and "Year" column.
Chart1.Series["Series1"].Points.DataBind( myReader, "Name", "Sales", "Tooltip=Year, Label=Commissions{C2}");
Points.DataBind[X]Y
The DataBindXY method allows for the binding of X and Y values of a series, while DataBindY binds Y values only. When binding X and Y values using DataBindXY the same or different data sources may be used.
Some data sources support multiple values (e.g. data sources that have columns of data). For example, OleDbDataReader may have access to more than one column of data. If the column to be used is not specified, then the first available column will be used. To use a column other than the first one just specify the column name in the method call.
Note that when specifying the column names to be bound to the Y values a comma can be embedded as part of a column name by specifying a double comma.
Example
Code below demonstrates how to bind series points to the array of doubles.
// Initialize an array of doubles. double [] array = { 2.8, 4.4, 6.5, 8.3, 3.6, 5.6, 7.3, 9.2, 1.0}; // Bind the double array to the Y axis points of the data series. Chart1.Series["Series1"].Points.DataBindY(array);
'Manual' series population
In case you need to perform some custom actions while binding and none of the above methods works, you can always 'manually' bind chart by iterating through the data source and add data points to the series as needed. This approach is also very useful when series data is calculated using some formula.
Example
// Resolve the address to the Access database string fileNameString = this.MapPath("."); fileNameString += "..\\..\\..\\data\\chartdata.mdb"; // Initialize a connection string string myConnectionString = "PROVIDER=Microsoft.Jet.OLEDB.4.0;Data Source=" + fileNameString; // Define the database query string mySelectQuery="SELECT * FROM SALESCOUNTS;"; // Create a database connection object using the connection string OleDbConnection myConnection = new OleDbConnection(myConnectionString); // Create a database command on the connection using query OleDbCommand myCommand = new OleDbCommand(mySelectQuery, myConnection); // Open the connection myCommand.Connection.Open(); // Initializes a new instance of the OleDbDataAdapter class OleDbDataAdapter myDataAdapter = new OleDbDataAdapter(); myDataAdapter.SelectCommand = myCommand; // Initializes a new instance of the DataSet class DataSet myDataSet = new DataSet(); // Adds rows in the DataSet myDataAdapter.Fill(myDataSet, "Query"); foreach(DataRow row in myDataSet.Tables["Query"].Rows) { // For each Row add a new series string seriesName = row["SalesRep"].ToString(); Chart1.Series.Add(seriesName); Chart1.Series[seriesName].ChartType = SeriesChartType.Line; Chart1.Series[seriesName].BorderWidth = 2; for(int colIndex = 1; colIndex < myDataSet.Tables["Query"].Columns.Count; colIndex++) { // For each column (column 1 and onward) add the value as a point string columnName = myDataSet.Tables["Query"].Columns[colIndex].ColumnName; int YVal = (int) row[columnName]; Chart1.Series[seriesName].Points.AddXY(columnName, YVal); } } DataGrid.DataSource = myDataSet; DataGrid.DataBind(); // Closes the connection to the data source. This is the preferred // method of closing any open connection. myCommand.Connection.Close();
Other useful things to know
Here are couple things that you should know about when binding chart:
- Empty Points - Understand what empty points are and how you can use them. Right now the best source of the information is Chart Sample Environment but I will blog about it later.
- AlignDataPointsByAxisLabel - If you are using a stacked chart type with categorical X axis this helper method can be very useful. Find more information in the documentation and Chart Sample Environment.
Comments
- Anonymous
April 13, 2009
Hi,I'm trying to bind to nearly identical data source in your DataBindTable example but a "Specified method is not supported" exception is thrown. I'm using an oracle data reader and the query returns 1 text column (my "x") and 4 numeric columns.Any ideas why I'm getting this error? Thanks. - Anonymous
April 15, 2009
This maybe caused by the Reset() method we call internally in DataBindTable. Please make sure that data source you are using supports resetting.Alex. - Anonymous
June 18, 2009
The comment has been removed - Anonymous
June 18, 2009
The comment has been removed - Anonymous
August 19, 2009
The comment has been removed - Anonymous
October 12, 2009
Binding and re-painting the chart can be a time consuming operation and chart does not automatically update itself on every data source change. You will need to re-bind the chart as nessesary when the data source is changed.Alex. - Anonymous
December 31, 2009
Hi Alex,Thanks for the excellent tutorials on MS Chart Control.I am having problems with retrieving the index of a specific datapoint in a dataSeries on the chart. This supposed to be trivial because it is essential for many tasks.For example I can find the first datapoint visible in a ScaleView and would need to find out its index. However, such property does not exist for the datapoint... Or am I missing something?Thanks for help,Regards,Zoltan - Anonymous
June 03, 2010
The comment has been removed - Anonymous
June 09, 2010
AlexI refer to this page frequently and noticed the layout/formatting of the page has recently changed. Some of the text, for example in the Binding Options Overview, is cut off on the right side. - Anonymous
June 29, 2010
The comment has been removed - Anonymous
October 13, 2010
H,I am not able to view the points on grah area. Is there anything to set to view the plotted points. - Anonymous
March 13, 2011
is there a way to refresh the chart after an update was executed on the data? example from 100 rows to 10 rows?hope u can help me on this one ? - Anonymous
March 13, 2011
is there a way to refresh the chart after an update was executed on the data? example from 100 rows to 10 rows?hope u can help me on this one ? - Anonymous
March 27, 2011
arsonist...the way to refresh the chart..keep the existing points which drown in the serious in a collection like a datatable then add the new points to this datatable then draw the all points. - Anonymous
April 05, 2011
Hi,I'm facing issue with Series of Pie chart. Pie chart is not slicing based on data. its loading the data properly in label but not showing slice ie.. my pie chart would be having 2 slice (Exceptions & Non-review) based on there figures value raiot will change.Here is Data fromLegend FiguresExceptions 144351Non-review 747440670<asp:Chart ID="PieChartWIPException" runat="server" PaletteCustomColors="IndianRed; CornflowerBlue" Palette="None" BackColor="WhiteSmoke" Height="280px" Width="450px" BorderlineDashStyle="Solid" BackSecondaryColor="White" BackGradientStyle="TopBottom" BorderWidth="2" ImageLocation="~/Images/ChartPic_#SEQ(300,3)" ImageStorageMode="UseImageLocation" ImageType="Jpeg"> <Legends> <asp:Legend BackColor="Transparent" Alignment="Center" Docking="Bottom" Font="Trebuchet MS, 8.25pt, style=Bold" IsTextAutoFit="True" Name="Default" LegendStyle="Row"> </asp:Legend> </Legends> <BorderSkin SkinStyle="Emboss"></BorderSkin> <Series> <asp:Series IsValueShownAsLabel="true" Name="PieSeriesWIPException" ChartType="Pie"> </asp:Series> </Series> <ChartAreas> <asp:ChartArea Name="PieCharAreaWIPException" BorderColor="64, 64, 64, 64" BackSecondaryColor="Transparent" BackColor="Transparent" ShadowColor="Transparent" BorderWidth="0"> <Area3DStyle Inclination="68" Enable3D="true" LightStyle="Realistic" /> </asp:ChartArea> </ChartAreas> </asp:Chart>Code behidePieChartWIPException.Series["PieSeriesWIPException"].Points.DataBind(WipSummaries.WIPSummaryLegends.AsEnumerable(), "Legend", "Figures", "LabelFormat=Figures{C}"); - Anonymous
April 06, 2011
Hi Alex,I am using VB.NET to draw a chart. My data source is a Grid. and I use two fields to StartTime and DescriptionDescription consists of five or six unique strings : H-N Sag,Outage,N-GSurge,1 N-G Impulse, Sync ...I want to draw a bar chart based on the number of each desc in Time (X axis) .I am using this code but there is no result, only the legends are showed.C.DataBindCrossTable(DataGridView1.DataSource, "Description", "StartTime", "Description", String.Empty)My question is :1-How dynamic series can be shown from a two column data set.2-In Y-fields , when I type comma separeted fields (values) it gets an error that there is no such flelds ( it is true)Thank you - Anonymous
September 19, 2011
The comment has been removed - Anonymous
September 30, 2011
The comment has been removed - Anonymous
September 30, 2011
Hi Alex,I have a chart with multiple series using DataBindCrossTable method, exactly like yours in this tutorials. How do I set the origin of the chart to be very first X value of the series? I've tried using axisX.Minimum but no luck.Tnx - Anonymous
November 29, 2011
Outstanding, I just wish I would have found it yesterday. Would have saved me a lot of trouble. - Anonymous
December 29, 2011
The comment has been removed - Anonymous
February 05, 2012
The comment has been removed - Anonymous
February 07, 2012
Got it;TryChart1.ChartAreas(0).AxisX.IsMarginVisible = FalseRegards,Archana. - Anonymous
February 23, 2012
I'd appreciate your help so very much.I'm sorry but I have error in this code.Can you help me?private void Page_Load(object sender, System.EventArgs e) { OdbcConnection myConnectionString = new OdbcConnection(ConfigurationManager.ConnectionStrings["ConnMySQL"].ConnectionString); myConnectionString.Open(); Chart1.ChartAreas["ChartArea1"].Area3DStyle.Inclination = 30; Chart1.ChartAreas["ChartArea1"].Area3DStyle.Enable3D = false; this.Chart1.SaveImage(GraficoPNG, ChartImageFormat.Png); Chart1.Series["Default"].ChartType = SeriesChartType.Column; Chart1.Series["Default"]["PointWidth"] = "0.3"; Chart1.Series["Default"].IsValueShownAsLabel = true; Chart1.Series["Default"]["BarLabelStyle"] = "Center"; Chart1.Series["Default"]["PixelPointDepth"] = "20"; Chart1.Series["Default"]["DrawingStyle"] = "Cylinder"; Chart1.Series["Default2"].ChartType = SeriesChartType.Column; Chart1.Series["Default2"]["PointWidth"] = "0.3"; Chart1.Series["Default2"].IsValueShownAsLabel = true; Chart1.Series["Default2"]["BarLabelStyle"] = "Center"; Chart1.Series["Default2"]["PixelPointDepth"] = "20"; Chart1.Series["Default2"]["DrawingStyle"] = "Cylinder"; Chart1.Series["Default2"].Points.DataBind(myConnectionString, "x_value", "y_value", "Tooltip=x_value, Label=y_value{C2}"); myConnectionString.Close(); myConnectionString.Dispose(); } <asp:Chart ID="Chart1" runat="server" DataSourceID="SqlDataSource1" Width="400px"> <Series> <asp:Series Name="Default" XValueMember="zDesc" YValueMembers="t0"> </asp:Series> </Series> <Series> <asp:Series Name="Default2" XValueMember="x_value" YValueMembers="y_value"> </asp:Series> </Series> <ChartAreas> <asp:ChartArea Name="ChartArea1"> </asp:ChartArea> </ChartAreas> </asp:Chart> <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:ConnMySQL %>" ProviderName="<%$ ConnectionStrings:ConnMySQL.ProviderName %>" SelectCommand="SELECT * from first_table; "> </asp:SqlDataSource> <asp:SqlDataSource ID="SqlDataSource2" runat="server" ConnectionString="<%$ ConnectionStrings:ConnMySQL %>" ProviderName="<%$ ConnectionStrings:ConnMySQL.ProviderName %>" SelectCommand="SELECT * from second_table ;"></asp:SqlDataSource>Server Error in '/' Application.Compilation ErrorDescription: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.Compiler Error Message: CS1502: The best overloaded method match for 'System.Web.UI.DataVisualization.Charting.DataPointCollection.DataBind(System.Collections.IEnumerable, string, string, string)' has some invalid arguments - Anonymous
July 18, 2012
Can i use microsoft charts to show organisational structure....can someone elaborate - Anonymous
January 22, 2013
I am new to MS Chart Control. I am binding datatable with the chart control. but when the number of rows more then 4000, the chart takes to long to render. I have a datatable with 20,000 rows and chart falis to render. Is there any thing i am doing wrong ControlChart.DataSource = table ControlChart.Series("Series1").XValueMember = "Coulmn1" ControlChart.Series(("Series1").YValueMembers ="Coulmn2" ControlChart.DataBind() - Anonymous
March 05, 2013
How can i assign datasource to graph .. i want make a graph with grouping details - Anonymous
August 11, 2013
Here is my dataSalesPerson Jan-2008 Feb-2008 Mar-2008 Apr-2008 Mat-2008Joe 1 100 200 99 10 250Mary M 50 250 90 50 200Now I want want year and month in x-axis and corresponding value in y-axis. grouping by sales person. - Anonymous
March 21, 2014
Joe 1 100 200 99 10 250Mary M 50 250 90 50 200 - Anonymous
April 22, 2014
Badly written - difficult to understand.eg: For the Chart.DataSource example, do you still need to call DataBindTable() or not? - Anonymous
July 07, 2014
Hola, como puedo dejar el plot area como rojo, amarillo, verde - Anonymous
November 11, 2014
Sir can u please make a code for Manual Series Population in vb201.net because i am getting error on the Datarow part.. thank you - Anonymous
May 21, 2015
Hi there, What should i do to change the font family and font size of those three labels "Andrew", "David" and "Bryan" ? Thanks