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++;
}
Related
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());
}
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);
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));
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!
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.