Page 1 of 1
Marks inside of stacked bars?
Posted: Wed Nov 19, 2003 1:27 pm
by 8577662
The marks of a stacked TBarSeries appear above the top of each bar. I'd like to have the marks appear inside of each stack (with the same distance for each stack from the bottom of the stack) and with a mark at
the top of the topmost stack showing the total of all the Series in the
stack.
I've already searched in the demo application but wasn't able to find a way to set the position of the marks
Is there any way to do this?
Thanks in advance
Pascal
Posted: Wed Nov 19, 2003 2:49 pm
by Marjan
Hi, Pascal.
One easy workarund for this is to set marks ArrowLength propety to negative (reasonable) value. For example, the following code:
will display marks inside bars. Of course, the problem might arise if bars heights are less than 25 pixels, but in other cases it will work fine. There are additional refinements you can introduce - calculate best negative value to position series marks in the middle of bars, add code for the eventuality bar height is too small for mark, ...
Posted: Wed Nov 19, 2003 3:02 pm
by 8577662
Marjan wrote:
One easy workarund for this is to set marks ArrowLength propety to negative (reasonable) value.
This is what i currently do, but for the reasons you mentioned it's not an acceptable solution for me.
Marjan wrote:
calculate best negative value to position series marks in the middle of bars, add code for the eventuality bar height is too small for mark, ...
Do you have any code examples for this?
Is there also a solution for displaying an additional mark with the total of the entire bar (sum of all stacks) at the top of each bar?
Posted: Fri Nov 21, 2003 6:29 am
by Marjan
8577662 wrote:Do you have any code examples for this?
Yes, sure. Try using the following code:
Code: Select all
procedure CenterMarks(barSeries: TBarSeries);
var i : Integer;
yPos,yPos1,yPos2: Integer;
xPos: Integer;
MarkPos: TSeriesMarkPosition;
begin
MarkPos := TSeriesMarkPosition.Create;
for i := 0 to barSeries.Count - 1 do
begin
// just an example, you can do further customization here
MarkPos.Width := barSeries.BarWidth - 10;
MarkPos.Height := 16;
yPos1 := barSeries.CalcYPos(i); // get y screen pixel coordinate
if barSeries.UseYOrigin then yPos2 := barSeries.CalcYPosValue(0.0)
else yPos2 := barSeries.GetHorizAxis.PosAxis;
yPos := (YPos1+YPos2-MarkPos.Height) div 2;
xPos := barSeries.CalcXPos(i);
MarkPos.Custom := True;
MarkPos.LeftTop.X := xPos;
MarkPos.LeftTop.Y := yPos;
barSeries.Marks.Positions[i] := MarkPos;
end;
MarkPos.Free;
barSeries.Repaint;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Series1.Marks.Arrow.Visible := False;
Series1.Marks.Visible := True;
Series1.Add(5);
Series1.Add(11);
Series1.Add(-3);
Series1.Add(2.5);
end;
procedure TForm1.Series1BeforeDrawValues(Sender: TObject);
begin
CenterMarks(Sender as TBarSeries);
end;
Of course, you can do further customization and refinements, but the basic code will remain the same.
8577662 wrote:Is there also a solution for displaying an additional mark with the total of the entire bar (sum of all stacks) at the top of each bar?
Yes, it can be done. Basically, hide all other marks and display only last (top) series marks. Then in it's OnGetMarkText event, calculate the sum for each stack. Something like this:
Code: Select all
procedure TForm1.LastSeriesGetMarkText(Sender: TChartSeries;
ValueIndex: Integer; var MarkText: String);
var i:integer;
tmp:double;
begin
//sweeps through all values and calculates total
tmp:=0;
for i:=0 to Chart1.SeriesList.Count-1 do
if Chart1.Series[i].Active then
tmp:=tmp+Chart1.Series[i].YValue[ValueIndex]; //sum YValues
MarkText:=FloatToStr(tmp); //write a new MarkText
end;
procedure TForm1.FormCreate(Sender: TObject);
var i:Integer;
begin
for i:=0 to Chart1.SeriesList.Count-1 do
with Chart1.Series[i] do
begin
FillSampleValues(10);
Marks.Visible:=false; //we don't want marks for series
end;
with Chart1.Series[i-1] do
begin
OnGetMarkText:=LastSeriesGetMarkText; //assign OnGetMarkText event to last series
Marks.Visible:=true; //on the other hand, we want a mark for last series
end;
end;
Posted: Fri Nov 21, 2003 6:51 pm
by 8577662
Marjan wrote:
Yes, it can be done. Basically, hide all other marks and display only last (top) series marks. Then in it's OnGetMarkText event, calculate the sum for each stack
Is there also a possibility to have the summary *AND* the marks (the summary in an additional mark above all stacks?
Thanks
Pascal
Posted: Sun Nov 23, 2003 5:11 pm
by Marjan
Hi. Pascal.
Not automatically. But you can do several things:
1) Add extra line (summary) to existing mark text. This can be done in TChartSeries.OnGetMarkText event.
2) Manually draw required texts above series marks in TChart OnAfterDraw event. Basically, use TChart.Canvas.TextOut method to paint specific text at given screen coordinate.
3) Use series of TAnnotationTool tools to add extra text above series marks,
I hope any of these methods will help you
Posted: Mon Nov 24, 2003 1:16 pm
by 8577662
Marjan wrote:
Yes, sure. Try using the following code:
The problem with this code is, that it will center the Marks for the size of
all stacked bars. What I need is to center the mark between the top of a stack and the bottom of a stack (and not the bottom of the bar / position of the x axes).
Is there a way to get the bottom position of a stack? or the top position of the underlying stack?
Posted: Mon Nov 24, 2003 3:06 pm
by Marjan
You'll have to calculate it manually. First calculate the sum of all values, except the last series value. Then the middle of last bar will be equal to ("sum of all values" + "sum of all except the last value")*0.5.
Posted: Mon Nov 24, 2003 3:21 pm
by 8577662
Marjan wrote:You'll have to calculate it manually. First calculate the sum of all values, except the last series value. Then the middle of last bar will be equal to ("sum of all values" + "sum of all except the last value")*0.5.
I think you misunderstood my question. My problem is, that the code you've posted for centering the marks in the stacks (CenterMarks procedure), does only work for the first stack.
For every other stack the mark is centered in the *full* bar height and not in the *stack* height
Thanks
Pascal
Posted: Wed Nov 26, 2003 11:01 am
by Pep
How about using the following code ? :
Code: Select all
procedure TForm1.PositionChartMarks(BarSeries: TBarSeries);
var
i: integer;
YPos: integer;
BarTop: integer;
BarBottom: integer;
XPos: integer;
MarkPos: TSeriesMarkPosition;
begin
MarkPos := TSeriesMarkPosition.Create;
try
for i := 0 to BarSeries.Count - 1 do begin
// just an example, you can do further customization here
MarkPos.Width := BarSeries.BarWidth;
MarkPos.Height := 16;
BarTop := BarSeries.CalcYPos(i); // get y screen pixel coordinate
BarBottom := BarSeries.CalcYPosValue(BarSeries.PointOrigin(i,false));
YPos := (BarTop + BarBottom - MarkPos.Height) div 2;
// Make sure that the value isn't painted below the X Axis
if YPos > (BarSeries.GetHorizAxis.PosAxis - (MarkPos.Height)) then begin
YPos := BarSeries.GetHorizAxis.PosAxis - (MarkPos.Height);
end;
XPos := BarSeries.CalcXPos(i);
MarkPos.Custom := True;
MarkPos.LeftTop.X := XPos;
MarkPos.LeftTop.Y := YPos;
BarSeries.Marks.Positions[i] := MarkPos;
end;
finally
MarkPos.Free;
end;
BarSeries.Repaint;
end;
procedure TForm1.Series1BeforeDrawValues(Sender: TObject);
begin
PositionChartMarks(Sender as TBarSeries);
end;
Josep Lluis Jorge
http://support.steema.com
Posted: Wed Nov 26, 2003 3:00 pm
by 8577662
Pep wrote:How about using the following code ? :
Many thanks, works fine now.
How about adding this features to a future version (it's something I normaly expect built-in in a charting component)?
Thanks again
Pascal
Posted: Wed Nov 26, 2003 10:04 pm
by Pep
Ok, I'll add on our wish list to be considered for the next releases.
Josep Lluis Jorge
http://support.steema.com