How can I draw such a graph using Swing? I have used a JFreeChart library, but I don't know how can I draw such a line graph using that library?
import org.jfree.chart.*;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.*;
public class DrawGraph{
public void drawGraph(int[][] drawPoints) {
XYSeries series = new XYSeries("Average Weight");
for(int i=0;i<drawPoints.length;i++){
for(int j=0;j<=1;j+=2){
if(drawPoints[i][j]!=0){
series.add(bla...bla...bla...);
}
}
}
XYDataset xyDataset = new XYSeriesCollection(series);
JFreeChart chart = ChartFactory.createXYLineChart
("XYLine Chart using JFreeChart", "Age", "Weight",
xyDataset, PlotOrientation.VERTICAL, true, true, false);
ChartFrame frame1=new ChartFrame("XYLine Chart",chart);
frame1.setVisible(true);
frame1.setSize(300,300);
}
}
I have drawn graph using this but isn't working...
It looks like you're having trouble constructing a dataset. You can use a method like that shown below with either ChartFactory.createXYAreaChart() or ChartFactory.createXYLineChart().
private static XYDataset createDataset() {
XYSeriesCollection result = new XYSeriesCollection();
XYSeries series = new XYSeries("Test");
series.add(0, 2);
// more points here
series.add(10, 10);
result.addSeries(series);
return result;
}
See also these examples.
As an aside, it's not clear what's important in you picture, and I can't make sense of the unordered axis at the top. In my opinion, the better question is not How do I make this graph? but rather How can I best display this data?
http://sourceforge.net/apps/trac/jung/wiki/JUNGManual
Use JUNG instead. Its easy and written in java.
Related
I am currently trying to figure out, howjfreechart's splitting into swing(1.5) and JavaFX (1.0.1) affects the JavaFX part. As far as I (very limited knowledge on this topic) understand The jfree-fx uses fxgraphics2d to draw its original swing components(?) into an FX-canvas to add this into JavaFX nodes.
Now my question is, if that fxgraphics2d object is still interactable with? I mean things like tooltips and scrolling and similar stuff normal jfreecharts offer. Since my knowledge and time is somewhat limited, I would want to know, if it is worth digging deeper into jfree-fx (if those charts are still interactable with) or if those charts are solely pictures of the actual chart and not interactable with. Then I would need to find a better solution.
I am currently learning how to build a candlestick chart within my java application. While I managed to build a chart only using JavaFX, its performance was really bad as soon as there were drawn some hundred candlesticks.
Then I came across jfreechart, of which I read, that its performance is well above the internal JavaFX charting possibilities. So today I managed to construct my first chart with jfreechart-fx and performance is quite ok. Further I find it much more intuitive to build those charts... but I am not sure if the jfree-fx version only prints images or real chart objects to the nodes. (I read somewhere something about converting a chart into an image to increase performance of drawing...)
Thank you for any information on that topic.
For example here is my JFreeChart Class, which is drawn correctly, but I just do not get any interaction with the chart with my mouse. E.g. I'd like to zoom in/out using the mousewheel and I'd like to pan the chart to the left/right by clickhold leftmouse. That why I am concerned that I am only looking at an image right now. All viable solutions I find through google seem to address only JFreeChart and not JFreeChart-FX.
package org.ezstrats.jfreeChart;
import javafx.collections.ObservableList;
import org.ezstrats.model.chartData.Candlestick;
import org.ezstrats.model.chartData.Chart;
import org.ezstrats.model.chartData.Exchange;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartRenderingInfo;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.labels.HighLowItemLabelGenerator;
import org.jfree.chart.labels.StandardXYToolTipGenerator;
import org.jfree.chart.plot.CombinedDomainXYPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.PlotRenderingInfo;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.CandlestickRenderer;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.data.time.FixedMillisecond;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.time.ohlc.OHLCSeries;
import org.jfree.data.time.ohlc.OHLCSeriesCollection;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
public class JFreeCandlestickChart extends JPanel {
private static final DateFormat READABLE_TIME_FORMAT = new SimpleDateFormat("kk:mm:ss");
private OHLCSeries ohlcSeries;
private TimeSeries volumeSeries;
private JFreeChart candlestickChart;
public JFreeCandlestickChart(String title) {
ObservableList<Candlestick> candlesticks = Exchange.getCandlesticks();
// Create new chart
candlestickChart = createChart(title, candlesticks);
// Create new chart panel
final ChartPanel chartPanel = new ChartPanel(candlestickChart);
chartPanel.setPreferredSize(new Dimension(832, 468));
chartPanel.getChart().getXYPlot().getDomainAxis().setAutoRange(false);
chartPanel.getChart().getXYPlot().getDomainAxis().setLowerBound(candlesticks.get(candlesticks.size() - 300).getTimestampOpen());
chartPanel.getChart().getXYPlot().getDomainAxis().setUpperBound(candlesticks.get(candlesticks.size() - 1).getTimestampOpen());
// Enable zooming - not workign?! ...
chartPanel.setMouseZoomable(true);
chartPanel.setMouseWheelEnabled(true);
chartPanel.addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
// process before
super.mouseDragged(e);
chartPanel.getChart().getXYPlot().getDomainAxis().configure();
// process after
}
});
add(chartPanel, BorderLayout.CENTER);
}
public JFreeChart createChart(String title, ObservableList<Candlestick> candlesticks){
/**
* 1st:
* Creating candlestick subplot
*/
// Create OHLCSeriesCollection as a price dataset for candlestick chart
OHLCSeriesCollection candlestickDataset = new OHLCSeriesCollection();
ohlcSeries = new OHLCSeries("Price");
candlestickDataset.addSeries(ohlcSeries);
// Create candlestick chart priceAxis
NumberAxis priceAxis = new NumberAxis("Price");
priceAxis.setAutoRangeIncludesZero(false);
// Create candlestick chart renderer
CandlestickRenderer candlestickRenderer = new CandlestickRenderer(CandlestickRenderer.WIDTHMETHOD_AVERAGE,
false,
new HighLowItemLabelGenerator(new SimpleDateFormat("kk:mm"), new DecimalFormat("0.00000000")));
// Create candlestickSubplot
XYPlot candlestickSubplot = new XYPlot(candlestickDataset, null, priceAxis, candlestickRenderer);
candlestickSubplot.setBackgroundPaint(Color.white);
/**
* 2nd:
* Creating volume subplot
*/
// creates TimeSeriesCollection as a volume dataset for volume chart
TimeSeriesCollection volumeDataset = new TimeSeriesCollection();
volumeSeries = new TimeSeries("Volume");
volumeDataset.addSeries(volumeSeries);
// Create volume chart volumeAxis
NumberAxis volumeAxis = new NumberAxis("Volume");
volumeAxis.setAutoRangeIncludesZero(true);
// Set to no decimal
volumeAxis.setNumberFormatOverride(new DecimalFormat("0"));
// Create volume chart renderer
XYBarRenderer timeRenderer = new XYBarRenderer();
timeRenderer.setShadowVisible(false);
timeRenderer.setDefaultToolTipGenerator(new StandardXYToolTipGenerator("Volume--> Time={1} Size={2}",
new SimpleDateFormat("kk:mm"), new DecimalFormat("0")));
// Create volumeSubplot
XYPlot volumeSubplot = new XYPlot(volumeDataset, null, volumeAxis, timeRenderer);
volumeSubplot.setBackgroundPaint(Color.white);
/**
* 3rd:
* Adding Candles to this chart
**/
for (Candlestick candle: candlesticks){
addCandleToChart(candle.getTimestampOpen(),
candle.getPriceOpen(),
candle.getPriceHigh(),
candle.getPriceLow(),
candle.getPriceClose(),
candle.getVolumeQuote());
}
/**
* 4th:
* Create chart main plot with two subplots (candlestickSubplot,
* volumeSubplot) and one common dateAxis
*/
// Creating charts common dateAxis
DateAxis dateAxis = new DateAxis("Time");
dateAxis.setDateFormatOverride(new SimpleDateFormat("dd.mm.yy kk:mm"));
//dateAxis.setRange();
// reduce the default left/right margin from 0.05 to 0.02
dateAxis.setLowerMargin(0.02);
dateAxis.setUpperMargin(0.02);
dateAxis.setLabelAngle(0);
// Create mainPlot
CombinedDomainXYPlot mainPlot = new CombinedDomainXYPlot(dateAxis);
mainPlot.setGap(10.0);
mainPlot.add(candlestickSubplot, 4);
mainPlot.add(volumeSubplot, 1);
mainPlot.setOrientation(PlotOrientation.VERTICAL);
mainPlot.setDomainPannable(true);
JFreeChart chart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT, mainPlot, false);
//chart.removeLegend();
// Einbetten in JScrollPaenl??? um Scrollen zu ermöglichen...
// ChartPanel chartPanel = new ChartPanel(chart);
return chart;
}
/**
* Fill series with data.
*
* #param c opentime
* #param o openprice
* #param h highprice
* #param l lowprice
* #param c closeprice
* #param v volume
*/
private void addCandleToChart(long time, double o, double h, double l, double c, double v) {
// Add bar to the data. Let's repeat the same bar
FixedMillisecond t = new FixedMillisecond(time);
//READABLE_TIME_FORMAT.parse(String.valueOf(time)));
ohlcSeries.add(t, o, h, l, c);
volumeSeries.add(t, v);
}
public void setOhlcSeries(OHLCSeries ohlcSeries) {
this.ohlcSeries = ohlcSeries;
}
public void setVolumeSeries(TimeSeries volumeSeries) {
this.volumeSeries = volumeSeries;
}
public OHLCSeries getOhlcSeries() {
return ohlcSeries;
}
public TimeSeries getVolumeSeries() {
return volumeSeries;
}
public JFreeChart getCandlestickChart() {
return candlestickChart;
}
}
I haven't looked at jFreeChart in detail, but I think the main difference between it and the in-built JavaFX charting API is that jFreeChart uses a canvas for its implementation, whereas the in-built charts use the scene graph. Roughly, though not exactly, its similar to this definition of a retained mode (scene graph) vs immediate mode (canvas).
It's probably possible to add interactivity to canvas rendered graphics. It is likely technically challenging beyond basic whole-chart zoom and drag ops. Implementing or demonstrating the addition of such interactivity with canvas rendered graphics is beyond what I would be prepared to do within the context of a StackOverflow answer.
JFreeChart includes an interaction package:
https://github.com/jfree/jfreechart-fx/tree/master/src/main/java/org/jfree/chart/fx/interaction
I suggest you investigate the interaction package, try using it and see if it offers the level of interaction you need.
As Roger mentions in the comments, you can get some basic interaction on a JFreeChartFX chart by wrapping the chart in a ChartViewer using ChartViewer(JFreeChart myChart).
Related question:
How do I properly add a MouseHandler to my JFreeChart-FX to drag the chart from left to right
An aside on Canvas vs SceneGraph
This info on how canvas works is included so that you might have a better idea of what is going on here (note everything here may not be 100% correct, but is close enough to help understanding).
Technically, JavaFX only uses a SceneGraph for rendering. How canvas is internally implemented, as far as I understand, is that each canvas is a node in the scenegraph and comes with a command queue of drawing instructions. When you draw to the canvas, it doesn't draw immediately, instead it puts the drawing commands into a queue, then, at some point, before the next 60fps drawing pulse completes, it renders those to an image buffer that it relays into a JavaFX node. Old commands are forgotten by the canvas command queue once executed, so everything just ends up as pixels eventually. You can keep track of drawing commands within your application and re-issue them to repaint the canvas from scratch if you wish, but canvas won't help with that.
What JFreeChartFX is doing is providing an adapter which makes a JavaFX canvas look like a Swing painting surface, so that the heavy lifting and internal engine of JFreeChart can be used to issue all of the drawing commands, and those can be rendered to either a JavaFX canvas or Swing canvas depending upon the desired output UI tech.
If JFreeChart also provided a similar adapter for JavaFX events, rather than Swing events, and if JFreeChart already has a way to do interactivity using Swing events, then it could potentially add interactivity to JFreeChartFX using a similar adapter or replacement for Swing event mechanisms. Perhaps that is what the interaction package linked above is doing.
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();
I have a data source in which there are three departments and each department has equal employees that are 8.
I want to make a pie chart using jFreeChart such that first we partition the pie into 3 equal parts for departments that is 120' for each department. Then in these partitions I want to show the sales of each employee. How can I do this in jFreeChart.
public class PieChart extends JFrame {
private PieDataset createDataset() {
DefaultPieDataset result = new DefaultPieDataset();
result.setValue("department1", 33.33);
result.setValue("department2", 33.33);
result.setValue("department3", 33.33);
return result;
}
private JFreeChart createChart(PieDataset dataset, String title) {
JFreeChart chart = ChartFactory.createPieChart3D(title, // chart title
dataset, // data
true, // include legend
true,
false);
PiePlot3D plot = (PiePlot3D) chart.getPlot();
plot.setStartAngle(290);
plot.setDirection(Rotation.CLOCKWISE);
plot.setForegroundAlpha(0.5f);
return chart;
}
}
public static void main(String[] args) {
PieChart demo = new PieChart("Comparison", "Which operating system are you using?");
demo.pack();
demo.setVisible(true);
}
PieChartDemo1 is a good starting point; focus on createDataset(); the full source is included in the distribution.
Addendum: How to further create partitions?
Ah, you want to sub-divide each 120° partition. DefaultPieDataset doesn't support a hierarchical structure directly, but you can use color in the PiePlot to highlight the grouping. Create related colors using Color.getHSBColor(), as shown here, and use setSectionPaint() to apply the colors accordingly.
i'm using jfreechart, and i need to add labels to my series data. There are bold dots on graphic and they need labels... Following code does not work.
XYSeries series = new XYSeries("Average Size");
series.add(.60, .70);
XYDataset xyDataset = new XYSeriesCollection(series);
XYItemRenderer rend = new XYShapeRenderer();
XYItemLabelGenerator generator = new XYItemLabelGenerator() {
#Override
public String generateLabel(XYDataset xyd, int i, int i1) {
return "Some label?";
}
};
//SeriesItemLabelGenerator
rend.setBaseItemLabelGenerator(generator);
rend.setBaseItemLabelsVisible(true);
ItemLabelPosition pos = new ItemLabelPosition(ItemLabelAnchor.CENTER, TextAnchor.TOP_LEFT);
rend.setBasePositiveItemLabelPosition(pos);
I think the problem is that XYShapeRenderer(http://www.jfree.org/jfreechart/api/javadoc/src-html/org/jfree/chart/renderer/xy/XYShapeRenderer.html), which extends AbstractXYItemRenderer, does not implement ItemLabelGenerator logic yet.
So, or you will need to use another Renderer.
For example, XYLineAndShapeRenderer(http://www.jfree.org/jfreechart/api/javadoc/src-html/org/jfree/chart/renderer/xy/XYLineAndShapeRenderer.html) implements it:
// draw the item label if there is one...
if (isItemLabelVisible(series, item)) {
drawItemLabel(g2, orientation, dataset, series, item, xx, yy,(y1 < 0.0));
}
Or you will need to extend XYShapeRenderer yourself and add the label drawing logic, using any of the other Renderer's source code as an example.
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.