Home » Archived » BIRT » [chart] with multiple categories (on x)
|
Re: [chart] with multiple categories (on x) [message #908607 is a reply to message #908333] |
Wed, 05 September 2012 16:29 |
|
Currently the only way to do this is with some scripting to move the
labels around. If you want an example of this I can post one. BTW for
crosstabs and tables, they can automatically be converted to charts.
See this post:
http://birtworld.blogspot.com/2010/04/multi-view-report-items.html
Jason
On 9/5/2012 3:25 AM, moritz du wrote:
> i need to visualize pivot tables (cross tables) in bar charts. i just switched from jfree chart (mainly beacuse of bad svg output), but with it i created such a chart:
>
>
>
> Is it possible to get multiple categories on x-Axis (a hierarchical grouping)?
>
|
|
|
Re: [chart] with multiple categories (on x) [message #908875 is a reply to message #908607] |
Thu, 06 September 2012 06:46 |
moritz du Messages: 102 Registered: February 2010 |
Senior Member |
|
|
thx jason,
In my case the tables are self made and table representation in web, pdf, excel, csv is done. Now i only need the chart. First we tried jfreechart but their svg output is unusable (no interactivity).
thx to you i can create charts from all tables as specified. the only problem remaining is the formatting of x labels for pivot tables. they have up to 3 dimension on one axis and concatenating all dimensions will be too much (the real label are much longer than in the example). in most cases the regional dimension should be separated (R3, R8 in example).
So an example how to achieve the label moving will be great.
[Updated on: Thu, 06 September 2012 07:14] Report message to a moderator
|
|
| | |
Re: [chart] with multiple categories (on x) [message #909721 is a reply to message #909445] |
Fri, 07 September 2012 16:38 |
|
If you imported the report, you should have layout, Master Page, Script, XML Source and Preview tabs. If you create a new report do you get those? You can always select the xml tab and copy and paste the report contents in. Specifically this was done with chart script. Select the chart and click on the script tab:
last = "";
function beforeDrawAxisLabel( axis, label, icsc )
{
importPackage(
Packages.org.eclipse.birt.chart.model.attribute.impl );
importPackage(
Packages.org.eclipse.birt.chart.model.attribute );
if( axis.getType() == AxisType.TEXT_LITERAL ){
var cp =label.getCaption().getValue();
if( cp.substr(0,2) == last ){
label.getCaption().setValue(cp.substr( (cp.length()-2)));
}else{
label.getCaption().setValue(cp.substr( (cp.length()-2))+"\n\r "+cp.substr(0,2));
}
last = cp.substr(0,2);
}
}
It uses a beforeDrawAxisLabel script. When using the Chart API you can set a script like:
ChartWithAxes cwaBar = ChartWithAxesImpl.create( );
cwaBar.setScript( "function afterDataSetFilled( series, idsp,Iicsc )"
+ "{importPackage(Packages.java.lang); "
+ "if (series.getLabel().isVisible() == true)"
+ "{System.out.println(\"ok\");} "
+ "else"
+ "{System.out.println(\"false\");}} "
);
Jason
|
|
| | | | | |
Re: [chart] with multiple categories (on x) [message #912470 is a reply to message #911687] |
Thu, 13 September 2012 16:31 |
|
The afterDataSetFilled was just an example of one event that you could override. You need to put the script in a Java String and use the setScript to set in on the chart. For a list of all events look at this post:
http://birtworld.blogspot.com/2010/08/birt-charting-scripting-overview.html
You could also use setScript to set a fully qualified classname that extends the ChartEventHandlerAdapter class. Like:
import org.eclipse.birt.chart.model.attribute.AxisType;
import org.eclipse.birt.chart.model.component.Axis;
import org.eclipse.birt.chart.model.component.Label;
import org.eclipse.birt.chart.script.ChartEventHandlerAdapter;
import org.eclipse.birt.chart.script.IChartScriptContext;
/**
*
*/
public class AxisScript extends ChartEventHandlerAdapter
{
/*
* (non-Javadoc)
*
* @see org.eclipse.birt.chart.script.IChartItemScriptHandler#beforeDrawAxisLabel(org.eclipse.birt.chart.model.component.Axis,
* org.eclipse.birt.chart.model.component.Label,
* org.eclipse.birt.chart.script.IChartScriptContext)
*/
public void beforeDrawAxisLabel( Axis axis, Label label,
IChartScriptContext icsc )
{
if (axis.getType() == AxisType.TEXT_LITERAL)
{
label.getCaption( ).getColor( ).set( 140, 198, 62 );
}else
{
label.getCaption().getColor( ).set( 208, 32, 0);
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.birt.chart.script.IChartItemScriptHandler#beforeDrawAxisTitle(org.eclipse.birt.chart.model.component.Axis,
* org.eclipse.birt.chart.model.component.Label,
* org.eclipse.birt.chart.script.IChartScriptContext)
*/
public void beforeDrawAxisTitle( Axis axis, Label label,
IChartScriptContext icsc )
{
if (axis.getType() == AxisType.TEXT_LITERAL)
{
label.getCaption( ).getColor( ).set( 140, 198, 62 );
}else
{
label.getCaption().getColor( ).set( 208, 32, 0);
}
}
}
and in your code you could do chart.setScript("AxisScript"); Note that this name you be fully qualified. In my example I did not have AxisScript in a package.
Jason
|
|
| | |
Re: [chart] with multiple categories (on x) [message #916986 is a reply to message #916847] |
Wed, 19 September 2012 17:57 |
|
In the report example I use row["FILIAL"]+" Week "+row["weekno"] as the expression in the birt design. This would result in category value of something like "SF Week 19". The script splits this up. When the chart engine is used in the BIRT designer it implements its on data set processor that does aggregations, etc before passing the data to the chart engine. So you need to either modify your data before passing it to the chart or implement your own data set process. Here is an example of that:
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import org.eclipse.birt.chart.api.ChartEngine;
import org.eclipse.birt.chart.device.IDeviceRenderer;
import org.eclipse.birt.chart.device.IDisplayServer;
import org.eclipse.birt.chart.exception.ChartException;
import org.eclipse.birt.chart.factory.GeneratedChartState;
import org.eclipse.birt.chart.factory.Generator;
import org.eclipse.birt.chart.factory.IDataRowExpressionEvaluator;
import org.eclipse.birt.chart.factory.IGenerator;
import org.eclipse.birt.chart.factory.RunTimeContext;
import org.eclipse.birt.chart.model.Chart;
import org.eclipse.birt.chart.model.ChartWithAxes;
import org.eclipse.birt.chart.model.ChartWithoutAxes;
import org.eclipse.birt.chart.model.attribute.Anchor;
import org.eclipse.birt.chart.model.attribute.AxisType;
import org.eclipse.birt.chart.model.attribute.Bounds;
import org.eclipse.birt.chart.model.attribute.ChartDimension;
import org.eclipse.birt.chart.model.attribute.DataType;
import org.eclipse.birt.chart.model.attribute.SortOption;
import org.eclipse.birt.chart.model.attribute.impl.BoundsImpl;
import org.eclipse.birt.chart.model.attribute.impl.ColorDefinitionImpl;
import org.eclipse.birt.chart.model.attribute.impl.GradientImpl;
import org.eclipse.birt.chart.model.component.Axis;
import org.eclipse.birt.chart.model.component.Series;
import org.eclipse.birt.chart.model.component.impl.SeriesImpl;
import org.eclipse.birt.chart.model.data.BaseSampleData;
import org.eclipse.birt.chart.model.data.DataFactory;
import org.eclipse.birt.chart.model.data.OrthogonalSampleData;
import org.eclipse.birt.chart.model.data.Query;
import org.eclipse.birt.chart.model.data.SampleData;
import org.eclipse.birt.chart.model.data.SeriesDefinition;
import org.eclipse.birt.chart.model.data.impl.QueryImpl;
import org.eclipse.birt.chart.model.data.impl.SeriesDefinitionImpl;
import org.eclipse.birt.chart.model.impl.ChartWithAxesImpl;
import org.eclipse.birt.chart.model.impl.ChartWithoutAxesImpl;
import org.eclipse.birt.chart.model.layout.Legend;
import org.eclipse.birt.chart.model.layout.Plot;
import org.eclipse.birt.chart.model.type.LineSeries;
import org.eclipse.birt.chart.model.type.PieSeries;
import org.eclipse.birt.chart.model.type.impl.LineSeriesImpl;
import org.eclipse.birt.chart.model.type.impl.PieSeriesImpl;
import org.eclipse.birt.core.framework.PlatformConfig;
/**
* Test decription:
* </p>
* Chart script: afterDataSetFilled()
* </p>
*/
public class AfterDatasetFilled
{
private static String OUTPUT = "output/DataRowEvaluator.png";
/**
* The swing rendering device
*/
private IDeviceRenderer dRenderer = null;
private IDisplayServer dServer = null;
private GeneratedChartState gcs = null;
private IGenerator gr = null;
/**
* A chart model instance
*/
private Chart cm = null;
/**
* execute application
*
* @param args
*/
public static void main( String[] args )
{
new AfterDatasetFilled( );
System.out.println("finished");
System.exit(0);
}
/**
* Constructor
*/
public AfterDatasetFilled( )
{
PlatformConfig pf = new PlatformConfig();
pf.setProperty("STANDALONE", true);
//Returns a singleton instance of the Chart Engine
ChartEngine ce = ChartEngine.instance(pf);
//Returns a singleton instance of the Generator
gr = ce.getGenerator();
try {
//device renderers for dv.SWT, dv.PNG, dv.JPG
//dv.PDF, dv.SVG, dv.SWING, dv.PNG24, div.BMP
dRenderer = ce.getRenderer("dv.PNG");
dServer = dRenderer.getDisplayServer();
} catch (Exception ex) {
ex.printStackTrace();
}
cm = createChart( );
bindGroupingData( cm );
BufferedImage img = new BufferedImage(
600,
600,
BufferedImage.TYPE_INT_ARGB );
Graphics g = img.getGraphics( );
Graphics2D g2d = (Graphics2D) g;
dRenderer.setProperty( IDeviceRenderer.GRAPHICS_CONTEXT, g2d );
dRenderer.setProperty( IDeviceRenderer.FILE_IDENTIFIER, OUTPUT ); //$NON-NLS-1$
Bounds bo = BoundsImpl.create( 0, 0, 600, 600 );
bo.scale( 72d / dRenderer.getDisplayServer( ).getDpiResolution( ) );
try
{
gcs = gr.build(
dServer,
cm,
bo,
null,
null,
null );
gr.render( dRenderer, gcs );
}
catch ( ChartException e )
{
// TODO Auto-generated catch block
e.printStackTrace( );
}
}
public Chart GetChartModel(){
return cm;
}
private void bindGroupingData( Chart chart )
{
//IDataRowExpressionEvaluator
// close, evaluate, first, and next
// Data Set
final Object[][] data =
new Object[][]
{{"x1", new Integer( 1 ), "g1"},
{"x1", new Integer( 2 ), "g2"},
{"x1", new Integer( 3 ), "g1"},
{"x1", new Integer( 4 ), "g3"},
{"x1", new Integer( 5 ), "g2"},
{"x2", new Integer( 6 ), "g1"},
{"x2", new Integer( 7 ), "g3"},
{"x2", new Integer( 8 ), "g2"},
{"x2", new Integer( 9 ), "g2"},
{"x0", new Integer( 0 ), "g2"},};
try
{
//Binds data to chart model
gr.bindData( new IDataRowExpressionEvaluator( ) {
int idx = 0;
public void close( )
{
}
public Object evaluate( String expression )
{
if ( "X".equals( expression ) )
{
return data[idx][0];
}
else if ( "Y".equals( expression ) )
{
return data[idx][1];
}
else if ( "G".equals( expression ) )
{
return data[idx][2];
}
return null;
}
public Object evaluateGlobal( String expression )
{
return evaluate( expression );
}
public boolean first( )
{
idx = 0;
return true;
}
public boolean next( )
{
idx++;
return ( idx < 9 );
}
}, chart, new RunTimeContext( ) );
}
catch ( ChartException e )
{
e.printStackTrace( );
}
}
private Chart createChart( )
{
ChartWithAxes cwaBar = ChartWithAxesImpl.create( );
// X-Axis
Axis xAxisPrimary = cwaBar.getPrimaryBaseAxes( )[0];
xAxisPrimary.setType( AxisType.TEXT_LITERAL );
// Y-Axis
Axis yAxisPrimary = cwaBar.getPrimaryOrthogonalAxis( xAxisPrimary );
yAxisPrimary.setType( AxisType.LINEAR_LITERAL );
// X-Series
Series seCategory = SeriesImpl.create( );
Query xQ = QueryImpl.create( "G" );
seCategory.getDataDefinition( ).add( xQ );
SeriesDefinition sdX = SeriesDefinitionImpl.create( );
xAxisPrimary.getSeriesDefinitions( ).add( sdX );
sdX.getSeries( ).add( seCategory );
// -------------------------------------------------------------
sdX.setSorting( SortOption.ASCENDING_LITERAL );
sdX.getGrouping( ).setEnabled( true );
sdX.getGrouping( ).setGroupType( DataType.TEXT_LITERAL );
sdX.getGrouping( ).setAggregateExpression( "Sum" );
sdX.getGrouping( ).setGroupingInterval( 0 );
// -------------------------------------------------------------
// Y-Series
LineSeries ls = (LineSeries) LineSeriesImpl.create( );
ls.getLabel( ).setVisible( true );
Query yQ = QueryImpl.create( "Y" );
ls.getDataDefinition( ).add( yQ );
SeriesDefinition sdY = SeriesDefinitionImpl.create( );
Query query = QueryImpl.create( "X" );//$NON-NLS-1$
sdY.setQuery( query );
yAxisPrimary.getSeriesDefinitions( ).add( sdY );
sdY.getSeriesPalette( ).shift( 0 );
sdY.getSeries( ).add( ls );
return cwaBar;
}
}
Jason
|
|
| |
Re: [chart] with multiple categories (on x) [message #917478 is a reply to message #908333] |
Thu, 20 September 2012 05:54 |
moritz du Messages: 102 Registered: February 2010 |
Senior Member |
|
|
thx jason
i came to work, the first thing i did was pressing f5 on this thread's tab and i am glad to see your answer.
i just tired your example it yields an line chart with 2 lines. But i don't get the link to your "adjustxaxislabelsmultiline.rptdesign" report.
I probably don't understand "In the report example I use row["FILIAL"]+" Week "+row["weekno"] as the expression in the birt design."
Or how to do this in java. In this example it seems that each bar has 2 labels given via separate array indexes. And your "beforeDrawAxisLabel" moves the second label - the filial name. I don't really understand the moving - or how it would look without this script. i guess "var cp =label.getCaption().getValue();" will only return the filial name not the week number?
(i attached the output as pdf, as i mentioned some day ago i can't preview the report nor use "Web Viewer", only the other file formats work. i also attached the source - it was converted to birt 4.2 by eclipse - don't no if this changed something else)
so at the moment my problem is the same - how to get a bar chart like "adjustxaxislabelsmultiline" with java. and if i got this i could try to apply your script. (but probably i misunderstood some other things?)
[Updated on: Thu, 20 September 2012 07:05] Report message to a moderator
|
|
|
Re: [chart] with multiple categories (on x) [message #917956 is a reply to message #917478] |
Thu, 20 September 2012 15:42 |
|
The x-axis does not have two labels, it has one that that the script splits into two lines. From a Java perspective this would look like:
TextDataSet dsStringValue = TextDataSetImpl.create( new String[]{
"SF Week 19", "SF Week 20", "KF Week 19", "KF Week 20", "PF Week 19", "PF Week 20" } );
Series seCategory = SeriesImpl.create( );
seCategory.setDataSet( dsStringValue );
So this script:
last = "";
function beforeDrawAxisLabel( axis, label, icsc )
{
importPackage(
Packages.org.eclipse.birt.chart.model.attribute.impl );
importPackage(
Packages.org.eclipse.birt.chart.model.attribute );
if( axis.getType() == AxisType.TEXT_LITERAL ){
var cp =label.getCaption().getValue();
if( cp.substr(0,2) == last ){
label.getCaption().setValue(cp.substr( (cp.length()-2)));
}else{
label.getCaption().setValue(cp.substr( (cp.length()-2))+"\n\r "+cp.substr(0,2));
}
last = cp.substr(0,2);
}
}
So for the first label that comes in this line:
label.getCaption().setValue(cp.substr( (cp.length()-2))+"\n\r "+cp.substr(0,2));
puts the week number on top and the Fial number on the bottom. The second label will just put the week number on top:
label.getCaption().setValue(cp.substr( (cp.length()-2)));
The reason I posted the afterdatasetfilled example was to show you how the data for a chart could be made to be dynamic if you wanted it to.
Jason
|
|
| |
Re: [chart] with multiple categories (on x) [message #919079 is a reply to message #918612] |
Fri, 21 September 2012 17:03 |
|
public static final Chart createBarChart( )
{
ChartWithAxes cwaBar = ChartWithAxesImpl.create( );
// Chart Type
cwaBar.setType( "Bar Chart" );
cwaBar.setScript("AxisScriptSplit");
cwaBar.getTitle().setVisible(false);
cwaBar.getBlock( ).setBackground( ColorDefinitionImpl.WHITE( ) );
// Legend
Legend lg = cwaBar.getLegend( );
lg.setVisible( false );
// X-Axis
Axis xAxisPrimary = ( (ChartWithAxesImpl) cwaBar ).getPrimaryBaseAxes( )[0];
xAxisPrimary.getTitle( ).setVisible( false );
xAxisPrimary.setType( AxisType.TEXT_LITERAL );
xAxisPrimary.getOrigin( ).setType( IntersectionType.VALUE_LITERAL );
//xAxisPrimary.getLabel( ).getCaption( ).setColor(
// ColorDefinitionImpl.GREEN( ).darker( ) );
xAxisPrimary.getLabel( ).getCaption( ).getFont( ).setSize(6);
xAxisPrimary.setLabelSpan(30);
// Y-Axis
Axis yAxisPrimary = ( (ChartWithAxesImpl) cwaBar )
.getPrimaryOrthogonalAxis( xAxisPrimary );
yAxisPrimary.getLabel( ).getCaption( ).setValue( "Sales Growth" ); //$NON-NLS-1$
yAxisPrimary.getLabel( ).getCaption( ).setColor(
ColorDefinitionImpl.BLUE( ) );
yAxisPrimary.getLabel( ).getCaption( ).getFont( ).setSize(6);
yAxisPrimary.getTitle( ).setVisible( false );
yAxisPrimary.setType( AxisType.LINEAR_LITERAL );
yAxisPrimary.getOrigin( ).setType( IntersectionType.VALUE_LITERAL );
TextDataSet dsStringValue = TextDataSetImpl.create( new String[]{
"SF Week 19", "SF Week 20", "KF Week 19", "KF Week 20", "PF Week 19", "PF Week 20" } );
NumberDataSet dsNumericValues1 = NumberDataSetImpl
.create( new double[]{43.26, 56.55, 75.25, 47.56, 55.55, 32.1} );
// X-Series
Series seBase = SeriesImpl.create( );
seBase.setDataSet( dsStringValue );
SeriesDefinition sdX = SeriesDefinitionImpl.create( );
xAxisPrimary.getSeriesDefinitions( ).add( sdX );
sdX.getSeries( ).add( seBase );
// Y-Series
BarSeries bs = (BarSeries) BarSeriesImpl.create( );
bs.getLabel( ).getCaption( ).setColor( ColorDefinitionImpl.RED( ) );
bs.getLabel( ).setBackground( ColorDefinitionImpl.CYAN( ) );
bs.getLabel( ).setVisible( true );
bs.setDataSet( dsNumericValues1 );
bs.setStacked( false );
SeriesDefinition sdY = SeriesDefinitionImpl.create( );
yAxisPrimary.getSeriesDefinitions( ).add( sdY );
sdY.getSeriesPalette( ).update( ColorDefinitionImpl.GREEN( ) );
sdY.getSeries( ).add( bs );
return cwaBar;
}
Use the following for the AxisScriptSplit class:
import org.eclipse.birt.chart.model.attribute.AxisType;
import org.eclipse.birt.chart.model.component.Axis;
import org.eclipse.birt.chart.model.component.Label;
import org.eclipse.birt.chart.script.ChartEventHandlerAdapter;
import org.eclipse.birt.chart.script.IChartScriptContext;
/**
*
*/
public class AxisScriptSplit extends ChartEventHandlerAdapter
{
String last ="";
public void beforeDrawAxisLabel( Axis axis, Label label,
IChartScriptContext icsc )
{
if (axis.getType() == AxisType.TEXT_LITERAL)
{
String cp =label.getCaption().getValue();
if( cp.substring(0,2).compareToIgnoreCase(last) == 0){
label.getCaption().setValue(cp.substring( (cp.length()-2)));
}else{
label.getCaption().setValue(cp.substring( (cp.length()-2))+"\n\r "+cp.substring(0,2));
last = cp.substring(0,2);
}
}
}
}
If you put the AxisScriptClass in a package make sure to change the setScript method to include the package name. A pic out the output is attached.
|
|
| | | |
Re: [chart] with multiple categories (on x) [message #934166 is a reply to message #933689] |
Fri, 05 October 2012 18:19 |
|
This is a bit tougher. In the beforeGeneration you should be able to get the number of series count (in this case bars)
//global bar count
bar_count=0;
function beforeGeneration(chart, icsc)
{
importPackage( Packages.org.eclipse.birt.chart.model.attribute );
xAxis = chart.getBaseAxes()[0];
yAxis = chart.getOrthogonalAxes( xAxis, true)[0]
seriesDef = yAxis.getSeriesDefinitions().get(0)
runSeries = seriesDef.getRunTimeSeries();
bar_count = runSeries.size();
}
You should be able to use bar count in your script as it runs later. You should be able to convert this script to Java as well.
Take a look at this post to see how wide a datapoint set will be:
http://birtworld.blogspot.com/2012/06/birt-area-chart-modifications.html
You should be able to come up with a calculation to add a number of spaces.
Jason
|
|
| |
Goto Forum:
Current Time: Fri Dec 13 15:31:59 GMT 2024
Powered by FUDForum. Page generated in 0.04844 seconds
|