Page 1 of 1
Bar Charts Custom Mark Placement
Posted: Sun Mar 06, 2016 10:41 pm
by 16566546
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
- Bar chart when first displayed
- Image1.png (18.22 KiB) Viewed 18622 times
- Bar chart ofer Undo Zoom
- Image2.png (20.95 KiB) Viewed 18613 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;
Re: Bar Charts Custom Mark Placement
Posted: Mon Mar 07, 2016 10:22 am
by yeray
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;
Re: Bar Charts Custom Mark Placement
Posted: Tue Mar 08, 2016 1:42 am
by 16566546
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
- Appearance of chart when first displayed
- Image3.png (21.05 KiB) Viewed 18574 times
- Correct appearance of chart after UbdoZoom
- Image4.png (20.43 KiB) Viewed 18564 times
Re: Bar Charts Custom Mark Placement
Posted: Tue Mar 08, 2016 8:20 am
by yeray
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.
Re: Bar Charts Custom Mark Placement
Posted: Wed Mar 23, 2016 5:16 am
by 16566546
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.
- Horizontal Axis Labels
- Image001.png (58.59 KiB) Viewed 18511 times
- Annotations clipped
- Image002.png (47.54 KiB) Viewed 18511 times
Many thanks
Errol
Re: Bar Charts Custom Mark Placement
Posted: Wed Mar 30, 2016 10:23 am
by yeray
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:
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.
Re: Bar Charts Custom Mark Placement
Posted: Wed Mar 30, 2016 11:30 pm
by 16566546
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).
- Annotations correctly aligned with bottom axis
- AnnotationsOnBottomAxis.png (75.56 KiB) Viewed 18478 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).
- Annotations not correctly aligned on top axis
- AnnotationsOnTopAxis.png (75.35 KiB) Viewed 18482 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.
- Marks slightly misaligned vertically
- MarksOffVerticalCentre.png (1.45 KiB) Viewed 18477 times
I look forward to your comments.
Re: Bar Charts Custom Mark Placement
Posted: Thu Mar 31, 2016 11:28 am
by yeray
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
Re: Bar Charts Custom Mark Placement
Posted: Thu Apr 07, 2016 10:47 pm
by 16566546
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 (13.99 KiB) Viewed 18454 times
Can you suggest a way to align the annotation with the top of the stacked bar chart.
Thanks in anticipation.
Errol
Re: Bar Charts Custom Mark Placement
Posted: Mon Apr 11, 2016 10:40 am
by yeray
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;
Re: Bar Charts Custom Mark Placement
Posted: Mon May 02, 2016 1:06 am
by 16566546
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
Re: Bar Charts Custom Mark Placement
Posted: Mon May 02, 2016 8:55 am
by yeray
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 (27.73 KiB) Viewed 18363 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;