Bar Charts Custom Mark Placement

TeeChart VCL for Borland/CodeGear/Embarcadero RAD Studio, Delphi and C++ Builder.
Post Reply
Errol
Newbie
Newbie
Posts: 75
Joined: Thu Jul 11, 2013 12:00 am

Bar Charts Custom Mark Placement

Post by Errol » Sun Mar 06, 2016 10:41 pm

I am using a self-stacked bar chart to represent lithology down a well. I create one series from a dataset to draw the lithology and place marks representing the lithology type. This works fine. I then create another series from the same dataset to place a short comment beside each lithology. I am using code proposed by Yeray on 18 March 2014 in reply to my topic "Stacked Bar Chart and Marks". My code is shown below. On first display, the bar chart looks like Image 1, with the marks centred, while Unzoom gives Image 2. with the marks left-aligned but not in the correct y-position.

Can you suggest what I may be doing wrong?

Another problem that I have is if the Strata Comment field is blank in the dataset, TeeChart writes the thickness of the lithology (see the highest lithology in the image). How can I tell TeeChart to not draw a mark in this case.

Thanks in anticipation

Errol
Image1.png
Bar chart when first displayed
Image1.png (18.22 KiB) Viewed 15893 times
Image2.png
Bar chart ofer Undo Zoom
Image2.png (20.95 KiB) Viewed 15884 times

Code: Select all

// ---------- InsertGeologicalComment ------------------------------------------
procedure TQSCollection.InsertGeologicalComment
                    (AFldCode,AFld:string; AIndex: integer; ADataset: TDataset);
var
  i,iIndex: integer;
  Ltitle : string;

// assumes IntervalQuery has been filled. EBA 20160302
begin
  IntervalQuery.Open;
  IntervalQuery.First;

  LTitle := IntToStr(owner.Chart.SeriesList.Count);
  SeriesListB.AddObject(LTitle,TUnitBarSeries.Create(Owner)) 

  iIndex := SeriesListB.IndexOf(LTitle);

  with TUnitBarSeries(SeriesListB.Objects[iIndex]) do
  begin
    ParentChart := self.Owner.Chart;
    DataSource := IntervalQuery;  // after parent chart

    MultiBar := mbSelfStack;
    CustomBarWidth := 60;
    BarPen.Visible := False;
    MarksLocation := mlCenter;
    MarksOnBar := True;
    Marks.Clip := True;
    Marks.Shadow.Visible := False;
    ShowInLegend := False;

    Marks.Visible := True;
    Marks.Pen.Color := clWhite;
    Marks.Transparent := True;
    Marks.Font.Size := 8;

    ColorSource := 'Foreground';
    XLabelsSource := 'Strata Comment';
    XValues.ValueSource := 'ProfileDistance';
    YValues.ValueSource := 'Depth';
		VertAxis := aLeftAxis;

    active := true;
  end;

  self.owner.chart.refreshdata;
  self.owner.PlaceComments;

end;

// ---------- PlaceComments ----------------------------------------------------
procedure TPBQuickGraph.PlaceComments;
var
  s, i, tmpSize: Integer;

begin
  Chart.Draw;
  for s:=0 to IntervalQueryCollection.SeriesListB.Count-1 do
    if (s div 2 <> s/2) then // every second series in SeriesListB
      with TUnitBarSeries(IntervalQueryCollection.SeriesListB.Objects[s]) do
      begin
        for i := 0 to TUnitBarSeries(IntervalQueryCollection.SeriesListB.Objects[s]).Count - 1 do
          with Marks.Positions[i] do
          begin
            Custom := true;
            LeftTop.X := CalcXPos(0) + 80;
            tmpSize:=CalcYSizeValue(YValue[i]);
            LeftTop.Y:=CalcYPos(i)+(tmpSize div 2)-(Marks.Height div 2);
          end;
      end;
end;

procedure TPBQuickGraph.BarUndoZoom(Sender: TObject);
begin
  PlaceComments;
end;

Yeray
Site Admin
Site Admin
Posts: 9514
Joined: Tue Dec 05, 2006 12:00 am
Location: Girona, Catalonia
Contact:

Re: Bar Charts Custom Mark Placement

Post by Yeray » Mon Mar 07, 2016 10:22 am

Hello Errol,
Errol wrote:I am using code proposed by Yeray on 18 March 2014 in reply to my topic "Stacked Bar Chart and Marks". My code is shown below.
Do you mean this one?
I'm using the example I posted there because I can't access the data from your code.
Errol wrote:On first display, the bar chart looks like Image 1, with the marks centred, while Unzoom gives Image 2. with the marks left-aligned but not in the correct y-position.

Can you suggest what I may be doing wrong?
I can't reproduce that problem with the simple example I posted on the referenced post here. I'm not sure about where the "highly altered", "less altered" etc texts come from.
Errol wrote:Another problem that I have is if the Strata Comment field is blank in the dataset, TeeChart writes the thickness of the lithology (see the highest lithology in the image). How can I tell TeeChart to not draw a mark in this case.
I could reproduce that one modifying the code I posted here.
You could clear the text in the mark when you loop in your PlaceComments method. In the simple example this works:

Code: Select all

uses Series;

procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
begin
  Chart1.Legend.Visible:=false;
  Chart1.View3D:=false;

  with Chart1.AddSeries(TBarSeries) as TBarSeries do
  begin
    for i:=0 to 4 do
      if i=4 then
        Add(25+random*75)
      else
        Add(25+random*75, 'S0, I' + IntToStr(i));

    MultiBar:=mbSelfStack;
    MarksLocation:=mlCenter;
    MarksOnBar:=true;
    CustomBarWidth:=60;
  end;

  PlaceMarks;
end;

procedure TForm1.PlaceMarks;
var s, i, tmpSize: Integer;
begin
  Chart1.Draw;

  for s:=0 to Chart1.SeriesCount-1 do
    if Chart1[s] is TBarSeries then
      with Chart1[s] as TBarSeries do
      begin
        for i:=0 to Count-1 do
          with Marks.Positions[i] do
          begin
            if (Labels[i] <> '') then
            begin
              Custom:=true;
              LeftTop.X:=CalcXPos(i);

              if MarksLocation=mlEnd then
                LeftTop.Y:=CalcYPos(i)
              else
              begin
                tmpSize:=CalcYSizeValue(YValue[i]);
                if MarksLocation=mlStart then
                  LeftTop.Y:=CalcYPos(i)+tmpSize-Marks.Height
                else
                  LeftTop.Y:=CalcYPos(i)+(tmpSize div 2)-(Marks.Height div 2);
              end;
            end
            else
              Marks.Item[i].Text.Text:='';
          end;
      end;
end;

procedure TForm1.Chart1Scroll(Sender: TObject);
begin
  PlaceMarks;
end;

procedure TForm1.Chart1Zoom(Sender: TObject);
begin
  PlaceMarks;
end;

procedure TForm1.Chart1UndoZoom(Sender: TObject);
begin
  PlaceMarks;
end;
Best Regards,
ImageYeray Alonso
Development & Support
Steema Software
Av. Montilivi 33, 17003 Girona, Catalonia (SP)
Image Image Image Image Image Image Please read our Bug Fixing Policy

Errol
Newbie
Newbie
Posts: 75
Joined: Thu Jul 11, 2013 12:00 am

Re: Bar Charts Custom Mark Placement

Post by Errol » Tue Mar 08, 2016 1:42 am

Thanks Yeray. Your suggestion regarding clearing the text in the mark works correctly. I also solved the problem of the mark placement. Because I was using an inverted vertical axis, I had to change the sign of the variable tmpSize used in your previous example code. Sorry about not picking that up earlier.

However, I still have one outstanding problem. When I first display the bar chart it looks like Image3, and I have to UndoZoom to obtain the correct image, Image4. The general structure of the program is given in the previous query (note this is not a test program, but actual code using real data). When PlaceComments is called after creating the series, the CalcXPos and CalcYPos values seem reasonable. Can you suggest how I might get the chart to display correctly at the start?

Thanks again, Errol
Image3.png
Appearance of chart when first displayed
Image3.png (21.05 KiB) Viewed 15845 times
Image4.png
Correct appearance of chart after UbdoZoom
Image4.png (20.43 KiB) Viewed 15835 times

Yeray
Site Admin
Site Admin
Posts: 9514
Joined: Tue Dec 05, 2006 12:00 am
Location: Girona, Catalonia
Contact:

Re: Bar Charts Custom Mark Placement

Post by Yeray » Tue Mar 08, 2016 8:20 am

Hello,

Try forcing a Chart1.Draw; again at the end of your PlaceComments method. Maybe it is being called when the marks have already been drawn and the changes don't take effect until the next drawing cycle.
Best Regards,
ImageYeray Alonso
Development & Support
Steema Software
Av. Montilivi 33, 17003 Girona, Catalonia (SP)
Image Image Image Image Image Image Please read our Bug Fixing Policy

Errol
Newbie
Newbie
Posts: 75
Joined: Thu Jul 11, 2013 12:00 am

Re: Bar Charts Custom Mark Placement

Post by Errol » Wed Mar 23, 2016 5:16 am

I have made significant progress on using self-stacked bar charts to represent well lithology. I found that I had to trigger an OnResize event to get everything looking good, as the chart is automatically resized when drawn on a large screen - something that a test program will not always pick up.

However, I have a number of small but intransigent problems that I would appreciate your comments:
1. The horizontal axis labels do not extend across the whole axis - see Image001. I use a Custom Axis for the bottom axis, and I have checked that this is a perfectly standard axis with default settings. However, the axis labels are not displayed in the left-most 20% of the axis. Can you suggest what may be causing this?
2. To draw the comments, also shown on Image001, I create another self-stacked barchart using the same dataset. I set CustomBarWidth := 1 and BarPen.Visible := False. However, this bar chart still creates a small 1-pixel break in the horizontal lines between lithologies. I tried creating the comment bar chart first and the lithology bar chart after it, but this wasn't successful (the displayed bar chart was only one pixel wide). Is there any easy way to draw the comment bar chart behind the lithology bar chart?
3. Control of annotation placement. As shown on Image001, the well names, placed as annotations, are a long way from the top axis. (The varying annotation level is somehow caused by the comments placement which I am still working on). If I rotate the text direction to 90°(Image002) the well names are truncated. I would like to place the well names close to the top axis, and then write a title above this. I would appreciate some suggestions here.
4. The marks on the bar chart are not quite centred in the vertical direction (Image001). I use MarksLocation := mlCenter;
5. Scrolling with the mouse wheel. When I scroll the bar chart up, the comments move up about the height of the text, and when I scroll down, the comments more in the other direction. How can I stop this happening.
Image001.png
Horizontal Axis Labels
Image001.png (58.59 KiB) Viewed 15782 times
Image002.png
Annotations clipped
Image002.png (47.54 KiB) Viewed 15782 times
Many thanks

Errol

Yeray
Site Admin
Site Admin
Posts: 9514
Joined: Tue Dec 05, 2006 12:00 am
Location: Girona, Catalonia
Contact:

Re: Bar Charts Custom Mark Placement

Post by Yeray » Wed Mar 30, 2016 10:23 am

Hello Errol,
Errol wrote:1. The horizontal axis labels do not extend across the whole axis - see Image001. I use a Custom Axis for the bottom axis, and I have checked that this is a perfectly standard axis with default settings. However, the axis labels are not displayed in the left-most 20% of the axis. Can you suggest what may be causing this?
By default the axis LabelStyle is set to talAuto, and this mode shows the series labels if present. You can force an axis to show the axis scale setting the LabelStyle to talValue.
Adding this to the example here shows labels for me here even if I scroll horizontally:

Code: Select all

  DBChart1.Axes.Bottom.LabelStyle:=talValue;
Errol wrote:2. To draw the comments, also shown on Image001, I create another self-stacked barchart using the same dataset. I set CustomBarWidth := 1 and BarPen.Visible := False. However, this bar chart still creates a small 1-pixel break in the horizontal lines between lithologies. I tried creating the comment bar chart first and the lithology bar chart after it, but this wasn't successful (the displayed bar chart was only one pixel wide). Is there any easy way to draw the comment bar chart behind the lithology bar chart?
Try hiding the bar with this instead of setting a small CustomBarWidth:

Code: Select all

Brush.Clear;
Errol wrote:3. Control of annotation placement. As shown on Image001, the well names, placed as annotations, are a long way from the top axis. (The varying annotation level is somehow caused by the comments placement which I am still working on). If I rotate the text direction to 90°(Image002) the well names are truncated. I would like to place the well names close to the top axis, and then write a title above this. I would appreciate some suggestions here.
This may be related to the ticket #528. However, to be able to confirm it we'd need a simple example project we can run as-is to reproduce the problem you are suffering here.
Errol wrote:4. The marks on the bar chart are not quite centred in the vertical direction (Image001). I use MarksLocation := mlCenter;
I'm not sure to understand this one. What exact marks do you see are not behaving as expected in that image? Can you please arrange a simple example project we can run as-is to reproduce this here?
Errol wrote:5. Scrolling with the mouse wheel. When I scroll the bar chart up, the comments move up about the height of the text, and when I scroll down, the comments more in the other direction. How can I stop this happening.
This is probably because the code you are using to manually calculate the position is not perfect.
Can you please arrange a simple example project we can run as-is to reproduce this here?

Thanks in advance.
Best Regards,
ImageYeray Alonso
Development & Support
Steema Software
Av. Montilivi 33, 17003 Girona, Catalonia (SP)
Image Image Image Image Image Image Please read our Bug Fixing Policy

Errol
Newbie
Newbie
Posts: 75
Joined: Thu Jul 11, 2013 12:00 am

Re: Bar Charts Custom Mark Placement

Post by Errol » Wed Mar 30, 2016 11:30 pm

Thank you for your reply to my previous queries:
Item 1 (axis labels not fully displayed): This was my error and now solved - many apologies.
Item 2 (second bar chart showing on first): solved using Brush-Clear - thanks.
Item 3 (annotation placement): I am unable to place the annotations just above the top axis. If I use:

Code: Select all

  with (Chart.Tools[H] as TAnnotationTool) do
    Top := Chart.Axes.Bottom.PosAxis;
the annotations are nicely placed below the bottom axis (see AnnotationsonBottomAxis).
AnnotationsOnBottomAxis.png
Annotations correctly aligned with bottom axis
AnnotationsOnBottomAxis.png (75.56 KiB) Viewed 15749 times
However, if I use:

Code: Select all

  with (Chart.Tools[H] as TAnnotationTool) do
    Top :=  Chart.Axes.Top.PosAxis;
the annotations are placed at the top of the chart, not on the top axis (AnnotationsOnTopAxis).
AnnotationsOnTopAxis.png
Annotations not correctly aligned on top axis
AnnotationsOnTopAxis.png (75.35 KiB) Viewed 15753 times
How can I place the annotations on the top axis?
Item 4. (marks on the bar chart not centred). MarksOffVerticalcentre shows the problem. The text vertical offset is small but significant.
MarksOffVerticalCentre.png
Marks slightly misaligned vertically
MarksOffVerticalCentre.png (1.45 KiB) Viewed 15748 times
I look forward to your comments.

Yeray
Site Admin
Site Admin
Posts: 9514
Joined: Tue Dec 05, 2006 12:00 am
Location: Girona, Catalonia
Contact:

Re: Bar Charts Custom Mark Placement

Post by Yeray » Thu Mar 31, 2016 11:28 am

Hello Errol,
Errol wrote: Item 3 (annotation placement): I am unable to place the annotations just above the top axis.
[...]
How can I place the annotations on the top axis?
Using this at your OnAfterDraw event seems to work fine for me:

Code: Select all

Top := DBChart1.ChartRect.Top - 20;
Errol wrote:Item 4. (marks on the bar chart not centred). MarksOffVerticalcentre shows the problem. The text vertical offset is small but significant.
I see the automatic positioning of the marks on the centre considers the text width/height instead of considering the whole mark rectangle width/height.
I've added it to the public tracker:
http://bugs.teechart.net/show_bug.cgi?id=1487
Best Regards,
ImageYeray Alonso
Development & Support
Steema Software
Av. Montilivi 33, 17003 Girona, Catalonia (SP)
Image Image Image Image Image Image Please read our Bug Fixing Policy

Errol
Newbie
Newbie
Posts: 75
Joined: Thu Jul 11, 2013 12:00 am

Re: Bar Charts Custom Mark Placement

Post by Errol » Thu Apr 07, 2016 10:47 pm

Hello Yeray

Thanks for your response - using ChartRect (rather than Axes.Top.PosAxis) worked fine for placing the annotations above the top axis.

However, I have now decided to place the annotations just above the bar charts, to simplify placing a title on the top axis. However, when I use the command:
Top := TUnitBarSeries(fIntervalQueryCollection.SeriesListB.Objects[h]).CalcYPos(0);
the annotation is placed underneath the first section of the stacked bar chart (see image AnnotationPlacement), as my bar charts are built from the top down.
AnnotationPlacement.png
AnnotationPlacement.png (13.99 KiB) Viewed 15725 times
Can you suggest a way to align the annotation with the top of the stacked bar chart.

Thanks in anticipation.

Errol

Yeray
Site Admin
Site Admin
Posts: 9514
Joined: Tue Dec 05, 2006 12:00 am
Location: Girona, Catalonia
Contact:

Re: Bar Charts Custom Mark Placement

Post by Yeray » Mon Apr 11, 2016 10:40 am

Hello Errol,

If I'm not wrong, your customized Bars start at YPosition, so you should use that value as the reference to place your annotations.
If I set this at the DBChart1AfterDraw in the example here, it seems to work as you expected:

Code: Select all

      Top := DBChart1.Axes.Left.CalcYPosValue(TMyBarSeries(SeriesListB.Objects[j]).YPosition) - Height;
Best Regards,
ImageYeray Alonso
Development & Support
Steema Software
Av. Montilivi 33, 17003 Girona, Catalonia (SP)
Image Image Image Image Image Image Please read our Bug Fixing Policy

Errol
Newbie
Newbie
Posts: 75
Joined: Thu Jul 11, 2013 12:00 am

Re: Bar Charts Custom Mark Placement

Post by Errol » Mon May 02, 2016 1:06 am

Everything is working nicely with the geological bar charts on a cross-section - thanks Yeray - except for one persistent error.

I now place the well names as an Annotation above the wells. I call the PlaceWellNames procedure only in the OnBeforeDrawSeries event. If the horizontal axis scaling is not automatic, the well names are correctly centred at all times, with Zoom, Drag and UndoZoom. I calculate the annotation left position as follows:
Left := TUnitBarSeries(fIntervalQueryCollection.SeriesListB.Objects[h]).CalcXPos(0) - Width div 2

However if the horizontal axis is set to automatic, the well names are centred over the left edge of the bar chart on UndoZoom but jump to the centre when dragging the charts.

Can you suggest what might cause this behaviour?

Thanks and regards

Errol

Yeray
Site Admin
Site Admin
Posts: 9514
Joined: Tue Dec 05, 2006 12:00 am
Location: Girona, Catalonia
Contact:

Re: Bar Charts Custom Mark Placement

Post by Yeray » Mon May 02, 2016 8:55 am

Hello Errol,

Taking again the code for here, I see the Annotation tools (AT-* texts on the top) are correctly displaced when dragging the chart. However, they aren't updated when I unzoom the chart:
anotations.png
anotations.png (27.73 KiB) Viewed 15634 times
I can fix this if I force a chart repaint at UndoZoom event:

Code: Select all

procedure TForm1.DBChart1UndoZoom(Sender: TObject);
begin
  DBChart1.Draw;
end;
Best Regards,
ImageYeray Alonso
Development & Support
Steema Software
Av. Montilivi 33, 17003 Girona, Catalonia (SP)
Image Image Image Image Image Image Please read our Bug Fixing Policy

Post Reply