Home
Analytics
Dynamic Y-axis scale
paqman
Hello BIRT Experts,<br />
<br />
I am trying to adjust the y-axis of a report based on a report parameter. If the report parameter is greater than the default y-axis maximum, the y-axis maximum should be set to the parameter. Otherwise, the y-axis scale should keep its default formatting.<br />
<br />
I've made some progress with the following script (note that the y and x axes are inverted in this report):<br />
<br />
<pre class='_prettyXprint _lang-auto _linenums:0'>function beforeGeneration( chart, icsc )
{
// Force the y-axis scale to increase if load mark is greater than its default
yAxis1 = chart.primaryBaseAxes[0];
yScale1 = yAxis1.getScale();
if(icsc.externalContext.scriptable.getParameterValue("LoadMark") > yScale1.getMax())
{
yScale1.setMax(NumberDataElementImpl.create(icsc.externalContext.scriptable.getParameterValue("LoadMark")));
yAxis1.setScale(yScale1);
}
}</pre>
<br />
The problem I'm having is that yScale1.getMax() is returning nothing (I'm assuming it gets set later on in the chart rendering) and the y-scale ends up always being set to the report parameter. Which event function sets the y-axis min and max, and what would be the best way to work out this problem?<br />
<br />
Thanks for your help<br />
<br />
David
Find more posts tagged with
Comments
mwilliams
What is your BIRT version? I'll check it out in your version.
paqman
We are using 2.6.1 - thanks for the help!
mwilliams
The min and max values aren't set yet in the beforeGeneration. I'll keep working to see if I can find a way to set the scale if the parameter is higher than the max.
mwilliams
Is there any way you can figure out the max value of the chart from your dataSet data so you could know in the beforeGeneration what you needed to do?
paqman
Yes, good point. I can add a script to the dataset to determine the maximum value, and then put that into a global variable.
mwilliams
Awesome. Let me know if you have any issues with this. Let us know whenever you have questions!
paqman
Will definitely have more questions in the near future!
Thanks guys
paqman
Forgot to post the working code. A report parameter, 'LoadMark', is used to draw a marker line in the chart. The script determines the maximum value of all datasets and forces the y-axis to be the value of LoadMark if LoadMark is greater than the dataset maximum. <br />
<br />
<pre class='_prettyXprint _lang-auto _linenums:0'>importPackage(Packages.org.eclipse.birt.chart.model.data.impl);
maxValue = 0;
/**
* Called before generation of chart model to GeneratedChartState.
*
*
@param
chart
* Chart
*
@param
icsc
* IChartScriptContext
*/
function beforeGeneration( chart, icsc )
{
// Force the y-axis scale to increase if the load mark is greater than its default
yAxis1 = chart.primaryBaseAxes[0];
yScale1 = yAxis1.getScale();
if (icsc.externalContext.scriptable.getParameterValue("LoadMark") > maxValue)
{
yScale1.setMax(NumberDataElementImpl.create(icsc.externalContext.scriptable.getParameterValue("LoadMark")));
yAxis1.setScale(yScale1);
}
}
/**
* Called before drawing each marker line in an Axis.
*
*
@param
axis
* Axis
*
@param
markerLine
* MarkerLine
*
@param
icsc
* IChartScriptContext
*/
function beforeDrawMarkerLine( axis, markerLine, icsc )
{
// Draw the LoadMark line if specified.
var loadMark = icsc.externalContext.scriptable.getParameterValue("LoadMark");
if (Number(loadMark) == 0)
markerLine.getLineAttributes().setVisible(false);
else
markerLine.setValue(NumberDataElementImpl.create(loadMark));
}
/**
* Called after populating the series dataset.
*
*
@param
series
* Series
*
@param
dataSet
* DataSet
*
@param
icsc
* IChartScriptContext
*/
function afterDataSetFilled( series, dataSet, icsc )
{
importPackage(Packages.java.io);
importPackage(Packages.org.eclipse.birt.chart.model.type.impl);
importPackage(Packages.org.eclipse.birt.chart.util);
importPackage(Packages.java.util);
ps = PluginSettings.instance();
dsp = ps.getDataSetProcessor(series.getClass());
if (dsp.getMaximum(dataSet) > maxValue)
{
maxValue = dsp.getMaximum(dataSet);
}
}
</pre>
mwilliams
Yeah, I completely wasn't thinking right when I answered you above. I've posted examples getting the min and max this same way before. Sorry about that! Glad you got it done the right way despite me having a brain lapse!
Feel free to post this as an example in the devShare, if you'd like!
paqman
No worries - you're allowed 1 brain lapse per 20 questions of mine that you answer
Your suggestion pointed me in the right direction, so all is good.
paqman
Actually, I just realized there's a mistake in afterDataSetFilled() - it will run through both the x and y axis for each dataset, so when the x-axis has larger numbers than the y axis, it won't work properly.
Is there a way to run getMaximum() on a single axis/component of a dataSet?
mwilliams
Yeah. Wrap your getMax code in an if statement that checks the series:
if (series.eClass().getName().equals("Series 1")){
dsp = ps.getDataSetProcessor(series.getClass());
if (dsp.getMaximum(dataSet) > maxValue)
{
maxValue = dsp.getMaximum(dataSet);
}
}
paqman
And one final thing - my chart is a flipped axis chart which seems to be causing some other issues (see attachment). In that chart, I've set the marker line to be at a value of 200 (and am using my workaround code to adjust the axis maximum accordingly). But when I check the maxValue variable in that code, it comes back as 745 and not 142 which makes me think it is looping through what appears to be the x-axis (but in reality is the y-axis in the chart, since the chart is flipped).
Is there a way to only check the one axis' value? Thanks for all the help on this one
mwilliams
Did my last post not help you? In the above code, "Series" would be the x-axis and "Series 1" would be the first y-axis series. When you flip the axis, maybe that is switched. Let me know. If not, if you can recreate the issue with the sample database and post it in here, I'll do some testing.
paqman
Sorry, I thought that was referring to the series name - didn't realize it was the eClass() property. I played around with it and checking if it equaled 'Series' was what I needed - this ignored what appeared to be the x-axis in my report and only ran through the y-axis values for all datasets.
mwilliams
So, it's good now?
paqman
All good - thanks for all the help!
mwilliams
You're very welcome!
actuser9
Hi,
I am trying to get the dynamic scale and the marker line based on the data set. X-axis seems to be working based on the series values but Y-axis does not. In the attached report, first chart has the code applied to X-axis scale and the second chart has the OnRender script applied to both X-axis and Y-axis.
Any idea why the dynamic scale logic is not working for the Y-axis?
Thanks
UY
mwilliams
When I run your report, it appears to me that the second chart's axis values are set based on the min and max values of the data in both the x and y. Am I not understanding the issue?
Edit: Is it the scale you're wanting to be fixed?
actuser9
Hi Michael,<br />
<br />
The Y-axis scale should look into the min and max values of the "Series 1" and get the Y scale. That does not seem to happen with the code below. <br />
<br />
<pre class='_prettyXprint _lang-auto _linenums:0'>if (series.getSeriesIdentifier() == "Series 1"){
//(series.eClass().getName().equals("Series 1")){
dsp = ps.getDataSetProcessor( series.getClass() );
//dataset max
ymax = dsp.getMaximum( dataSet );
ymin = dsp.getMinimum( dataSet );
}</pre>
<br />
Not sure why the code is not reading the mimimum and maximum values of "Series 1".<br />
<br />
Thanks<br />
UY
mwilliams
It is, for me, in the second chart. I'm not sure what you're seeing. Can you show me the screenshot? Maybe I'm not understanding the issue.
actuser9
Hi Michael,
I could resolve this with disabling the grouping on the X-axis series.
Thanks for all your support.
Regards
UY
mwilliams
Glad you figured it out!
klt64
<p>Hello,</p>
<p> </p>
<p>I am trying to dynamically change the multiplier and suffix on the y-axis at run time.</p>
<p> </p>
<p>For example in a bar chart if the min value of the chart is in excess of £1m, to have the scale shown as £1m, £2m,.... but if the min and max values are between £1k and £1m to have the scale shown as £1k, £2k, .....</p>
<p> </p>
<p>How might I be able to code that in the beforeGeneration() function ?</p>
<p> </p>
<p>Many thanks</p>
Clement Wong
<p>What version of BIRT are you using? Is this commercial BIRT, or open source BIRT?</p>
klt64
<p>We are using Actuate Birt Designer Professional Version 4.2.3.</p>
<p> </p>
<p>Have managed to find a working solution with the following :</p>
<p> </p>
<p>yAxis,formatSpecifier.multiplier</p>
<p>yAxis.formatSpecifier.suffix<br>
</p>
Clement Wong
<p>You can also do this in the <em>beforeRendering</em> event:</p>
<pre class="_prettyXprint">
beforeRendering: function(options, chart)
{
if (chart.getYAxisMax() < 1000000)
options.yAxis[0].labels.formatter = function() {
return (this.value / 10000) + ' K';
};
else if (chart.getYAxisMax() > 1000000)
options.yAxis[0].labels.formatter = function() {
return (this.value / 1000000) + ' M';
};
},
</pre>
<p>Attached is a sample.</p>
<p> </p>
<p>In the future, please specify what version of BIRT you are using so that we can assist you more efficiently.</p>
suresh@anumolu
<p>Clement Wong, </p>
<p> </p>
<p> </p>
<p>Qucik question: </p>
<p>what happens when you have secondary Y-axis. getYAxis just updates on primary -Yaxis. Any help would be appreciated. </p>
<p> </p>
<p>Thanks</p>
<p>Suresh</p>
Clement Wong
<p><span style="font-family:'courier new', courier, monospace;">chart.getYAxisMax()</span> only works for the first Y axis.</p>
<p> </p>
<p>However, if you want to check on the max of the secondary axis, you can get its value via:</p>
<pre class="_prettyXprint">
chart.getCore().yAxis[1].max
</pre>