|
Re: BubbleChart Y-AXIS String Input [message #1780816 is a reply to message #1780266] |
Sun, 28 January 2018 16:52 |
Richard Kielmann Messages: 2 Registered: January 2018 |
Junior Member |
|
|
Hello,
one Update of mine.
1. I tried fixing that problem by using a scatter chart and scripting. Unfortunately the problem here is, that I can't position the labels into the markers in a scatter chart.
Is there a way to do that through scripting?
2. I tried using a bubblechart with the same script, but I can't create an output chart that way. I will attach my BubbleChartGenerator.java file. It's not the clearest code, but it should illustrate the idea.
Could maybe someone look it up and show me how to do it properly?
Thanks again.
BubbleChartGenerator.java
public class BubbleChartGenerator
{
public final static Chart createBubble(List<BubbleDataContainer> input, Term first, Term second )
{
StringBuilder jsScript = new StringBuilder();
ChartWithAxes cwaBubble = ChartWithAxesImpl.create( );
cwaBubble.setType( "Bubble Chart" ); //$NON-NLS-1$
cwaBubble.setSubType( "Standard Bubble Chart" ); //$NON-NLS-1$
// Plot
cwaBubble.getBlock( ).setBackground( ColorDefinitionImpl.WHITE( ) );
cwaBubble.getBlock( ).getOutline( ).setVisible( true );
Plot p = cwaBubble.getPlot( );
p.getClientArea( ).setBackground( ColorDefinitionImpl.create( 255,
255,
225 ) );
// Title
cwaBubble.getTitle( )
.getLabel( )
.getCaption( )
.setValue( "Bubble Chart" ); //$NON-NLS-1$
// Legend
Legend lg = cwaBubble.getLegend( );
lg.setItemType( LegendItemType.SERIES_LITERAL );
// X-Axis
Axis xAxisPrimary = cwaBubble.getPrimaryBaseAxes( )[0];
xAxisPrimary.setType( AxisType.TEXT_LITERAL );
xAxisPrimary.getMajorGrid( ).setTickStyle( TickStyle.BELOW_LITERAL );
xAxisPrimary.getMajorGrid().getLineAttributes().setVisible(true);
xAxisPrimary.getOrigin( ).setType( IntersectionType.MIN_LITERAL );
Scale xScale = xAxisPrimary.getScale();
long numberOfXTerms = input.stream().map(x -> x.getxTerm().getName()).distinct().count();
xScale.setStep(1);
xScale.setMin(NumberDataElementImpl.create(0));
xScale.setMax(NumberDataElementImpl.create(numberOfXTerms));
xScale.setMinorGridsPerUnit(2);
xAxisPrimary.getLabel().getCaption().getFont().setRotation(45);
if(numberOfXTerms > 15){
xAxisPrimary.getLabel().getCaption().getFont().setRotation(90);
}
//TODO: Find a more intelligent way to set the rotation...
//Rotate labels even further if we have many bars
xAxisPrimary.getLabel().getCaption().getFont().setName("Arial");
// Y-Axis
Axis yAxisPrimary = cwaBubble.getPrimaryOrthogonalAxis( xAxisPrimary );
yAxisPrimary.getMajorGrid( ).setTickStyle( TickStyle.LEFT_LITERAL );
yAxisPrimary.getOrigin().setType(IntersectionType.MIN_LITERAL);
yAxisPrimary.getMajorGrid().getLineAttributes().setVisible(true);
yAxisPrimary.setType( AxisType.LINEAR_LITERAL);
yAxisPrimary.setLabelPosition(Position.LEFT_LITERAL);
yAxisPrimary.getLabel().getCaption().getFont().setWordWrap(true);
yAxisPrimary.getLabel( ).getCaption( ).getFont( ).setRotation( 90 );
long numberOfYTerms = input.stream().map(x -> x.getyTerm().getName()).distinct().count();
Scale yScale = yAxisPrimary.getScale();
yScale.setStep(1);
yScale.setMin(NumberDataElementImpl.create(0));
yScale.setMax(NumberDataElementImpl.create(numberOfYTerms + 1));
if(numberOfYTerms <= 10){
yAxisPrimary.getLabel().getCaption().getFont().setRotation(45);
yAxisPrimary.getLabel().getCaption().getFont().setName("Arial");
}
//Label span defines the margin between axis and page border.
//Setting a fixed value is far from ideal because it should depend
//on the size of the labels. Automatic label span doesn't work, since labels are change with scripts.
//The following is a bad approximation to ensure that labels aren't cut-off
OptionalInt maxStringLength = input.stream().map(x -> x.getyTerm().getName().length()).mapToInt(Integer::intValue).max();
if(maxStringLength.isPresent()){
double factor = yAxisPrimary.getLabel().getCaption().getFont().getRotation() != 0 ? 1 : 1.4;
double margin = maxStringLength.getAsInt() * 4.2 * factor;
yAxisPrimary.setLabelSpan(margin >= 20 ? margin : 20);
} else {
yAxisPrimary.setLabelSpan(75);
}
List<String> xTerms = createXTerms(input, jsScript);
TextDataSet dsNumericValues1 = TextDataSetImpl.create(xTerms);
OptionalInt maxValue = input.stream().mapToInt(x -> x.getBubbleSize()).max();
jsScript.append("var maxValue = " + maxValue.getAsInt() + ";\n");
SampleData sd = DataFactory.eINSTANCE.createSampleData( );
BaseSampleData sdBase = DataFactory.eINSTANCE.createBaseSampleData( );
sdBase.setDataSetRepresentation( "" );//$NON-NLS-1$lman
sd.getBaseSampleData( ).add( sdBase );
OrthogonalSampleData sdOrthogonal1 = DataFactory.eINSTANCE.createOrthogonalSampleData( );
sdOrthogonal1.setDataSetRepresentation( "" );//$NON-NLS-1$
sdOrthogonal1.setSeriesDefinitionIndex( 0 );
sd.getOrthogonalSampleData( ).add( sdOrthogonal1 );
//cwaBubble.setSampleData( sd );
// X-Series
Series seCategory = SeriesImpl.create( );
seCategory.setDataSet( dsNumericValues1);
SeriesDefinition sdX = SeriesDefinitionImpl.create( );
sdX.getSeriesPalette( ).shift( 0 );
xAxisPrimary.getSeriesDefinitions( ).add( sdX );
sdX.getSeries( ).add( seCategory );
SeriesDefinition sdY = SeriesDefinitionImpl.create();
yAxisPrimary.getSeriesDefinitions().add(sdY);
createYSeries(input, xTerms, sdY, jsScript);
appendJsScript(jsScript);
cwaBubble.setScript(jsScript.toString());
return cwaBubble;
}
private static List<String> createXTerms(List<BubbleDataContainer> input, StringBuilder jsScript) {
List<String> xTerms = input.stream().map(x -> x.getxTerm().getName()).distinct().sorted().collect(Collectors.toList());
jsScript.append("\n");
jsScript.append("var seriesLength = " + xTerms.size() + ";\n");
jsScript.append("var columns = " + xTerms.size() + ";\n");
return xTerms;
}
private static void createYSeries(List<BubbleDataContainer> input, List<String> xTerms, SeriesDefinition sd, StringBuilder jsScript) {
int xTermsLength = xTerms.size();
List<String> yTerms = input.stream().map(x -> x.getyTerm().getName()).distinct().sorted().collect(Collectors.toList());
StringBuilder jsLabels = new StringBuilder();
jsLabels.append("var labels = {\"0\" : \"\", ");
jsScript.append("var rows = " + (yTerms.size() + 1) + ";\n");
jsScript.append("var seriesPosition = {");
int count = 1;
for(String yTerm : yTerms){
BubbleSeries ss = (BubbleSeries) BubbleSeriesImpl.create( );
ss.getMarkers().stream().forEach(m -> m.setType(MarkerType.CIRCLE_LITERAL));
ss.getMarkers().stream().forEach(m -> m.getOutline().setColor(ColorDefinitionImpl.RED()));
ss.getMarkers().stream().forEach(m -> m.getOutline().setThickness(20));
ss.getLabel().setVisible(true);
//ss.setLabelPosition(Position.INSIDE_LITERAL);
ss.setDataSet(NumberDataSetImpl.create(DoubleStream.iterate(count, i -> i).limit(xTermsLength).toArray()));
String jsonKey = sanitizeJsonKey(yTerm);
ss.setSeriesIdentifier(jsonKey);
sd.getSeries().add(ss);
sd.getSeriesPalette().getEntries().clear();
sd.getSeriesPalette().getEntries().add(ColorDefinitionImpl.WHITE());
sd.getSeriesPalette().getEntries().add(ColorDefinitionImpl.WHITE());
sd.getSeriesPalette().getEntries().add(ColorDefinitionImpl.WHITE());
sd.getSeriesPalette().getEntries().add(ColorDefinitionImpl.WHITE());
jsScript.append("\"" + jsonKey +"\": [");
input.stream().filter(x -> x.getyTerm().getName().equals(yTerm))
.sorted((a, b) -> a.getxTerm().getName().compareTo(b.getxTerm().getName()))
.mapToInt(y -> y.getBubbleSize()).forEach(z -> {jsScript.append(z); jsScript.append(",");});
jsScript.append("],");
jsLabels.append("\"" + count + "\": \"");
jsLabels.append(yTerms.get(count - 1));
jsLabels.append("\", ");
count++;
}
jsLabels.append("\"" + (yTerms.size() + 1) + "\": \"\"};\n");
jsScript.append("};\n");
jsScript.append(jsLabels);
}
/**
* Sanitize term names (or any other string) for use as JSON key.
* @param Any string
* @return Sanitized string
*/
private static String sanitizeJsonKey(String str) {
return str.replaceAll("[^\\w]", "_");
}
/**
* Add JS code.
* @param jsValues
*/
private static void appendJsScript(StringBuilder jsValues) {
jsValues.append("var count = 0;\n");
jsValues.append("var labelCount = 0;\n");
jsValues.append("var resizeFactor;\n");
jsValues.append("/**\n");
jsValues.append(" * Called before drawing each marker.\n");
jsValues.append(" * \n");
jsValues.append(" * @param marker\n");
jsValues.append(" * Marker\n");
jsValues.append(" * @param dph\n");
jsValues.append(" * DataPointHints\n");
jsValues.append(" * @param icsc\n");
jsValues.append(" * IChartScriptContext\n");
jsValues.append(" */\n");
jsValues.append("function beforeDrawMarker( marker, dph, icsc ) {\n");
jsValues.append("\tvar seriesValue = dph.getSeriesValue();\n");
jsValues.append("\tvar size = 1;\n");
jsValues.append("\tif(seriesPosition[seriesValue] != void 0 && seriesPosition[seriesValue][count%seriesLength] != void 0){\n");
jsValues.append("\t\tsize = seriesPosition[seriesValue][count%seriesLength];\n");
jsValues.append("\t}\n");
jsValues.append("\tif(resizeFactor == void 0){\n");
jsValues.append("\t\tvar chart = icsc.getChartInstance()\n");
jsValues.append("\t\tvar bounds = chart.getBlock().getBounds();\n");
jsValues.append("\t\tvar width = bounds.getWidth();\n");
jsValues.append("\t\tvar height = bounds.getHeight();\n");
jsValues.append("\t\tvar maxSize = width/columns;\n");
jsValues.append("\t\tif(height/rows < maxSize){\n");
jsValues.append("\t\t\tmaxSize = height/columns;\n");
jsValues.append("\t\t}\n");
jsValues.append("\t\n");
jsValues.append("\t\tresizeFactor = ((maxSize/2)/maxValue) * 0.9;\n");
jsValues.append("\t}\n");
jsValues.append("\tmarker.setSize(size * resizeFactor);\n");
jsValues.append("\tcount++;\n");
jsValues.append("\tmarker.getOutline().setThickness(20);\n");
jsValues.append("}\n");
jsValues.append("/**\n");
jsValues.append(" * Called before rendering each label on a given Axis.\n");
jsValues.append(" * \n");
jsValues.append(" * @param axis\n");
jsValues.append(" * Axis\n");
jsValues.append(" * @param label\n");
jsValues.append(" * Label\n");
jsValues.append(" * @param icsc\n");
jsValues.append(" * IChartScriptContext\n");
jsValues.append(" */\n");
jsValues.append("function beforeDrawAxisLabel( axis, label, icsc )\n");
jsValues.append("{\n");
jsValues.append("\tif(labels[label.getCaption().getValue()] != void 0){\n");
jsValues.append("\t\tlabel.getCaption().setValue(labels[label.getCaption().getValue()]);\n");
jsValues.append("\t}\n");
jsValues.append("}\n");
jsValues.append("/**\n");
jsValues.append(" * Called before rendering the label for each datapoint.\n");
jsValues.append(" * \n");
jsValues.append(" * @param dph\n");
jsValues.append(" * DataPointHints\n");
jsValues.append(" * @param label\n");
jsValues.append(" * Label\n");
jsValues.append(" * @param icsc\n");
jsValues.append(" * IChartScriptContext\n");
jsValues.append(" */\n");
jsValues.append("function beforeDrawDataPointLabel( dph, label, icsc )\n");
jsValues.append("{\n");
jsValues.append("\tvar seriesValue = dph.getSeriesValue();\n");
jsValues.append("\tvar size = void 0;\n");
jsValues.append("\tif(seriesPosition[seriesValue] != void 0 && seriesPosition[seriesValue][count%seriesLength] != void 0){\n");
jsValues.append("\t\tsize = seriesPosition[seriesValue][labelCount%seriesLength];\n");
jsValues.append("\t}\n");
jsValues.append("\tlabel.getCaption().setValue(size);\n");
jsValues.append("\t(size <= 10) && label.setVisible(false);\n");
jsValues.append("\t(size > 10) && label.setVisible(true);\n");
jsValues.append("\tlabelCount++;\n");
jsValues.append("\ticsc.getChartInstance().getSeries().setLabelPosition(Position.INSIDE_LITERAL);\n");
jsValues.append("}\n");
}
}
|
|
|
Powered by
FUDForum. Page generated in 0.02947 seconds