This is my code at the moment (updated):
public DynamicTimeSeriesCollection dataset;
private static final String TITLE = "Stripchart";
private static final int COUNT = 3 * 60;
private static final int TEMP_MIN = -10;
private static final int TEMP_MAX = 50;
private static final int AIR_MIN = 0;
private static final int AIR_MAX = 20;
private static final int INSO_MIN = 0;
private static final int INSO_MAX = 1;
public void draw(Data data) {
float[] newData = new float[3];
newData[0] = (float) data.getTemp();
newData[1] = (float) data.getAir();
newData[2] = (float) data.getInso();
dataset.advanceTime();
dataset.appendData(newData);
}
private ChartPanel createChart() {
dataset = new DynamicTimeSeriesCollection(3, COUNT, new Second());
dataset.setTimeBase(new Second(0, 0, 0, 1, 1, 2016));
dataset.addSeries(new float[1], 0, "Temperature");
dataset.addSeries(new float[1], 1, "Air");
dataset.addSeries(new float[1], 2, "Insolation");
final JFreeChart result = ChartFactory.createTimeSeriesChart(
TITLE, "hh:mm:ss", " ", dataset, true, true, false);
final XYPlot plot = result.getXYPlot();
ValueAxis domain = plot.getDomainAxis();
domain.setAutoRange(true);
NumberAxis temp = new NumberAxis("Temperature");
NumberAxis air = new NumberAxis("Air");
NumberAxis inso = new NumberAxis("Insolation");
plot.setRangeAxis(0, temp);
plot.setRangeAxisLocation(0, AxisLocation.BOTTOM_OR_LEFT);
plot.setRangeAxis(1, air);
plot.setRangeAxisLocation(1, AxisLocation.BOTTOM_OR_LEFT);
plot.setRangeAxis(2, inso);
plot.setRangeAxisLocation(2, AxisLocation.BOTTOM_OR_LEFT);
List<Integer> axes = Arrays.asList(0, 1, 2);
plot.mapDatasetToRangeAxes(0, axes);
temp.setRange(TEMP_MIN, TEMP_MAX);
air.setRange(AIR_MIN, AIR_MAX);
inso.setRange(INSO_MIN, INSO_MAX);
ChartPanel chartPanel = new ChartPanel(result);
return chartPanel;
}
The units are °C , m/s and lux respectively.
Everything works fine but it does not map the series as exactly as I want.
As you can see, the blue line and green line are not mapped with the second and third axis.
Any ideas to get it working?
Your help will be appreciated.
// Updated :
I have tried using this but the result is the same:
List<Integer> axes = Arrays.asList(0, 1, 2);
plot.mapDatasetToRangeAxes(0, axes);
In your fragment, I see three axes and one dataset with three series. Your calls to mapDatasetToRangeAxis() appear to assume three distinct datasets. As suggested in this related example, you may want something like this:
List<Integer> axes = Arrays.asList(0, 1, 2);
plot.mapDatasetToRangeAxes(0, axes);
The approach assumes that the three series have linearly dependent scales, and you'll have to scale the individual axes accordingly, as shown here. You could try separate datasets, but I haven't tried it.
Addendum: Based on your update, it appears that the three datasets are not commensurate. Instead, create three individual datasets. Use the first in your chart factory, use setDataset() to establish the other two and map them accordingly:
final JFreeChart result = ChartFactory.createTimeSeriesChart(
TITLE, "hh:mm:ss", " ", createDatasetTemp(), true, true, false);
…
plot.setDataset(1, createDatasetAir());
plot.setDataset(2, createDatasetInso());
plot.setRangeAxis(0, temp);
plot.setRangeAxisLocation(0, AxisLocation.BOTTOM_OR_LEFT);
plot.setRangeAxis(1, air);
plot.setRangeAxisLocation(1, AxisLocation.BOTTOM_OR_LEFT);
plot.setRangeAxis(2, inso);
plot.setRangeAxisLocation(2, AxisLocation.BOTTOM_OR_LEFT);
plot.mapDatasetToRangeAxis(0, 0);
plot.mapDatasetToRangeAxis(1, 1);
plot.mapDatasetToRangeAxis(2, 2);
Related
I am trying to add annotations to my XYPlot; but unfortunately, they don't seem to show up.
Here is my code:
public JFreeChart createGraph() {
int[][] audiogramR = {{250, 25}, {500, 15}, {1000, 30}, {2000, 40}, {4000, 50}, {8000, 60}};
int[][] audiogramL = {{250, 60}, {500, 50}, {1000, 40}, {2000, 30}, {4000, 15}, {8000, 25}};
XYSeries r = new XYSeries("Right");
XYSeries l = new XYSeries("Left");
for (int i = 0; i <= 5; i++) { //add data to series
r.add(audiogramR[i][0], audiogramR[i][1]);
l.add(audiogramL[i][0], audiogramL[i][1]);
}
XYSeriesCollection dataset = new XYSeriesCollection(); //add series to dataset
dataset.addSeries(r);
dataset.addSeries(l);
NumberAxis yAxis = new NumberAxis("Decibels"); //create axes
LogAxis xAxis = new LogAxis("Frequency");
xAxis.setBase(2);
xAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
yAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
yAxis.setInverted(true);
yAxis.setRange(-10, 120);
Shape cross = ShapeUtilities.createDiagonalCross(3, 1);
Shape outer = new Ellipse2D.Float(-3.5f, -3.5f, 7, 7);
Shape inner = new Ellipse2D.Float(-3f, -3f, 6, 6); //shapes for plot
Area area = new Area(outer);
area.subtract(new Area(inner));
Shape ring = area;
XYPlot plot = new XYPlot(dataset, xAxis, yAxis, new XYLineAndShapeRenderer(true, true)); //create xy plot for dataset and axes
plot.getRenderer().setSeriesShape(1, cross);
plot.getRenderer().setSeriesShape(0, ring);
plot.setDomainGridlinesVisible(false);
XYTextAnnotation label = new XYTextAnnotation("Annotation text here", 50, 1024); //create annotation
plot.addAnnotation(label, true);
JFreeChart chart = new JFreeChart("Audiogram", JFreeChart.DEFAULT_TITLE_FONT, plot, true);
ChartPanel myChart = new ChartPanel(chart);
myChart.setPreferredSize(pGraph.getSize()); //size according to my window
myChart.setMouseWheelEnabled(false);
pGraph.setLayout(new java.awt.BorderLayout());
pGraph.add(myChart, BorderLayout.CENTER); //add chart to jPanel in netbeans
pGraph.validate();
}
which produces this:
Evidently, there is no annotation. Any thoughts?
As noted here,
The coordinates are specified in data space (they will be converted to Java2D space for display).
Your y value of 1024 is outside the range specified for your yAxis. As noted here, it may be useful to query the data itself for the required coordinates. In the fragment below, the series r provides the data space coordinates for the penultimate point:
double x = (double) r.getX(r.getItemCount() - 2);
double y = (double) r.getY(r.getItemCount() - 2);
XYTextAnnotation label = new XYTextAnnotation("Annotation", x, y);
plot.addAnnotation(label);
I have created a stacked bar chart using a template file. In my chart, there is one series and more than 100 legends. To show all legends I have adjusted the plot area Y-axis value, now the bar size bigger than expected. Are there any methods to adjust the Plot area height?
int additionalRows = barCount * barSize;
additionalRows = additionalRows + (addressList.size()/3);
chart = graphSheet.createDrawingPatriarch().createChart(new XSSFClientAnchor(100, 100, 100, 100, 1, currentIndex, 2, currentIndex+= additionalRows));
XSSFChart stackedFullBarChart = templateSheet.getDrawingPatriarch().getCharts().get(ChartType.STACKED_FULL_CHART.getValue());
chart.importContent(stackedFullBarChart);
chart.setTitleText(title);
XDDFChartData chartData = chart.getChartSeries().get(0);
XDDFDataSource<?> category = XDDFDataSourcesFactory.fromStringCellRange(dataSheet, categoryCells);
for (int i = 0; i < addressList.size(); i++) {
XDDFNumericalDataSource<?> values = XDDFDataSourcesFactory.fromNumericCellRange(dataSheet, addressList.get(i));
int seriesNameRow = addressList.get(i).getFirstRow() - 2;
int seriesNameCol = addressList.get(i).getFirstColumn();
XSSFCell seriesNameCell = dataSheet.getRow(seriesNameRow).getCell(seriesNameCol);
String seriesName = seriesNameCell.getStringCellValue();
if (i >= chartData.getSeriesCount()) {
XDDFChartData.Series series1 = chartData.addSeries(category, values);
series1.setTitle(seriesName, new CellReference(seriesNameCell));
} else {
chartData.getSeries(i).setTitle(seriesName, new CellReference(seriesNameCell));
chartData.getSeries(i).replaceData(category, values);
}
}
chart.getOrAddManualLayout().setWidthRatio(0.8);
**chart.getOrAddManualLayout().setHeightRatio(0.9);
chart.getOrAddManualLayout().setY(1.1);**
chart.plot(chartData);
chart.getOrAddLegend().setPosition(LegendPosition.TOP);
CTLegend ctLegend = chart.getCTChart().addNewLegend();
ctLegend.addNewLegendPos().setVal(STLegendPos.T);
CTBoolean ctBoolean = CTBoolean.Factory.newInstance();
ctBoolean.setVal(false);
ctLegend.setOverlay(ctBoolean);
CTDouble ctdouble = CTDouble.Factory.newInstance();
ctdouble.setVal(0.1);
chart.getCTChart().getPlotArea().getLayout().getManualLayout().setH(ctdouble);
Expected Output:
I am trying to obtain the equivalent of a matlab Pcolor added on a polar() function but in java.
I am pretty new to the language, but managed to obtain a polar plot already, with the following code:
public class Polar extends JFrame {
public Polar(double[][] vec){
XYDataset dataset = getXYDataset(vec);
JFreeChart chart = ChartFactory.createPolarChart("test", dataset, true, true, true);
PolarPlot plot = (PolarPlot) chart.getPlot();
DefaultPolarItemRenderer render = (DefaultPolarItemRenderer)
plot.getRenderer();
render.setFillComposite(...);
render.setSeriesFilled(0,true);
ChartPanel panel = new ChartPanel(chart);
panel.setMouseZoomable(false);
setContentPane(panel);
}
private XYDataset getXYDataset(double[][] vec){
XYSeriesCollection dataset = new XYSeriesCollection();
XYSeries faultDP =new XYSeries("Serie1");
for(int i = 0; i<vec.length; i++){
faultDP.add(vec[i][1],vec[i][0]);
}
dataset.addSeries(faultDP);
return dataset;
}
}
The array vec contains the speed and angle of my variable, and should be plotted on the polar plot. this works fine.
The next step would be to pass a new variable, a double[][] vector of dimension 90x360. Each cell should be plotted on the polar plot with background color value, a bit like in the picture below.
Any idea on how to do so ?
Cheers,
Flo
So, I've looked into what trashgod offered me and came with this code:
public class PolarTest extends JFrame {
public PolarTest(double[][] dipaz, double[][] val){
JFrame f = new JFrame("Title");
ChartPanel panel = new ChartPanel(createChart(val, dipaz));
panel.setPreferredSize(new Dimension(500,500));
f.add(panel);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private JFreeChart createChart(double[][] val,double[][] dipaz){
XYSeriesCollection dataset = new XYSeriesCollection ();
double step, min, max;
min = val[0][2];
max = val[val.length-1][2];
step = (max-min)/10; //creation of 10 areas of similar heat range
dataset = (XYSeriesCollection) createDataset(val,step);
JFreeChart chart = ChartFactory.createPolarChart("test", dataset, true, true, true);
PolarPlot plot = (PolarPlot) chart.getPlot();
DefaultPolarItemRenderer r = (DefaultPolarItemRenderer) plot.getRenderer();
r.setFillComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,0.5f));
for(int i =0; i<dataset.getSeriesCount(); i++){
r.setSeriesFilled(i, true);
r.setShapesVisible(false);
r.setDrawOutlineWhenFilled(false);
}
NumberAxis rangeAxis = (NumberAxis) plot.getAxis();
rangeAxis.setTickLabelsVisible(false);
return chart;
}
private XYDataset createDataset(double[][] val, double step){
XYSeriesCollection result = new XYSeriesCollection();
double dpTmp, breakPoint;
int cpt=1;
boolean t;
t= true;
dpTmp = val[0][2];
breakPoint = dpTmp + step;
XYSeries series = null ;
for(int i = 0; i< val.length; i++){
if(val[i][2] < breakPoint){
if(t){
series = new XYSeries(String.valueOf(cpt));
t = false;
}
series.add(val[i][1],val[i][0]);
cpt++;
}else{
result.addSeries(series);
i--;
t=true;
breakPoint = val[i][2] + step;
}
}
return result;
}
The array dipaz contains my angle and dip (of X,Y dots I'd like to later plot on the polar representation), while val a 3 by N array:
val[][0] = dip
val[][1] = angle
val[][2] = value of "heat" , if we see that problem as a heatmap.
val is ascending sorted by the third column. My idea was to split the whole array in 10 (or more) areas of similar heat values.
if I run this code, I obtain the following output (cf pic). We can see that it's getting there, but not quite. I am not sure that this code is able to map correctly my heat on the polar plot>
How could I get closer to the picture I posted in my first post?
Thank you for your help.
Flo
I have two data series with two different Y-axis and a single X-axis. I am trying to plot a Dual Y-Axis (or in Excel known as Secondary Y-Axis) so that the chart are scaled. But I only get a single Y-axis for both data series. Note: I am using AChartEngine 1.1.0
Can anyone please advise.
My code is given below with a screenshot.
public class LineChart {
public Intent getIntent(Context context){
int[] x = {1,2,3,4,5,6,7,8,9,10};
int[] y = {22,45,34,45,55,65,74,85,93,100};
TimeSeries series = new TimeSeries("Data1");
for(int i = 0; i<x.length; i++){
series.add(x[i], y[i]);
}
int[] x2 = {1,2,3,4,5,6,7,8,9,10};
int[] y2 = {223,454,334,454,554,655,745,855,935,510};
TimeSeries series2 = new TimeSeries("Data2");
for(int i = 0; i<x.length; i++){
series2.add(x2[i], y2[i]);
}
//Multiple Series Data Set
XYMultipleSeriesDataset dataset = new XYMultipleSeriesDataset();
dataset.addSeries(series); //First Data Series
dataset.addSeries(series2); //Second Data Series
//Multiple Series Renderer
XYMultipleSeriesRenderer mRenderer = new XYMultipleSeriesRenderer(2);
//Background
mRenderer.setApplyBackgroundColor(true);
mRenderer.setBackgroundColor(Color.BLACK);
//mRenderer.setMarginsColor(Color.parseColor("#F5F5F5"));
//Grid
mRenderer.setShowGridY(true);
mRenderer.setShowGridX(true);
mRenderer.setGridColor(Color.WHITE);
//Label
mRenderer.setLabelsTextSize(14);
mRenderer.setXLabelsColor(Color.GREEN);
//Min and Max
mRenderer.setXAxisMax(series.getMaxX());
mRenderer.setXAxisMin(series.getMinX());
//Dual yaxis
mRenderer.setYLabelsColor(0, Color.GREEN);
mRenderer.setYLabelsColor(1, Color.RED);
mRenderer.setYTitle("Y-AXIS1", 0);
mRenderer.setYTitle("Y-AXIS2", 1);
mRenderer.setYAxisAlign(Align.LEFT, 0);
mRenderer.setYAxisAlign(Align.RIGHT, 1);
mRenderer.setYLabelsAlign(Align.LEFT, 0);
mRenderer.setYLabelsAlign(Align.RIGHT, 1);
//First Series - Single Series Renderer
XYSeriesRenderer renderer = new XYSeriesRenderer();
renderer.setColor(Color.RED);
renderer.setPointStyle(PointStyle.CIRCLE);
renderer.setFillPoints(true);
//Second Series - Single Series Renderer
XYSeriesRenderer renderer2 = new XYSeriesRenderer();
renderer2.setColor(Color.GREEN);
renderer2.setPointStyle(PointStyle.CIRCLE);
renderer2.setFillPoints(true);
//Add renderers to multiple series Renderer
mRenderer.addSeriesRenderer(renderer);
mRenderer.addSeriesRenderer(renderer2);
Intent intent = ChartFactory.getLineChartIntent(context, dataset, mRenderer, "Line Graph Title");
return intent;
}
}
Finally, I have done it using this example - here
I'm trying to implement XYTextAnnotation in DynamicTimeSeriesCollection.
I have no idea how to find X value of series in DynamicTimeSeriesCollection. My code so far:
DynamicTimeSeriesCollection dataset = new DynamicTimeSeriesCollection(1, 60, new Minute());
final JFreeChart result = ChartFactory.createTimeSeriesChart(TITLE, "A", "B", dataset, true, true, false);
float[] series1Small = new float[10];
dataset.setTimeBase(new Minute(1, 1, 1, 1, 2013));
dataset.addSeries(series1Small,0,"1");
JFreeChart result = ChartFactory.createTimeSeriesChart(TITLE, "Время", "Платежи", dataset, true, true, false);
final XYPlot plot = result.getXYPlot();
-----------------------------------------------------------Below line doesn't work.
TimeSeriesDataItem item1 = series1.getDataItem(series1.getItemCount() - 1);
createAnnotation(item1,plot);
This is a function that used to work for annotation with TimeSeriesCollection.
public static void createAnnotation(TimeSeriesDataItem item,XYPlot plot)
{
double xAnnotation = item.getPeriod().getFirstMillisecond();
double yAnnotation = item.getValue().doubleValue();
XYTextAnnotation annotation = new XYTextAnnotation(item.getValue().toString(), xAnnotation, yAnnotation);
annotation.setFont(new Font("Arial",Font.BOLD,11));
plot.addAnnotation(annotation);
}
Starting form this example, I added the following lines in createChart() to obtain the image below:
double x = dataset.getXValue(0, COUNT - 1);
double y = dataset.getYValue(0, COUNT - 1);
String s = dataset.getY(0, COUNT - 1).toString();
XYTextAnnotation a = new XYTextAnnotation(s, x, y);
a.setFont(a.getFont().deriveFont(24f));
plot.addAnnotation(a);