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);
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 have tried the following.
Am using the MP android charts specifically the combined chart
// draw bars behind lines
mChart.setDrawOrder(new CombinedChart.DrawOrder[]{
CombinedChart.DrawOrder.BAR,
CombinedChart.DrawOrder.LINE,
});
YAxis rightAxis = mChart.getAxisRight();
rightAxis.setDrawGridLines(false);
rightAxis.setAxisMinimum(0f); // this replaces setStartAtZero(true)
YAxis leftAxis = mChart.getAxisLeft();
leftAxis.setDrawGridLines(false);
leftAxis.setAxisMinimum(0f); // this replaces setStartAtZero(true)
XAxis xAxis = mChart.getXAxis();
xAxis.setPosition(XAxis.XAxisPosition.BOTH_SIDED);
xAxis.setAxisMinimum(0f);
xAxis.setGranularity(1f);
CombinedData data = new CombinedData();
data.setData(generateLineData());
data.setData(setnewBarData());
mChart.setData(data);
So the above generates
As from the image above the values of bar chart are not centralized example the moles first bar is much to the center.
Also the line chart should be at the middle of each bar graph but it doesn't move to the middle
Where am i going wrong?
ADDITION
methods that set bar data
THe setnewBarData method is
public BarData setnewBarData() {
ArrayList<BarEntry> yVals1 = new ArrayList<BarEntry>();
for (int i = 0; i < itemcount + 1; i++) {
float mult = (itemcount + 1);
float val1 = (float) (Math.random() * mult) + mult / 3;
float val2 = (float) (Math.random() * mult) + mult / 3;
yVals1.add(new BarEntry(
i,
new float[]{val1, val2,},
getResources().getDrawable(R.drawable.back_arrow_white)));
}
BarDataSet set1;
set1 = new BarDataSet(yVals1, "Statistics Test 2018");
set1.setDrawIcons(false);
set1.setColors(new int[]{Color.rgb(61, 165, 255),Color.rgb(128, 133, 233)});
set1.setStackLabels(new String[]{"Births", "Divorces"});
set1.setAxisDependency(YAxis.AxisDependency.LEFT);
ArrayList<IBarDataSet> dataSets = new ArrayList<IBarDataSet>();
dataSets.add(set1);
BarData data = new BarData(dataSets);
data.setValueTextColor(Color.BLACK);
data.setBarWidth(0.5f);
return data;
}
THe method to generate line data is
private LineData generateLineData() {
LineData d = new LineData();
ArrayList<Entry> entries = new ArrayList<Entry>();
for (int index = 0; index < itemcount; index++)
entries.add(new Entry(index + 0.5f, getRandom(15, 5)));
LineDataSet set = new LineDataSet(entries, "Percentage Compliance");
set.setColor(Color.rgb(240, 238, 70));
set.setLineWidth(2.5f);
set.setCircleColor(Color.rgb(240, 238, 70));
set.setCircleRadius(5f);
set.setFillColor(Color.rgb(240, 238, 70));
set.setMode(LineDataSet.Mode.CUBIC_BEZIER);
set.setDrawValues(true);
set.setValueTextSize(10f);
set.setValueTextColor(Color.rgb(240, 238, 70));
set.setAxisDependency(YAxis.AxisDependency.LEFT);
d.addDataSet(set);
return d;
}
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);
i tried MPAndroidChart dynamic multiple line
private LineChart mChart;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mChart = (LineChart) findViewById(R.id.chart1);
mChart.setDrawGridBackground(false);
mChart.setDescription("");
mChart.setNoDataTextDescription("You need to provide data for the chart.");
mChart.setTouchEnabled(true);
mChart.setDragEnabled(true);
mChart.setScaleEnabled(true);
mChart.setPinchZoom(true);
LimitLine llXAxis = new LimitLine(10f, "Index 10");
llXAxis.setLineWidth(4f);
llXAxis.enableDashedLine(10f, 10f, 0f);
llXAxis.setLabelPosition(LimitLine.LimitLabelPosition.RIGHT_BOTTOM);
llXAxis.setTextSize(10f);
XAxis xAxis = mChart.getXAxis();
xAxis.enableGridDashedLine(10f, 10f, 0f);
YAxis leftAxis = mChart.getAxisLeft();
leftAxis.removeAllLimitLines();
leftAxis.enableGridDashedLine(10f, 10f, 0f);
leftAxis.setDrawZeroLine(false);
leftAxis.setDrawLimitLinesBehindData(true);
mChart.getAxisRight().setEnabled(false);
float[] lineData_0 = {37500, 38000, 38500, 39000, 39500, 40000, 40500};
float[] lineData_1 = {3000, 3500, 3800, 3600, 3400, 2000, 2800};
float[] lineData_2 = {0, 0, 6000, 25000, 24800, 24750, 5000};
float[] lineData_3 = {0, 6500, 11000, 12500, 13000, 14000, 2000};
float[] lineData_4 = {0, 9000, 12400, 12450, 9300, 8000, 6000};
float[][] all_line_data = {lineData_0, lineData_1, lineData_2, lineData_3, lineData_4};
ArrayList<ILineDataSet> dataSets = null;
ArrayList<Entry>[] values = (ArrayList<Entry>[]) new ArrayList[all_line_data.length];
for (int j = 0; j < all_line_data.length; j++) {
for (int i = 0; i < all_line_data[j].length; i++) {
values[j].add(new Entry(all_line_data[j][i], i));
}
LineDataSet[] set0 = new LineDataSet[j];
set0[j].enableDashedLine(10f, 5f, 0f);
set0[j].enableDashedHighlightLine(10f, 5f, 0f);
set0[j].setColor(Color.BLACK);
set0[j].setCircleColor(Color.BLACK);
set0[j].setLineWidth(1f);
set0[j].setCircleRadius(3f);
set0[j].setDrawCircleHole(false);
set0[j].setValueTextSize(9f);
set0[j].setDrawFilled(true);
dataSets = new ArrayList<ILineDataSet>();
dataSets.add(set0[j]);
}
LineData data = new LineData(dataSets);
mChart.setData(data);
}
I am getting the following error....
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.util.ArrayList.add(java.lang.Object)' on a null object reference
i solved this problem
LineChart mChart = (LineChart) findViewById(R.id.chartLine);
mChart.setDrawGridBackground(true);
// no description text
mChart.setDescription("");
mChart.setNoDataTextDescription("You need to provide data for the chart.");
// enable touch gestures
mChart.setTouchEnabled(true);
// enable scaling and dragging
mChart.setDragEnabled(true);
mChart.setScaleEnabled(true);
// if disabled, scaling can be done on x- and y-axis separately
mChart.setPinchZoom(true);
CustomMarkerView mv = new CustomMarkerView (MainActivity.this, R.layout.line_graph_marker_view, colors);
mChart.setMarkerView(mv);
// x-axis limit line
LimitLine llXAxis = new LimitLine(10f, "Index 10");
llXAxis.setLineWidth(4f);
llXAxis.setLabelPosition(LimitLine.LimitLabelPosition.RIGHT_BOTTOM);
llXAxis.setTextSize(10f);
XAxis xAxis = mChart.getXAxis();
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
YAxis leftAxis = mChart.getAxisLeft();
leftAxis.removeAllLimitLines(); // reset all limit lines to avoid overlapping lines
leftAxis.setAxisMinValue(0);
leftAxis.setDrawZeroLine(true);
// limit lines are drawn behind data (and not on top)
leftAxis.setDrawLimitLinesBehindData(true);
mChart.getAxisRight().setEnabled(false);
float[] lineData_0 = {37500, 38000, 38500, 39000, 39500, 40000, 40500};
float[] lineData_1 = {3000, 3500, 3800, 3600, 3400, 2000, 2800};
float[] lineData_2 = {0, 0, 6000, 25000, 24800, 24750, 5000};
float[] lineData_3 = {0, 6500, 11000, 12500, 13000, 14000, 2000};
float[] lineData_4 = {0, 9000, 12400, 12450, 9300, 8000, 6000};
float[][] all_line_data = {lineData_0, lineData_1, lineData_2, lineData_3, lineData_4};
int[] graph_linear_background = {R.drawable.graph_background_0, R.drawable.graph_background_1, R.drawable.graph_background_2, R.drawable.graph_background_3, R.drawable.graph_background_4};
int[] graph_linear_point_color = {Color.rgb(100, 199, 255), Color.rgb(109, 220, 124), Color.rgb(236, 91, 102), Color.rgb(184, 85, 240), Color.rgb(70, 119, 191)};
List<ArrayList<Entry>> values_all = new ArrayList<ArrayList<Entry>>();
for (int k = 0; k < all_line_data.length; k++) {
ArrayList<Entry> list = new ArrayList<>();
for (int i = 0; i < all_line_data[k].length; i++) {
list.add(new Entry(i, all_line_data[k][i]));
}
values_all.add(list);
}
ArrayList<ILineDataSet> dataSets = new ArrayList<ILineDataSet>();
String[] arr = new String[]{"a", "b", "c", "d", "e", "f"};
Map<String, LineDataSet> map = new HashMap<>();
for(int i = 0; i < all_line_data.length; i++) {
map.put("set0" + i, new LineDataSet(values_all.get(i), arr[i]));
// set the line to be drawn like this "- - - - - -"
map.get("set0" + i).setColor(graph_linear_point_color[i]);
map.get("set0" + i).setCircleColor(graph_linear_point_color[i]);
map.get("set0" + i).setLineWidth(3f);
map.get("set0" + i).setDrawValues(false);
map.get("set0" + i).setCircleRadius(4f);
map.get("set0" + i).setDrawCircleHole(false);
map.get("set0" + i).setDrawFilled(true);
dataSets.add(map.get("set0" + i));
if (Utils.getSDKInt() >= 18) {
// fill drawable only supported on api level 18 and above
Drawable drawable = ContextCompat.getDrawable(this, graph_linear_background[i]);
map.get("set0" + i).setFillDrawable(drawable);
} else {
map.get("set0" + i).setFillColor(Color.TRANSPARENT);
}
}
// create a data object with the datasets
LineData line_data = new LineData(dataSets);
// set data
mChart.setData(line_data);
output is....