Monday, March 5, 2012

Microsoft Chart Controls

Introduction


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. Web developers have long searched for ways to express numerical data in a graphical format; until recently, doing so required the use of an open source or third-party charting or reporting package or some homegrown technique using HTML, GDI+, or some other technology. In September 2008 Microsoft released a free charting suite named Microsoft Chart Controls for the .NET Framework 3.5 SP1. The Microsoft Chart Controls are an encompassing set of charts for WinForms and ASP.NET applications. Despite being a first release, the Chart Controls suite offers a wide array of chart types and charting features. The Chart Controls offer all of the standard chart types - line charts, bar charts, pie charts, and so forth - as well as more specialized ones, like pyramid and bubble charts. The Chart Controls suite offers a comprehensive set of charting features, including support for multiple series, customizable legends, trend lines, and labels. And the Chart Controls API makes it easy to sort, search, filter, group, and export the chart data. Unfortunately, this first version of the Chart Controls has limited support for customizing the chart from the Designer. There are no wizards to guide you through customizing the chart's look and feel and specifying its data source. Instead, you have to set the properties and bind the chart data yourself.
While the Microsoft Chart Controls have some rough edges, their cost (free), number of chart types, and array of supported charting features make them an excellent choice for adding charts to an ASP.NET web application. This article, the first in a series of articles on the Chart Controls, shows how to download, install, and get started using the Microsoft Chart Controls. Future installments will explore the Chart Controls in more detail and explore more advanced features. Read on to learn more!

Downloading and Installing the Microsoft Chart Controls


The Microsoft Chart Controls were released in September 2008 as a stand-alone product for the .NET Framework 3.5 Service Pack 1. Consequently, you can only use the Chart Controls if you are developing an ASP.NET website on the .NET Framework 3.5 SP1 or beyond. Moreover, in order to use the Chart Controls you must first download and install them, as they are not included as part of Visual Studio 2008 SP1. (NOTE: The Microsoft Chart Controls are part of the .NET Framework 4.0 and beyond. If you are using ASP.NET 4 (or beyond) you do not need to download any of these files, although you may want to download the Samples Environment for Microsoft Chart Controls.) The files to download follow:
  • Microsoft Chart Controls - the assemblies (DLLs) that provide the core functionality for the ASP.NET and WinForms Chart Controls. When you download and execute this program (MSChart.exe), the installer places the assemblies in the Program Files\Microsoft Chart Controls\Assemblies folder; it also adds them to the Global Assembly Cache (GAC), meaning that you can use the Chart Controls from any ASP.NET application on the server without having to add the DLL files to the application's /Bin folder. (If you are hosting your application in a shared hosting environment and the web server does not have the Chart Controls installed then you will need to upload these assemblies to the /Bin folder in your hosted environment.)
  • Microsoft Chart Controls Add-on for Microsoft Visual Studio 2008 - adds Toolbox and IntelliSense support for the Chart Controls in Visual Studio 2008.
  • Samples Environment for Microsoft Chart Controls - click the Download tab and then download the ASP.NET Samples. The samples are packaged into a website project and include demos and source code (in VB and C#) for the various chart types and charting features.
The Microsoft Chart Controls is the only requisite download, but the Add-On for VS 2008 and the samples environment are quite helpful for learning and using the Chart Controls.

Adding a Chart to an ASP.NET Page


After you have downloaded and installed the above programs, fire up Visual Studio and create a new ASP.NET website. Open (or create) an ASP.NET page and go to the Toolbox. Assuming you installed the Visual Studio Add-On you should see a Chart item in the Data section of the Toolbox, as the screen shot to the right shows. To add a chart to a web page simply drag the Chart control from the Toolbox onto the page. Doing so adds the Chart control's declarative markup to the page:
<asp:Chart ID="Chart1" runat="server">
   <series>
      <asp:Series Name="Series1">
      </asp:Series>
   </series>
   <chartareas>
      <asp:ChartArea Name="ChartArea1">
      </asp:ChartArea>
   </chartareas>
</asp:Chart>
Note that the Chart control is identified in the declarative markup via the tag prefix and name <asp:Chart>. This prefix (asp) is mapped to the Chart Controls assembly in Web.config:
<controls>
   ...
   
   <add tagPrefix="asp" namespace="System.Web.UI.DataVisualization.Charting"
      assembly="System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</controls>
Additionally, an HTTP Handler named ChartHttpHandler is mapped to requests to ChartImg.axd. As we'll see in a bit, when visited through a browser the Chart control renders an <img> element with a src attribute of ChartImg.axd. As a result, the browser makes a request to this file (ChartImg.axd) to display the chart image. This request is routed to the ChartHttpHandler HTTP Handler which generates the image contents and returns that binary data to the browser for display. This mapping between the ChartImg.axd path and the ChartHttpHandler HTTP Handler is implemented via the following Web.config markup:
<httpHandlers>
   ...

   <add path="ChartImg.axd" verb="GET,HEAD" type="System.Web.UI.DataVisualization.Charting.ChartHttpHandler, System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="false" />
</httpHandlers>
Both of the above configuration additions are automatically added to Web.config when you add a Chart control to a web page for the first time in your project.

The Main Components of a Chart


Before we look at displaying data in a chart, let's take a moment to dissect the most important pieces of a chart and explore some of the jargon. The Chart control renders a single "Chart Picture." The Chart Picture may be composed of multiple charts - say, a line chart and a bar chart. Each chart within the Chart Picture is referred to as a Chart Area. (Typically the Chart control will have only one Chart Area.) A chart contains one or more series, which are associated with a particular Chart Area. A series is a collection of data points. How the series is rendered depends on its type. A series configured to display as a line will render its data points as a continuous line. To have multiple lines in the chart you would define one series for each line. If the series is configured to display a bar or column then a bar or column is drawn for each data point. (This article focuses on single-series charts, but we'll explore multi-series charts in a future installment.)
The data points that make up a series usually have two components - an X value and a Y value - although some series types only require a single data point. For line and column series the X value indicates the position of the data point along the chart area's X axis and the Y value indicates the position of the line or the height of the column along the chart area's Y axis.

Specifying Chart Data


The chart area(s), series, and data points can be specified declaratively (either by entering the declarative markup by hand or via the Properties window) or programmatically in the code-behind class. Typically the series and chart area(s) are specified declaratively and the data points are populated programmatically by querying a database or some other dynamic data store. Let's start by discussing how to display a chart whose chart area, series, and data points are all specified declaratively. The download available at the end of this article includes a number of charting demos. The StaticChartData.aspx demo provides an example of specifying the chart data declaratively to display the number of NBA championships won by the seven most winning teams and does so using the following declarative markup:
<asp:Chart ID="chtNBAChampionships" runat="server">
   <Series>
      <asp:Series Name="Championships" YValueType="Int32" ChartType="Column" ChartArea="MainChartArea">
         <Points>
            <asp:DataPoint AxisLabel="Celtics" YValues="17" />
            <asp:DataPoint AxisLabel="Lakers" YValues="15" />
            <asp:DataPoint AxisLabel="Bulls" YValues="6" />
            <asp:DataPoint AxisLabel="Spurs" YValues="4" />
            <asp:DataPoint AxisLabel="76ers" YValues="3" />
            <asp:DataPoint AxisLabel="Pistons" YValues="3" />
            <asp:DataPoint AxisLabel="Warriors" YValues="3" />
         </Points>
      </asp:Series>
   </Series>
   <ChartAreas>
      <asp:ChartArea Name="MainChartArea">
      </asp:ChartArea>
   </ChartAreas>
</asp:Chart>
Note that the Chart control has a <Series> section and a <ChartAreas> section, which define the series and the chart areas, respectively. The <ChartAreas> section in the above markup defines a single ChartArea named MainChartArea. The <Series> section defines a single Series named Championships. This Championship series is configured to render as a column and is displayed in the MainChartArea. Next, its data points are defined via the <Points> collection. There are seven data points, each data point displaying the NBA team name via the AxisLabel property and the number of championships in the YValues property.
After defining this markup, visit this page through a browser. You should see a chart in your browser similar to the screen shot below:

This chart shows the number of NBA championships won by the seven most winning teams.
If you do a View/Source in your browser you'll find that the Chart control renders as an <img> element that instructs the browser to go get the image from a file named ChartImg.axd:
<img id="ctl00_ContentPlaceHolder1_chtNBAChampionships"
     src="/MSChart/ChartImg.axd?i=chart_13bd2162f4044728a3983173cc7054ac_0.png&g=bfad8f222bc94a239b4e43f9020eaff2"
     alt="" style="height:300px;width:300px;border-width:0px;" />
The ChartImg.axd file does not actually exist in the website; instead, it's rendered by the ChartHttpHandler HTTP Handler, which is part of the Chart Controls. This HTTP Handler returns the chart image data to the client. You can alternatively configure the Chart control to save the chart image to the file system and to have its rendered <img> element point directly to the that generated image rather than to ChartImg.axd. Moreover, you can configure the naming pattern used when saving the images to the file system as well as how many total image files to keep on disk before deleting them. There are also a bevy of configuration options when using the HTTP Handler. These topics will be covered in a future installment.

Programmatically Specifying the Chart Data


The previous demo (StaticChartData.aspx) showed how to declaratively specify the chart's data points. These data points are more commonly specified programmatically. The demo DynamicChartData.aspx displays the same chart as StaticChartData.aspx, but adds the data points programmatically in the Page_Load event handler. The Chart control's declarative markup in DynamicChartData.aspx does not include the hard-coded <Points> collection, but is otherwise the same in that the markup defines a single chart area named MainChartArea and a single column series named Championships:
<asp:Chart ID="chtNBAChampionships" runat="server">
   <Series>
      <asp:Series Name="Championships" ChartType="Column" ChartArea="MainChartArea">
      </asp:Series>
   </Series>
   <ChartAreas>
      <asp:ChartArea Name="MainChartArea">
      </asp:ChartArea>
   </ChartAreas>
</asp:Chart>
The code to add the data points to the Championships series is simple enough. The Chart control's Championships series is accessed via chtNBAChampionships.Series("Championships") and stored in a variable named ChampionshipsSeries. Series have a Points collection, which has an AddXY method from which you can specify the X and Y values for a new data point. The AddXY method is used seven times in the code below to add the seven most winning teams and the number of championships they've each won.
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
   If Not Page.IsPostBack Then
      Dim ChampionshipsSeries = chtNBAChampionships.Series("Championships")

      'Add data points
      ChampionshipsSeries.Points.AddXY("Celtics", 17)
      ChampionshipsSeries.Points.AddXY("Lakers", 15)
      ChampionshipsSeries.Points.AddXY("Bulls", 6)
      ChampionshipsSeries.Points.AddXY("Spurs", 4)
      ChampionshipsSeries.Points.AddXY("76ers", 3)
      ChampionshipsSeries.Points.AddXY("Pistons", 3)
      ChampionshipsSeries.Points.AddXY("Warriors", 3)


   End If
End Sub
While the data programmatically bound to the chart in the above code snippet is hard-coded, there's no reason why you could replace the above code with a query to a database and then loop through the results, calling the AddXY method once for every record returned from the database. (We'll look at binding database data to the Chart control in the next section.)
The chart, when viewed through a browser, is the same for both demos.

Binding Database Data to the Chart


In addition to adding specific points to a series via the AddXY method, the Chart Controls API includes methods for binding a set of data to the chart in just a line or two of code. If you have an enumerable collection of data with two properties that contain the X and Y values, you can use the Chart control's DataBindTable method, passing in the data to bind to the chart and the name of the property that is the X values. The following code snippet, taken from the DBChartData.aspx demo, connects to the Northwind database, runs a query that gets each category and the number of products it contains, and then binds this resultset to the Chart control via the DataBindTable 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()

   chtCategoriesProductCount.DataBindTable(myReader, "CategoryName")

   myReader.Close()
   myConnection.Close()
End Using
The SQL query used returns a record for each category, where each record includes two columns: CategoryName, the name of the category; and ProductCount, the number of products associated with the category. As you can see, in the call to the DataBindTable method I've specified that the "CategoryName" column returned from the database should be used as the X value (thereby indicating that ProductCount should be the Y value.)
The DataBindTable adds a new series to the Chart control so you do not need to specifically define a series in the declarative markup. The DBChartData.aspx demo's declarative markup follows. Note that I've specified a title for the chart via the <Titles> collection.
<asp:Chart ID="chtCategoriesProductCount" runat="server">
   <Titles>
      <asp:Title Text="Number of Products in Categories"></asp:Title>
   </Titles>
   
   <ChartAreas>
      <asp:ChartArea Name="MainChartArea">
      </asp:ChartArea>
   </ChartAreas>
</asp:Chart>
The resulting chart, when viewed through a browser, is shown below.

This chart shows the number of products in each category in the Northwind database.
Alternatively, you can bind data by using the Chart control's DataSource property. This involves retrieving the data from the database (or from wherever you get the data to display), assigning it to the DataSource property, and calling the Chart's DataBind method. Unlike with the DataBindTable method, when using the DataSource property you need to define a series and specify the name of the properties in the data that are to be displayed in the X and Y values in the series.
To use the DataSource property we'd need to explicitly define the series for the Chart. The following declarative markup accomplishes this; moreover, it defines that the series is a line chart as opposed to a column chart. The series also sets some formatting properties, indicating that the line is red and has a width of 5 pixels.
<asp:Chart ID="chtCategoriesProductCountBarChart" runat="server">
   <Titles>
      <asp:Title Text="Number of Products in Categories"></asp:Title>
   </Titles>
   
   <Series>
      <asp:Series Name="Categories" ChartType="Line" ChartArea="MainChartArea" BorderWidth="5" Color="Red"></asp:Series>
   </Series>

   
   <ChartAreas>
      <asp:ChartArea Name="MainChartArea">
      </asp:ChartArea>
   </ChartAreas>
</asp:Chart>
The code for binding the data to the chart follows. I've removed the code that connects to the database and issues the query:
chtCategoriesProductCountBarChart.Series("Categories").XValueMember = "CategoryName"
chtCategoriesProductCountBarChart.Series("Categories").YValueMembers = "ProductCount"

chtCategoriesProductCountBarChart.DataSource = myReader
chtCategoriesProductCountBarChart.DataBind()
The code starts by specifying the XValueMember and YValueMembers properties of the Categories series, which specifies the names of the database columns to use to grab the X and Y values when binding to the data. (These settings could have been specified declaratively.) Next, the Chart control's DataSource property is assigned to the SqlDataReader myReader and its DataBind method is called. The DataBind method enumerates the DataSource and adds a data point to the series for each record in the data.

This chart shows the number of products in each category in the Northwind database.

Looking Forward


This article highlighted only the simplest of charts and only scratched at the surface of what the Microsoft Chart Controls are capable of. Future installments in this article series will examine: customizing the appearance of the charts; using different chart types; sorting, grouping, filtering, and exporting chart data; and using AJAX to simulate real-time charts, among other topics.

No comments:

Post a Comment