TeeChart Firemonkey LineSeries NULL Points - firemonkey

I am creating a Firemonkey (FMX) application. I use TChart with a Line Series (TLineSeries). I need to draw a chart line that is not continuous. The x-axis is date time and I want the line to be drawn say between 10 and 11AM and then again between 3PM and 4PM. I tried the following but it always draws a continuous line from the first point (X1) to the last point (X4):
Series.TreatNulls:=TTreatNullsStyle.tnDontPaint;
Series.AddXY(X1,1);
Series.AddXY(X2,1);
Series.AddNullXY(X2,1);
Series.AddNullXY(X3,1);
Series.AddXY(X3,1);
Series.AddXY(X4,1);
Where
X1=date value at 10AM
X2=date value at 11AM
X3=date value at 3PM
X4=date value at 4PM
I tried various combinations of TreatNulls but still no success. I am using TeeChart Version 2021.32
Any suggestions would be appreciated.

I've given it a try and it seems to work fine for me here with the code below.
Note a single null point is enough to avoid drawing two sectors (A-null-B)
uses Series, Constants;
procedure TForm1.FormCreate(Sender: TObject);
var X1, X2, X3, X4: TDateTime;
begin
Caption:=TeeMsg_Version;
X1:=Date+DateTimeStep[dtOneHour]*10;
X2:=Date+DateTimeStep[dtOneHour]*11;
X3:=Date+DateTimeStep[dtOneHour]*15;
X4:=Date+DateTimeStep[dtOneHour]*16;
with Chart1.AddSeries(TLineSeries) do
begin
XValues.DateTime:=True;
AddXY(X1,1);
AddXY(X2,1);
//AddNullXY(X2,1);
AddNullXY(X3,1);
AddXY(X3,1);
AddXY(X4,1);
end;
Chart1.Legend.Hide;
//Chart1.View3D:=False;
Chart1.Axes.Left.SetMinMax(0,2);
Chart1.Axes.Left.Increment:=0.5;
Chart1.Axes.Bottom.Increment:=DateTimeStep[dtOneHour];
end;

Related

Independent Component Analysis as Images

I have applied Independent Component Analysis on set of face images using FastICA. I have successfully retrieved independent components and mixing matrix. The values of independent components are in double and I want to display these components as images like available on web, e.g., http://research.ics.aalto.fi/ica/imageica/. I don't know how to show this.
One way you might do this more automatically is with the montage function. Or you can look at subimage. See also this StackOverflow question and answer.
Try the follwing function
function [XX,fh]=dispImgs(X,cols,gap,ihw,fh)
% Courtesy A. Leonardis, D. Skocaj
% see http://vicos.fri.uni-lj.si/danijels/downloads
[M,N]=size(X);
if nargin<2 cols=floor(sqrt(N)); end;
if nargin<3 gap=0; end;
if nargin<4 ihw=[sqrt(M),sqrt(M)]; end;
if nargin<5 fh = figure; end; % new figure
ih=ihw(1);iw=ihw(2);
maxv=max(X(:));
rows=floor(N/cols);
XX=zeros((rows*ih)+(rows-1)*gap,(cols*iw)+(cols-1)*gap)+maxv;
for i=1:N
a=(iw+gap)*mod(i-1,cols)+1;
b=(iw+gap)*mod(i-1,cols)+iw;
c=(ih+gap)*(floor((i-1)/cols))+1;
d=(ih+gap)*(floor((i-1)/cols))+ih;
XX(c:d,a:b)=reshape(X(:,i)',ih,iw);
end;
xxmax=max(XX(:));
xxmin=min(XX(:));
fh = figure(fh);
imshow((XX-xxmin)/(xxmax-xxmin));
axis off;
Example:
X: imsize by N
dispImgs( X, 8, 4, imsize );%show all N images in 8 columns with Gap=4

How do i undo the effect of IntersectClipRect?

Given the following code snippet:
procedure TPicture.PaintLine(_Canvas: TCanvas; _Left, _Top, _Right, _Bottom: Integer);
begin
IntersectClipRect(_Canvas.Handle, _Left, _Top, _Right, _Bottom);
try
_Canvas.MoveTo(_Left - 10, _Top - 10);
_Canvas.LineTo(_Right + 10, _Bottom + 10);
// (This is an example only, the actual drawing is much more complex.)
finally
SelectClipRgn(_Canvas.Handle, 0); // This does too much
end;
end;
I want to undo the clipping effected by the call to IntersectClipRect so the previously active clipping becomes active again. In the above code, this is done by SelectClipRgn(...,0) which turns off clipping altogether. This works, kind of, but afterwards there is no clipping active so any drawing that is executed after the above will paint to areas that should not be painted to.
So, what is the correct way to undo only the effect of IntersectClipRect?
EDIT: Removed the unnecessary CreateRectRgn and DeleteObject code after I understood the comment from Sertac, to make the question more readable for others that might stumble upon it later.
You can save and restore the state of the DC:
var
// RGN: HRGN;
SavedDC: Integer;
begin
// RGN := CreateRectRgn(_Left, _Top, _Right, _Bottom);
SavedDC := SaveDC(_Canvas.Handle);
try
IntersectClipRect(_Canvas.Handle, _Left, _Top, _Right, _Bottom);
_Canvas.MoveTo(_Left - 10, _Top - 10);
_Canvas.LineTo(_Right + 10, _Bottom + 10);
// (This is an example only, the actual drawing is much more complex.)
finally
RestoreDC(_Canvas.Handle, SavedDC);
end;
...
IIRC, first store the current clip region using GetClipRgn, and after you're done, SelectClipRgn the stored region again.
Looking at your code, it should be enough to SelectClipRgnyour RGN again, because:
The IntersectClipRect function creates a new clipping region from the intersection of the current clipping region and the specified rectangle.

GetAxisLabel always passes -1 for ValueIndex

I need to be able to format the X Axis labels on a TeeChart Standard 2012 chart. I’m handling the GetAxisLabel event, but the ValueIndex is always -1.
I found this bit of documentation:
Axis Labels are Values.
In this case, the Series parameter will be nil, and the ValueIndex will be -1.
Axis Labels are Series points.
The Series parameter will be a valid TChartSeries, and the ValueIndex will be the current Series point position.
The problem is that I can find no way to set the Axis Labels to series points.
Can someone help me out?
You need to set LabelStyle to be:
Chart1.Axes.Bottom.LabelStyle:=talPointValue;
or
Chart1.Axes.Bottom.LabelStyle:=talText;
in your chart. Then you'll be able to do something like this:
procedure TForm2.Chart1GetAxisLabel(Sender: TChartAxis; Series: TChartSeries;
ValueIndex: Integer; var LabelText: string);
begin
if ((Series <> nil) and (ValueIndex <> -1)) then
begin
LabelText:=FormatFloat('#.00', Series.XValue[ValueIndex]);
end;
end;
However, it's much easier to achieve what the method above does using AxisValuesFormat property:
Chart1.Axes.Bottom.AxisValuesFormat:='#.00';

Get X and Y values under mouse pointer

I have a simple chart using only TLineSeries with a single Y axis. As the mouse pointer moves over the chart, I’d like to get the X and Y values associated with the pointer’s position independent of any series.
I can handle the MouseMove event and get the screen X and Y coordinates, but the only way I’ve found to convert them is via the Series->XValues->Locate and Series->YValue->Locate methods.
There are two problems with this:
1 - The value returned from Series->YValue->Locate is always -1 regardless of whether the pointer is over a series line or not.
2 – The value returned from Series->XValue->Locate is -1 unless the pointer is over a part of the chart containing a series line.
Why does Series->YValue->Locate always return -1?
More importantly, how can I get the values regardless of whether the pointer is over a part of the chart with series lines or not?
I’m using the version of TeeChart that ships with Rad Studio XE3.
Why does Series->YValue->Locate always return -1?
That's because Locate uses a series value and returns its point index in the series. OnMouseMove provides screen pixel coordinates, not series values.
More importantly, how can I get the values regardless of whether the
pointer is over a part of the chart with series lines or not?
You can use axes as a reference instead of series, for example:
procedure TForm2.Chart1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
var
XVal: double;
YVal: double;
begin
XVal:=Chart1.Axes.Bottom.CalcPosPoint(X);
YVal:=Chart1.Axes.Left.CalcPosPoint(Y);
Chart1.Title.Text[0]:=FormatFloat('#.##', XVal) + ' - ' + FormatFloat('#.##', YVal);
end;

Viewing Part of a figure

I made a simulation of 10000 times and want to view part of simulation between 5000-5200. I am able to view it with the code below, but the x-axis says 0-250. I want the x-axis to display the exact figure of 5000-5200. Also there seems to be a small gap at the end of the figure as the axis runs up to 250 for some reason. I just want to view the figure in for this set time with the x-axis showing the exact labels and without the gap at the end.
Thanks
N=10000;%Number of simulation
P=0.02;
Q = zeros(N,1); %current value of queue
X=zeros(N,1);%simulation data
Ci=0;
L=0.9;
Bu=zeros(N,1);
Bs=30;
Bd1=50;
Bd2=270;
Ti=0;
for Ti=2:N
U=rand(1);
a=log10(U);
b=log10(1-P);
c=(a/b);
d=1+c;
X(Ti)=round(d);
Ci=Ci+1;
if X(Ti)< (L)*(Bs)
Bu(Ti)=Bs;
else if X(Ti) < (L)*(Bs+Bd1)
Bu(Ti)=Bs+Bd1;
else
Bu(Ti)=Bs+Bd1+Bd2;
end
end
Ti=Ti+1;
end
plot(X(5000:5200,1),'r');
set (gca,'ylim',[0 400]);
hold on;
plot(Bu(5000:5200,1),'b');
set (gca,'ylim',[0 400]);
hold off
Plot expects two inputs, the first depicting the horizontal axis and the second depicting the vertical axis. When you do not supply two inputs, then it computes the length of the single input (in this case that length is 5200-5000 = 200), and it just uses 1 through that length (1:200 in this case) as if it is the values for the horizontal axis variable.
I think you want to issue the command:
plot(5000:5200, X(5000:5200,1), 'r')
Often Matlab will adjust plot axes for better default views, so it's probably showing the axis out to the index 250 just by virtue of some default plotting convention. You can similarly use set(gca, 'xlim', [5000 5200]) if you wish.

Resources