How to create stacked interval charts with JFreeChart? - java

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

Related

JFreeChart Candlestick zoom into last n candles on creation

I have an app and I somehow successfully managed to get a candlestick chart visible. However, once the chart is displayed, it shows all the candles (can be several hundred) which causes the chart to be very tiny and zoomed out. What I actually want is, the chart to be zoomed into the range of the last N candles so it looks more visible to the eye.
Here is how my charts look once they get created
I tried working with setRange, the Range on the Date Axis returns values in the format of [09.02.2023, 23:21:02 --> 10.02.2023, 08:29:56]
I dont seem to get how to make the chart like zoom in to a range of for example range.length-100 -> range.length. Whatever I tried, I always end up somewhere randomly without any data really shown.
Is there a way to define the last n entries on the range and set the dateAxis to start showing this range?
What I actually want to see after creation is something like this
private void displayChart(String title, String quoteMarket, BarSeries series) {
OHLCDataset dataSet = createOHLCDataset(title,series);
JFreeChart chart = ChartFactory.createCandlestickChart(
title,
"Time",
quoteMarket,
dataSet,
false);
chart.setBackgroundPaint(new Color(28, 39, 57));
chart.setBorderVisible(false);
chart.getTitle().setPaint(Color.WHITE);
// Candlestick rendering
CandlestickRenderer renderer = new CandlestickRenderer();
renderer.setAutoWidthMethod(CandlestickRenderer.WIDTHMETHOD_INTERVALDATA);
renderer.setUpPaint(new Color(0, 214, 110));
renderer.setDownPaint(new Color(196, 19, 30));
renderer.setSeriesPaint(0,new Color(211, 211, 211));
renderer.setCandleWidth(3.0);
XYPlot plot = chart.getXYPlot();
plot.setRenderer(renderer);
plot.setRangeGridlinePaint(Color.lightGray);
plot.setBackgroundPaint(new Color(28, 39, 57));
plot.setDomainGridlinesVisible( false );
plot.setRangeGridlinesVisible( false );
NumberAxis numberAxis = (NumberAxis) plot.getRangeAxis();
numberAxis.setAutoRangeIncludesZero(false);
numberAxis.setLabelPaint(Color.WHITE);
numberAxis.setTickLabelPaint(Color.WHITE);
numberAxis.setAutoRangeIncludesZero(false);
DateAxis dateAxis = (DateAxis) plot.getDomainAxis();
dateAxis.setAutoRange(true);
dateAxis.setLabelPaint(Color.WHITE);
dateAxis.setTickLabelPaint(Color.WHITE);
dateAxis.setTickMarkPosition(DateTickMarkPosition.MIDDLE);
plot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
ChartPanel panel = new ChartPanel(chart);
panel.setMouseWheelEnabled(true);
panel.setMouseZoomable(true);
panel.setRangeZoomable(true);
panel.setDomainZoomable(true);
this.add(panel);
System.out.println(dateAxis.getRange());
}

Dynamic Pie chart in Jfreechart - how to set colours

I am trying to plot a dynamic pie chart using JFreeChart. I do not know how many sections will be present in advance. I receive data every second which updates the graph.
How can I set colour for each section of the chart ? I do not wish to have the default colours.
I have tried setting the DrawingSupplier. Doesn't work. Can anybody help ?
The Plot of the chart for pie charts can be cast to a PiePlot which lets you set the paint color, outline color, shadow color ect.. of each piece of the pie. Heres a little sample of setting the colors for each piece of the pie. If the number of pieces is greater than the amount of colors defined in our array then it will reuse the colors.
The setSectionPaint method takes any type of java.awt.Paint so you can also pass in gradient paints among other things.
PieDataset dataset = ...
JFreeChart chart = ChartFactory.createPieChart("My Chart", dataset, false, true, false);
// all possible colors for each piece of the pie
Color[] colors = new Color[] { new Color(232, 124, 35),
new Color(51, 109, 178), new Color(182, 52, 49),
new Color(103, 131, 45), new Color(108, 77, 146),
new Color(46, 154, 183), new Color(151, 64, 64) };
PiePlot plot = (PiePlot) chart.getPlot();
// set each sections inside paint
int i = 0;
for (Object key : dataset.getKeys()) {
plot.setSectionPaint((Comparable) key, colors[i % colors.length]);
i++;
}

JFreeChart Bar chart custom color?

I am using JFreeCharts in java to create a bar chart. My question is fairly simple... how can I choose a custom color for all of the bars in a bar chart? I'm not sure if this customization would be done in a GradientPaint. An example of my code that determines bar color is:
final GradientPaint gp0 = new GradientPaint(
0.0f, 0.0f, Color.blue,
0.0f, 0.0f, Color.blue
);
I'm not sure if this is the right way to go for custom colors or not. Basically, I don't know if GradientPaint is the right way to go or not. If it is, could someone let me know how I could edit this code to make it a custom color rather than blue?
I'm not sure if this helps, but say the information for the custom color was
hue: 142
Sat: 109
Lum:126
Red: 79
Green: 129
Blue: 189
With this is there a way to customize the color of the chart?
It was a while since i coded with jfreechart.Bud if i remember corectly this was code that i wrote to change bar paint ;).
CategoryPlot cplot = (CategoryPlot)chart.getPlot();
cplot.setBackgroundPaint(SystemColor.inactiveCaption);//change background color
//set bar chart color
((BarRenderer)cplot.getRenderer()).setBarPainter(new StandardBarPainter());
BarRenderer r = (BarRenderer)chart.getCategoryPlot().getRenderer();
r.setSeriesPaint(0, Color.blue);
Im looking at the code for my first application ever written.Im not sure if it will work now.
For future i recommend to google out or purchase PDF guide to jfreechart.You find all the references and samples there.Bud if you can ,skip to JavaFX i strongly recommend it ,working with jfreechart is pain.To be honest.Implementing charts in javafx is easy and looks way better ;)
CategoryPlot plot = chart.getCategoryPlot();
BarRenderer renderer = (BarRenderer) plot.getRenderer();
// set the color (r,g,b) or (r,g,b,a)
Color color = new Color(79, 129, 189);
renderer.setSeriesPaint(0, color);
This will set all bars to that specific color. If you would like the colors to change for each row (say, for a stacked bar chart), you can call dataset.getRowCount(), with dataset being of type CategoryDataset, to return to you the number of rows involved for each column of the bar chart. Then, you could index the series in the renderer.setSeriesPaint() call based on the index of the row.
for (int i = 0; i < dataset.getRowCount(); i++){
switch (i) {
case 0:
// red
color = new Color(255, 0, 0);
break;
case 1:
// blue
color = new Color(0, 0, 255);
break;
default:
// green
color = new Color(0, 255, 0);
break;
}
}
Custom Colors in Bar Chart using JfreeChart
CategoryItemRenderer barColor = new CustomRenderer(new Paint[]{});
plot.setRenderer(barColor);
create a new class name is CustomRenderer extends BarRenderer3D or you choose BarRenderer
class CustomRenderer extends BarRenderer3D {
private Paint[] colors;
public CustomRenderer(final Paint[] colors) {
this.colors = colors;
}
public Paint getItemPaint(final int row, final int column) {
if(column==0)
return Color.blue;
else if(column==1)
return Color.CYAN;
else
return Color.RED;
}
}
I think easiest way is using getRenderer().setSeriesPaint(index, color) method.
So as an example you can try the below code for a bar chart which has 3 bars grouped.
JFreeChart barChart = ChartFactory.createBarChart(
"Bar Chart Titke",
"Category", "Score",
dataset,PlotOrientation.HORIZONTAL,
true, true, false);
CategoryPlot plot = barChart.getCategoryPlot();
plot.getRenderer().setSeriesPaint(0, new Color(128, 0, 0));
plot.getRenderer().setSeriesPaint(1, new Color(0, 0, 255));
plot.getRenderer().setSeriesPaint(2, new Color(0, 230, 255));

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.

Plot with gridline on top of XYDifferenceRenderer

I'm making (time series) moutain chart using JFreeChart. So, i made 2 timeseries - the data one and the one with all range values are zero.
TimeSeriesCollection dataset2 = new TimeSeriesCollection();
dataset2.addSeries(close); //my data series/
dataset2.addSeries(zeroseries); /zero series/
Then, i used XYDifferenceRenderer to fill the gap between 2 series with my desired color.
Code to create the chart and set renderer :
final JFreeChart chart = garch_differencechart(url);//my method to create the chart//
final ChartPanel chartPanel = new ChartPanel(chart);
final XYPlot plot = (XYPlot) chart.getPlot();
chart.setBackgroundPaint(Color.WHITE);
plot.setBackgroundPaint(Color.WHITE);
XYDifferenceRenderer renderer = new XYDifferenceRenderer();
renderer.setPositivePaint(new Color(202, 225, 255));
renderer.setSeriesPaint(0, new Color(72, 118, 255));
renderer.setSeriesStroke(0, new BasicStroke(1.2f));
plot.setRenderer(renderer);
Code to set GridLines visible :
plot.setDomainGridlinesVisible(true);
plot.setDomainGridlinePaint(new Color(234,234,234));
plot.setDomainGridlineStroke(new BasicStroke(0.5f));
plot.setRangeGridlinesVisible(true);
plot.setRangeGridlinePaint(new Color(234,234,234));
plot.setRangeGridlineStroke(new BasicStroke(0.5f));
However, the renderer covered the plot's gridline (it seems that the gridline was painted before the XYDifferenceRenderer).
How could I get the plot with gridline on top of XYDifferenceRenderer?
The gridlines show though in the demos and API. An sscce would be dispositive, but I suspect your grid and fill paints just need more contrast.

Categories

Resources