Jfree chart value Axis label is getting cropped - java

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);

Related

JFreeChart XYTextAnnotation Location with AutoRange

I have a realtime time series chart where I add vertical value markers when certain events occur. I want to also label those markers with XYTextAnnotation (also vertically). I tried to locate the label along the right side and top of the marker. However, the Y axis of chart uses AutoRange but the annotation is in an absolute X,Y location. The result is that it moves off the chart in the Y axis and disappears as the range increases. How can I add the label so it stays on the chart relative to the changing range? TIA.
Here is my current code:
public void addMarker(String id_,String name_) {
Functions.logger("Adding open door marker for "+id_+" "+name_,false);
Long tod=new Date().getTime();
ValueMarker marker=new ValueMarker(tod);
XYTextAnnotation label=new XYTextAnnotation("Door Open: "+name_,tod-1,360);
label.setRotationAnchor(TextAnchor.BASELINE_CENTER);
label.setTextAnchor(TextAnchor.BASELINE_CENTER);
label.setRotationAngle(-Math.PI/2);
label.setPaint(Color.BLACK);
marker.setStroke(new BasicStroke(2));
marker.setPaint(Color.BLACK);
chart.addDomainMarker(marker);
chart.addAnnotation(label);
}

JFreeChart with XYBoxAnnotation Open on One Side

I'm using an XYBoxAnnotation to demarcate a rectangular area on a JFreeChart. I would like one side of the box to be "open", i.e go out to infinity. I tried setting the value to Double.POSITIVE_INFINITY but this did not seem to work. I also tried setting it to Double.MAX_VALUE, with no luck either. In these cases, the annotation doesn't even show up on the plot at all. And there are no exceptions thrown.
Below is a very simple version of my code in which I generate the XYBoxAnnotation and add it to the plot.
XYBoxAnnotation _axisMarker = new XYBoxAnnotation(xLow, yLow, Double.POSITIVE_INFINITY, yHigh, new BasicStroke(0.5F), Color.WHITE, Color.WHITE);
_plot.getRenderer().addAnnotation(_axisMarker, Layer.BACKGROUND);
EDIT:
I figured out that the reason the annotation wasn't showing up was because the x value for the annotation was much much larger than the axis scale. For some reason, this causes the annotation to not be visible until you zoom out enough.
Thanks to #trashgod's answer below, I came up with a solution. His answer didn't quite work for me since my plot allows zooming and you could see the edge of the box when you zoomed out.
First, I added a PlotChangeListener to listen for when the plot is zoomed:
// define PlotChangeListener to update the annotation when the plot is zoomed
private PlotChangeListener _zoomListener = new PlotChangeListener() {
#Override
public void plotChanged(PlotChangeEvent plotChangeEvent) {
if (_basisIsotope != null) {
updateAxisMarkers();
}
}
};
Then I created a function to re-draw the annotation based on the new plot bounds:
// function to re-draw the annotation
private void updateAxisMarkers() {
_plot.removeChangeListener(_zoomListener); // remove to prevent triggering infinite loop
// define xLow, yLow and yHigh...
double xHigh = _plot.getDomainAxis().getUpperBound() * 1.1;
XYBoxAnnotation _axisMarker = new = new XYBoxAnnotation(xLow, yLow, xHigh, yHigh, new BasicStroke(0.5F), Color.WHITE, Color.WHITE);
_plot.getRenderer().addAnnotation(annotation);
_plot.addChangeListener(_zoomListener); // add back
}
Double.MAX_VALUE is too large to scale to the relevant axis, but Double.MAX_VALUE / 2 works as well as any value larger than the upper bound of the axis. A better choice might be a value that exceeds the maximum value of the domain by some margin. The fragment below shades a plot of some Gaussian data with an XYBoxAnnotation that has domain bounds extending from 42 to the maximum domain value + 10%; the range bounds are ±1σ.
XYSeriesCollection dataset = createDataset();
JFreeChart chart = createChart(dataset);
Color color = new Color(0, 0, 255, 63);
double max = dataset.getSeries(0).getMaxX() * 1.1;
XYBoxAnnotation annotation = new XYBoxAnnotation(
42, -1, max, 1, new BasicStroke(1f), color, color);
chart.getXYPlot().getRenderer().addAnnotation(annotation);

java JFreeChart how do I use renderers to set different paints

I have a single series XYAreaChart
final JFreeChart chart = ChartFactory.createXYAreaChart(
"",
"", "Rolling",
dataset,
PlotOrientation.VERTICAL,
false, // legend
true, // tool tips
false // URLs
);
final XYPlot plot = chart.getXYPlot();
I want to set paint color to Red when RangeValue >0 otherwise set it to Green. This is the nearest bit of code I can find BUT I think it is for two series:
plot.setRenderer(new XYDifferenceRenderer(Color.green, Color.red, false));
Which renderer do I need for a single series?
This may be able to help you. Below is an example showing a basic chart from a JFreechart tutorial. I have added the renderer in your example to it, my theory is that when you have 1 series the 'second series' as it were is effectively 0. Therefore when you apply the two series renderer, if the first series dips below 0 it becomes the negative color, and when it is above 0 becomes the positive colour.
When I opened my saved chart it had red on the minus points, and green on the posotive. See if it helps:
public class SO{
public static void main(String[] args) {
// Create a simple XY chart
XYSeries series = new XYSeries("Gradient logs chopped");
series.add(1, -7);
series.add(2, -2);
series.add(3, 4);
series.add(4, 7);
series.add(5, 10);
// Add the series to your data set
XYSeriesCollection dataset = new XYSeriesCollection();
dataset.addSeries(series);
// Generate the graph
JFreeChart chart = ChartFactory.createXYLineChart(
"Logs chopped", // Title
"Week", // x-axis Label
"Logs", // y-axis Label
dataset, // Dataset
PlotOrientation.VERTICAL, // Plot Orientation
true, // Show Legend
true, // Use tooltips
false // Configure chart to generate URLs?
);
//The renderer part
XYPlot plot = chart.getXYPlot();
XYDifferenceRenderer rend = new XYDifferenceRenderer(Color.GREEN, Color.RED, false);
rend.setSeriesFillPaint(0, Color.DARK_GRAY);
rend.setRoundXCoordinates(true);
plot.setRenderer(rend);
//The renderer part
try {
ChartUtilities.saveChartAsJPEG(new File("D:\\Users\\user2777005\\Desktop\\XYchart.jpg"), chart, 500, 300);
} catch (IOException e) {
System.err.println("Problem occurred creating chart.");
}
}
}
Good luck!

JFreeChart Margin

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.

JFreeChart align BarChart width across subplots

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.

Categories

Resources