I have two classes, the first contains the existing GUI and the second is for creating a line chart.
Now my question is how can I include the created Chart in my existing GUI without creating a new Window like it is now?
Chart Creating Method:
public void start(Stage s) throws Exception {
s.setTitle("JavaFX Realtime Chart Demo");
//defining the axes
final CategoryAxis xAxis = new CategoryAxis(); // we are gonna plot against time
final NumberAxis yAxis = new NumberAxis(0,10,1);
xAxis.setLabel("Time/s");
xAxis.setAnimated(false); // axis animations are removed
yAxis.setLabel("Value");
yAxis.setAnimated(false); // axis animations are removed
//creating the line chart with two axis created above
final LineChart<String, Number> lineChart = new LineChart<>(xAxis, yAxis);
lineChart.setTitle("Realtime JavaFX Charts");
lineChart.setAnimated(true); // disable animations
//defining a series to display data
XYChart.Series<String, Number> series = new XYChart.Series<>();
series.setName("U/s");
XYChart.Series<String, Number> series2 = new XYChart.Series<>();
series2.setName("km/h");
// add series to chart
lineChart.getData().addAll(series,series2);
// setup scene
Scene scene = new Scene(lineChart, 800, 600);
s.setScene(scene);
// show the stage
s.show();
// this is used to display time in HH:mm:ss format
final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
// setup a scheduled executor to periodically put data into the chart
scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
// put dummy data onto graph per second
scheduledExecutorService.scheduleAtFixedRate(() -> {
// get a random integer between 0-10
wert = G.gebeInt();
wert_2 = G.gebeV();
// Update the chart
Platform.runLater(() -> {
// get current time
Date now = new Date();
// put random number with current time
series.getData().add(new XYChart.Data<>(simpleDateFormat.format(now), wert));
series2.getData().add(new XYChart.Data<>(simpleDateFormat.format(now), wert_2));
if (series.getData().size() > WINDOW_SIZE) {
series.getData().remove(0);
}
if (series2.getData().size() > WINDOW_SIZE) {
series2.getData().remove(0);
}
});
}, 0, 2, TimeUnit.SECONDS);
}
I use Swing for the GUI and JavaFX for creating the charts, in this case a LineChart.
Related
Currently I'm working on charts and want to achieve an output.
I wanted to achieve two things.
To display candle stick chart of stocks data. [done]
To display the stock split log above or below the candle. [pending]
I'm using JFreeChart SDK to build the charts.
I'm using OHLCDataItem[] to build data for daily high/low etc of stock. unfortunately jfreechart does not have any extension of OHLCDataItem to show additional information (logo + text metadata) on the candle.
Sample code:
TimeSeries timeSeriesDailyMovingAverage = new TimeSeries("day moving average");
List<OHLCDataItem> dataItems = new ArrayList<OHLCDataItem>(); //to collect High low close prices
OHLCDataItem item = new OHLCDataItem(date, open, high, low, adjClose, volume);//this code is in loop with do that more data can be added for each day
dataItems.add(item);
OHLCDataItem[] data = dataItems.toArray(new OHLCDataItem[dataItems.size()]);
OHLCDataset dataset = new DefaultOHLCDataset(symbol, data);
//now initializing the candleStickRanderer and setting its properties series strock + paint
CandlestickRenderer CandleStickRenderer = new CandlestickRenderer();
XYLineAndShapeRenderer LineRenderer = new XYLineAndShapeRenderer(true, false);
HighLowRenderer OHLCRenderer = new HighLowRenderer();
DateAxis domainAxis = new DateAxis();
NumberAxis rangeAxis = new NumberAxis();
rangeAxis.setStandardTickUnits(NumberAxis.createStandardTickUnits());
XYPlot plot = new XYPlot(dataset, domainAxis, rangeAxis, LineRenderer);//set other properties
JFreeChart chart = new JFreeChart(info, new Font("SansSerif", Font.PLAIN, 15), plot, false);
ChartPanel chartPanel = new ChartPanel(chart);
JPanel panel = new JPanel(new BorderLayout());
panel.add(chartPanel, BorderLayout.CENTER);
getContentPane().add(panel);
XYPlot xyplot = (XYPlot) chart.getPlot();
xyplot.setRenderer(CandleStickRenderer);
This is some rough code which is working fine. I'm getting the desired out of Candle chart.
current output of candle stick
But I cannot figure out how can I add text/logo on XYPlot based on dataset.
What I want to achieve is that, add text/or shape containing text information at the bottom/top of a particular candle.
It would be a great help if someone can guide me how I can do it based on the dataset.
The desired output is like this chart.
desired output
Or
desired output
Is there a way to wrap plot label for Category axis?
I'm facing a problem where these titles merge between the plots. It would be best if they would wrap at least once. Is it possible?
The titles are dynamic.
Here's the classes I use to construct it.
var renderer = new LineAndShapeRenderer();
...
var yAxis = new NumberAxis();
...
var xAxis = new CategoryAxis(title);
...
CategoryPlot plot = new CategoryPlot(dataset, xAxis, yAxis, renderer);
...
var combinedPlot = new CombinedRangeCategoryPlot();
combinedPlot.add(plot, weight);
...
I'm using version 1.0.19 of JFreeChart since newer versions produce some visual artifacts.
I have created one graph which shows strings at x axis and dollars at y axis. I am able to see the values on graph but my data is too much to show on graph.
Graph is scrollable so I want to show minimun number of values on bar like below graph.
But now I am getting too much bars in graph like this:
This is my code:
public void setGraph() {
if (sessionData.getString("graphType", "").equals("d") || sessionData.getString("graphType", "").equals("m"))
{
int index = 0;
String[] dates = new String[totalOrdersList.size()];
mChart.setDrawBarShadow(false);
mChart.setDrawValueAboveBar(false);
mChart.getDescription().setEnabled(false);
mChart.setBackgroundColor(ContextCompat.getColor(getActivity(), R.color.lightGrey));
// mChart.setScaleEnabled(false);
// if more than 60 entries are displayed in the chart, no values will be
// drawn
mChart.setMaxVisibleValueCount(60);
// scaling can now only be done on x- and y-axis separately
mChart.setPinchZoom(false);
mChart.setDrawGridBackground(false);
// mChart.setDrawYLabels(false);
IndexAxisValueFormatter xAxisFormatter = new IndexAxisValueFormatter(dates);
XAxis xAxis = mChart.getXAxis();
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
xAxis.setDrawGridLines(false);
xAxis.setLabelCount(3);
xAxis.setValueFormatter(xAxisFormatter);
xAxis.setGranularity(1f);
com.github.mikephil.charting.formatter.IAxisValueFormatter custom = new MyAxisValueFormatter();
YAxis leftAxis = mChart.getAxisLeft();
leftAxis.setLabelCount(8, false);
leftAxis.setValueFormatter(custom);
leftAxis.setPosition(YAxis.YAxisLabelPosition.OUTSIDE_CHART);
leftAxis.setSpaceTop(15f);
leftAxis.setAxisMinimum(0f); // this replaces setStartAtZero(true)
YAxis rightAxis = mChart.getAxisRight();
rightAxis.setDrawGridLines(false);
rightAxis.setLabelCount(8, false);
rightAxis.setValueFormatter(custom);
rightAxis.setSpaceTop(15f);
rightAxis.setAxisMinimum(0f);
rightAxis.setEnabled(false);
// this replaces setStartAtZero(true)
Legend l = mChart.getLegend();
l.setVerticalAlignment(Legend.LegendVerticalAlignment.BOTTOM);
l.setHorizontalAlignment(Legend.LegendHorizontalAlignment.LEFT);
l.setOrientation(Legend.LegendOrientation.HORIZONTAL);
l.setDrawInside(false);
l.setForm(Legend.LegendForm.SQUARE);
l.setFormSize(9f);
l.setTextSize(11f);
l.setXEntrySpace(4f);
ArrayList<BarEntry> barEntries = new ArrayList<>();
for (Order o : totalOrdersList) {
dates[index] = o.getDate();
barEntries.add(new BarEntry(index, Float.parseFloat(o.getAmount())));
index++;
}
BarDataSet set1 = new BarDataSet(barEntries, "Months");
set1.setValues(barEntries);
set1.setColor(ContextCompat.getColor(getActivity(), R.color.orange));
ArrayList<IBarDataSet> dataSets = new ArrayList<IBarDataSet>();
dataSets.add(set1);
BarData data = new BarData(dataSets);
data.setValueTextSize(10f);
data.setBarWidth(0.9f);
mChart.setData(data);
mChart.animateXY(3000, 3000);
}
Please help.. Thank you..
I've created a BoxAndWhiskerRenderer plot using JFreeChart and it seems that it is automatically creating a sort of legend (see attached picutre).
Is there a way to remove the outside border of this legend and customize the font of the labels in the legend items?
Here is an example of my code:
//Get the desired BoxAndWhiskerCategoryDataset from a LinkedHashMap
BoxAndWhiskerCategoryDataset dataset = values.get(b);
//Create X axis
CategoryAxis xAxis = new CategoryAxis();
xAxis.setAxisLineVisible(false);
//Create Y axis
NumberAxis yAxis = new NumberAxis(b.getLabel());
yAxis.setAxisLineVisible(false);
yAxis.setTickLabelFont(FDFont.getFont(12f));
yAxis.setLabelFont(FDFont.getFont());
yAxis.setLabelPaint(FDPalette.secondaryText);
yAxis.setTickLabelPaint(FDPalette.secondaryText);
yAxis.setAutoRangeIncludesZero(false);
//Create renderer
BoxAndWhiskerRenderer renderer = new BoxAndWhiskerRenderer();
int count = 0;
for(Map.Entry<Integer,Color> map : clusterColor.entrySet()){
//Set color for the series (I have a previously created map which links colors and series)
renderer.setSeriesPaint(count,map.getValue());
count++;
}
renderer.setFillBox(true);
renderer.setToolTipGenerator(new BoxAndWhiskerToolTipGenerator());
CategoryPlot plot = new CategoryPlot(dataset, xAxis, yAxis, renderer);
JFreeChart chart = new JFreeChart(plot);
chart.setBackgroundPaint(white);
chart.setBorderVisible(false);
ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new java.awt.Dimension(300, 270));
As shown here, the simplest JFreeChart constructor adds a legend by default. The code for doing so is seen here; simply substitute your desired frame, color and position.
Starting from this example, the following changes produce the chart shown below:
private void createChartPanel() {
…
JFreeChart chart = new JFreeChart("BoxAndWhiskerDemo", plot);
LegendTitle legend = chart.getLegend();
legend.setFrame(new LineBorder(Color.white, new BasicStroke(1.0f),
new RectangleInsets(1.0, 1.0, 1.0, 1.0)));
legend.setItemFont(legend.getItemFont().deriveFont(16f));
chartPanel = new ChartPanel(chart);
}
Compare to this default legend:
I am trying to plot a real time graph using the data from serial port which arrives approx 1 sample/5 msec. So it is basically a Integer_Value Vs Time graph. Below is code to draw graph using JFreeChar (ScatterChart). In receive event handler of serial port listener I call method xySeries.add(x, y); with appropriate x and y co-ordinates.
Now plot appearance as expected is like
1. start from left end point of chart
2. Plot till right end
3. Restart from left end point of char
4. keep repeating this refresh cycles as I keep receiving continuous data over serial port.
However, I am stuck with problem #3 and #4. How to clean off the chart and restart from left end point? Also in #1 and #2 I am able to plot the points but it starts somewhere in right bottom end of chart. But I have used
xyPlot.setRangeAxisLocation(AxisLocation.BOTTOM_OR_LEFT);
xyPlot.setDomainAxisLocation(AxisLocation.BOTTOM_OR_LEFT);
which should ideally start from bottom left end of chart, but it does not.
Would appreciate some pointers in this direction
Thank you in advance.
public void addPoint(Number x, Number y) {
Comment:This function is called from Serial Port receive event handler that supplies X,Y values
XYItemRenderer renderer = xyPlot.getRenderer();
//System.out.println("addPoint y = " + y.doubleValue() + " minThresholdMarker" + minThresholdMarker);
if(y.doubleValue() > minThresholdMarker) {
GradientPaint gPaint = new GradientPaint(2.0f, 6.0f, Color.lightGray, 2.0f, 6.0f, Color.green);
xyPlot.setBackgroundPaint(gPaint);
renderer.setSeriesPaint(0, Color.green);
if(!countDownTimerRunning /*&& !bTimeOver */) {
timerCountDown = new Timer(1000, countDownTimeListener);
timerCountDown.setInitialDelay(0);
countDown = TREATMENT_DURATION;
countElapsed = 0;
timerCountDown.start();
countDownTimerRunning = true;
timerDispPanel.setBackground(new Color(240, 230, 140));
}
}
else {
GradientPaint gPaint = new GradientPaint(4.0f, 6.0f, Color.lightGray, 3.0f, 6.0f, Color.lightGray);
xyPlot.setBackgroundPaint(gPaint);
if(countDownTimerRunning) {
stopCountDownTimer();
}
if(patientReady) {
renderer.setSeriesPaint(0, Color.blue);
}
else {
renderer.setSeriesPaint(0, Color.black);
}
timerDispPanel.setBackground(new Color(240, 240, 240));
if(bTimeOver)
bTimeOver = false;
else
bTimeOver = true;
}
xyPlot.setRenderer(renderer);
xySeries.add(x, y);
}
private ChartPanel drawChart() {
XYSeriesCollection xySeriesCollection = new XYSeriesCollection();
xySeries = new XYSeries("");
xySeriesCollection.addSeries(xySeries);
JFreeChart chart = ChartFactory.createScatterPlot("Breathing Co-ordinator", "Time (ms)", "Volume (liters)", xySeriesCollection);
// Get the XY Plot from the scatter chart
xyPlot = (XYPlot) chart.getPlot();
xyPlot.setDomainCrosshairVisible(true);
xyPlot.setRangeCrosshairVisible(true);
ValueAxis Xaxis = xyPlot.getDomainAxis();
Xaxis.setAutoRange(true);
Xaxis.setFixedAutoRange(80.0);
ValueAxis Yaxis = xyPlot.getRangeAxis();
Yaxis.setFixedAutoRange(6.0);
// Create the renderer
XYItemRenderer renderer = xyPlot.getRenderer();
renderer.setSeriesPaint(1, Color.blue);
NumberAxis domain = (NumberAxis) xyPlot.getDomainAxis();
domain.setVerticalTickLabels(false);
NumberAxis range = (NumberAxis) xyPlot.getRangeAxis();
range.setVerticalTickLabels(false);
chartPanel_1 = new ChartPanel(chart);
chartPanel_1.setZoomAroundAnchor(true);
chartPanel_1.setMaximumDrawHeight(700);
chartPanel_1.setRefreshBuffer(true);
chartPanel_1.setLocation(0, 0);
chartPanel_1.setSize(1200, 519);
chartPanel_1.setLayout(new BorderLayout(0, 0));
NumberAxis xAxis = (NumberAxis) xyPlot.getDomainAxis();
NumberAxis yAxis = (NumberAxis) xyPlot.getRangeAxis();
yAxis.setRange(-3.0, 4.0);
xyPlot.setRangeAxisLocation(AxisLocation.BOTTOM_OR_LEFT);
xyPlot.setDomainAxisLocation(AxisLocation.BOTTOM_OR_LEFT);
return chartPanel_1;
}