Discussions
Categories
Groups
Community Home
Categories
INTERNAL ENABLEMENT
POPULAR
PUBLIC CLOUD
PRIVATE CLOUD
Quick Links
MY LINKS
HELPFUL TIPS
Back to website
Home
Intelligence (Analytics)
Line chart dynamic y-axis scale
yannickb
<p>I have the following in the onRender script of a line chart (can hold 2 series, but only 1 generated in the current dataset):</p>
<pre class="_prettyXprint _lang-js _linenums:5">
function beforeGeneration( chart, icsc )
{
// set y scale
//
importPackage(Packages.org.eclipse.birt.chart.model.component.impl);
importPackage(Packages.org.eclipse.birt.chart.model.attribute);
importPackage(Packages.org.eclipse.birt.chart.model.attribute.impl);
importPackage(Packages.org.eclipse.birt.chart.model.data.impl);
var chart = icsc.getChartInstance();
var yAxis = chart.getAxes().get(0).getAssociatedAxes().get(0);
var yScale = yAxis.getScale();
var tag1_max = getParamValue(icsc,"tag1_max");
var tag1_min = getParamValue(icsc,"tag1_min");
var tag2_max = getParamValue(icsc,"tag2_max");
var tag2_min = getParamValue(icsc,"tag2_min");
var max_val1 = getParamValue(icsc,"max_val1");
var min_val1 = getParamValue(icsc,"min_val1");
var max_val2 = getParamValue(icsc,"max_val2");
var min_val2 = getParamValue(icsc,"min_val2");
var min;
var max;
if (tag2_min != null)
min = Math.min(tag1_min, tag2_min, min_val1, min_val2);
else if (tag1_min != null)
min = Math.min(tag1_min, min_val1);
else
min = min_val1;
if (tag2_max != null)
max = Math.max(tag1_max, tag2_max, max_val1, max_val2);
else if (tag1_max != null)
max = Math.max(tag1_max, max_val1);
else
max = max_val1;
// breathing space
var range = max - min;
var space;
if (range > 0)
space = range * 0.1;
else
space = min * 0.1;
var minScale = min - space;
var maxScale = max + space;
yScale.setMin( NumberDataElementImpl.create(minScale) );
yScale.setMax( NumberDataElementImpl.create(maxScale) );
yAxis.setScale(yScale);
}
</pre>
<p>...which gives this output (evidently out of range/scale and hence blank):</p>
<p>
Find more posts tagged with
Comments
Clement Wong
<p>To assist you further....</p>
<p> </p>
<p>Are you using OS BIRT, or commercial BIRT? Also, what version?</p>
<p> </p>
<p>What is the expected output? Description, and/or mock-up would help.</p>
<p> </p>
<p>Do you have a sample design that goes against Classic Models that can replicate this issue?</p>
<p> </p>
<p>Or can you attach your design with sample data that we can run so that we can troubleshoot in our environment?</p>
yannickb
<p>Thank you for your reply, Clement.</p>
<p> </p>
<p>I am using OS BIRT v4.5.</p>
<p> </p>
<p>The expected output is the second attachment (output_without_space), with padding - i.e. the trendlines should not be trimmed; the yAxis min and max should be at least 10% (for example, as per my code) less than and greater than, respectively, the min and max values of the trends.</p>
<p> </p>
<p>I've attached my design with sample data.</p>
<p> </p>
yannickb
<p>Okay, I think I've found the problem - it seems the y-axis maximum cannot be a decimal; when I parse maxScale as an integer, it works.</p>
<p> </p>
<p>Not sure why it works for the minimum value regardless, can you confirm if this is the case?</p>
Clement Wong
<p>The "output_without_space" attachment was not attached.</p>
<p> </p>
<p>1. Looks like you may have stripped the Data Source and Data Set from the attached design so I needed to recreate a few bindings.</p>
<p> </p>
<p>2. I'm not sure why you are using report parameters to set and retrieve values? Please use Persistent Global Variables (PGV) instead.</p>
<p> </p>
<p>We don't need to save these values, <strong>but if you do need </strong>then you can hange onCreate from:</p>
<pre class="_prettyXprint">
reportContext.setParameterValue("tag1_min", tag1_min);
reportContext.setParameterValue("tag1_max", tag1_max);
reportContext.setParameterValue("tag2_min", tag2_min);
reportContext.setParameterValue("tag2_max", tag2_max);
reportContext.setParameterValue("min_val1", min_val1);
reportContext.setParameterValue("max_val1", max_val1);
reportContext.setParameterValue("min_val2", min_val2);
reportContext.setParameterValue("max_val2", max_val2);</pre>
<p>To:</p>
<pre class="_prettyXprint">
reportContext.setPersistentGlobalVariable("tag1_min", tag1_min);
reportContext.setPersistentGlobalVariable("tag1_max", tag1_max);
reportContext.setPersistentGlobalVariable("tag2_min", tag2_min);
reportContext.setPersistentGlobalVariable("tag2_max", tag2_max);
reportContext.setPersistentGlobalVariable("min_val1", min_val1);
reportContext.setPersistentGlobalVariable("max_val1", max_val1);
reportContext.setPersistentGlobalVariable("min_val2", min_val2);
reportContext.setPersistentGlobalVariable("max_val2", max_val2);
</pre>
<p>And in onRender from:</p>
<pre class="_prettyXprint">
var tag1_max = getParamValue(icsc,"tag1_max");
var tag1_min = getParamValue(icsc,"tag1_min");
var tag2_max = getParamValue(icsc,"tag2_max");
var tag2_min = getParamValue(icsc,"tag2_min");
var max_val1 = getParamValue(icsc,"max_val1");
var min_val1 = getParamValue(icsc,"min_val1");
var max_val2 = getParamValue(icsc,"max_val2");
var min_val2 = getParamValue(icsc,"min_val2");</pre>
<p>To:</p>
<pre class="_prettyXprint">
var tag1_max = icsc.getExternalContext().getScriptable().getPersistentGlobalVariable("tag1_max");
var tag1_min = icsc.getExternalContext().getScriptable().getPersistentGlobalVariable("tag1_min");
var tag2_max = icsc.getExternalContext().getScriptable().getPersistentGlobalVariable("tag2_max");
var tag2_min = icsc.getExternalContext().getScriptable().getPersistentGlobalVariable("tag2_min");
var max_val1 = icsc.getExternalContext().getScriptable().getPersistentGlobalVariable("max_val1");
var min_val1 = icsc.getExternalContext().getScriptable().getPersistentGlobalVariable("min_val1");
var max_val2 = icsc.getExternalContext().getScriptable().getPersistentGlobalVariable("max_val2");
var min_val2 = icsc.getExternalContext().getScriptable().getPersistentGlobalVariable("min_val2");
</pre>
<p>3. We can actually <em>delete </em>the onCreate of the cell.</p>
<p> </p>
<p>We will save the values on the onCreate of the row using PGVs. And incrementing an "index" by using the 'order' row value. So now for <strong>each </strong>group header/chart, we are saving the minimum and maximum.</p>
<pre class="_prettyXprint">
reportContext.setPersistentGlobalVariable(this.getRowData().getColumnValue("order") + "tag1_min", this.getRowData().getColumnValue("MinValue1"));
reportContext.setPersistentGlobalVariable(this.getRowData().getColumnValue("order") + "tag1_max", this.getRowData().getColumnValue("MaxValue1"));</pre>
<p>4. Added a new (invisible) series to the chart so that we can access 'order' value in the onRender. It's 'Series 7' but I renamed it to "INVISIBLE".</p>
<p> </p>
<p>5. Added to the onRender code so that we have an afterDataSetFilled to read the order.</p>
<pre class="_prettyXprint">
function afterDataSetFilled( series, dataSet, icsc )
{
// This only works in commercial BIRT
//logger = java.util.logging.Logger.getLogger("birt.report.logger");
//logger.warning ("afterDataSetFilled");
if( series.getSeriesIdentifier() == "INVISIBLE") {
var list = dataSet.getValues();
ctr = parseInt (list[0]);
//logger.warning (ctr);
}
}
</pre>
<p>And a new beforeGeneration to set the scale.</p>
<pre class="_prettyXprint">
function beforeGeneration( chart, icsc )
{
// set y scale
//
importPackage(Packages.org.eclipse.birt.chart.model.component.impl);
importPackage(Packages.org.eclipse.birt.chart.model.attribute);
importPackage(Packages.org.eclipse.birt.chart.model.attribute.impl);
importPackage(Packages.org.eclipse.birt.chart.model.data.impl);
var chart = icsc.getChartInstance();
var yAxis = chart.getAxes().get(0).getAssociatedAxes().get(0);
var yScale = yAxis.getScale();
// This only works in commercial BIRT
//logger = java.util.logging.Logger.getLogger("birt.report.logger");
//logger.warning ("beforeGeneration");
//logger.warning(ctr);
var min = icsc.getExternalContext().getScriptable().getPersistentGlobalVariable(ctr + "tag1_min");
var max = icsc.getExternalContext().getScriptable().getPersistentGlobalVariable(ctr + "tag1_max");
//logger.warning(ctr + ': ' + min);
//logger.warning(ctr + ': ' + max);
// breathing space
var range = max - min;
var space;
if (range > 0)
space = range * 0.1;
else
space = min * 0.1;
//logger.warning ('
range: ' + range);
//logger.warning ('
space: ' + space);
var minScale = ( parseFloat(min) - parseFloat(space));
var maxScale = ( parseFloat(max) + parseFloat(space));
//logger.warning ('
minScale: ' + minScale);
//logger.warning ('
maxScale: ' + maxScale);
// show full min-max range (including tag_min and tag_max)
yScale.setMin( NumberDataElementImpl.create(minScale) );
yScale.setMax( NumberDataElementImpl.create(maxScale) );
yAxis.setScale(yScale);
}
</pre>
<p>We do steps 3 - 5, we need to save the unique minimum and maximum values for each chart (each 'order' group) in a PGV. Then, when the chart is rendered, we read in the 'order' (or some unique value associated with the chart) and then access the PGV associated with it.</p>
<p> </p>
<p>I tested the revised design in OS BIRT 4.5.0 and appears to be working as I expect it. You may need to tweak it a little so it meets all your requirements.</p>
<p> </p>
<p>Attached is the design and here's screenshot of what I see on the first page: