Auto-Scale Y-Axis in JfreeChart - java

I am using JFreeChart to create candlestick charts in my Java app. However, my charts end up looking like this:
http://imageshack.us/photo/my-images/69/capturebhx.png/
I would like to have the Y-axis automatically scaled so that the chart looks more like this:
http://imageshack.us/photo/my-images/717/capture2wl.png/
I think org.jfree.chart.axis.NumberAxis.configure() will do this, but I'm not sure. I can't seem to find a way to tie my JFreeChartobject, or ChartPanel object to this NumberAxis object. Please help me, I am lost and have been looking for a long time to try and tie these objects together. Or, if you can find another way, that'd be great too!
Some code:
...
private DefaultHighLowDataset dataset;
private JFreeChart chart;
private ChartPanel chart_panel;
...
// creates dataset, then chart from dataset, then chart_panel from chart
dataset = new DefaultHighLowDataset("", date, high, low, open, close, volume);
chart = ChartFactory.createCandlestickChart("Blank", "Time", "Price", dataset, false);
chart_panel = new ChartPanel(chart); // what you see in the images
...

Be sure to setAutoRangeIncludesZero(false) or "the axis range…is forced to include zero."
Addendum:
I still don't know how to link a NumberAxis object to a ChartPanel object or JFreeChart object.
You may want to look into the examples in org.jfree.chart.demo and here. If this is terra incognita, I'd recommend The JFreeChart Developer Guide†.
†Disclaimer: Not affiliated with Object Refinery Limited; just a satisfied customer and very minor contributor.

I did it like this:
final JFreeChart chart = ChartFactory.createCandlestickChart(
"Candlestick Demo", "Time", "Price", dataset, false);
double lowestLow = getLowestLow(dataset);
double highestHigh = getHighestHigh(dataset);
chart.getXYPlot().getRangeAxis().setRange(lowestLow*0.95, highestHigh*1.05);
I calculate the lowest low and lowest high using these functions
private double getLowestLow(DefaultHighLowDataset dataset){
double lowest;
lowest = dataset.getLowValue(0,0);
for(int i=1;i<dataset.getItemCount(0);i++){
if(dataset.getLowValue(0,i) < lowest){
lowest = dataset.getLowValue(0,i);
}
}
return lowest;
}
private double getHighestHigh(DefaultHighLowDataset dataset){
double highest;
highest = dataset.getHighValue(0,0);
for(int i=1;i<dataset.getItemCount(0);i++){
if(dataset.getLowValue(0,i) > highest){
highest = dataset.getHighValue(0,i);
}
}
return highest;
}
This seems to give me a very nice candlestick chart that makes good use of the Y-axis range. Hope this helps.

Related

JFreeChart: Bar chart X axis labels overlapping with large datasets

I'm facing the below issue while using JFreeChart for creating bar chart with relatively large dataset:
Bar chart generated with overlapping X-axis labels. I have tried positioning the labels vertical, still no help. Please provide the best possible way to solve this issue. Code snipped below:
CategoryDataset categoryDataSet = getBarDataset();
JFreeChart barChart = ChartFactory.createBarChart("TITLE", "X-LABEL","Y-LABEL", categoryDataSet, PlotOrientation.VERTICAL, true, true, false);
barChart.getCategoryPlot().getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_90);
barChart.getCategoryPlot().getDomainAxis().setMaximumCategoryLabelLines(4);
jpg = Image.getInstance(im, null);
document.add(jpg);
Update:
As per the suggestion from #trashgod, I've used SlidingCategoryDataset indexing from 0 to the column count. When the column count is large(50 here), the X-Label's are overlapping. When the column count is set to a lower number, it's working fine. I want to find a solution for large column size. Importantly, I need to export the chart image to pdf. Please help me in arriving to a feasible solution. Thanks!
private static void createBarChart() throws DocumentException, IOException {
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(FILE_LOCN));
writer.setStrictImageSequence(true);
document.open();
CategoryDataset categoryDataset = createDataset();
int colCount = categoryDataset.getColumnCount();
SlidingCategoryDataset slidingCategoryDataSet = new SlidingCategoryDataset(categoryDataset, 0, colCount);
JFreeChart barChart = ChartFactory.createBarChart("TITLE", "X-LABEL","Y-LABEL", slidingCategoryDataSet,
PlotOrientation.VERTICAL, true, true, false);
barChart.getCategoryPlot().getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_90);
barChart.getCategoryPlot().getDomainAxis().setMaximumCategoryLabelLines(4);
java.awt.Image im = barChart.createBufferedImage(400, 400);
Image jpg = Image.getInstance(im, null);
jpg.scaleToFit(400, 400);
document.add(jpg);
document.close();
writer.close();
}
private static CategoryDataset createDataset() {
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
for (int i = 0; i <= 50; i++) {
dataset.addValue(i, "R", "C" + i);
}
return dataset;
}
With a large number of categories, specifying vertical labels via setCategoryLabelPositions() is a good choice for maximizing legibility. Arbitrary CategoryLabelPositions are supported.
In an interactive chart, SlidingCategoryDataset, mentioned here, allows your application to set the count and starting index of visible categories as desired, perhaps using a slider or spinner, as shown here.
How can I achieve this in a PDF?…More pixels seems a good idea, but how can we implement that here?
In a fixed size context with a given number of categories, you can optimize the size of the chart image via createBufferedImage(), as shown here, or Image.scaleToFit(). For yet larger datasets, it may be possible to create multiple linked charts in a domain specific way, e.g. by year or subsidiary.

CategoryPlot from a JTable - JFreeChart

I have to implement an histogram using JFreeChart API. This histogram has to represent the datas of this JTable:
So I have a JTable with three columns: "thea", "type", "Number of occurrences". My histogram has two targets: the first is to count the number of occurrences of each thea field; the second is to mark with different colors the bars corresponding to JTable records with different types.
To implement my histogram I used a DefaultCategoryDataset:
private DefaultCategoryDataset createDataset(ArrayList<String>fieldsOccs) {
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
for(int i = 0; i<this.fieldsOccs.size() && i<end; i++) {
String thea = fieldsOccs.get(i).getFieldName();
String type = fieldsOccs.get(i).getType();
int occurrences = fieldsOccs.get(i).getOccurrences();
dataset.setValue(occurrences, type, thea);
}
return dataset;
}
Anf then I create my chart using a createChart method:
private JFreeChart createChart(DefaultCategoryDataset dataset) {
JFreeChart chart = ChartFactory.createBarChart(
"",
"", //X-axis title
"", //Y-axis title
dataset, //dataset
PlotOrientation.HORIZONTAL, //plot orientation
true, //show legends
true, //use tooltips
false //generate URLs
);
return chart;
}
This is what I get:
As you can see in the picture it is not nice to see. The values on x axes are not formatted correctly.
How can I solve this rendering problem?
--edit
I have this problem just in case of more types in the JTable. For example if my JTable is:
and there is just String, the correspondig histogram is nice:
--edit1
What dou you think about StackedBarChart3D? I get this output:
My histogram has two targets:
You may get a more appealing result with ChartFactory.createHistogram() and a SimpleHistogramDataset, seen here.
To get diverse colors, override the getItemPaint() method in a custom XYBarRenderer, as suggested here.

Box plot using JFreeChart

First off, I am new to Java and to Stackoverflow. So I hope I can supply enough clarity in my question.
My goal is to create a box plot using jfreechart to keep track of measurement values from every day use. I want to do this by storing minimal amount of data ie. by storing statists of mean, standard deviation, median, 1Q,3Q, min and maximum. This should then be visualized by a box plot for each day measured.
I have looked at the box plot demo here
http://www.java2s.com/Code/Java/Chart/JFreeChartBoxAndWhiskerDemo.htm
In this demo they create the dataset and add all the values to the dataset, then adds it to the plot. The dataset itself contains methods to return the mean, median etc. of the dataset to be able to create the plot. See the code below for a snip from the demo in the link above.
DefaultBoxAndWhiskerCategoryDataset dataset = new DefaultBoxAndWhiskerCategoryDataset();
//some type of algorithm to add values to the dataset
dataset.add(//values, series and type here);
// Return the finished dataset
CategoryAxis xAxis = new CategoryAxis("Type");
NumberAxis yAxis = new NumberAxis("Value");
yAxis.setAutoRangeIncludesZero(false);
BoxAndWhiskerRenderer renderer = new BoxAndWhiskerRenderer();
renderer.setFillBox(false);
renderer.setToolTipGenerator(new BoxAndWhiskerToolTipGenerator());
CategoryPlot plot = new CategoryPlot(dataset, xAxis, yAxis,
renderer);
JFreeChart chart = new JFreeChart("Box-and-Whisker Demo",
new Font("SansSerif", Font.BOLD, 14), plot, true);
So my question is, how should I do to just add the median, Q1,Q3, mean, minimum and maximum values to create the box plot? Because in the demo above they base the plot of a complete sample set.
You can create your own dataset class and use it to create the chart.
Create your own implementation of BoxAndWhiskerCategoryDataset and use it in place of DefaultBoxAndWhiskerCategoryDataset.

Dynamic JFreeChart not redrawing on changes

I am making use of the JFreeChart library to plot the progress of a genetic algorithm in real time.
I'm using Swing for the UI. I have a panel where I draw all the various parameters for the algorithm, and a ChartPanel object. This object is drawn before I call the algorithm's search method (which updates the chart's XYSeries object at each generation), and at the end of the search, with all the values being accurately plotted.
According to the docs, the ChartPanel object is redrawn when its respective chart is updated. Obviously, the Swing panel itself isn't being redrawn until after the search is done, and I call repaint(), but what can I do to fix this?
This is the chart code:
public class XYSeriesDemo {
private static final long serialVersionUID = 1L;
private XYSeries series;
private JFreeChart chart;
public XYSeriesDemo(String str) {
series = new XYSeries(str);
XYSeriesCollection data = new XYSeriesCollection(series);
chart = createChart(data);
}
public XYSeries getSeries() {
return series;
}
public ChartPanel getChartPanel() {
return new ChartPanel(chart);
}
private JFreeChart createChart(final XYDataset data) {
JFreeChart chart = ChartFactory.createXYLineChart(
"Best fitness across generations",
"Generation",
"Fitness",
data,
PlotOrientation.VERTICAL,
true,
true,
false
);
XYPlot plot = chart.getXYPlot();
ValueAxis axis = plot.getDomainAxis();
axis.setAutoRange(true);
axis = plot.getRangeAxis();
axis.setAutoRange(true);
return chart;
}
}
In my panel constructor, I'm doing the following (this gets an empty chart drawn):
demo = new XYSeriesDemo("Best fitness");
this.add(demo.getChartPanel());
This is the method that the Swing frame calls in my JPanel object when the user orders a search:
public void solve() {
gen = new Random(seed);
XYSeries s = demo.getSeries();
GeneticAlgorithm ga = new GeneticAlgorithm(pop, crossoverP, mutationP,
eliteSize, maxGens, gen, s);
best = ga.search();
state = State.SOLVED;
time = ga.getTime() / 1E9;
}
At each generation, the search method in the algorithm simply does:
series.add(generation, pop.getBestFitness());
Thank you for reading.
Make sure that you are updating the dataset or series for the chart, ideally directly. The chart should refresh itself.
I would recommend buying the JFreeChart developer guide as it includes all sorts of examples including dynamic charts. The cost of the developer guide is what supports JFreeChart development.
I think you call your search process in EDT because of that it can't repaint components.
For updating your panel from code try to use SwingWorker, it can update UI and continue background process. You can find a lot of examples of using in Internet.
Or you can try to use Executors for background search process and updating UI.
I think this will work for you
JFreeChart jf = // Your JFreeChart chart Object.
ChartPanel chartPanel = new ChartPanel(jf);
myPanel.add(chartPanel);
myPanel.repaint();
myPanel.revalidate();

Y tags in XYSeriesCollection (JFreeChart)

I have an XY chart where I want to represent X values along some dates. The creation of the dataset is simple:
XYSeries serie = new XYSeries("valor");
for(int i=0;i<lista.size();i++){
serie.add(i,lista.get(i).getValue());
}
dataset.addSeries(serie);
where serie.add uses as arguments (y.value, x.value). I am representing the x value along time, but it appears as just the index of the arraylist (obvious, I use i as the first parameter). My question is, how could I show dates (or Strings) as the Y values?
I know that this possible to be done with a BarChart, for instance:
DefaultCategoryDataset dataSet = new DefaultCategoryDataset();
dataSet.addValue(51, "series", "Colonel Forbin");
dataSet.addValue(92, "series", "The Lizards");
Something like this is what I need to do, hope you could help, thanks
As shown here, if the range values in your series represent milliseconds from the Java epoch, a DateAxis should display the values correctly.
NumberAxis domain = new NumberAxis("X");
DateAxis range = new DateAxis("Y");
domain.setAutoRangeIncludesZero(false);
XYItemRenderer renderer = new XYLineAndShapeRenderer(true, false);
XYPlot plot = new XYPlot(dataset, domain, range, renderer);
JFreeChart chart = new JFreeChart(
"Title", JFreeChart.DEFAULT_TITLE_FONT, plot, false);
Addendum: I just want to set … tags that change dynamically.
It looks like you want SymbolAxis, seen here.

Categories

Resources