Recent

Author Topic: T a Chart box and whisker width  (Read 5829 times)

M@RIU5

  • Newbie
  • Posts: 4
T a Chart box and whisker width
« on: January 11, 2015, 08:56:15 pm »
Hi
I am plotting data using Tchart box and whisker series  but the box widths appears to randomly decide what they want to plot at. I had a look at the demo samples and use  both the following addxy() functions to load the data with the same results. Resulting graph attached. Any ideas how to work around this please?

 While not dm1.tblroughdist.eof do
        begin
        ylist[1] := dm1.tblroughdist.FieldByName('p_low').value;   //lower whisker
        ylist[2] := dm1.tblroughdist.FieldByName('p10').value;     //lower bound of box
        ylist[3] := dm1.tblroughdist.FieldByName('p50').value;     //medium line
        ylist[4] := dm1.tblroughdist.FieldByName('p90').value;  //upper bound of box
        ylist[5] := dm1.tblroughdist.FieldByName('p_high').value;    //upper whisker
        chart2boxandwhiskerseries1.AddXY(
        dm1.tblroughdist.FieldByName('surveyyear').value,//AX
        dm1.tblroughdist.FieldByName('p50').value,//Ay
        ylist);
        chart2.Repaint;
        dm1.tblroughdist.next;

        end;
        chart2.Repaint;     
 
//function overload 2

 //rut
        chart3boxandwhiskerseries1.BoxWidth:=30;
        chart3boxandwhiskerseries1.WhiskersWidth:=30;
        chart3boxandwhiskerseries1.ListSource.ycount := dm1.tblrutdist.RecordCount;
        dm1.tblrutdist.first;
        While not dm1.tblrutdist.eof do
        begin
        chart3boxandwhiskerseries1.AddXY(
        dm1.tblrutdist.FieldByName('surveyyear').value,//AX
        dm1.tblrutdist.FieldByName('p_low').value,//AYlowWhisker
        dm1.tblrutdist.FieldByName('p10').value,//Aylowbox
        dm1.tblrutdist.FieldByName('p50').value,//Ay
        dm1.tblrutdist.FieldByName('p90').value,//Ayhibox
        dm1.tblrutdist.FieldByName('p_high').value,//Ayhiwisker
        '',//axlabel
        clred//Acolor
        );
        dm1.tblrutdist.next;
        end;                       

wp

  • Hero Member
  • *****
  • Posts: 13511
Re: T a Chart box and whisker width
« Reply #1 on: January 11, 2015, 10:49:24 pm »
Sorry, I don't quite understand what the issue is and how your code relates to the screenshots shown. They just look as if the y values are screwed up.

Have a look at wiki.lazarus.freepascal.org/TAChart_documentation  for some documentation of TAChart in general and the box/whisker series in particular.

Generally, when working with Box-Whisker-Series I'd prefer the AddXY overload with the many parameters (your second code snippet) since it is clear which parameter means what:
Code: [Select]
function TBoxAndWhiskerSeries.AddXY( AX, AYLoWhisker, AYLoBox, AY, AYHiBox, AYHiWhisker: Double;
      AXLabel: String = ''; AColor: TColor = clTAColor): Integer;

In addition this method uses the correct YCount value of the ChartSource now (you have to use Lazarus trunk to get that feature, otherwise you have to set YCount to 5 manually before populating the series - see also below).

The shorter method with the YList is more complicated because the YList is to be counted in addition to the ordinary Y value provided as the second parameter of the AddXY call. Therefore YCount is equal to the length of the YList plus 1 (for the ordinary Y), and Y[0] = LoWhisker is Y, Y[1]=YLoBox is YList[0], etc. Therefore, your first code snipped is not correct since it screws up the Y values. That's the way it should be (with some optimizations as explained below):
Code: [Select]
var
  ylist: array[0..3] of double;
...
  chart2boxandwhiskerseries1.ListSource.YCount = 5;  // Prepare space for 5 y values
  chart2boxandwhiskerseries1.ListSource.BeginUpdate;
  dm1.tblroughdist.DisableControls;
  try
    while not dm1.tblroughdist.eof do
    begin
      ylist[0] := dm1.tblroughdist.FieldByName('p10').value;     // Y[1] = lower bound of box --> see doc!
      ylist[1] := dm1.tblroughdist.FieldByName('p50').value;     // Y[2] = medium line
      ylist[2] := dm1.tblroughdist.FieldByName('p90').value;    // Y[3] = upper bound of box
      ylist[3] := dm1.tblroughdist.FieldByName('p_high').value;    //Y[4] = upper whisker
      chart2boxandwhiskerseries1.AddXY(
          dm1.tblroughdist.FieldByName('surveyyear').value,  //AX
          dm1.tblroughdist.FieldByName('p_low').value,   // Y[0] = lower whisker         
          ylist);
      dm1.tblroughdist.next;
    end;
  finally
    dm1.tblroughdist.EnableControls;
    chart2boxandwhisherseries1.ListSource.EndUpdate;
  end;

There is no need to call Chart.Repaint explicitly, this is done automatically whenever data points are added. Conversely, I'd recommend to turn off repainting while the series is populated because it can slow down the program. This can be done by calling "BeginUpdate"/"EndUpdate" of the ChartSource before/after populating, just like shown above - if you add data by calling AddXY of the series then the ChartSource can be accessed by the ListSource of the series.

Another optimization is the database access which you are using. If the table that you want to plot is linked to data-sensitive controls like a DBGrid it is highly recommended to disable updating the visual controls while you are looping through all records for building the series. This is done by calling "DisableControls"/"EnableControls" of the dataset.
« Last Edit: January 11, 2015, 11:16:32 pm by wp »

M@RIU5

  • Newbie
  • Posts: 4
Re: T a Chart box and whisker width
« Reply #2 on: January 12, 2015, 01:53:12 am »
Thanks WP

My issue relates to the box width. If I set the width for both the box and whisker to 30 why does the box width varies for the different survey years?
The code below  generates the texture graph(the green box and whisker graph) as Shown in the attached screenshot the box and whisker widths vary from year to year?
 //text

        chart4boxandwhiskerseries1.BoxWidth:=30;
        chart4boxandwhiskerseries1.WhiskersWidth:=30;
        chart4boxandwhiskerseries1.ListSource.ycount := dm1.tbltextdist.RecordCount;
        dm1.tbltextdist.first;
        While not dm1.tbltextdist.eof do
        begin
        chart4boxandwhiskerseries1.AddXY(
        dm1.tbltextdist.FieldByName('surveyyear').value,//AX
        dm1.tbltextdist.FieldByName('p_low').value,//AYlowWhisker
        dm1.tbltextdist.FieldByName('p10').value,//Aylowbox
        dm1.tbltextdist.FieldByName('p50').value,//Ay
        dm1.tbltextdist.FieldByName('p90').value,//Ayhibox
        dm1.tbltextdist.FieldByName('p_high').value,//Ayhiwisker
        '',//axlabel
        clgreen//Acolor
        );
        dm1.tbltextdist.next;
        end;                                   

wp

  • Hero Member
  • *****
  • Posts: 13511
Re: T a Chart box and whisker width
« Reply #3 on: January 12, 2015, 12:18:46 pm »
Please see the attached demo project based on your screen shots.

The BoxWidth and WhiskerWidths are not given in pixels, but they are calculated for each data point as the percentages of the interval between the previous and next data x value. Therefore, I'd guess that your data are not sorted - for non-sorted data, the x-intervals of subsequent data points vary. Please sort your data by the year.

In my "Roughness" plot, the 1st bar, however, is wider because of the missing data points for the next years. From your screenshot I guess that you may have added zeros to fill the gap, but probably not in order. Using the current trunk version of TAChart/Lazarus you can avoid this by changing the new property "WidthStyle" to "bwsPercentMin" which uses the smallest data point interval to calculate the bar widths. But again, x must be sorted.

To get this feature either install the current trunk version of Lazarus, or copy the ]"]>BlockedltiSeries.pas from the attached zip file into your project folder or - if this does not work - to the folder "components\tachart" of your Lazarus installation; in the latter case you must recompile Lazarus (menu "Tools" / "Build Lazarus with profile xxx"), and you must repeat this every time you install a new Lazarus version until the new unit is in Lazarus stable.

Still a few comments on your code:
  • The YCount of the Box/Whisker series' ListSource is the number of y values per data point, and this is 5, not the recordcount of the underlying data table.
  • It is better to define the series color by means of the Box/Whisker series' BoxBrush.Color than assigning it to each data point - if you need a legend then the legend symbol will not be drawn in the correct color. The idea behind the color parameter of the AddXY method is the possibility to highlight some data points by giving them a different color.

M@RIU5

  • Newbie
  • Posts: 4
Re: T a Chart box and whisker width
« Reply #4 on: January 12, 2015, 08:13:53 pm »
Thanks WP

That solved the issue. Can you please direct me to how/where I can find the trunk version of TaChart and instructions for installation?

wp

  • Hero Member
  • *****
  • Posts: 13511
Re: T a Chart box and whisker width
« Reply #5 on: January 12, 2015, 09:42:42 pm »
My name "trunk version of TAChart" is a bit unprecise: since TAChart is part of Lazarus you have to use the trunk version of Lazarus

I assume that you are on Windows. Then this link http://wiki.lazarus.freepascal.org/Installing_Lazarus#Installing_from_source_starting_with_a_stable_release is probably what you need. Before you do this you should install "tortoisesvn" (http://tortoisesvn.net/index.de.html) which provides nice explorer extensions to simplify access to the svn source code repository of Lazarus (and others).

Or: you could just wait a few weeks, Lazarus 1.4RC1 with a standard installer is on its way, the new TAChart will be contained in this version.

Ah, and I forgot in the previous posting that you can also call "Chart1BoxWhiskerSeries.Sorted := true" to sort the data points by the x value.
« Last Edit: January 12, 2015, 11:07:19 pm by wp »

 

TinyPortal © 2005-2018