I'm building multiple stacked bar charts (subplots) that are combined through a CombinedRangeCategoryPlot.
As the subplots datasets do not have the same number of items and since JFreeChart decides to allocate the same space for each subplot, I have different widths of bars.
Is there any way I can align their width (even if it means that the subplots have different widths)?
Please see below for the result and the code I have so far.
Many thanks,
Thomas
//Builds commong range axis
NumberAxis rangeAxis = new NumberAxis("%");
rangeAxis.setRange(0, 1.0);
rangeAxis.setNumberFormatOverride(NumberFormat.getPercentInstance());
//Builds common data set
CombinedRangeCategoryPlot combinedPlots = new CombinedRangeCategoryPlot(rangeAxis);
for (int groupIndex=0; groupIndex<LeakGroups.values().length; ++groupIndex){
//Builds category axis
CategoryAxis categoryAxis = new CategoryAxis(GuiConstants.LEAK_GROUPS_LABELS[groupIndex]);
//Sets margins between bars
categoryAxis.setCategoryMargin(0.5f);
//Builds bar renderer
StackedBarRenderer barRenderer = new StackedBarRenderer();
barRenderer.setRenderAsPercentages(true);
//Builds dot/level renderer
LineAndShapeRenderer dotRenderer = new LineAndShapeRenderer();
//dotRenderer.setSeriesLinesVisible(0, false);
//dotRenderer.setSeriesShapesVisible(0, false);
//dotRenderer.setSeriesLinesVisible(1, false);
//Defines level shape height (depends on chart size): nominal values are for a height of 1000px
int shapeHeightPx = (int) Math.round(20 * (this.getHeight() / 1000.0));
dotRenderer.setSeriesShape(1, new Rectangle(-1, -shapeHeightPx/2, 2, shapeHeightPx));
//Builds plot
CategoryPlot plot = new CategoryPlot();
plot.setDomainAxis(categoryAxis);
plot.setDataset(0, data[groupIndex].bars);
plot.setRenderer(0, barRenderer);
plot.setDataset(1, data[groupIndex].dots);
plot.setRenderer(1, dotRenderer);
//Adds to combined
combinedPlots.add(plot);
}
combinedPlots.setOrientation(PlotOrientation.HORIZONTAL);
//Puts range axis at the bottom
combinedPlots.setRangeAxisLocation(AxisLocation.BOTTOM_OR_RIGHT);
//Changes plot render sequence so that bars are in the background and shapes in front
combinedPlots.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
//Shows gridlines for categories and not for values
combinedPlots.setDomainGridlinesVisible(true);
combinedPlots.setRangeGridlinesVisible(false);
//Creates chart
JFreeChart chart = new JFreeChart("Leaks", combinedPlots);
//Sets a margin right to allow space for last catergory label ("100%")
chart.setPadding(new RectangleInsets(0, 0, 0, 20));
return chart;
For some reason, the weight gets reset to value 1 when adding the plot.
By way of explanation,
The add(CategoryPlot subplot) method specifies a default weight of 1,
The add(CategoryPlot subplot, int weight) method lets you specify a weight value.
After a few hours of search, found the solution: use plot.setWeight().
For some reason, the weight gets reset to value 1 when adding the plot to the CombinedRangeCategoryPlot, hence it has to be set after.
Hope this helps.
Related
Is there a way to change the position of the Category Plot Labels (title) (censored with black bars in the image) to be on top of the chart and / or aligned vertically to each other?
Here's the classes I use to construct it.
var renderer = new LineAndShapeRenderer();
...
var yAxis = new NumberAxis();
...
var xAxis = new CategoryAxis(title);
...
CategoryPlot plot = new CategoryPlot(dataset, xAxis, yAxis, renderer);
...
var combinedPlot = new CombinedRangeCategoryPlot();
combinedPlot.add(plot, weight);
...
I'm using version 1.0.19 of JFreeChart since newer versions produce some visual artifacts.
There has been a misunderstanding: I meant the labels, "Plot 0" and "Plot1", in your example; and I'm asking for the ability to move them on top of the chart…
Invoke setDomainAxisLocation() on each subplot domain axis to move the axis and its label. Alternatively, obtain the required axis references from the List<CategoryPlot> shown below.
plot0.setDomainAxisLocation(AxisLocation.TOP_OR_LEFT);
plot1.setDomainAxisLocation(AxisLocation.TOP_OR_LEFT);
I only need those "Plot 0" and "Plot1" labels on top, not the tick labels…
You can hide the tick labels as desired using setTickLabelsVisible(false), and you can have multiple axes, as shown here.
To adjust the tick label orientation, invoke setCategoryLabelPositions() on each sublot comprising the combined plot. Do this either
When the plot is created.
CategoryAxis axis0 = new CategoryAxis("Plot 0");
axis0.setCategoryLabelPositions(CategoryLabelPositions.UP_90);
CategoryPlot plot0 = new CategoryPlot(…, axis0, …);
…
CategoryAxis axis1 = new CategoryAxis("Plot 1");
axis1.setCategoryLabelPositions(CategoryLabelPositions.UP_90);
CategoryPlot plot1 = new CategoryPlot(…, axis1, …);
After creating the combined plot.
CombinedRangeCategoryPlot combinedplot = new CombinedRangeCategoryPlot(…);
…
List<CategoryPlot> list = combinedplot.getSubplots();
list.get(0).getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_90);
list.get(1).getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_90);
Vertical labels are illustrated below.
I am plotting the bar and line chart using the jfree chart .
One of the value axis is having the large label which doesn't fit in.
The label is suppose to be Greenhouse gas emissions (Tonnes).
Unable to find a way to control the width of the lable or wrap it.
final JFreeChart chart = ChartFactory.createBarChart(chartDetails.getTitle(),
chartDetails.getCategoryAxisLabel(), chartDetails.getValueAxisLabelLabelOne(),
dataSets.get(0),
PlotOrientation.VERTICAL, false,
true,
false
);
final ValueAxis rangeAxis = new NumberAxis(chartDetails.getValueAxisLabelLabelTwo());
plot.setRangeAxis(1, axis2);
final Font yaxisFont = getFont(yaxisFontAttibutes, xfactor);
rangeAxis.setLabelFont(yaxisFont);
rangeAxis.setLabelPaint(Color.decode(yaxisFontAttibutes.getColor()));
rangeAxis.setTickLabelFont(yaxisFont);
rangeAxis.setTickLabelPaint(Color.decode(yaxisFontAttibutes.getColor()));
rangeAxis.setLabelFont(yaxisFont);
rangeAxis.setAxisLineVisible(false);
rangeAxis.setLabelInsets(new RectangleInsets(2, 2, 2, 2));
return chart.createBufferedImage((int) (chartAttributes.getWidth() * xfactor),
(int) chartAttributes.getHeight() * xfactor);
Tried using LabelInsets but no use.
Note: I dont want to increase the heigth
Any sample code will be of great help.
Thanks
I have set the label at high end and rotated it .
But results are not desirable.
rangeAxis.setLabelLocation(AxisLabelLocation.HIGH_END);
rangeAxis.setLabelAngle(135);
I am drawing a bar chart using a chart i want to customize the chart.
give spave between first bar from start
Increase the width of each bar
incerese text size of numbers which are at top of the bars
Following is the code for my bar chart
private void openChart()
{
int[] x = { 0,1,2,3,4,5,6};
// Creating an XYSeries for Income
XYSeries wSeries = new XYSeries("Workout");
// Creating an XYSeries for Expense
for(int i=0;i<x.length;i++){
wSeries.add(i,workout[i]);
}
// Creating a dataset to hold each series
XYMultipleSeriesDataset dataset = new XYMultipleSeriesDataset();
// Adding Income Series to the dataset
dataset.addSeries(wSeries);
// Adding Expense Series to dataset
// Creating XYSeriesRenderer to customize incomeSeries
XYSeriesRenderer wRenderer = new XYSeriesRenderer();
wRenderer.setColor(getResources().getColor(R.color.header_blue)); //color of the graph set to cyan
wRenderer.setFillPoints(true);
wRenderer.setLineWidth(5);
wRenderer.setDisplayChartValues(true);
wRenderer.setDisplayChartValuesDistance(20); //setting chart value distance
// Creating a XYMultipleSeriesRenderer to customize the whole chart
XYMultipleSeriesRenderer multiRenderer = new XYMultipleSeriesRenderer();
multiRenderer.setOrientation(XYMultipleSeriesRenderer.Orientation.HORIZONTAL);
multiRenderer.setXLabels(0);
/***
* Customizing graphs
*/
//setting text size of the title
multiRenderer.setChartTitleTextSize(30);
//setting text size of the axis title
multiRenderer.setAxisTitleTextSize(30);
//setting text size of the graph lable
multiRenderer.setLabelsTextSize(30);
//setting zoom buttons visiblity
multiRenderer.setZoomButtonsVisible(false);
//setting pan enablity which uses graph to move on both axis
multiRenderer.setPanEnabled(false, false);
//setting click false on graph
multiRenderer.setClickEnabled(false);
//setting zoom to false on both axis
multiRenderer.setZoomEnabled(false, false);
//setting lines to display on y axis
multiRenderer.setShowGridY(false);
//setting lines to display on x axis
multiRenderer.setShowGridX(false);
//setting legend to fit the screen size
multiRenderer.setFitLegend(true);
//setting displaying line on grid
multiRenderer.setShowGrid(false);
//setting zoom to false
multiRenderer.setZoomEnabled(false);
//setting external zoom functions to false
multiRenderer.setExternalZoomEnabled(false);
//setting displaying lines on graph to be formatted(like using graphics)
multiRenderer.setAntialiasing(true);
//setting to in scroll to false
multiRenderer.setInScroll(false);
//setting to set legend height of the graph
multiRenderer.setLegendHeight(30);
//setting x axis label align
multiRenderer.setXLabelsAlign(Align.CENTER);
//setting y axis label to align
multiRenderer.setYLabelsAlign(Align.RIGHT);
//setting text style
multiRenderer.setTextTypeface("sans_serif", Typeface.BOLD);
//change y axis label color
multiRenderer.setYLabelsColor(0,Color.BLACK);
//change x axis label color
multiRenderer.setXLabelsColor(Color.BLACK);
//setting no of values to display in y axis
multiRenderer.setYLabels(7);
// setting y axis max value, Since i'm using static values inside the graph so i'm setting y max value to 4000.
// if you use dynamic values then get the max y value and set here
multiRenderer.setYAxisMin(0);
multiRenderer.setYAxisMax(49);
//setting used to move the graph on xaxiz to .5 to the right
multiRenderer.setXAxisMin(0);
//setting max values to be display in x axis
multiRenderer.setXAxisMax(7);
//setting bar size or space between two bars
multiRenderer.setBarSpacing(3);
//Setting background color of the graph to transparent
multiRenderer.setBackgroundColor(Color.TRANSPARENT);
//Setting margin color of the graph to transparent
multiRenderer.setMarginsColor(getResources().getColor(R.color.light_red));
multiRenderer.setApplyBackgroundColor(true);
//setting the margin size for the graph in the order top, left, bottom, right
multiRenderer.setMargins(new int[]{20, 40, 20, 20});
for(int i=0; i< x.length;i++){
multiRenderer.addXTextLabel(i, week[i]);
}
// Adding incomeRenderer and expenseRenderer to multipleRenderer
// Note: The order of adding dataseries to dataset and renderers to multipleRenderer
// should be same
multiRenderer.addSeriesRenderer(wRenderer);
//this part is used to display graph on the xml
LinearLayout chartContainer = (LinearLayout) findViewById(R.id.nut_sum_graphLayout);
//remove any views before u paint the chart
chartContainer.removeAllViews();
//drawing bar chart
mChart = ChartFactory.getBarChartView(HealthNutritionSummary.this, dataset, multiRenderer,Type.DEFAULT);
//adding the view to the linearlayout
chartContainer.addView(mChart);
}![enter image description here][2]
to give space on the left side a chart, I set X axis min to smaller size. For example, this should do the trick in your case.
multiRenderer.setXAxisMin(-0.5);
To increase width, you have two options.You can set bar spacing or bar width.
multiRenderer.setBarSpacing(0.5);
or
multiRenderer.setBarWidth(20); // I think this is in pixels
And finally, for text size there is option for XYSeriesRenderer, in your case:
wRenderer.setChartValuesTextSize(20);
I am using JasperReports to create a line chart for my webapps.
I have successfully passed the dataset to the compiled report (created in iReport) and can see the data correctly.
However, I want to do some customization on the margin.
The value shown on the line chart is trimming for the highest value as there is no margin.
The X-Axis label is coming after few empty space from Y-Axis 0 value. I want to remove that margin and start the X-Axis from very close to the meeting point of X & Y.
Please see the picture:
I am using customized class which is defined in my webspps. I am able to change the font size and rotation of the label but don't know how to adjust margin.
public class LineChartCustomizer implements JRChartCustomizer {
#Override
public void customize(JFreeChart jFreeChart, JRChart jrChart) {
CategoryPlot plot = jFreeChart.getCategoryPlot();
DecimalFormat dfKey = new DecimalFormat("###,###");
StandardCategoryItemLabelGenerator labelGenerator = new StandardCategoryItemLabelGenerator("{2}", dfKey);
LineAndShapeRenderer renderer = new LineAndShapeRenderer();
renderer.setBaseItemLabelsVisible(true);
renderer.setBaseItemLabelGenerator(labelGenerator);
renderer.setBaseItemLabelFont(new java.awt.Font("SansSerif", java.awt.Font.PLAIN, 4));
renderer.setSeriesShape(0, ShapeUtilities.createDiamond(1F));
plot.setRenderer(renderer);
}
}
I think* you're looking for ValueAxis#setUpperMargin(double) and CategoryAxis#setLowerMargin(double). You can get the CategoryAxis and ValueAxis from plot.getDomainAxis() and plot.getRangeAxis(). Note that the margins are a percentage of the axis length and not pixel values.
* I'm not familiar with JasperReports, but it seems a little strange that you have a CategoryPlot in hand as opposed to an XYPlot. I would have expected the chart in your picture to have used an xy time series. I have only ever tested this with an XYPlot, so I'm not entirely sure how it will behave with a CategoryPlot.
Objective is to build an interval bar chart indicating, for each category, a range of acceptable values (between 0 - 100%).
As for each category, I would like to indicate 2 intervals (i.e. a center interval that is green and a surrounding interval that is grey), I think that it is not feasible with a IntervalBarRenderer and I have thus been using a StackedBarRenderer (with transparent layers at the extreme left & right of each bar).
Would this be the right approach?
Also, if this is the right approach, it seems that the bar intervals that are transparent (at the extreme left and right of each bar), do not show their outline: is their any way to have an outline for a transparent paint?
Please see below for the main code and a screenshot of current results.
Many thanks for any help or hint !
Thomas
private JFreeChart createChart(LeaksChartSeriesVO data){
JFreeChart chart = ChartFactory.createStackedBarChart(
"Leak meters", //Title
"Leaks", //Domain axis (X) label
"%", //Range axis (Y) label
data.bars,
PlotOrientation.HORIZONTAL,
true, //Legend?
true, //Tooltip?
false); //Urls?
CategoryPlot plot = (CategoryPlot) chart.getPlot();
//Sets X axis sub-legends
SubCategoryAxis subCat = new SubCategoryAxis("Leak meters");
//Adds second dataset
plot.setDataset(1, data.dots);
//Defines level renderer
LevelRenderer renderer1 = new LevelRenderer();
renderer1.setSeriesPaint(0, Color.black);
plot.setRenderer(1, renderer1);
//Sets Y axis as %
((StackedBarRenderer) plot.getRenderer()).setRenderAsPercentages(true);
//Sets colors
((StackedBarRenderer) plot.getRenderer()).setSeriesPaint(0, new Color(0, 0, 0, 0)); //Transparent for start
((StackedBarRenderer) plot.getRenderer()).setSeriesPaint(1, Color.gray); //Grey low
((StackedBarRenderer) plot.getRenderer()).setSeriesPaint(2, Color.green); //Green
((StackedBarRenderer) plot.getRenderer()).setSeriesPaint(3, Color.gray); //Grey high
((StackedBarRenderer) plot.getRenderer()).setSeriesPaint(4, new Color(0, 0, 0, 0)); //Transparent for end
((StackedBarRenderer) plot.getRenderer()).setDrawBarOutline(true);
((StackedBarRenderer) plot.getRenderer()).setBaseOutlinePaint(Color.black);
//Setup which items not to see in legend
((StackedBarRenderer) plot.getRenderer()).setSeriesVisibleInLegend(0, false);
((StackedBarRenderer) plot.getRenderer()).setSeriesVisibleInLegend(3, false);
((StackedBarRenderer) plot.getRenderer()).setSeriesVisibleInLegend(4, false);
//Sets renderer & axis
plot.setDomainAxis(subCat);
//Changes plot render sequence so that bars are in the background and shapes in front
chart.getCategoryPlot().setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
//Sets margins between bars
chart.getCategoryPlot().getDomainAxis().setCategoryMargin(0.5f);
return chart;
}
This is the default behaviour of the GradientBarPainter which is used to draw the bars: when the bar is transparent, it doesn't draw the outline.
You can instead use the StandardBarPainter which will draw the outline.
Just add:
StackedBarRenderer renderer = (StackedBarRenderer) plot.getRenderer();
renderer.setBarPainter(new StandardBarPainter());
Another solution is to keep the GradientBarPainter but use an almost transparent color for the bar:
setSeriesPaint(0, new Color(0, 0, 0, 1));