Use a gradient fill to individually color line segments
From ZedGraphWiki
Gradient Fills to Color Line Segments
Here's a technique you can use to apply different colors to individual segments of a LineItem. The technique involves using a GradientByValue fill applied to the LineItem.Line property of the LineItem. This is similar to the Multi-Colored Bar Demo, except that it applies to lines instead of bars.
A Simple Application
A simple application is shown below. This application will color all line segments red, unless they are within a certain data range (from Y=4.0 to 6.0), in which case they will be colored blue. Note that the coloration applies from any given point up to the following point. That is, even though the coloration applies to an individual point, the line segment is colored all the way until the next point in the PointPairList or IPointList. The code shown below produces the following graph:
This graph clearly demonstrates that the line segments are colored from any given point, up to the following point. In fact, you can see that the a point that crosses into the green zone will be colored red since it starts outside the green zone, and vice-versa. Following is the associated code:
private void CreateGraph_LineColorGradient( ZedGraphControl zgc )
{
GraphPane myPane = zgc.GraphPane;
PointPairList list = new PointPairList();
const int count = 30;
for ( int i = 0; i < count; i++ )
{
// Use an ordinary sine function to generate the curve
double x = i + 1;
double y = 5 * Math.Sin( (double) i * Math.PI * 3 / count ) + 5.0;
// Set the Z value to be 2.0 if y is between 4 and 6, otherwise, it's 1.0
list.Add( x, y, y > 4 && y < 6 ? 2.0 : 1.0 );
}
// Create a curve
LineItem myCurve = myPane.AddCurve( "Test Curve", list, Color.Red, SymbolType.Diamond );
// use a gradient fill to color the each line segment according to its Z value
// Color will be blue for Z = 2, and red for Z = 1
Fill fill = new Fill( Color.Red, Color.Blue );
fill.RangeMin = 1;
fill.RangeMax = 2;
fill.Type = FillType.GradientByZ;
myCurve.Line.GradientFill = fill;
// make the line fat
myCurve.Line.Width = 2.0f;
// Fill the symbols with white
myCurve.Symbol.Fill = new Fill( Color.White );
// Create a band of green to show the highlighted region
BoxObj box = new BoxObj( 0.0, 6.0, 1.0, 2.0, Color.Empty,
Color.FromArgb( 150, Color.LightGreen ) );
// Use CoordType.XChartFractionYScale, so that Y values are regular scale values, and
// X values are chart fraction, ranging from 0 to 1
box.Location.CoordinateFrame = CoordType.XChartFractionYScale;
box.Fill = new Fill( Color.White, Color.FromArgb( 200, Color.LightGreen ), 45.0F );
box.ZOrder = ZOrder.F_BehindGrid;
box.IsClippedToChartRect = true;
myPane.GraphObjList.Add( box );
// Pretty it up
myPane.Title.Text = "Line Segments Colored by Value";
myPane.Title.FontSpec.Size = 18;
myPane.XAxis.Title.Text = "Time, seconds";
myPane.YAxis.Title.Text = "Potential, volts";
myPane.Legend.IsVisible = false;
myPane.Fill = new Fill( Color.WhiteSmoke, Color.Lavender, 0F );
myPane.Chart.Fill = new Fill( Color.FromArgb( 255, 255, 245 ),
Color.FromArgb( 255, 255, 190 ), 90F );
zgc.IsAntiAlias = true;
zgc.AxisChange();
}
A Detailed Approach
In order to solve the problem of points sometimes crossing into or out of the green band, we need to improve the resolution of the graph. Although there are many possible approaches, one of the simplest is to just increase the number of points on the graph to improve the resolution. However, we don't want to increase the number of symbols on the chart. So, we can accomplish this by making two LineItems -- one LineItem to show only the symbols (and only the number of symbols in the original PointPairList), and a second LineItem to show the line with no symbols at a much higher resolution. The higher resolution curve will be able to better display when the curve is inside the green band, and when it is outside.
Note that, for this method to work, the second curve (the high-resolution one) must be displayed last so that the symbols from the first curve appear on top. In this case, the legend is not displayed, but you can just hide the legend for any curve by setting:
myCurve.Label.IsVisible = false;
Following is a modified graph that shows line segments that appear to change color right at the edge of the green zone.
This graph uses a technique called linear interpolation to "fill in" the extra points. See the topic Create a difference curve using interpolation for more information. The following is the modified version of the code:
private void CreateGraph_LineColorGradient2( ZedGraphControl zgc )
{
GraphPane myPane = zgc.GraphPane;
PointPairList list = new PointPairList();
const int count = 30;
for ( int i = 0; i < count; i++ )
{
// Use an ordinary sine function to generate the curve
double x = i + 1;
double y = 5 * Math.Sin( (double) i * Math.PI * 3 / count ) + 5.0;
// Set the Z value to be 2.0 if y is between 4 and 6, otherwise, it's 1.0
list.Add( x, y, y > 4 && y < 6 ? 2.0 : 1.0 );
}
// Create a curve with symbols only
LineItem myCurve = myPane.AddCurve( "Test Curve", list, Color.Red, SymbolType.Diamond );
myCurve.Line.IsVisible = false;
myCurve.Symbol.Fill = new Fill( Color.White );
// Create a second curve, with lots of extra points
const int count2 = 1000;
PointPairList list2 = new PointPairList();
// Points are equal-spaced, across all the X range
double dx = ( list[list.Count - 1].X - list[0].X ) / (double) count2;
// Calculate the extra points values using linear interpolation
for ( int i = 0; i <= count2; i++ )
{
double x2 = list[0].X + dx * (double) i;
double y2 = list.InterpolateX( x2 );
list2.Add( x2, y2, y2 > 4 && y2 < 6 ? 2.0 : 1.0 );
}
// Add the second curve with no symbols
LineItem myCurve2 = myPane.AddCurve( "Curve2", list2, Color.Blue, SymbolType.None );
// use a gradient fill to color the each line segment according to its Z value
// Color will be blue for Z = 2, and red for Z = 1
Fill fill = new Fill( Color.Red, Color.Blue );
fill.RangeMin = 1;
fill.RangeMax = 2;
fill.Type = FillType.GradientByZ;
myCurve2.Line.GradientFill = fill;
// make the line fat
myCurve2.Line.Width = 2.0f;
// Create a band of green to show the highlighted region
BoxObj box = new BoxObj( 0.0, 6.0, 1.0, 2.0, Color.Empty,
Color.FromArgb( 150, Color.LightGreen ) );
// Use CoordType.XChartFractionYScale, so that Y values are regular scale values, and
// X values are chart fraction, ranging from 0 to 1
box.Location.CoordinateFrame = CoordType.XChartFractionYScale;
box.Fill = new Fill( Color.White, Color.FromArgb( 200, Color.LightGreen ), 45.0F );
box.ZOrder = ZOrder.F_BehindGrid;
box.IsClippedToChartRect = true;
myPane.GraphObjList.Add( box );
// Pretty it up
myPane.Title.Text = "Line Segments Colored by Value\nExtra Points Are Interpolated";
myPane.Title.FontSpec.Size = 18;
myPane.XAxis.Title.Text = "Time, seconds";
myPane.YAxis.Title.Text = "Potential, volts";
myPane.Legend.IsVisible = false;
myPane.Fill = new Fill( Color.WhiteSmoke, Color.Lavender, 0F );
myPane.Chart.Fill = new Fill( Color.FromArgb( 255, 255, 245 ),
Color.FromArgb( 255, 255, 190 ), 90F );
zgc.IsAntiAlias = true;
zgc.AxisChange();
}




