ASE Home Page Products Download Purchase Support About ASE
ChartDirector Support
Forum HomeForum Home   SearchSearch

Message ListMessage List     Post MessagePost Message

  Grid Line
Posted by Sean L on Jun-23-2023 02:20
Hi Peter,

  I have a bar chart that has both positive and negative values. I need to hide all horizontal grid lines BUT keep the 1 horizontal gridline @ y=0.

Here is what I tried:
double[] data = {-56, 156, 179.5, 211, 123};
String[] labels = {"2020","2019","2018","2017","2016"};

VErsion 1:
  When i use the standard bar chart code snippet and hide the gridlines (set hGridColor of the setPlotArea), I lose the horizontal line @ y=0

Version 2:
  When I use the setAxisAtOrigin(1), I get the desired horizontal line @ y=0 but the x-axis labels are now displayed right under this line - not good if there are negative values as the negative bar overlaps the label

Is there a way to get the line @ y=0 with grid lines hidden AND display the labels at the bottom? If all values are +ve, there is no issues.

Note: I tried to hack by adding a line layer with all zero values BUT the horizontal line does not extend all the way to the y-axis but stops at the middle of the first bar.
   I tried Chart.addline() method but could not figure out the x,y, parm for this method dynamically

Thanks in advance

  Re: Grid Line
Posted by Sean L on Jun-23-2023 18:30
Hi Peter,

  Upon further digging, I was able to find 2 XYChart methods to get the coordinates. I used the following code.

*******************************
double[] data = {-256, 156, 179.5, 211, 823};


        int xcor;
        int ycor;


      String[] labels = {"2020","2019","2018","2017","2016"};


        XYChart c = new XYChart(600, 550);


        c.setPlotArea(30, 20, 500, 300,-1,-1,Chart.Transparent,Chart.Transparent);

     xcor= c.getXCoor(0);
     ycor= c.getYCoor(0);



        c.addBarLayer(data).setBarWidth(45);
        c.addLine(xcor,ycor,xcor+300,ycor,0x99004c,5);
// Set the labels on the x axis.
      c.xAxis().setLabels(labels);

        byte[] byteArray2  = c.makeChart2(5);
*****************************************

I am running into an issue with this approach.

Scenario 1: If there are no NEGATIVE values in data array, the ycor is correct. I am good here. In fact in this case, I don't even need to draw the line as the hidegridlines leaves the X-axis intact

Scenario 2: Is there are negative values, the  ycor= c.getYCoor(0) returns 320 which corresponds to the y coordinate of the xaxis crossover. i.e. the line I draw overlaps with the x-axis.  I can see 320 = 300+20 which are y-coordinates of the plotarea.
What am I missing in case of negative values?

  Re: Grid Line
Posted by Sean L on Jun-23-2023 19:20
BTW - I was able to get the y-cor manually from the SVG file (ycor = 227.5 Line #8 below) which matches perfectly

*********************************
<svg viewBox='0 0 600 550' width='600' height='550' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' xml:space='preserve'><style>text,tspan {white-space:pre}</style><g font-family='Arial' font-size='11px' fill='none' fill-rule='evenodd' stroke-linecap='square' stroke-miterlimit='1.42'>
<rect id='b24' x='0' y='0' width='600' height='550'/><use xlink:href='#b24' fill='#FFFFFF'/>
<rect id='b25' x='58.5' y='227.5' width='44' height='53'/><use xlink:href='#b25' fill='#FF3333' stroke='#000000'/>
<rect id='b26' x='158.5' y='195.5' width='44' height='32'/><use xlink:href='#b26' fill='#FF3333' stroke='#000000'/>
<rect id='b27' x='258.5' y='190.5' width='44' height='37'/><use xlink:href='#b27' fill='#FF3333' stroke='#000000'/>
<rect id='b28' x='358.5' y='183.5' width='44' height='44'/><use xlink:href='#b28' fill='#FF3333' stroke='#000000'/>
<rect id='b29' x='458.5' y='57.5' width='44' height='170'/><use xlink:href='#b29' fill='#FF3333' stroke='#000000'/>
<line id='b30' x1='30.5' y1='310.5' x2='30.5' y2='20.5'/><use xlink:href='#b30' stroke='#000000'/><line id='b31' x1='26.5' y1='310.5' x2='29.5' y2='310.5'/><use xlink:href='#b31' stroke='#000000'/><line id='b32' x1='26.5' y1='289.5' x2='29.5' y2='289.5'/><use xlink:href='#b32' stroke='#000000'/><line id='b33' x1='26.5' y1='269.5' x2='29.5' y2='269.5'/><use xlink:href='#b33' stroke='#000000'/><line id='b34' x1='26.5' y1='248.5' x2='29.5' y2='248.5'/><use xlink:href='#b34' stroke='#000000'/><line id='b35' x1='26.5' y1='227.5' x2='29.5' y2='227.5'/><use xlink:href='#b35' stroke='#000000'/><line id='b36' x1='26.5' y1='206.5' x2='29.5' y2='206.5'/><use xlink:href='#b36' stroke='#000000'/><line id='b37' x1='26.5' y1='186.5' x2='29.5' y2='186.5'/><use xlink:href='#b37' stroke='#000000'/><line id='b38' x1='26.5' y1='165.5' x2='29.5' y2='165.5'/><use xlink:href='#b38' stroke='#000000'/><line id='b39' x1='26.5' y1='144.5' x2='29.5' y2='144.5'/><use xlink:href='#b39' stroke='#000000'/><line id='b40' x1='26.5' y1='124.5' x2='29.5' y2='124.5'/><use xlink:href='#b40' stroke='#000000'/><line id='b41' x1='26.5' y1='103.5' x2='29.5' y2='103.5'/><use xlink:href='#b41' stroke='#000000'/><line id='b42' x1='26.5' y1='82.5' x2='29.5' y2='82.5'/><use xlink:href='#b42' stroke='#000000'/><line id='b43' x1='26.5' y1='61.5' x2='29.5' y2='61.5'/><use xlink:href='#b43' stroke='#000000'/><line id='b44' x1='26.5' y1='41.5' x2='29.5' y2='41.5'/><use xlink:href='#b44' stroke='#000000'/><line id='b45' x1='26.5' y1='20.5' x2='29.5' y2='20.5'/><use xlink:href='#b45' stroke='#000000'/><text id='b46' style="font-family:'Arial';font-size:11px;" x='2' y='314' textLength='22'>-400</text><use xlink:href='#b46' fill='#000000'/><text id='b47' style="font-family:'Arial';font-size:11px;" x='2' y='293' textLength='22'>-300</text><use xlink:href='#b47' fill='#000000'/><text id='b48' style="font-family:'Arial';font-size:11px;" x='2' y='273' textLength='22'>-200</text><use xlink:href='#b48' fill='#000000'/><text id='b49' style="font-family:'Arial';font-size:11px;" x='2' y='252' textLength='22'>-100</text><use xlink:href='#b49' fill='#000000'/><text id='b50' style="font-family:'Arial';font-size:11px;" x='18' y='231' textLength='6'>0</text><use xlink:href='#b50' fill='#000000'/><text id='b51' style="font-family:'Arial';font-size:11px;" x='6' y='210' textLength='18'>100</text><use xlink:href='#b51' fill='#000000'/><text id='b52' style="font-family:'Arial';font-size:11px;" x='6' y='190' textLength='18'>200</text><use xlink:href='#b52' fill='#000000'/><text id='b53' style="font-family:'Arial';font-size:11px;" x='6' y='169' textLength='18'>300</text><use xlink:href='#b53' fill='#000000'/><text id='b54' style="font-family:'Arial';font-size:11px;" x='6' y='148' textLength='18'>400</text><use xlink:href='#b54' fill='#000000'/><text id='b55' style="font-family:'Arial';font-size:11px;" x='6' y='128' textLength='18'>500</text><use xlink:href='#b55' fill='#000000'/><text id='b56' style="font-family:'Arial';font-size:11px;" x='6' y='107' textLength='18'>600</text><use xlink:href='#b56' fill='#000000'/><text id='b57' style="font-family:'Arial';font-size:11px;" x='6' y='86' textLength='18'>700</text><use xlink:href='#b57' fill='#000000'/><text id='b58' style="font-family:'Arial';font-size:11px;" x='6' y='65' textLength='18'>800</text><use xlink:href='#b58' fill='#000000'/><text id='b59' style="font-family:'Arial';font-size:11px;" x='6' y='45' textLength='18'>900</text><use xlink:href='#b59' fill='#000000'/><text id='b60' style="font-family:'Arial';font-size:11px;" x='0' y='24' textLength='24'>1000</text><use xlink:href='#b60' fill='#000000'/><text id='b61' style="font-family:'Arial';font-size:11px;" x='69' y='325' textLength='24'>2020</text><use xlink:href='#b61' fill='#000000'/><text id='b62' style="font-family:'Arial';font-size:11px;" x='169' y='325' textLength='24'>2019</text><use xlink:href='#b62' fill='#000000'/><text id='b63' style="font-family:'Arial';font-size:11px;" x='269' y='325' textLength='24'>2018</text><use xlink:href='#b63' fill='#000000'/><text id='b64' style="font-family:'Arial';font-size:11px;" x='369' y='325' textLength='24'>2017</text><use xlink:href='#b64' fill='#000000'/><text id='b65' style="font-family:'Arial';font-size:11px;" x='469' y='325' textLength='24'>2016</text><use xlink:href='#b65' fill='#000000'/><rect id='b66' x='0' y='541' width='600' height='9'/><use xlink:href='#b66' fill='#FFFF00'/><text id='b67' style="font-family:'Arial';font-size:9px;" x='184' y='548' textLength='232'>ChartDirector (unregistered) from www.advsofteng.com</text><use xlink:href='#b67' fill='#000000'/></g></svg>

*****************

  Re: Grid Line
Posted by Peter Kwan on Jun-23-2023 20:30
Hi Sean,

The easiest way to add a grid line at any position is to use Axis.addMark.

See:https://www.advsofteng.com/doc/cdnet.htm#markzone.htm

For your case, you can just add a mark line at y = 0.

c.yAxis().addMark(0, 0x000000, "0", "Arial", 8);

The getXCoor and getYCoor methods only works after you have already "make" the chart.
It is because the x and y axis scale depends on all your data. Before your code "make" the chart (create a chart image), ChartDirector cannot know if you have already added all the data, so it would not bother to automatically determine the axis scale. Without fixing the axis scale, it cannot know the correct pixel coordinates of any value.

The document methods several methods you can call first, so that ChartDirector will fix the axis scale, and then you can use getXCoor and getYCoor.

https://www.advsofteng.com/doc/cdnet.htm#Layer.getXCoor.htm

Best Regards
Peter Kwan

  Re: Grid Line
Posted by Sean L on Jun-23-2023 21:45
Hi Peter

  As always, thanks for the quick response. I now understand why the get* methods did not work as I expected.

  Your solution works like a charm.

On a related note, I also have a need to position the Legend at the same x-coordinate as the x axis at the zero crossover. So I may have a NEED to obtain the x,y coordinates for a specific condition.

  In general if I had a (theoretical) need to obtain coordinates of a specific object - say the y-coordinate of the top of the tallest bar, can I leverage parsing the SVG file to get the required coordinates. This is a a extreme theoretical use case and I ask purely out of academic interest.

Thanks
Sean

  Re: Grid Line
Posted by Sean L on Jun-23-2023 21:49
I just moved the getx* statement after makechart and I see the correct  x,y coordinates. Maybe I can use this approach to get the specific values as opposed to parsing the SVG?

  Re: Grid Line
Posted by Peter Kwan on Jun-23-2023 22:43
Hi Sean L,

The most common method of using getXCoor and getYCoor is like:

(a) Create the chart as usual, and add all the data and layers to the chart

(b)
// Ask ChartDirector for fix the axis scale based on the data available. After calling
// layoutAxes, you cannot add more data layers to the chart, but you can add custom
// lines, text labels, etc, and you can still move the legend box.
c.layoutAxes();

(c) You can now use getXCoor and getYCoor.

If you want to get the coordinates of the tallest bar, you can use getXCoor/getYCoor at (c). If you want to add some text at the top of the tallest bar, there are other methods, such as using Layer.addCustomAggregateLabel (at a label at the data end - the top end for positive bars) of a given bar.

Best Regards
Peter Kwan

  Re: Grid Line
Posted by Sean L on Jun-29-2023 19:18
A quick follow up> Looking at my bar chart  data

double[] data = {-256, 156, 179.5, 211, 823};
String[] labels = {"2020","2019","2018","2017","2016"};

I am able to get the ycoor by passing the desired y-axis value.
However if I wanted to get the xcor, the only x-axis values I have are the ones in the labels array. If I pass any of the label values in the method, I get xcor way larger than the chart size.

In general, how do I get the xcooor when the x-axis values are string or some data type not compatible with the int type the method requires me to pass?

Thanks

  Re: Grid Line
Posted by Sean L on Jun-29-2023 19:20
In the case of the bar chart, any xcoor I get represents the xcoor corresponding to the MIDDLE of the given bar and not the right or left edge (my questionable observation )

  Re: Grid Line
Posted by Peter Kwan on Jun-29-2023 23:20
Hi Sean L,

The items in the labels array are just for human reading only and have no meaning to ChartDirector. For example, you can use {"Apple", "1286", "Elephant", "Apple", "Apple"} as labels, and ChartDirector will just display them on the chart.

For label based axis, the coordinates are the array index 0, 1, 2, 3, ... The x=0 is the position of the first label, and x=1 is the position of the second label, and so on.

If you do not specify the x-coordinates for the bar (there is no Layer.setXData), ChartDirector will also use the array indices as the x-coordinates. That's why the bars match the labels.

The bars are drawn centered on its x-coordinate. The bar width can be specified using BarLayer.setBarWidth, or you may specify the gap between the bars (which indirectly set the bar width) using BarLayer.setBarGap. If you do not specify the bar width or bar gap, the default is to use 0.25 (25%) as the bar gap.

See:

https://www.advsofteng.com/doc/cdnet.htm#BarLayer.setBarGap.htm
https://www.advsofteng.com/doc/cdnet.htm#BarLayer.setBarWidth.htm
https://www.advsofteng.com/doc/cdnet.htm#gapbar.htm

Best Regards
Peter Kwan

  Re: Grid Line
Posted by Sean L on Jun-30-2023 01:00
Got it. I used the subscript value as you stated and all looks good

  Re: Grid Line
Posted by Sean L on Jun-30-2023 18:58
In the case of the bar chart, any xcoor I get represents the xcoor corresponding to the MIDDLE of the given bar and not the right or left edge (my questionable observation )