TeeChart VCL for Borland/CodeGear/Embarcadero RAD Studio, Delphi and C++ Builder.
-
RJRJ
- Newbie
- Posts: 4
- Joined: Mon Sep 25, 2017 12:00 am
Post
by RJRJ » Thu Dec 14, 2017 3:24 pm
Hi, I want to create an option where with one checkbox it is possible to see last 20 minutes of the graph.
I started with
Code: Select all
// Graph settings
if CheckBoxGraphsLast20m.Checked then
with ChartRaw.BottomAxis do
begin
Automatic := False;
AutomaticMaximum := True;
AutomaticMinimum := False;
Minimum := Now-(5/86400); // 5 secs
end
else
ChartRaw.BottomAxis.Automatic := true;
But when the checkbox is checked,
Y axes do not scale to the visible data points but keep the range concerning the full data set
Which properties/methods should I look into the get the basic effect of only showing the last x minutes of data?
-
Yeray
- Site Admin
- Posts: 9614
- Joined: Tue Dec 05, 2006 12:00 am
- Location: Girona, Catalonia
-
Contact:
Post
by Yeray » Fri Dec 15, 2017 2:27 pm
Hello,
Here it is a simple example showing how to do what I understand you are trying to achieve:
Code: Select all
uses Series, Math;
const nLastPointsToShow=10;
const oneSecond=1.0/86400.0;
procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
tmp: Double;
const initValues=100;
begin
Chart1.View3D:=False;
Chart1.Legend.Visible:=False;
with Chart1.AddSeries(TFastLineSeries) do
begin
XValues.DateTime:=True;
tmp:=Now;
AddXY(tmp-(oneSecond*initValues), 100+random*10);
for i:=initValues-1 downto 0 do
AddXY(tmp-oneSecond*i, YValue[Count-1] + random*10-5);
end;
Chart1.Axes.Bottom.LabelStyle:=talPointValue;
Chart1.Axes.Bottom.LabelsAngle:=90;
Chart1.Axes.Bottom.DateTimeFormat:='hh:mm:ss';
Timer1.Interval:=1000;
Timer1.Enabled:=True;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
with Chart1[0] do
AddXY(Now, YValue[Count-1] + random*10-5);
CheckAxes;
end;
procedure TForm1.CheckAxes;
var i: Integer;
tmpMax, tmpMin: Double;
begin
if CBShowLast.Checked then
begin
Chart1.Axes.Bottom.AutomaticMinimum:=False;
with Chart1[0] do
begin
Chart1.Axes.Bottom.Minimum:=XValue[Count-nLastPointsToShow];
Chart1.Repaint;
tmpMin:=YValue[FirstDisplayedIndex];
tmpMax:=YValue[FirstDisplayedIndex];
for i:=Chart1[0].FirstDisplayedIndex+1 to Chart1[0].LastDisplayedIndex do
begin
tmpMin:=Min(tmpMin, YValue[i]);
tmpMax:=Max(tmpMax, YValue[i]);
end;
end;
Chart1.Axes.Left.SetMinMax(tmpMin, tmpMax);
end
else
begin
Chart1.Axes.Bottom.Automatic:=True;
Chart1.Axes.Left.Automatic:=True;
end;
end;
procedure TForm1.CBShowLastClick(Sender: TObject);
begin
CheckAxes;
end;
-
RJRJ
- Newbie
- Posts: 4
- Joined: Mon Sep 25, 2017 12:00 am
Post
by RJRJ » Mon Dec 18, 2017 11:12 am
Thanks for the help.
I have one shared standard bottom ax and three custom Y-axes on the right. I do not fully understand the code because I had no time to read the docs (got to run to airport now), but it seems to work.
Code: Select all
procedure TFormCoultCell2.CheckAxes(const aChart: TChart; const nLastPointsToShow: Cardinal);
var
I, Ax: Integer;
tmpMax, tmpMin: Double;
begin
// 0 and 1 give full scale
if (nLastPointsToShow > 1) and (aChart.Series[0].Count > nLastPointsToShow) then
begin
aChart.Axes.Bottom.AutomaticMinimum:=False;
with aChart[0] do // Refers to ?
begin
aChart.Axes.Bottom.Minimum:=XValue[max(0, Count-nLastPointsToShow)];
aChart.Repaint;
// Loop all custom axes (they're all Y-axes on right, sharing standard bottom axe)
for Ax := 0 to aChart.CustomAxes.Count-1 do
begin
tmpMin:=YValue[FirstDisplayedIndex];
tmpMax:=YValue[FirstDisplayedIndex];
for I:=aChart[Ax].FirstDisplayedIndex+1 to aChart[Ax].LastDisplayedIndex do
begin
tmpMin:=Min(tmpMin, YValue[i]);
tmpMax:=Max(tmpMax, YValue[i]);
end;
end;
aChart.Axes[Ax].SetMinMax(tmpMin, tmpMax);
end;
end
else
begin
aChart.Axes.Bottom.Automatic:=True;
for Ax := 0 to aChart.CustomAxes.Count-1 do
aChart.CustomAxes[Ax].Automatic := true;
end;
end;
-
Yeray
- Site Admin
- Posts: 9614
- Joined: Tue Dec 05, 2006 12:00 am
- Location: Girona, Catalonia
-
Contact:
Post
by Yeray » Mon Dec 18, 2017 2:53 pm
Hello,
Note aChart[0] gives the first series in the Chart. So in your case, where you seem to have one series assigned to each custom axis, you should calculate the tmpMin and tmpMax using aChart[Ax] YValue
. Ie:
Code: Select all
procedure TFormCoultCell2.CheckAxes(const aChart: TChart; const nLastPointsToShow: Cardinal);
var
I, Ax: Integer;
tmpMax, tmpMin: Double;
begin
// 0 and 1 give full scale
if (nLastPointsToShow > 1) and (aChart.Series[0].Count > nLastPointsToShow) then
begin
aChart.Axes.Bottom.AutomaticMinimum:=False;
with aChart[0] do // Assuming all the series have the same number of XValues
begin
aChart.Axes.Bottom.Minimum:=XValue[max(0, Count-nLastPointsToShow)];
aChart.Repaint;
end;
// Loop all custom axes (they're all Y-axes on right, sharing standard bottom axe)
for Ax := 0 to aChart.CustomAxes.Count-1 do
begin
tmpMin:=aChart[Ax].YValue[aChart[Ax].FirstDisplayedIndex];
tmpMax:=aChart[Ax].YValue[aChart[Ax].FirstDisplayedIndex];
for I:=aChart[Ax].FirstDisplayedIndex+1 to aChart[Ax].LastDisplayedIndex do
begin
tmpMin:=Min(tmpMin, aChart[Ax].YValue[i]);
tmpMax:=Max(tmpMax, aChart[Ax].YValue[i]);
end;
end;
aChart.Axes[Ax].SetMinMax(tmpMin, tmpMax);
end
else
begin
aChart.Axes.Bottom.Automatic:=True;
for Ax := 0 to aChart.CustomAxes.Count-1 do
aChart.CustomAxes[Ax].Automatic := true;
end;
end;
-
RJRJ
- Newbie
- Posts: 4
- Joined: Mon Sep 25, 2017 12:00 am
Post
by RJRJ » Wed Dec 27, 2017 10:16 am
OK this is what I ended up with.
I have one standard shared X axis, 3 custom Y axes, some of which may or may not have data.
Code: Select all
procedure TFormCoultCell2.CheckAxes(const aChart: TChart; const nLastPointsToShow: Cardinal);
var
I, S, Ax: Integer;
tmpMax, tmpMin: Double;
begin
// 0 and 1 give full scale
if (nLastPointsToShow > 1) and (aChart[0].Count-nLastPointsToShow > 0) then
begin
aChart.Axes.Bottom.AutomaticMinimum:=False;
with aChart[0] do // Refers to first normal series, all series have same X-data, if data lacks, will have Y=Null
begin
aChart.Axes.Bottom.Minimum:=XValue[max(0, Count-nLastPointsToShow)];
aChart.Repaint;
end;
// Loop each series
for S := 0 to aChart.SeriesCount-1 do
begin
tmpMin := high(integer);
tmpMax := low(integer);
// If the series have positive amount of points
if (aChart[S].YValues.Count > nLastPointsToShow) then
begin
// Loop the last n points and get min and max
for I := (aChart[S].YValues.Count-1) downto (aChart[S].YValues.Count -nLastPointsToShow) do
begin
tmpMin:=Min(tmpMin, aChart[S].YValue[I]);
tmpMax:=Max(tmpMax, aChart[S].YValue[I]);
end;
// Turn of automatic and apply min and max
aChart[S].CustomVertAxis.AutomaticMinimum := false;
aChart[S].CustomVertAxis.AutomaticMaximum := false;
aChart[S].CustomVertAxis.Maximum := tmpMax;
aChart[S].CustomVertAxis.Minimum := tmpMin;
end;
end;
end
// Set bottom and all customs to auto
else
begin
aChart.Axes.Bottom.Automatic:=True;
for Ax := 0 to aChart.CustomAxes.Count-1 do
aChart.CustomAxes[Ax].Automatic := true;
end;
end;
-
RJRJ
- Newbie
- Posts: 4
- Joined: Mon Sep 25, 2017 12:00 am
Post
by RJRJ » Fri Dec 29, 2017 3:46 pm
How is it that with
Code: Select all
// Turn of automatic and apply min and max
if tmpMax >= tmpMin then
begin
aChart[S].CustomVertAxis.AutomaticMinimum := false;
aChart[S].CustomVertAxis.AutomaticMaximum := false;
aChart[S].CustomVertAxis.Maximum := tmpMax;
aChart[S].CustomVertAxis.Minimum := tmpMin; // This one
end;
I get AxisException: 'Axis Maximum Value must be >= Minimum'.
Will remove the = from comparison. I added other things as well, but I still get the same exception.
Code: Select all
// Turn of automatic and apply min and max
if (tmpMax > tmpMin) and (assigned(aChart[S].YValues)) and (aChart[S].YValues.Count > 0) then
begin
aChart[S].CustomVertAxis.AutomaticMinimum := false;
aChart[S].CustomVertAxis.AutomaticMaximum := false;
aChart[S].CustomVertAxis.Maximum := tmpMax;
aChart[S].CustomVertAxis.Minimum := tmpMin;
end;
PS. There is a serie and axis without any data, plus 3 series and 2 axes with data.
-
Marc
- Site Admin
- Posts: 1272
- Joined: Thu Oct 16, 2003 4:00 am
- Location: Girona
-
Contact:
Post
by Marc » Tue Jan 02, 2018 12:20 pm
Hello,
Likely at the moment that the Maximum is being set it is less than the Minimum (the actual value of Minimum at the moment you're trying to set Maximum). You could check that and set Minimum first or use:
Code: Select all
if tmpMax >= tmpMin then
begin
aChart[S].CustomVertAxis.SetMinMax(tmpMin,tmpMax);
end;
Regards,
Marc Meumann
Steema Support
-
Sandra
- Site Admin
- Posts: 3132
- Joined: Fri Nov 07, 2008 12:00 am
Post
by Sandra » Tue Jan 02, 2018 12:52 pm
Hello RJRJ,
To complete the Marc's explanation, you find a simple example below:
Code: Select all
uses Series, Math;
const nLastPointsToShow=10;
const oneSecond=1.0/86400.0;
procedure TForm1.FormCreate(Sender: TObject);
var i,t: Integer;
tmp: Double;
const initValues=100;
begin
Chart1.View3D:=False;
Chart1.Legend.Visible:=False;
with Chart1.AddSeries(TFastLineSeries) do
begin
XValues.DateTime:=True;
tmp:=Now;
AddXY(tmp-(oneSecond*initValues), 100+random*10);
for i:=initValues-1 downto 0 do
AddXY(tmp-oneSecond*i, YValue[Count-1] + random*10-5);
end;
with Chart1.AddSeries(TFastLineSeries) do
begin
XValues.DateTime:=True;
tmp:=Now;
AddXY(tmp-(oneSecond*initValues), 100+random*10);
for i:=initValues-1 downto 0 do
AddXY(tmp-oneSecond*i, YValue[Count-1] + random*10-5);
end;
with Chart1.AddSeries(TFastLineSeries) do
begin
XValues.DateTime:=True;
tmp:=Now;
AddXY(tmp-(oneSecond*initValues), 100+random*10);
for i:=initValues-1 downto 0 do
AddXY(tmp-oneSecond*i, YValue[Count-1] + random*10-5);
end;
Chart1.Axes.Bottom.LabelStyle:=talPointValue;
Chart1.Axes.Bottom.LabelsAngle:=90;
Chart1.Axes.Bottom.DateTimeFormat:='hh:mm:ss';
Timer1.Interval:=1000;
Timer1.Enabled:=True;
Chart1.Draw();
Chart1.Axes.Left.StartPosition := 0;
Chart1.Axes.Left.EndPosition := 30;
Chart1[0].VertAxis := aLeftAxis;
Chart1[1].CustomVertAxis := Chart1.CustomAxes[0];
Chart1[2].CustomVertAxis := Chart1.CustomAxes[1];
Chart1.CustomAxes[0].StartPosition := 30;
Chart1.CustomAxes[0].EndPosition := 60;
Chart1.CustomAxes[0].Axis.Color := clRed;
Chart1.CustomAxes[1].StartPosition := 60;
Chart1.CustomAxes[1].EndPosition := 100;
Chart1.CustomAxes[1].Axis.Color := clBlue;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
with Chart1[0] do
AddXY(Now, YValue[Count-1] + random*10-5);
with Chart1[1] do
AddXY(Now, YValue[Count-1] + random*10-5);
with Chart1[2] do
AddXY(Now, YValue[Count-1] + random*10-5);
CheckAxes(Chart1,nLastPointsToShow);
end;
procedure TForm1.CheckAxes(const aChart: TChart; const nLastPointsToShow: Cardinal);
var
I, Ax: Integer;
tmpMax, tmpMin: Double;
begin
// 0 and 1 give full scale
if (nLastPointsToShow > 1) and (aChart.Series[0].Count > nLastPointsToShow) then
begin
aChart.Axes.Bottom.AutomaticMinimum:=False;
with aChart[0] do // Assuming all the series have the same number of XValues
begin
aChart.Axes.Bottom.Minimum:=XValue[max(0, Count-nLastPointsToShow)];
aChart.Repaint;
end;
// Loop all custom axes (they're all Y-axes on right, sharing standard bottom axe)
for Ax := 0 to aChart.CustomAxes.Count-1 do
begin
tmpMin:=aChart[Ax+1].YValue[aChart[Ax+1].FirstDisplayedIndex];
tmpMax:=aChart[Ax+1].YValue[aChart[Ax+1].FirstDisplayedIndex];
for I:=aChart[Ax+1].FirstDisplayedIndex+1 to aChart[Ax].LastDisplayedIndex do
begin
tmpMin:=Min(tmpMin, aChart[Ax+1].YValue[i]);
tmpMax:=Max(tmpMax, aChart[Ax+1].YValue[i]);
end;
end;
aChart.Axes[Ax].SetMinMax(tmpMin, tmpMax);
end
else
begin
aChart.Axes.Bottom.Automatic:=True;
for Ax := 0 to aChart.CustomAxes.Count-1 do
aChart.CustomAxes[Ax].Automatic := true;
end;
end;
procedure TForm1.CBShowLastClick(Sender: TObject);
begin
CheckAxes(Chart1,nLastPointsToShow);
end;
Thanks in advance
Regards