Creating area chart coloring the part of overflowed values with other color
delphi, teechart
Solution
There is a tool called TSeriesBandTool which can do this with a little bit of work.
Add an extra series and make it identical as your series, but with a maximum of your limit.
This is how it looks in the Tools editor :
It will fill the difference between the two series with a color of your choice.
Update
Made a proof of concept, see image.
Added a third Series and a second TSeriesBandTool to fill the bottom part with a second color. I'm sure it's possible to do with less code, but this is good enough for a demonstration.
Update 2
Made some code refreshments.
Update 2.5
Now handles arbitrary X-values as well, not only integers.
Here is the code :
uses Series, TeeTools, TeeSeriesBandTool;
Procedure DrawLimitAreaChart(S1, S2, S3: TLineSeries; YLimit: Double;
BT1, BT2: TSeriesBandTool; OutlineWidth: Integer;
OutlineCL, TopCl, BottomCL: TColor);
Var
i: Integer;
iX: Double;
Begin
S1.LinePen.Width := OutlineWidth;
S1.Color := OutlineCL;
S2.Color := OutlineCL;
S3.Color := OutlineCL;
for i := 0 to S1.Count - 1 do
if (S1.YValue[i] > YLimit) then
begin
if (i > 0) and (S1.YValue[i - 1] < YLimit) then
begin // Last point below limit
iX := (S1.XValue[i] - S1.XValue[i - 1]) * (YLimit - S1.YValue[i - 1]) /
(S1.YValue[i] - S1.YValue[i - 1]) + S1.XValue[i - 1];
S2.AddXY(iX, YLimit);
if (i < S1.Count - 1) then
Continue;
end;
S2.AddXY(S1.XValue[i], YLimit); // Set to Ylimit
end
else // Below Ylimit
begin
if (i > 0) and (S1.YValue[i - 1] > YLimit) then
begin // Last point above limit
iX := (S1.XValue[i] - S1.XValue[i - 1]) * (YLimit - S1.YValue[i - 1]) /
(S1.YValue[i] - S1.YValue[i - 1]) + S1.XValue[i - 1];
S2.AddXY(iX, YLimit);
end;
S2.AddXY(S1.XValue[i], S1.YValue[i]); // Same value
end;
for i := 0 to S2.Count - 1 do
begin
S3.AddXY(S2.XValue[i], 0.0);
end;
{ - First TSeriesBandTool }
BT1.Series := S1;
BT1.Series2 := S2;
BT1.Brush.BackColor := TopCl;
BT1.DrawBehindSeries := True;
BT1.Transparency := 50;
{ - Second TSeriesBandTool }
BT2.Series := S2;
BT2.Series2 := S3;
BT2.Brush.BackColor := BottomCL;
BT2.DrawBehindSeries := True;
BT2.Transparency := 50;
End;
procedure TForm1.Button1Click(Sender: TObject);
const
// Example data
YVAL: array [0 .. 10] of Double = (10,40,45,20,48,5,47,47,47,47,30);
var
i: Integer;
YLimit: Double;
S1, S2, S3: TLineSeries;
begin
Chart1.SeriesList.Clear;
S1 := TLineSeries.Create(Self); // Contains real data
Chart1.AddSeries(S1);
S2 := TLineSeries.Create(Self); // Data below Ylimit
Chart1.AddSeries(S2);
S3 := TLineSeries.Create(Self); // baseline data
Chart1.AddSeries(S3);
for i := 0 to 10 do
S1.AddXY(i, YVAL[i]);
YLimit := S1.MaxYValue * 0.75;
DrawLimitAreaChart(S1, S2, S3, YLimit, ChartTool1, ChartTool2, 2, clBlack,
TColor($0024FF){clOrangeRed}, TColor($FF4D4D){clNeonBlue});
end;
So what the code does :
Fills in the X,Y data into series[0]. Calls `DrawLimitAreaChart` procedure where a new series is calculated from series[0] such that no part is above the Ylimit. Finally a third series is applied as a baseline to the second series. The three curves together with the two `TSeriesBandTools` now forms a two color region area chart.
Update 3
As per request here is a chart example with the X axis as time. The code for doing this is in my comment below.
Problem
Can you help me creating the area chart, where the part (top) of chart has other color? I would like to indicate that the values over any number value are critical. This is a screenshot: I've created two area charts but as you can see, each chart has own left axis. The best solution would be coloring chart above particular values.