Click here to Skip to main content
15,867,453 members
Articles / Desktop Programming / WPF
Article

A WPF Graph Control Library

Rate me:
Please Sign up or sign in to vote.
4.44/5 (37 votes)
24 Apr 2008CPOL8 min read 294.9K   10.4K   96   22
An article presenting a WPF library for producing extensible runtime customisable graphs
Image 1

wpfgraph2.jpg

wpfgraph3.jpg

Introduction

The WPFGraph library allows production of scatter graphs (and in later versions other graph types) which can be customised by the user at runtime. The library allows dynamic loading of custom point and line renderers and automatically generates a customisation dialog to allow the end user a graphical user interface for configuration of dynamically loaded content.

Background

"A scatter graph or scatter diagram is a type of display that contains one or more scatter plots each of which use Cartesian coordinates to display values for two variables for a set of data. The data is displayed as a collection of points, each having the value of one variable determining the position on the horizontal axis and the value of the other variable determining the position on the vertical axis.

A scatter plot only specifies dependent or independent variables when a variable exists that is under the control of the experimenter. If a parameter exists that is systematically incremented and/or decremented by the experimenter, it is called the control parameter or independent variable and is customarily plotted along the horizontal axis. The measured or dependent variable is customarily plotted along the vertical axis. If no dependent variable exists, either type of variable can be plotted on either axis and a scatter plot will illustrate only the degree of correlation (not causation) between two variables.

A scatter plot can suggest various kinds of correlations between variables with a certain confidence level. Correlations may be positive (rising), negative (falling), or null (uncorrelated). If the pattern of dots slopes from lower left to upper right, it suggests a positive correlation between the variables being studied. If the pattern of dots slopes from upper left to lower right, it suggests a negative correlation. A line of best fit can be drawn in order to study the correlation between the variables. An equation for the correlation between the variables can be determined by established best-fit procedures. For a linear correlation, the best-fit procedure is known as linear regression and is guaranteed to generate a correct solution in a finite time. Unfortunately, no universal best-fit procedure is guaranteed to generate a correct solution for arbitrary relationships.

One of the most powerful aspects of a scatter plot, however, is its ability to show nonlinear relationships between variables. Furthermore, if the data is represented by a mixture model of simple relationships, these relationships will be visually evident as superimposed patterns.

For example, to display values for "lung capacity" (first variable) and how long that person could hold his breath (second variable), a researcher would choose a group of people to study, then measure each one's lung capacity (first variable) and how long that person could hold his breath (second variable). The researcher would then plot the data in a scatter plot, assigning "lung capacity" to the horizontal axis, and "time holding breath" to the vertical axis. A person with a lung capacity of 400 cc who held his breath for 21.7 seconds would be represented by a single dot on the scatter plot at the point (400, 21.7) in the Cartesian coordinates. The scatter plot of all the people in the study would enable the researcher to obtain a visual comparison of the two variables in the data set, and help to determine what kind of relationship there might be between the two variables."

From Wikipedia -> Scatterplot.

Using the Code

The WPFScatterGraph UserControl forms the core functionality and visual hook. The WPFScatterGraph may be added as per any WPF control, remembering to include the relevant namespace as below;

XML
<xmlns:graph="clr-namespace:DNBSoft.WPF.WPFGraph;assembly=WPFGraph">

<graph:WPFScatterGraph />

A WPFScatterGraph is comprised of WPFGraphSeries (representing a line of data, accessed via the .Series property of WPFScatterGraph), which is formed of WPFGraphDataPoints (an X and Y co-ordinate, accessed via the .Points property of WPFGraphSeries).

For example a graph showing a line of the formula y = 2 * x may be constructed via the following...

C#
WPFGraphSeries series = new WPFGraphSeries();

for (int i = 0; i < 16; i++) {
    WPFGraphDataPoint f = new WPFGraphDataPoint();
    f.X = i * 2;
    f.Y = i;

    series.Points.Add(f);
}

graphDisplay.Series.Add(series);

... where graphDisplay is a created WPFScatterGraph. When adding large numbers of points to a series, it is strongly recommended to add the points prior to adding the series to the graph to improve performance.

Graph Options

All graph options are available via the following properties of WPFScatterGraph:

  • AxisBrush - Sets/Gets the brush used to render the axis (both horizontal and vertical)
  • AxisThickness - Sets/Gets the thickness of the line used for the axis (both horizontal and vertical)
  • AxisVerticalWidth - Sets/Gets the distance between the vertical y axis and the left of the control
  • AxisHorizontalHeight - Sets/Gets the distance between the horizontal x axis and the bottom of the control
  • AxisFontSize - Sets/Gets the size of the font used to render the titles on the x and y axis
  • AxisTitleTickBrush - Sets/Gets the brush used to render axis ticks (both horizontal and vertical)
  • AxisTitleTickThickness - Sets/Gets the thickness of axis ticks (both horizontal and vertical)
  • MinXRange - Sets/Gets the minimum value shown on the x axis (see also MinYRange); values outside this range are not rendered
  • MaxXRange - Sets/Gets the maximum value shown on the x axis (see also MaxYRange); values outside this range are not rendered
  • IntervalXRange - Sets/Gets the tick interval for the x axis (see also IntervalYRange); does not affect rendering
  • XAxisTitle - Sets/Gets the title on the X axis (see also YAxisTitle)

Formatting

Both entire series and individual data points may be custom rendered via the .PointRenderer and .LineRenderer methods of both WPFGraphSeries and WPFGraphDataPoint; the properties take IWPFGraphPointRenderer and IWPFGraphLineRenderer objects respectively, however WPFGraphDataPoints may also be set to null indicating the rendering system should use the series renderer and not a point specific renderer. Typically the WPFGraphDataPoint renderers are only used to illustrate individual points and not to set the styling on an entire series (although it is possible to do this). The "Format A Data Series..." dialog (shown in Figure 3 above) currently only supports setting of the line and point renderers for the entire series and not individual data points. The dialog is accessible by right clicking anywhere on the graph space itself (not including axis or axis label space. The "Format A Data Series..." dialog should be relatively intuitive and therefore isn't discussed in detail herein, however will include a help button in later versions.

Custom Renderers

The WPFGraph library supports the use of custom renderers for both line renderers and point renderers, but rather than require recompiling of the library to include new renderers supports custom renderers via dynamic loading and reflection. To implement a custom renderer the steps are:

  1. Create a new DLL project
  2. Create objects implementing IWPFGraphPointRenderer and / or IWPFGraphLineRenderer
  3. Compile to DLL
  4. Place DLL in the same directory as the application (future versions any sub-directory)

Implementing the interfaces are relatively straightforward, however they are discussed below for completeness. Furthermore since many point renderers and line renderers will have a common base two helper classes are provided, WPFGraphLineRenderers.LineBase and WPFGraphLineRenderers.PointBase (hereafter LineBase and PointBase). While neither of these classes implement the interfaces of custom renderers, inheriting from these classes provides a basic custom render's required methods.

  • C#
    void render(WPFRenderParameters parameters, WPFGraphDataPoint p);

    Render the point at parameters.transpose(WPFGraphEnumerations.Axis axis, p.X), parameters.transpose(WPFGraphEnumerations.Axis axis, p.Y). The WPFRenderParameters.transpose method automatically converts from unscaled to scaled co-ordinates.

  • C#
    event WPFGraphDelegates.RendererChangedEventDelegate RendererChanged;

    Fired whenever any custom renderer parameter has changed. RendererChangedEventArgs contains the property altered, the old value, and the new value.

  • C#
    List<WPFGraphConfigurationParameter> getConfigurationParameters();

    Returns a list of WPFGraphConfigurationParameter objects, indicating which properties may be modified and the types they accept (currently only double and SolidColorBrush are supported, however other types will be added in the next release). When using LineBase or PointBase base.getConfigurationParameters() should be called and any custom properties added to the list before returning.

  • C#
    void setValue(String parameter, object value);

    Sets the property of name parameter to the value given. When using LineBase or PointBase base.setValue() should be called after testing to see if the property of name parameter is part of the custom renderer. It is preferable to set bounds on values but not throw an exception should the bounds be exceeded; e.g. for line thickness rather than throw an exception when a value of -1 is set, rather clip the value to the bounds of 0 to double.MaxValue.

  • C#
    void getValue(String parameter, object value);

    Gets the value of the property of the name given. When using LineBase or PointBase base.getValue() should be called after testing to see if the property of name parameter is part of the custom renderer.

Points of Interest

This is another example of something which should be standard in .NET but sadly isn't.

The color picker is not my code but rather a sample color picker as produced by Microsoft (all rights reserved), however it should be noted that it isn't very good and will be replaced eventually when I have time! The color picker currently only supports SolidColorBrushes and so manually setting a non-solid brush in code will cause the picker to crash.

Future Work

  • Other graph types
  • More default point and line renderers

Known Bugs

  • Some graph options do not automatically update graph, this can be fixed via calling IWPFGraph.Refresh().

History

  • Version 1.0.0.0 - First build, supports scatter graphs (scatter plots)

Additional Licensing Notes

Please feel free to use this in your work, however please be aware that a modified Code Project Open License (CPOL) is in use; basically it is the same as the standard license except that this code must not be used for commercial or not-for-profit commercial use without prior authorisation. Please see license.txt or license.pdf in the included source and demo files.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Rail Research UK
United Kingdom United Kingdom
I originally studied for a masters in engineering of software engineering at The University of Birmingham during 2000-2004, of which I received a 2:1. I continued at Birmingham University working with Civil Engineering and Rail Research UK where I am currently in my final year of a 3 year PhD project developing a Computational Intelligent Approach to Railway Intervention Planning. Although my work has a significant focus on railway engineering and associated practices much of my work is with data mining (on SQL Server 2008) and computational intelligence (CI) techniques. My key areas of expertise in CI are clustering algorithms (including Rival Penalised Competitive Learning) and evolutionary algorithms.

Outside of my formal work I enjoy testing the latest technologies such as .NET 3.5 and the many frameworks of which it comprises (mainly WPF). I have several projects on the go including a .NET and DirectX port of Quake 3 and many utility libraries. I also maintain an extensive website coded in Cold Fusion which is regularly updated; more information is available about me there.

Comments and Discussions

 
Questionwhat's the mean? Pin
zhaojianming19-Jun-17 17:09
zhaojianming19-Jun-17 17:09 
Praisepraise Pin
Member 121583769-Dec-15 23:31
Member 121583769-Dec-15 23:31 
GeneralMy vote of 5 Pin
maryam.saboor23-Nov-14 19:16
professionalmaryam.saboor23-Nov-14 19:16 
Bugsomething missing Pin
batsword6-Sep-11 22:21
batsword6-Sep-11 22:21 
Laugh | :laugh:
and not looks so good,another toolkit chart also do it well,but most i can't stand:
错误 21 未能找到类型或命名空间名称“ListenableList”(是否缺少 using 指令或程序集引用?) E:\c#_wpf\wpfgraph_src\WPFGraph\WPFScatterGraph.xaml.cs 463 81 WPFGraph

GeneralMy vote of 1 Pin
ujwaliyer31-Jul-11 22:37
ujwaliyer31-Jul-11 22:37 
QuestionVote - 1 Pin
ujwaliyer31-Jul-11 22:36
ujwaliyer31-Jul-11 22:36 
GeneralMy vote of 1 Pin
daok91111-Aug-09 8:26
daok91111-Aug-09 8:26 
GeneralMy vote of 2 [modified] ~ Updated Voted 4... Pin
ProtoBytes11-Jul-09 5:43
ProtoBytes11-Jul-09 5:43 
GeneralGenerics project Pin
ProphetLOD10-Jun-09 9:22
ProphetLOD10-Jun-09 9:22 
GeneralRe: Generics project (missing projects) Pin
ProtoBytes11-Jul-09 4:49
ProtoBytes11-Jul-09 4:49 
GeneralSource code absent Pin
Sergey L. Gladkiy17-Dec-08 18:41
professionalSergey L. Gladkiy17-Dec-08 18:41 
GeneralMinor bug Pin
Dragan Sahpaski15-Sep-08 0:26
Dragan Sahpaski15-Sep-08 0:26 
GeneralNo Source Code for Demo & Throws NotImplementedException Pin
MHohlios29-Apr-08 11:08
MHohlios29-Apr-08 11:08 
GeneralRe: No Source Code for Demo & Throws NotImplementedException Pin
Derek Bartram30-Apr-08 5:36
Derek Bartram30-Apr-08 5:36 
GeneralSave to bitmap Pin
trenskow23-Apr-08 22:38
trenskow23-Apr-08 22:38 
GeneralRe: Save to bitmap Pin
Derek Bartram24-Apr-08 0:28
Derek Bartram24-Apr-08 0:28 
QuestionDid you vote less than 5? Pin
Derek Bartram22-Mar-08 1:31
Derek Bartram22-Mar-08 1:31 
AnswerRe: Did you vote less than 5? Pin
Jan Seda22-Mar-08 12:59
professionalJan Seda22-Mar-08 12:59 
GeneralRe: Did you vote less than 5? Pin
Derek Bartram23-Mar-08 1:42
Derek Bartram23-Mar-08 1:42 
AnswerRe: Did you vote less than 5? Pin
Keith Rule22-Apr-08 9:59
professionalKeith Rule22-Apr-08 9:59 
GeneralRe: Did you vote less than 5? Pin
Derek Bartram25-Apr-08 10:47
Derek Bartram25-Apr-08 10:47 
AnswerRe: Did you vote less than 5? (vote 4) [modified] Pin
ProtoBytes11-Jul-09 5:54
ProtoBytes11-Jul-09 5:54 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.