Page 1 of 1
MultiBar for TCandleSeries
Posted: Sat Apr 16, 2011 10:34 am
by 10547054
I would like to display multiple Candle series, but stagger them on the X axis, similar to MultiBar=mbSide
Is that possible?
I am really truing help my users visualize uncertainty.
AddCandle(X, u+1SD, u+2SD, u-2SD, u-1SD)
Multiple series overlap each other.
Thanks,
Steve
Re: MultiBar for TCandleSeries
Posted: Mon Apr 18, 2011 9:58 am
by 10050769
Hello Steve,
I have added your request as a feature request in wish-list with number [TV52015508] to be considered for inclusion in future releases. On the other hand,
I recommend you try to work with only one series and adding slightly different X values when you want values side and achieve the same effect as Multibar= mbSide.
Thanks,
Re: MultiBar for TCandleSeries
Posted: Mon Apr 18, 2011 10:30 am
by 10547054
I have five series that the users can enable/disable with a checkbox in the legends.
might there be any other series that allows mbSide, with a error-box that I can control both the upper and lower location of the box, as well as the upper and lower limits of the error bars?
Or is there a work-around I can make in the source code to emulate mbSide?
Re: MultiBar for TCandleSeries
Posted: Tue Apr 19, 2011 9:07 am
by 10050769
Hello Steve,
might there be any other series that allows mbSide, with a error-box that I can control both the upper and lower location of the box, as well as the upper and lower limits of the error bars?
Yes, you can try to do the same with error bar. I recommend take a look in Demo Project concretely in
All features\Chart Style\Statistical .
Or is there a work-around I can make in the source code to emulate mbSide?
For now we don't have any work-around to it, but your request is in wish-list (TV52015508) to be considered inclusion in next versions, how I said previously.
Thanks,
Re: MultiBar for TCandleSeries
Posted: Tue Apr 19, 2011 11:32 am
by yeray
Hello Steve,
As an addition, I thought on a workaround.
You can inherit from the TBar3DSeries to create a new series that will have two errors.
Here you have a start point:
Code: Select all
uses Bar3D, Math;
type
TBar3DErrorSeries = class(TBar3DSeries)
private
BarErrors, OffsetErrors: TChartValueList;
protected
procedure AddSample(Index: Integer; const Y: Double);
procedure AddSampleValues(NumValues:Integer; OnlyMandatory:Boolean=False); override;
procedure DrawBar(BarIndex,StartPos,EndPos:Integer); override;
end;
procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
begin
Chart1.View3D:=false;
for i:=0 to 4 do
begin
with Chart1.AddSeries(TBar3DErrorSeries) as TBar3DErrorSeries do
begin
BarErrors:=TChartValueList.Create(Chart1[i], 'BarErrors');
OffsetErrors:=TChartValueList.Create(Chart1[i], 'OffsetErrors');
FillSampleValues();
Marks.Visible:=false;
end;
end;
end;
{ TBar3DErrorSeries }
procedure TBar3DErrorSeries.AddSampleValues(NumValues: Integer;
OnlyMandatory: Boolean);
var t : Integer;
begin
inherited;
for t:=0 to NumValues-1 do
AddSample(t, Max(YValues.MaxValue, OffsetValues.MaxValue) - Min(YValues.MinValue, OffsetValues.MinValue));
end;
procedure TBar3DErrorSeries.AddSample(Index: Integer; const Y: Double);
function TempRandom:Double;
begin
result:=(20+RandomValue(4));
end;
begin
BarErrors.Value[Index]:=Y/TempRandom;
OffsetErrors.Value[Index]:=Y/TempRandom;
end;
procedure TBar3DErrorSeries.DrawBar(BarIndex,StartPos,EndPos:Integer);
var XPos, BarPos, OffsetPos, BarErrPos, OffsetErrPos: Integer;
begin
inherited;
XPos:=CalcXPos(BarIndex) + BarWidth div 2;
BarPos:=CalcYPosValue(YValue[BarIndex]);
OffsetPos:=CalcYPosValue(OffsetValues[BarIndex]);
if (YValues[BarIndex] > OffsetValues[BarIndex]) then
begin
BarErrPos:=CalcYPosValue(YValue[BarIndex] + BarErrors[BarIndex]);
OffsetErrPos:=CalcYPosValue(OffsetValues[BarIndex] - OffsetErrors[BarIndex]);
end
else
begin
BarErrPos:=CalcYPosValue(YValue[BarIndex] - BarErrors[BarIndex]);
OffsetErrPos:=CalcYPosValue(OffsetValues[BarIndex] + OffsetErrors[BarIndex]);
end;
if BarErrors[BarIndex]<>0 then
begin
if ParentChart.View3D then
ParentChart.Canvas.VertLine3D(XPos, BarPos, BarErrPos, MiddleZ)
else
ParentChart.Canvas.DoVertLine(XPos, BarPos, BarErrPos);
end;
if OffsetErrors[BarIndex]<>0 then
begin
if ParentChart.View3D then
ParentChart.Canvas.VertLine3D(XPos, OffsetPos, OffsetErrPos, MiddleZ)
else
ParentChart.Canvas.DoVertLine(XPos, OffsetPos, OffsetErrPos);
end;
end;
Re: MultiBar for TCandleSeries
Posted: Wed Apr 20, 2011 2:19 pm
by 10547054
This is great, your sample code was very valuable.
I am down to a single issue, my left axis touches the left-most bar.
I am very appreciative of this level of support, including custom programming !
Re: MultiBar for TCandleSeries
Posted: Thu Apr 21, 2011 3:35 pm
by yeray
Hello Steve,
I'm happy to hear that!
vas wrote:I am down to a single issue, my left axis touches the left-most bar.
You could try setting some bottom axis MinimumOffset.
Re: MultiBar for TCandleSeries
Posted: Thu Apr 21, 2011 8:40 pm
by 10547054
I tried setting the MinimumOffset, which I really like, but failed.
Here is my feeble coding:
Code: Select all
unit EBar3D;
interface
uses
Windows, Messages, SysUtils, Classes,
Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls,
Bar3D,TeEngine, TeeProcs, Chart, Series;
type
TBar3DErrorSeries = class(TBar3DSeries)
public
Constructor Create(AOwner: TComponent); override;
Function AddEBar( Const AX,ABHi,AEHi,AElo,ABLo:Double;
Const AXLabel:String='';
AColor:TColor=clTeeColor):Integer;
private
ErrValHi, ErrValLo: TChartValueList;
protected
procedure DrawBar(BarIndex,StartPos,EndPos:Integer); override;
end;
TBarChForm = class(TForm)
Chart1: TChart;
procedure CreateForm(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
BarChForm: TBarChForm;
implementation
{$R *.dfm}
{ TBar3DErrorSeries }
Constructor TBar3DErrorSeries.Create(AOwner: TComponent);
begin
inherited;
ErrValHi := TChartValueList.Create(Self, 'ErrValHi');
ErrValLo := TChartValueList.Create(Self, 'ErrValLo');
end;
Function TBar3DErrorSeries.AddEBar( Const AX,ABHi,AEHi,AElo,ABLo:Double;
Const AXLabel:String='';
AColor:TColor=clTeeColor):Integer;
begin
Marks.Visible:=false;
XValues.DateTime := true;
ErrValHi.TempValue := AEHi;
ErrValLo.TempValue := AELo;
Result := AddBar( AX, ABHi, ABLo, AXLabel, AColor );
end;
procedure TBar3DErrorSeries.DrawBar(BarIndex,StartPos,EndPos:Integer);
var XPos, BarHiPos, BarLoPos, ErrHiPos, ErrLoPos: Integer;
begin
inherited;
XPos:=CalcXPos(BarIndex) + BarWidth div 2;
BarHiPos:=CalcYPosValue(YValue[BarIndex]);
BarLoPos:=CalcYPosValue(OffsetValues[BarIndex]);
ErrHiPos:=CalcYPosValue(ErrValHi[BarIndex]);
ErrLoPos:=CalcYPosValue(ErrValLo[BarIndex]);
if ErrValHi[BarIndex]<>0 then with ParentChart.Canvas do begin
DoVertLine(XPos-1, BarHiPos, ErrHiPos);
DoVertLine(XPos, BarHiPos, ErrHiPos); // make thicker error bars
DoVertLine(XPos+1, BarHiPos, ErrHiPos);
end;
if ErrValLo[BarIndex]<>0 then with ParentChart.Canvas do begin
DoVertLine(XPos-1, BarLoPos, ErrLoPos);
DoVertLine(XPos, BarLoPos, ErrLoPos);
DoVertLine(XPos+1, BarLoPos, ErrLoPos);
end;
end;
procedure TBarChForm.CreateForm(Sender: TObject);
begin
with Chart1 do begin
AddSeries(TBar3DErrorSeries.Create(Chart1));
AddSeries(TBar3DErrorSeries.Create(Chart1));
BottomAxis.MinimumOffset := 10;
BottomAxis.MaximumOffset := 10;
View3D := false;
with Series[0] as TBar3DErrorSeries do begin
AddEBar(30000,20,25,10,15);
AddEBar(30020,25,30,15,20);
AddEBar(30040,30,35,20,25);
AddEBar(30060,35,40,25,30);
end;
with Series[1] as TBar3DErrorSeries do begin
AddEBar(30000,40,50,25,30);
AddEBar(30020,35,45,20,25);
AddEBar(30040,30,40,15,20);
AddEBar(30060,25,35,10,15);
end;
ShowModal;
end;
end;
end.
Re: MultiBar for TCandleSeries
Posted: Fri Apr 22, 2011 8:07 am
by yeray
Hello Steve,
Here's what I get with your code.
- chart.png (9.83 KiB) Viewed 20036 times
It seems that the left axis needs some adjustment, more than the bottom. You could calculate the min and max values and set them with the SetMinMax method or, alternatively, you could override the CalcVerticalMargins and CalcHorizontalMargins. Here you have the heathers:
Code: Select all
Procedure CalcVerticalMargins(Var TopMargin,BottomMargin:Integer); override;
Procedure CalcHorizMargins(var LeftMargin,RightMargin:Integer); override;
FYI:
- You may want to change is the Bar series CustomBarWidth to make the bars a little thiner.
- To make the error lines wider you could change the Pen.Width instead of drawing three lines:
Code: Select all
ParentChart.Canvas.Pen.Width:=3;
if ErrValHi[BarIndex]<>0 then with ParentChart.Canvas do
DoVertLine(XPos, BarHiPos, ErrHiPos);
if ErrValLo[BarIndex]<>0 then with ParentChart.Canvas do
DoVertLine(XPos, BarLoPos, ErrLoPos);
Re: MultiBar for TCandleSeries
Posted: Fri Apr 22, 2011 12:48 pm
by 10547054
This service is beyond fantastic.
I implemented your suggestions about CustomBarWidth and PenWidth.
But my chart results differs from yours. I suspect I have an install error in Delphi,
so I am likely linked to an earlier version. I cannot see TeeChart Help either.
In any case, I am close enough.
Thank you very much.
Steve
Re: MultiBar for TCandleSeries
Posted: Fri Apr 22, 2011 7:28 pm
by 10547054
Here are my results.
I am guessing I have an install failure somewhere.
- EBarFail.png (5.88 KiB) Viewed 20062 times
Re: MultiBar for TCandleSeries
Posted: Tue Apr 26, 2011 10:00 am
by narcis
Hi Steve,
Thank you very much for your compliments, much appreciated!
Which TeeChart version are you using? Have you tried using the latest version available at the client download area?
Thanks in advance.