When you think ASP, think...
Recent Articles
All Articles
ASP.NET Articles
ASPFAQs.com
Message Board
Related Web Technologies
User Tips!
Coding Tips
Search

Sections:
Book Reviews
Sample Chapters
Commonly Asked Message Board Questions
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Security
Stump the SQL Guru!
Web Hosts
XML
Information:
Advertise
Feedback
Author an Article
Jobs

ASP ASP.NET ASP FAQs Message Board Feedback ASP Jobs
 
Print this Page!
Published: Wednesday, July 29, 2009

Using Microsoft's Chart Controls In An ASP.NET Application: Plotting Chart Data

By Scott Mitchell


A Multipart Series on Microsoft's Chart Controls
A picture is worth a 1,000 words... This adage rings especially true when it comes to reporting. Charts summarize and illuminate patterns in data in a way that long tables of numbers simply cannot. The Microsoft Chart Controls are a free and encompassing set of charts for WinForms and ASP.NET applications. This article series explores how to use these Chart Controls in an ASP.NET application.

  • Getting Started - walks through getting started using the Chart Controls, from version requirements to downloading and installing the Chart Controls, to displaying a simple chart in an ASP.NET page.
  • Plotting Chart Data - examines the multitude of ways by which data can be plotted on a chart, from databinding to manually adding the points one at a time.
  • Rendering the Chart - the Chart Controls offer a variety of ways to render the chart data into an image. This article explores these options.
  • Sorting and Filtering Chart Data - this article shows how to programmatically sort and filter the chart's data prior to display.
  • Programmatically Generating Chart Images - learn how to programmatically create and alter the chart image file.
  • Creating Drill Down Reports - see how to build drill down reports using the Chart control.
  • Adding Statistical Formulas - learn how to add statistical formulas, such as mean, median, variance, and forecasts, to your charts.
  • Enhancing Charts With Ajax - improve the user experience for dynamic and interactive charts using Ajax.
  • Serializing Chart Data - see how to persist a chart's data and appearance to a persistent store.
  • Using the Chart Controls with ASP.NET MVC - learn how to display charts in an ASP.NET MVC application.
  • Exporting Charts - allow visitors to export charts as images and PDF files.
  • (Subscribe to this Article Series! )

    Introduction


    The Microsoft Chart Controls enable developers to specify chart data in a number of ways. Chart data may be specified statically via the Chart Web control's declarative markup. Chart data may also be specified programmatically using a variety of techniques. For starters, you can add the points to plot one at a time via the Points collection's AddXY method. The Chart Controls API offers methods for binding enumerable data to the chart in one line of code. For example, you can pass an enumerable data source (such as a SqlDataReader) into the Chart control's DataBindTable method. Alternatively, you can assign data to the Chart's controls DataSource property and then call its DataBind method.

    The first installment in this article series - Getting Started - showed some simple examples of plotting chart data. This article delves into more intricate examples, showing how to plot database data, data from an XML file, and data from other types of data sources. We'll also look at plotting data using a library created by K. Scott Allen for his MSDN Magazine article, Charting With ASP.NET And LINQ. Read on to learn more!

    - continued -

    Plotting Chart Data Point By Point


    The most straightforward way to get your data onto a chart is to specify the data point by point. Each series in a chart has a Points collection that specifies the data points to plot for that series. As we saw in the previous installment, the Points collection data may be specified statically via the <Points> section in the Chart Web control's declarative markup. The values for this collection can also be defined programmatically via the Points collection's AddXY method.

    The following example shows how to specify chart data point by point by displaying a chart that shows the total number of sales per day of week for a fictional online retailer. (The complete code for this example, as well as all of the other demos in this article series, are available for download at the end of this article.) The data is shown in a three-dimensional area chart using the Earth Tones palette. This information - the chart type, the instructions to render the chart as a 3D chart, and the palette choice - are all configured in the Chart control's declaratively syntax:

    <asp:Chart ID="chtSalesPerDOW" runat="server" Width="500" Height="350">
       <Series>
          <asp:Series ChartType="Area" Palette="EarthTones" ChartArea="MainChartArea"></asp:Series>
       </Series>
       
       <ChartAreas>
          <asp:ChartArea Name="MainChartArea" Area3DStyle-Enable3D="true">
          </asp:ChartArea>
       </ChartAreas>
    </asp:Chart>

    The chart data is specified programmatically. The following code is from the Page_Load event handler. It starts by defining a string array that holds the X values, namely the days of the week. For each day of the week a point is added to the chart with the day of the week as the X value and the total number of sales (generated randomly) as the Y value. (While the chart data for this example is randomly generated, it could have been pulled from a database query, Web Service call, or some other data source. The main point to take away here is that it is possible to specify the points in a series one at a time via the Points collection's AddXY method.)

    Dim rnd As New Random

    Dim DaysOfWeek() As String = {"Sun", "Mon", "Tues", "Wed", "Thur", "Fri", "Sat"}

    For Each DOW As String In DaysOfWeek
       Dim totalSalesForDOW As Decimal = rnd.NextDouble * 5000 + 1000
       chtSalesPerDOW.Series(0).Points.AddXY(DOW, totalSalesForDOW)
    Next

    The screen shot below shows this chart when viewed through a browser. Note that each data point's value is determined randomly, so the screen shot you see below will not mirror what you see when you download and run the demo application available at the end of this article. In fact, the chart will change each time you reload or revisit the page.

    This chart's data points were specified one at a time via the Points collection's AddXY method.

    Binding Data to the Points Collection


    As we just saw, points can be added to the Points collection one at a time. Alternatively, any enumeration of data may be bound to a series in a single line of code using the Points collection's DataBindXY method. For example, the above example's code could be rewritten to gather the total sales per day of week in an array and then use the DataBindXY method to bind the X values (DaysOfWeek) and the Y values (SalesPerDOW) to the chart's first series:

    Dim DaysOfWeek() As String = {"Sun", "Mon", "Tues", "Wed", "Thur", "Fri", "Sat"}

    'Generate random sales data
    Dim rnd As New Random
    Dim SalesPerDOW(DaysOfWeek.Length - 1) As Decimal
    For i As Integer = 0 To DaysOfWeek.Length - 1
       Dim totalSalesForDOW As Decimal = rnd.NextDouble * 5000 + 1000
       SalesPerDOW(i) = totalSalesForDOW
    Next

    'Plot the points via databinding
    chtSalesPerDOW.Series(0).Points.DataBindXY(DaysOfWeek, SalesPerDOW)

    The end result is the same as specifying the data points one by one. The DataBindXY method enumerates the elements in the passed in data sources (DaysOfWeek and SalesPerDOW, in this example) and creates a DataPoint object for each element. It sets the DataPoint object's X and Y values using the current enumerated element and then adds it to the Points collection. Long story short, the DataBindXY method is just an alternative way to get the data to plot into to the Points collection.

    The Points collection's DataBindXY method can also be used to bind database data. The following demo shows how to display the number of products in each category in the Northwind database using the DataBindXY method. The Chart control's declarative syntax follows. Note that it differs from the previous example's declarative syntax in that the series has been given a Name value (Categories) and is of type Bar instead of type Area. Also, it uses the Chocolate palette instead of Earth Tones.

    <asp:Chart ID="chtCategoriesProductCount" runat="server" Width="550" Height="350">
       <Series>
          <asp:Series Name="Categories" ChartType="Bar" Palette="Chocolate" ChartArea="MainChartArea"></asp:Series>
       </Series>
       
       <ChartAreas>
          <asp:ChartArea Name="MainChartArea" Area3DStyle-Enable3D="true">
          </asp:ChartArea>
       </ChartAreas>
    </asp:Chart>

    The chart data is retrieved by connecting to the Northwind database and issuing an ad-hoc SQL query to retrieve the number of products associated with each category. This data is loaded into a SqlDataReader object named myReader, which is then bound to the Chart control's Categories Series's Points collection via the DataBindXY method. In this case we have one object (myReader) that contains both the X and Y values to plot. Therefore, we pass myReader into the DataBindXY method twice - once for the X values and once for the Y values. (In the previous example we had one object that held the X values - DaysOfWeek - and one object that held the Y values - SalesPerDOW.) Because the X and Y values are in the same object we need to specify what field to use for the X values ("CategoryName") and what field to use for the Y value ("ProductCount"). This information is provided as additional inputs to the DataBindXY method.

    Using myConnection As New SqlConnection
       myConnection.ConnectionString = ConfigurationManager.ConnectionStrings("NorthwindConnectionString").ConnectionString

       Dim myCommand As New SqlCommand
       myCommand.Connection = myConnection
       myCommand.CommandText = "SELECT CategoryName, COUNT(*) as ProductCount FROM Products p INNER JOIN Categories c ON c.CategoryID = p.CategoryID GROUP BY CategoryName ORDER BY CategoryName"

       myConnection.Open()
       Dim myReader As SqlDataReader = myCommand.ExecuteReader()

       'Bind the data using the DataBindTable method
       chtCategoriesProductCount.Series("Categories").Points.DataBindXY(myReader, "CategoryName", myReader, "ProductCount")

       myReader.Close()
       myConnection.Close()
    End Using

    The screen shot below shows the resulting chart.

    This chart's data points were specified using the Points collection's DataBindXY method.

    Binding Tabular Data to the Chart Control


    In addition to binding data to a particular series, the Chart control enables developers to programmatically bind data directly to the chart itself. This can be done by calling the Chart control's DataBindTable method or by assigning the data to display to the Chart control's DataSource property and then calling its DataBind method. We already examined using the DataBindTable method and the DataSource property in the previous installment, Getting Started.

    Another option for binding tabular data to the chart is to use a declarative data source control, such as a SqlDataSource or ObjectDataSource. From the Visual Studio Designer, expand the Chart control's smart tag to reveal a Choose Data Source drop-down list. From that drop-down list choose the New Data Source option and create and configure a data source control. (For more information on using data source controls see my article series, Accessing and Updating Data in ASP.NET.) Assigning a data source control to the Chart in this manner both adds a new data source control to the page and assigns the Chart's DataSourceID property to the ID of the data source control.

    After adding the data source control, make sure to tell the Chart control what fields from the data source should be used for the X and Y values via the XValueMember and YValueMembers property of the Series. The following declarative markup shows the markup for a Chart control that renders a bar chart showing the number of products per category in the Northwind database; when viewed through a browser, the chart appears precisely as the screen shot above. However, instead of assigning the data programmatically, in this case its assigned declaratively through the SqlDataSource control on the page (dsProductsPerCategory).

    <asp:Chart ID="chtCategoriesProductCount" runat="server" Width="550px"
       Height="350px" DataSourceID="dsProductsPerCategory">
       <Series>
          <asp:Series Name="Categories" XValueMember="CategoryName" YValueMembers="ProductCount" ChartType="Bar" Palette="Chocolate" ChartArea="MainChartArea"></asp:Series>
       </Series>
       
       <ChartAreas>
          <asp:ChartArea Name="MainChartArea" Area3DStyle-Enable3D="true">
             <Area3DStyle Enable3D="True"></Area3DStyle>
          </asp:ChartArea>
       </ChartAreas>
    </asp:Chart>

    <asp:SqlDataSource ID="dsProductsPerCategory" runat="server"
       ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
       SelectCommand="SELECT CategoryName, COUNT(*) as ProductCount FROM Products p INNER JOIN Categories c ON c.CategoryID = p.CategoryID GROUP BY CategoryName ORDER BY CategoryName">
    </asp:SqlDataSource>

    Plotting XML Data


    If you need to plot data from an XML file, Excel file, comma separated value (CSV) file, or some data store other than a relational database, you have a couple of options. One option is to write code that retrieves the data of interest and then adds it to the chart point by point. The other option is to use ADO.NET to connect to the data store. Most alternative data stores - including XML documents, Excel spreadsheets and CSV files - can be accessed by ADO.NET and queried similar to how you'd query a relational database. If this is the case with the data store of interest, you can get the data into a DataReader or DataTable or DataSet and then bind that object to the Chart control or one of its Series using any one of the techniques we've discussed in this article. The Samples Environment for Microsoft Chart Controls includes demos that plot data from an XML file, from Excel, and from a CSV file using this latter approach.

    The download available at the end of this article includes a demo that displays XML data using the former method. The code uses the LINQ to XML API to access the XML elements of interest and then loops through them, adding the points to the series. The XML file that contains the data is named SalesSummary.xml and resides in the App_Data folder, although it would certainly be possible to specify a URL to the XML file instead. The XML file contains information about the number of sales per day of week and has the following structure:

    <sales>
       <dayOfWeek>
          <day>Sun</day>
          <totalSales>5433</totalSales>
       </dayOfWeek>

       <dayOfWeek>
          <day>Mon</day>
          <totalSales>6978</totalSales>
       </dayOfWeek>

       ...
    </sales>

    The Chart control's declarative markup defines a single series of type Column using the palette Earth Tones. The code in the Page_Load event handler, shown below, loads the XML document and then traverses through each dayOfWeek element. For each dayOfWeek element it grabs out the value from the element's day and totalSales elements and then plots those as the X and Y values, respectively.

    Dim sales As XElement = XElement.Load(Server.MapPath("~/App_Data/SalesSummary.xml"))

    For Each node As XElement In sales.Elements("dayOfWeek")
       Dim dayValue As String = node.Element("day").Value
       Dim totalSales As String = node.Element("totalSales").Value

       chtSalesPerDOW.Series(0).Points.AddXY(dayValue, totalSales)
    Next

    The following screen shot shows the chart when viewed through a browser.

    This chart's data points came from an XML file, SalesSummary.xml, and were added to the series point by point.

    Generating Chart Data Using Scott Allen's ChartBuilder Class


    All of the techniques for plotting chart data that we have looked at so far have required that we write code in the ASP.NET page's code-behind class or that we used declarative data binding techniques in the ASP.NET page's declarative portion. While such approaches are fine for prototyping and one-off projects, they are not the best choice when building real-world projects where readability and maintainability is important. Ideally, the logic for formatting and plotting the chart's data should be handled by a specific class for which this task is its sole responsibility.

    In his MSDN Magazine article, Charting With ASP.NET And LINQ, author K. Scott Allen presents a class named ChartBuilder that can be used as a base class for building such chart construction-specific classes and for moving the chart formatting and plotting-specific code out of your ASP.NET pages. I've included the Visual Basic version of this class in the download available at the end of this article, but I encourage you to download the complete ChartBuilder class code, which is available in both C# and Visual Basic and includes a number of demos.

    In a nutshell, you use the ChartBuilder class by creating your own class that extends ChartBuilder. The ChartBuilder class has a constructor where you pass in the Chart Web control and the number of series. There's a BuildChart method that, when called, adds a chart area to the Chart, a title, a legend (if there are more than one series), and then each of the series. At each step a "customize" method is called which you can override to customize the formatting of the chart area, title, legend, or series, as well as specify the data added to the series. Once you have your custom class created you use it from an ASP.NET page like so: first, add a Chart control to the declarative markup. You don't need to specify the chart areas, series, or other formatting information as this should be handled by your class. Next, in the ASP.NET page's code-behind class you create an instance of your class, set any properties needed, and then call the BuildChart method.

    The download at the end of this article includes a demo that uses the ChartBuilder class. Specifically, I've created a class named SalesByCategoryChartBuilder that extends ChartBuilder. The SalesByCategoryChartBuilder defines two public properties - CategoryName and OrderYear. It overrides the ChartBuilder class's CustomizeChartSeries method and in that override it customizes the formatting of the series, specifying that the series is a line graph with a border width of 5 and no palette. It then connects to the Northwind database and calls the SalesByCategory stored procedure, passing in its CategoryName and OrderYear property values as inputs to the stored procedure. This stored procedure then computes and returns the gross number of sales for each product in the specified category. This information is added to the series one point at a time via the AddXY method.

    Protected Overrides Sub CustomizeChartSeries(ByVal seriesList As IList(Of Series))
       Dim mySeries As Series = seriesList.Single()
       mySeries.ChartType = SeriesChartType.Line
       mySeries.BorderWidth = 5
       mySeries.Palette = ChartColorPalette.None

       Using myConnection As New SqlConnection
          myConnection.ConnectionString = ConfigurationManager.ConnectionStrings("NorthwindConnectionString").ConnectionString

          Dim myCommand As New SqlCommand
          myCommand.Connection = myConnection
          myCommand.CommandText = "SalesByCategory"
          myCommand.CommandType = CommandType.StoredProcedure
          myCommand.Parameters.AddWithValue("@CategoryName", CategoryName)
          myCommand.Parameters.AddWithValue("@OrdYear", OrderYear)

          myConnection.Open()
          Dim myReader As SqlDataReader = myCommand.ExecuteReader()

          While myReader.Read
             mySeries.Points.AddXY(myReader("ProductName").ToString(), Convert.ToDecimal(myReader("TotalPurchase")))
          End While

          myReader.Close()
          myConnection.Close()
       End Using
    End Sub

    The SalesByCategoryChartBuilder class also overrides the CustomizeChartTitle method and provides a custom title based on the values of the CategoryName and OrderYear properties, displaying a title like: "Sales For CategoryName In OrderYear."

    In addition to a Chart control, the ASP.NET page also includes drop-down lists that allow the user to pick a category and order year. After making these selections and clicking a Button, there is a postback and the Button's Click event handler executes. In the Click event handler an instance of the SalesByCategoryChartBuilder class is created, its CategoryName and OrderYear properties are assigned to the values selected by the user, and the BuildChart method is called.

    Dim builder = New SalesByCategoryChartBuilder(chtSalesByCategory)
    builder.CategoryName = ddlCategoryNames.SelectedValue
    builder.OrderYear = Convert.ToInt32(ddlOrderYears.SelectedValue)
    builder.BuildChart()

    The following screen shot shows the gross sales for products in the Seafood category for 1998.

    This chart's data points and formatting are handled by a custom class, SalesByCategoryChartBuilder.

    Happy Programming!

  • By Scott Mitchell


    Attachments:

  • Download the code for this article
  • Further Readings:

  • Charting With ASP.NET And LINQ
  • Code for Scott Allen's ChartBuilder Class (available in C# and VB)
  • Samples Environment for Microsoft Chart Controls
  • A Multipart Series on Microsoft's Chart Controls
    A picture is worth a 1,000 words... This adage rings especially true when it comes to reporting. Charts summarize and illuminate patterns in data in a way that long tables of numbers simply cannot. The Microsoft Chart Controls are a free and encompassing set of charts for WinForms and ASP.NET applications. This article series explores how to use these Chart Controls in an ASP.NET application.

  • Getting Started - walks through getting started using the Chart Controls, from version requirements to downloading and installing the Chart Controls, to displaying a simple chart in an ASP.NET page.
  • Plotting Chart Data - examines the multitude of ways by which data can be plotted on a chart, from databinding to manually adding the points one at a time.
  • Rendering the Chart - the Chart Controls offer a variety of ways to render the chart data into an image. This article explores these options.
  • Sorting and Filtering Chart Data - this article shows how to programmatically sort and filter the chart's data prior to display.
  • Programmatically Generating Chart Images - learn how to programmatically create and alter the chart image file.
  • Creating Drill Down Reports - see how to build drill down reports using the Chart control.
  • Adding Statistical Formulas - learn how to add statistical formulas, such as mean, median, variance, and forecasts, to your charts.
  • Enhancing Charts With Ajax - improve the user experience for dynamic and interactive charts using Ajax.
  • Serializing Chart Data - see how to persist a chart's data and appearance to a persistent store.
  • Using the Chart Controls with ASP.NET MVC - learn how to display charts in an ASP.NET MVC application.
  • Exporting Charts - allow visitors to export charts as images and PDF files.
  • (Subscribe to this Article Series! )



    ASP.NET [1.x] [2.0] | ASPMessageboard.com | ASPFAQs.com | Advertise | Feedback | Author an Article