Page 1 of 1
Scale axes to shown data
Posted: Thu Dec 14, 2017 3:24 pm
by 16581937
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?
Re: Scale axes to shown data
Posted: Fri Dec 15, 2017 2:27 pm
by yeray
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;
Re: Scale axes to shown data
Posted: Mon Dec 18, 2017 11:12 am
by 16581937
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;
Re: Scale axes to shown data
Posted: Mon Dec 18, 2017 2:53 pm
by yeray
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;
Re: Scale axes to shown data
Posted: Wed Dec 27, 2017 10:16 am
by 16581937
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;
Re: Scale axes to shown data
Posted: Fri Dec 29, 2017 3:46 pm
by 16581937
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.
Re: Scale axes to shown data
Posted: Tue Jan 02, 2018 12:20 pm
by Marc
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
Re: Scale axes to shown data
Posted: Tue Jan 02, 2018 12:52 pm
by 10050769
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