I am using MPAndroid Library to create pie chart in my app, i am able take user input and display in pie chart but when user enter same value which is already in pie chart it won't displayed in pie chart and again when i enter different value, the previous value which i entered but didn't displayed will display in pie chart.
Any help will be appreciated !! Thank You.
Below is my pieChart method:
public void pieChart() {
mydb = new DBHelper(this);
try {
//Check for table in database
if (mydb.checkForTables())
{
stringItems.addAll(mydb.getAllItem());
intItems.addAll(mydb.getAllAmount());
} else {
Toast.makeText(this, "Data table is empty.", Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
e.printStackTrace();
}
List<Entry> yVals1 = new ArrayList<Entry>();
if(intItems.size() > 0)
{
for (int i = 0; i < intItems.size(); i++)
yVals1.add(new Entry(intItems.get(i), i));
}
else {
Toast.makeText(this,"intItem is empty !!",Toast.LENGTH_LONG).show();
}
List<String> xVals = new ArrayList<String>();
if(stringItems.size() > 0)
{
for (int i = 0; i < stringItems.size(); i++)
xVals.add(stringItems.get(i));
}else {
Toast.makeText(this,"stringItem is empty !!",Toast.LENGTH_LONG).show();
}
// create pieDataSet
PieDataSet dataSet = new PieDataSet(yVals1, " ");
dataSet.setSliceSpace(3);
dataSet.setSelectionShift(5);
// adding colors
List<Integer> colors = new ArrayList<Integer>();
// Added My Own colors
for (int c : MY_COLORS)
colors.add(c);
dataSet.setColors(colors);
// create pie data object and set xValues and yValues and set it to the pieChart
PieData data = new PieData(xVals, dataSet);
// data.setValueFormatter(new DefaultValueFormatter());
// data.setValueFormatter(new PercentFormatter());
data.setValueFormatter(new MyValueFormatter());
data.setValueTextSize(10f);
data.setValueTextColor(Color.WHITE);
mChart.setData(data);
// undo all highlights
mChart.highlightValues(null);
// refresh/update pie chart
mChart.invalidate();
// animate piechart
mChart.animateXY(1400, 1400);
// Legends to show on bottom of the graph
Legend l = mChart.getLegend();
l.setPosition(Legend.LegendPosition.BELOW_CHART_CENTER);
l.setXEntrySpace(7);
l.setYEntrySpace(5);
}
private SpannableString generateCenterSpannableText() {
SpannableString s = new SpannableString("Overview");
s.setSpan(new RelativeSizeSpan(1.7f), 0, 8, 0);
s.setSpan(new StyleSpan(Typeface.NORMAL), 8, s.length(), 0);
return s;
}
public class MyValueFormatter implements ValueFormatter {
private DecimalFormat mFormat;
public MyValueFormatter() {
mFormat = new DecimalFormat("###,###,##0"); // use one decimal if needed
}
#Override
public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
// write your logic here
return mFormat.format(value) + ""; // e.g. append a dollar-sign
}
}
Related
I am a newbie to using POI at work.Now i'm going to use POI in java to read a bar chart in the PPT.I've added several series x to it in advance,which are the column headers of the excel to which the bar graph belongs.
But i can only read the first three columns by default with the POI.In addition,once I modify the column header of the bar chart,or want to add a fourth column(thar is,add a color)to a bar chart with only three columns, the bar chart cannot be edited when I open the PPT,indicating that the node of the bar chart is damaged.
So is there a master who can help talking how to use POI to prroperly add a color to the bar chart(add a series)?
Eg: when I debug to the "
long ptCatCnt = catDataSource.getStrRef().getStrCache().getPtCount().getVal();
It show nullpointerexecption, I don't know how structure in ppt the bar-chart is.So I want know how to update the bar-chart。
The code is :
public class PPTDemo {
public void run() {
try {
SlideShow slideShow = SlideShowFactory.create(new File("./res/1.pptx"));
for (Object o : slideShow.getSlides()) {
XSLFSlide slider = (XSLFSlide) o;
// 第一页
if (slider.getSlideNumber() == 1) {
for (POIXMLDocumentPart.RelationPart part : slider.getRelationParts()) {
POIXMLDocumentPart documentPart = part.getDocumentPart();
// 是图表
if (documentPart instanceof XSLFChart) {
XSLFChart chart = (XSLFChart) documentPart;
// 查看里面的图表数据,才能知道是什么图表
CTPlotArea plot = chart.getCTChart().getPlotArea();
// 测试数据
List<SeriesData> seriesDatas = Arrays.asList(
new SeriesData("", Arrays.asList(
new NameDouble("行1", Math.random() * 100),
new NameDouble("行2", Math.random() * 100),
new NameDouble("行3", Math.random() * 100),
new NameDouble("行4", Math.random() * 100),
new NameDouble("行5", Math.random() * 100)
)),
new SeriesData("", Arrays.asList(
new NameDouble("行1", Math.random() * 100),
new NameDouble("行2", Math.random() * 100),
new NameDouble("行3", Math.random() * 100),
new NameDouble("行4", Math.random() * 100),
new NameDouble("行5", Math.random() * 100)
))
);
XSSFWorkbook workbook = chart.getWorkbook();
XSSFSheet sheet = workbook.getSheetAt(0);
// 柱状图
if (!plot.getBarChartList().isEmpty()) {
CTBarChart barChart = plot.getBarChartArray(0);
updateChartExcelV(seriesDatas, workbook, sheet);
workbook.write(chart.getPackagePart().getOutputStream());
int i = 0;
for (CTBarSer ser : barChart.getSerList()) {
updateChartCatAndNum(seriesDatas.get(i), ser.getTx(), ser.getCat(), ser.getVal());
++i;
}
}
// 饼图
else if (!plot.getPieChartList().isEmpty()) {
// 示例饼图只有一列数据
updateChartExcelV(Arrays.asList(seriesDatas.get(0)), workbook, sheet);
workbook.write(chart.getPackagePart().getOutputStream());
CTPieChart pieChart = plot.getPieChartArray(0);
int i = 0;
for (CTPieSer ser : pieChart.getSerList()) {
updateChartCatAndNum(seriesDatas.get(i), ser.getTx(), ser.getCat(), ser.getVal());
++i;
}
}
}
}
}
}
try {
try (FileOutputStream out = new FileOutputStream("./res/o1.pptx")) {
slideShow.write(out);
}
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
} catch (InvalidFormatException e) {
e.printStackTrace();
}
}
/**
* 更新图表的关联 excel, 值是纵向的
*
* #param param
* #param workbook
* #param sheet
*/
protected void updateChartExcelV(List<SeriesData> seriesDatas, XSSFWorkbook workbook, XSSFSheet sheet) {
XSSFRow title = sheet.getRow(0);
for (int i = 0; i < seriesDatas.size(); i++) {
SeriesData data = seriesDatas.get(i);
if (data.name != null && !data.name.isEmpty()) {
// 系列名称,不能修改,修改后无法打开 excel
// title.getCell(i + 1).setCellValue(data.name);
}
int size = data.value.size();
for (int j = 0; j < size; j++) {
XSSFRow row = sheet.getRow(j + 1);
if (row == null) {
row = sheet.createRow(j + 1);
}
NameDouble cellValu = data.value.get(j);
XSSFCell cell = row.getCell(0);
if (cell == null) {
cell = row.createCell(0);
}
cell.setCellValue(cellValu.name);
cell = row.getCell(i + 1);
if (cell == null) {
cell = row.createCell(i + 1);
}
cell.setCellValue(cellValu.value);
}
int lastRowNum = sheet.getLastRowNum();
if (lastRowNum > size) {
for (int idx = lastRowNum; idx > size; idx--) {
sheet.removeRow(sheet.getRow(idx));
}
}
}
}
/**
* 更新 chart 的缓存数据
*
* #param data 数据
* #param serTitle 系列的标题缓存
* #param catDataSource 条目的数据缓存
* #param numDataSource 数据的缓存
*/
protected void updateChartCatAndNum(SeriesData data, CTSerTx serTitle, CTAxDataSource catDataSource,
CTNumDataSource numDataSource) {
// 更新系列标题
// serTitle.getStrRef().setF(serTitle.getStrRef().getF()); //
// serTitle.getStrRef().getStrCache().getPtArray(0).setV(data.name);
// TODO cat 也可能是 numRef
long ptCatCnt = catDataSource.getStrRef().getStrCache().getPtCount().getVal();
long ptNumCnt = numDataSource.getNumRef().getNumCache().getPtCount().getVal();
int dataSize = data.value.size();
for (int i = 0; i < dataSize; i++) {
NameDouble cellValu = data.value.get(i);
CTStrVal cat = ptCatCnt > i ? catDataSource.getStrRef().getStrCache().getPtArray(i)
: catDataSource.getStrRef().getStrCache().addNewPt();
cat.setIdx(i);
cat.setV(cellValu.name);
CTNumVal val = ptNumCnt > i ? numDataSource.getNumRef().getNumCache().getPtArray(i)
: numDataSource.getNumRef().getNumCache().addNewPt();
val.setIdx(i);
val.setV(String.format("%.2f", cellValu.value));
}
// 更新对应 excel 的range
catDataSource.getStrRef().setF(
replaceRowEnd(catDataSource.getStrRef().getF(),
ptCatCnt,
dataSize));
numDataSource.getNumRef().setF(
replaceRowEnd(numDataSource.getNumRef().getF(),
ptNumCnt,
dataSize));
// 删除多的
if (ptNumCnt > dataSize) {
for (int idx = dataSize; idx < ptNumCnt; idx++) {
catDataSource.getStrRef().getStrCache().removePt(dataSize);
numDataSource.getNumRef().getNumCache().removePt(dataSize);
}
}
// 更新个数
catDataSource.getStrRef().getStrCache().getPtCount().setVal(dataSize);
numDataSource.getNumRef().getNumCache().getPtCount().setVal(dataSize);
}
/**
* 替换 形如: Sheet1!$A$2:$A$4 的字符
*
* #param range
* #return
*/
public static String replaceRowEnd(String range, long oldSize, long newSize) {
Pattern pattern = Pattern.compile("(:\\$[A-Z]+\\$)(\\d+)");
Matcher matcher = pattern.matcher(range);
if (matcher.find()) {
long old = Long.parseLong(matcher.group(2));
return range.replaceAll("(:\\$[A-Z]+\\$)(\\d+)", "$1" + Long.toString(old - oldSize + newSize));
}
return range;
}
/**
* 一个系列的数据
*/
public static class SeriesData {
/**
* value 系列的名字
*/
public String name;
public List<NameDouble> value;
public SeriesData(java.util.List<NameDouble> value) {
this.value = value;
}
public SeriesData(String name, List<NameDouble> value) {
this.name = name;
this.value = value;
}
public SeriesData() {
}
}
/**
*
*/
public class NameDouble {
public String name;
/**
*/
public double value;
public NameDouble(String name, double value) {
this.name = name;
this.value = value;
}
#SuppressWarnings("unused")
public NameDouble() {
}
}
}
Using current apache poi 5.0.0 updating a chart in PowerPoint is possible using the new XDDF classes. That avoids using the ooxml-schemas classes (CT... classes) directly. Using CT classes directly is error prone and needs very good knowlegde about the internally XML structure of Office Open XML.
What one needs to know is that chart data is stored in an embedded Excel workbook. So while updating the data the need is always updating the data in that workbook and updating the data in the chart.
The following example is a minimal reproducible example for how to do this.
The template BarChartSample.pptx contained a bar chart having only one series an one category. It defines the chart format. It looks like so:
The code is like this:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.poi.xslf.usermodel.*;
import org.apache.poi.xddf.usermodel.chart.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.AreaReference;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumns;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumn;
public class PowerPointChangeChartData {
//patched version of XSSFTable.updateHeaders, see https://stackoverflow.com/questions/55532006/renaming-headers-of-xssftable-with-apache-poi-leads-to-corrupt-xlsx-file/55539181#55539181
static void updateHeaders(XSSFTable table) {
XSSFSheet sheet = (XSSFSheet)table.getParent();
CellReference ref = table.getStartCellReference();
if (ref == null) return;
int headerRow = ref.getRow();
int firstHeaderColumn = ref.getCol();
XSSFRow row = sheet.getRow(headerRow);
DataFormatter formatter = new DataFormatter();
if (row != null /*&& row.getCTRow().validate()*/) {
int cellnum = firstHeaderColumn;
CTTableColumns ctTableColumns = table.getCTTable().getTableColumns();
if(ctTableColumns != null) {
for (CTTableColumn col : ctTableColumns.getTableColumnList()) {
XSSFCell cell = row.getCell(cellnum);
if (cell != null) {
col.setName(formatter.formatCellValue(cell));
}
cellnum++;
}
}
}
}
static void updateChart(XSLFChart chart, Object[][] data) throws Exception {
// get chart's data source which is a Excel sheet
XSSFWorkbook chartDataWorkbook = chart.getWorkbook();
String sheetName = chartDataWorkbook.getSheetName(0);
XSSFSheet chartDataSheet = chartDataWorkbook.getSheet(sheetName);
// current Office uses a table as data source
// so get that table if present
XSSFTable chartDataTable = null;
if (chartDataSheet.getTables().size() > 0) {
chartDataTable = chartDataSheet.getTables().get(0);
}
if (chart.getChartSeries().size() == 1) { // we will process only one chart data
XDDFChartData chartData = chart.getChartSeries().get(0);
if (chartData.getSeriesCount() == 1) { // we will process only templates having one series
int rMin = 1; // first row (0) is headers row
int rMax = data.length - 1;
// set new category data
XDDFCategoryDataSource category = null;
int c = 0;
for (int r = rMin; r <= rMax; r++) {
XSSFRow row = chartDataSheet.getRow(r); if (row == null) row = chartDataSheet.createRow(r);
XSSFCell cell = row.getCell(c); if (cell == null) cell = row.createCell(c);
cell.setCellValue((String)data[r][c]); // in sheet
}
category = XDDFDataSourcesFactory.fromStringCellRange(chartDataSheet, new CellRangeAddress(rMin,rMax,c,c)); // in chart
// series 1, is present already
c = 1;
// set new values in sheet and in chart
XDDFNumericalDataSource<Double> values = null;
for (int r = rMin; r < rMax+1; r++) {
XSSFRow row = chartDataSheet.getRow(r); if (row == null) row = chartDataSheet.createRow(r);
XSSFCell cell = row.getCell(c); if (cell == null) cell = row.createCell(c);
cell.setCellValue((Double)data[r][c]); // in sheet
}
values = XDDFDataSourcesFactory.fromNumericCellRange(chartDataSheet, new CellRangeAddress(rMin,rMax,c,c));
XDDFChartData.Series series1 = chartData.getSeries(0);
series1.replaceData(category, values); // in chart
// set new title in sheet and in chart
String series1Title = (String)data[0][c];
chartDataSheet.getRow(0).getCell(c).setCellValue(series1Title); // in sheet
series1.setTitle(series1Title, new CellReference(sheetName, 0, c, true, true)); // in chart
series1.plot();
//further series, all new created
int seriesCount = data[0].length - 1;
for (int s = 2; s <= seriesCount; s++) {
c++;
// set new values
for (int r = rMin; r < rMax+1; r++) {
XSSFRow row = chartDataSheet.getRow(r); if (row == null) row = chartDataSheet.createRow(r);
XSSFCell cell = row.getCell(c); if (cell == null) cell = row.createCell(c);
cell.setCellValue((Double)data[r][c]); // in sheet
}
values = XDDFDataSourcesFactory.fromNumericCellRange(chartDataSheet, new CellRangeAddress(rMin,rMax,c,c));
XDDFChartData.Series series = chartData.addSeries(category, values); // in chart
// set new title
String seriesTitle = (String)data[0][c];
XSSFCell cell = chartDataSheet.getRow(0).getCell(c); if (cell == null) cell = chartDataSheet.getRow(0).createCell(c);
cell.setCellValue(seriesTitle); // in sheet
series.setTitle(seriesTitle, new CellReference(sheetName, 0, c, true, true)); // in chart
series.plot();
}
// update the table if present
if (chartDataTable != null) {
CellReference topLeft = new CellReference(chartDataSheet.getRow(0).getCell(0));
CellReference bottomRight = new CellReference(chartDataSheet.getRow(rMax).getCell(c));
AreaReference tableArea = chartDataWorkbook.getCreationHelper().createAreaReference(topLeft, bottomRight);
chartDataTable.setArea(tableArea);
updateHeaders(chartDataTable);
}
}
}
}
public static void main(String[] args) throws Exception {
String filePath = "BarChartSample.pptx"; // has template bar chart
String filePathNew = "BarChartSample_New.pptx";
Object[][] data = new Object[][] { // new data 3 series, 5 categories
{"", "Amount", "Values", "Others"}, // series title
{"Jan", 321d, 456d, 222d}, // category 1
{"Feb", 543d, 567d, 111d}, // category 2
{"Mar", 432d, 123d, 333d}, // category 3
{"Apr", 210d, 234d, 444d}, // category 4
{"May", 198d, 345d, 444d} // category 5
};
XMLSlideShow slideShow = new XMLSlideShow(new FileInputStream(filePath));
XSLFChart chart = slideShow.getCharts().get(0);
updateChart(chart, data);
FileOutputStream out = new FileOutputStream(filePathNew);
slideShow.write(out);
out.close();
slideShow.close();
}
}
The result looks like so:
Hint: The code uses a patched version of XSSFTable.updateHeaders as the current version fails updating the table headers. See Renaming headers of XSSFTable with Apache Poi leads to corrupt XLSX-file.
I have developed a Word function that includes a Chart.
When editing chart data in a Word file, it returns to the data defined in the form.
Here are the steps:
I edit word(docx) xml data and workbook.
I open microsoft office - the data shown is normal.
I click Chart data edit function - it returns the original data.
library - ooxml-schemas-1.3, poi-4.0.0-SNAPSHOT
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
String inFilePath = "../file/temp/TEMP_Chart_Simple.docx";
String outFilePath = "../file/out/NEW_Chart_" + System.currentTimeMillis() + ".docx";
Map<String, Map<String, String>> CHART_MAP_DATA = new LinkedHashMap<>();
Map<String, String> inData = new LinkedHashMap<>();
inData.put("1", "8.3");
inData.put("2", "7.3");
CHART_MAP_DATA.put("temp", inData);
Path path = Paths.get(inFilePath);
byte[] byteData = Files.readAllBytes(path);
// read as XWPFDocument from byte[]
XWPFDocument document = new XWPFDocument(new ByteArrayInputStream(byteData));
XWPFChart xChart = null;
CTChart ctChart = null;
XSSFWorkbook wb = null;
for (POIXMLDocumentPart part : document.getRelations()) {
if (part instanceof XWPFChart) {
xChart = (XWPFChart) part;
wb = xChart.getWorkbook();
ctChart = xChart.getCTChart();
if(getTitle(ctChart).equals("FIELD_CHART")) {
break;
}
}
}
CTPlotArea plotArea = ctChart.getPlotArea();
List<CTBarChart> arBarChart = plotArea.getBarChartList();
List<CTBarSer> arBarSer = arBarChart.get(0).getSerList();
if(CHART_MAP_DATA != null && !CHART_MAP_DATA.isEmpty()) {
Set<String> keys = CHART_MAP_DATA.keySet();
Iterator<String> itKeys = keys.iterator();
while(itKeys.hasNext()) {
String inKey = itKeys.next();
Map<String, String> barData = CHART_MAP_DATA.get(inKey);
setBarChartData(ctChart, serCnt, inKey, barData);
}
}
XSSFSheet sheet = wb.getSheetAt(0);
sheet.getRow(1).getCell(1).setCellValue(8.3);
sheet.getRow(2).getCell(1).setCellValue(7.3);
FileOutputStream fos = new FileOutputStream(new File(outFilePath));
document.write(fos);
fos.close();
document.close();
}
public static void setBarChartData(CTChart ctChart, int serIdx, String series, Map<String, String> data) {
CTPlotArea plotArea = ctChart.getPlotArea();
List<CTBarChart> arBarChart = plotArea.getBarChartList();
if(arBarChart.size() > 0) {
List<CTBarSer> arBarSer = arBarChart.get(0).getSerList();
CTBarSer barSer = arBarSer.get(serIdx);
CTSerTx serTx = barSer.getTx();
CTStrRef strRef = serTx.getStrRef();
CTStrData strData = strRef.getStrCache();
List<CTStrVal> arStrVal = strData.getPtList();
for(int b=0; b<arStrVal.size(); b++) {
arStrVal.get(b).setV(series);
}
CTAxDataSource dataSource = barSer.getCat();
CTStrRef dStrRef = dataSource.getStrRef();
boolean isCatDataTypeStr = true;
List<CTStrVal> arDStrVal = null;
List<CTNumVal> arDNumVal = null;
CTStrData dStrData = null;
CTNumData dNumData = null;
if(dStrRef != null) {
dStrData = dStrRef.getStrCache();
arDStrVal = dStrData.getPtList();
dStrData.getPtCount().setVal(data.size());
if(arDStrVal.size() > data.size()) {
for(int i=arDStrVal.size(); i>data.size(); i--) {
dStrData.removePt(i-1);
}
}
isCatDataTypeStr = true;
} else {
CTNumRef dNumRef = dataSource.getNumRef();
dNumData = dNumRef.getNumCache();
arDNumVal = dNumData.getPtList();
dNumData.getPtCount().setVal(data.size());
if(arDNumVal.size() > data.size()) {
for(int i=arDNumVal.size(); i>data.size(); i--) {
dNumData.removePt(i-1);
}
}
isCatDataTypeStr = false;
}
CTNumDataSource numDataSource = barSer.getVal();
CTNumRef numRef = numDataSource.getNumRef();
CTNumData numData = numRef.getNumCache();
List<CTNumVal> arNumVal = numData.getPtList();
numData.getPtCount().setVal(data.size());
if(arNumVal.size() > data.size()) {
for(int i=arNumVal.size(); i>data.size(); i--) {
numData.removePt(i-1);
}
}
Set<String> keys = data.keySet();
Iterator<String> itKeys = keys.iterator();
int valSize = 0;
if(isCatDataTypeStr) {
valSize = arDStrVal.size();
} else {
valSize = arDNumVal.size();
}
int idx = 0;
while(itKeys.hasNext()) {
String stKey = itKeys.next();
if(valSize > idx) {
if(isCatDataTypeStr) {
arDStrVal.get(idx).setV(stKey);
} else {
arDNumVal.get(idx).setV(stKey);
}
} else {
if(isCatDataTypeStr) {
CTStrVal val = dStrData.addNewPt();
val.setIdx(idx);
val.setV(stKey);
} else {
CTNumVal val = dNumData.addNewPt();
val.setIdx(idx);
val.setV(stKey);
}
}
if(arNumVal.size() > idx) {
arNumVal.get(idx).setV(data.get(stKey));
} else {
CTNumVal val = numData.addNewPt();
val.setIdx(idx);
val.setV(data.get(stKey));
}
idx++;
}
}
}
public static String getTitle(CTChart chart) {
CTTitle title = chart.getTitle();
if (title != null) {
CTTx tx = title.getTx();
CTTextBody tb = tx.getRich();
return tb.getPArray(0).getRArray(0).getT();
}
return "";
}
Using apache poi 4.0.1 changing XDDFChart data needs parallel updating all changes in underlying chart data workbook and the chart itself. The chart holds the cached data while the workbook holds the source data. But both is possible using the high level apache poiclasses. No access to underlying XML beans needed.
Example
Word template which has template chart having 2 series and 3 categories:
Code:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.xddf.usermodel.chart.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.ss.util.CellRangeAddress;
public class WordChangeChartData {
public static void main(String[] args) throws Exception {
String filePath = "TEMP_Chart_SimpleBar.docx"; // has template chart having 2 series, 3 categories
String filePathNew = "New_Chart_Simple.docx";
Object[][] data = new Object[][] { // 2 series, 3 categories
{"", "male", "female"}, // series titles
{"health", 123d, 234d}, // category 1
{"amount", 345d, 123d}, // category 2
{"size", 180d, 160d} // category 3
};
XWPFDocument document = new XWPFDocument(new FileInputStream(filePath));
XWPFChart chart = document.getCharts().get(0);
XSSFWorkbook chartDataWorkbook = chart.getWorkbook();
String sheetName = chartDataWorkbook.getSheetName(0);
XSSFSheet chartDataSheet = chartDataWorkbook.getSheet(sheetName);
if (chart.getChartSeries().size() == 1) { // only one chart data
XDDFChartData chartData = chart.getChartSeries().get(0);
if (chartData.getSeries().size() == 2) { // exact two series
int rMin = 1;
int rMax = 3;
// set new category data (both series)
XDDFCategoryDataSource category = null;
int c = 0;
for (int r = rMin; r < rMax+1; r++) {
chartDataSheet.getRow(r).getCell(c).setCellValue((String)data[r][c]); // in sheet
}
category = XDDFDataSourcesFactory.fromStringCellRange(chartDataSheet, new CellRangeAddress(rMin,rMax,c,c)); // in chart
// series 1
XDDFChartData.Series series1 = chartData.getSeries().get(0);
c = 1;
// set new title
String series1Title = (String)data[0][c];
chartDataSheet.getRow(0).getCell(c).setCellValue(series1Title); // in sheet
if (chartDataSheet.getTables().size() > 0) {
if (chartDataSheet.getTables().get(0).getCTTable().getTableColumns().getTableColumnList().size() > c)
chartDataSheet.getTables().get(0).getCTTable().getTableColumns().getTableColumnList().get(c).setName(series1Title);
}
series1.setTitle(series1Title, new CellReference(sheetName, 0, c, true, true)); // in chart
// set new values
XDDFNumericalDataSource<Double> values = null;
for (int r = rMin; r < rMax+1; r++) {
chartDataSheet.getRow(r).getCell(c).setCellValue((Double)data[r][c]); // in sheet
}
values = XDDFDataSourcesFactory.fromNumericCellRange(chartDataSheet, new CellRangeAddress(rMin,rMax,c,c));
series1.replaceData(category, values);
series1.plot(); //in chart
// series 2
XDDFChartData.Series series2 = chartData.getSeries().get(1);
c = 2;
// set new title
String series2Title = (String)data[0][c];
chartDataSheet.getRow(0).getCell(c).setCellValue(series2Title); // in sheet
if (chartDataSheet.getTables().size() > 0) {
if (chartDataSheet.getTables().get(0).getCTTable().getTableColumns().getTableColumnList().size() > c)
chartDataSheet.getTables().get(0).getCTTable().getTableColumns().getTableColumnList().get(c).setName(series2Title);
}
series2.setTitle(series2Title, new CellReference(sheetName, 0, c, true, true)); // in chart
// set new values
for (int r = rMin; r < rMax+1; r++) {
chartDataSheet.getRow(r).getCell(c).setCellValue((Double)data[r][c]); // in sheet
}
values = XDDFDataSourcesFactory.fromNumericCellRange(chartDataSheet, new CellRangeAddress(rMin,rMax,c,c));
series2.replaceData(category, values);
series2.plot(); // in chart
}
}
FileOutputStream out = new FileOutputStream(filePathNew);
document.write(out);
out.close();
document.close();
}
}
Result:
In my project I have a method that draws a route inside of map and create a bounds for this route, the problem is, I need to create this bounds with the bottom sheet and not the entire screen!
First I open the Bottom Sheet:
private void openBottom(){
if(latLngs != null){
if(bottomSheetBehavior.getState() != BottomSheetBehavior.STATE_EXPANDED){
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
bottomSheetBehavior.setPeekHeight(300);
}
}
}
And then Draw and the bounds!
private void drawnNewRoute() {
if(polyline == null){
LatLngBounds.Builder builder = new LatLngBounds.Builder();
po = new PolylineOptions();
for(int i = 0, tam = latLngs.size(); i < tam; i++){
po.add(latLngs.get(i));
builder.include(latLngs.get(i));
}
String data = new Gson().toJson(latLngs);
po.color(Color.BLACK).width(10);
polyline = mMap.addPolyline(po);
ArrayList<LatLng> latlang = new ArrayList<>();
latlang.add(latLngs.get(0));
latlang.add(latLngs.get(latLngs.size() -1));
mMarkerNewPosition = mMap.addMarker(new MarkerOptions().position(finalLocaltion).title(finalLocationName));
mMarkerNewPosition.showInfoWindow();
mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), 120));
location_display_incl.setVisibility(View.GONE);
stopLocation();
InicialAddressTxt.setText(InicialAddress);
double finalLat = latLngs.get(latLngs.size() -1).latitude;
double finalLong = latLngs.get(latLngs.size() -1).longitude;
try {
ADRS = getAddress(finalLat,finalLong);
} catch (IOException e) {
e.printStackTrace();
}
FinalAddressTxt.setText(finalLocationName);
String finalComp = ADRS.getLocality() + "," + address.getAdminArea();
FinalComplement.setText(finalComp);
//zoomToCoverAllMarkersInMap(latlang);
}
else{
polyline.setPoints(latLngs);
}
}
But it keeps getting the whole screen and not just the "available" part of it!
I am trying to combign tiff image and shapefile and want show it. For this, I am using GeoTiff and I am stuck that my tiff file is now being displayed. Shapefile is showing properly but tiff image, which is having only 1 band and grey scale index, is not being shown because of some reason. I am getting one warning message as below.
2016-08-04T12:43:06.456+0530 WARNING Possible use of "Transverse_Mercator" projection outside its valid area.
Latitude 180°00.0'S is out of range (±90°).
How can I remove this message?
My code is as below
private void displayLayers() throws Exception {
AbstractGridFormat format = GridFormatFinder.findFormat(this.getBlueMarble());
this.setGridCoverageReader(format.getReader(this.getBlueMarble()));
Style rgbStyle = this.createRGBStyle();
// connect to the shapefile
FileDataStore dataStore = FileDataStoreFinder.getDataStore(this.getBorderShape());
SimpleFeatureSource shapefileSource = dataStore.getFeatureSource();
Style shpStyle = SLD.createPolygonStyle(Color.BLUE, null, 0.0f);
MapContent map = new MapContent();
map.getViewport().setCoordinateReferenceSystem(
DefaultGeographicCRS.WGS84);
map.setTitle("Illegal Mining");
Layer rasterLayer = new GridReaderLayer(this.getGridCoverageReader(), rgbStyle);
map.addLayer(rasterLayer);
Layer shpLayer = new FeatureLayer(shapefileSource, shpStyle);
map.addLayer(shpLayer);
System.out.println("Trying to show on map...");
JMapPane mapPane = new JMapPane();
mapPane.setMapContent(map);
mapPane.setDisplayArea(shapefileSource.getBounds());
//mapPane.setDisplayArea(this.getGridCoverageReader().getOriginalEnvelope());
this.add(mapPane, BorderLayout.CENTER);
}
private Style createRGBStyle() {
GridCoverage2DReader reader = this.getGridCoverageReader();
StyleFactory sf = this.getStyleFactory();
GridCoverage2D cov = null;
try {
cov = reader.read(null);
} catch (IOException giveUp) {
throw new RuntimeException(giveUp);
}
// We need at least three bands to create an RGB style
int numBands = cov.getNumSampleDimensions();
System.out.println("numBands:"+numBands);
if (numBands < 3) {
System.out.println("Bands are less than 3");
//return null;
}
// Get the names of the bands
String[] sampleDimensionNames = new String[numBands];
for (int i = 0; i < numBands; i++) {
GridSampleDimension dim = cov.getSampleDimension(i);
sampleDimensionNames[i] = dim.getDescription().toString();
}
final int RED = 0, GREEN = 1, BLUE = 2;
int[] channelNum = { -1, -1, -1 };
Boolean greyflag=false;
// We examine the band names looking for "red...", "green...",
// "blue...".
// Note that the channel numbers we record are indexed from 1, not 0.
for (int i = 0; i < numBands; i++) {
String name = sampleDimensionNames[i].toLowerCase();
System.out.println("name :"+name);
if (name != null) {
if (name.matches("red.*")) {
channelNum[RED] = i + 1;
} else if (name.matches("green.*")) {
channelNum[GREEN] = i + 1;
} else if (name.matches("blue.*")) {
channelNum[BLUE] = i + 1;
}else if(name.matches("gray.*")){
System.out.println("What to do here");
channelNum[RED] = 1;
channelNum[GREEN] = 2;
channelNum[BLUE] = 3;
greyflag=true;
}
}
}
// If we didn't find named bands "red...", "green...", "blue..."
// we fall back to using the first three bands in order
if(greyflag==false){
if (channelNum[RED] < 0 || channelNum[GREEN] < 0
|| channelNum[BLUE] < 0) {
channelNum[RED] = 1;
channelNum[GREEN] = 2;
channelNum[BLUE] = 3;
}
}
// Now we create a RasterSymbolizer using the selected channels
SelectedChannelType[] sct = new SelectedChannelType[cov
.getNumSampleDimensions()];
ContrastEnhancement ce = sf.contrastEnhancement(this.ff.literal(1.0),
ContrastMethod.NORMALIZE);
for (int i = 0; i < numBands; i++) {
sct[i] = sf.createSelectedChannelType(
String.valueOf(channelNum[i]), ce);
System.out.println(String.valueOf(channelNum[i]));
}
RasterSymbolizer sym = sf.getDefaultRasterSymbolizer();
ChannelSelection sel =sf.channelSelection(sct[RED]);
if(numBands>1){
sel = sf.channelSelection(sct[RED], sct[GREEN],
sct[BLUE]);
}
sym.setChannelSelection(sel);
return SLD.wrapSymbolizers(sym);
}
I just pass two files as below code
public MapImagePanel() {
this.setLayout(new BorderLayout(0, 0));
this.setBackground(Color.BLUE);
this.setPreferredSize(new Dimension(720, 360));
this.setBlueMarble(new File("E:/tifffilename.TIFF"));
this.setBorderShape(new File("E:/shapefilename.shp"));
try {
this.displayLayers();
} catch (Exception e) {
e.printStackTrace();
}
}
This is how i use this class in main class
//see output in main method
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MapImagePanel panel = new MapImagePanel();
panel.setPreferredSize(new Dimension(1024,768));
panel.setVisible(true);
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
frame.show();
TLDR; add the following line to your program start up:
System.setProperty("org.geotools.referencing.forceXY", "true");
From GeoTools FAQ as computer programmers they knew that coordinates would be expressed as longitude,latitude pairs so they could use existing graphics code easily by treating them as a simple (x,y) pair. but for sequence like (x,y) or (y,x) they confused that is why this error is coming.
I have produced a line graph like this. Even though there are no zero data for the blue line and also the red line only have the value until 100. So how do i set the blue line to start at zero and red to finish until 200 like this:
My data in textfile (outputAvgGen.txt) are:
11752.58,HC
11819.65,HC
11941.75,HC
12398.45,HC
12401.06,HC
12531.09,HC
12634.33,HC
12748.83,HC
12787.36,HC
12799.44,HC
.
.
.
30137.15,P3
31919.46,P3
32323.8,P3
.
.
.
and so on until 200 data
This is my code:
public class Graph2 extends JFrame{
public Graph2(){
setTitle("P3 Performance Analysis");
JPanel chartPanel = createChartPanel();
add(chartPanel, BorderLayout.CENTER);
setSize(640, 480);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Graph2().setVisible(true);
}
});
}
private JPanel createChartPanel() {
// creates a line chart object
// returns the chart panel
String chartTitle = "Average Fitness against No. of Generations";
String xAxisLabel = "No. of Generations";
String yAxisLabel = "Average Fitness";
XYDataset dataset = createDataset();
JFreeChart chart = ChartFactory.createXYLineChart(chartTitle,
xAxisLabel, yAxisLabel, dataset);
XYPlot plot = chart.getXYPlot();
NumberAxis yAxis = (NumberAxis) plot.getRangeAxis();
yAxis.setAutoRangeIncludesZero(true);
return new ChartPanel(chart);
}
private XYDataset createDataset() {
ArrayList<PlotData2> dataList = readData();
XYSeriesCollection dataset = new XYSeriesCollection();
XYSeries series1 = new XYSeries("Hill Climber");
XYSeries series2 = new XYSeries("P3");
for (int i = 0; i < dataList.size(); i++){
if (dataList.get(i).getAlgo().equals("HC")){
series1.add(i, dataList.get(i).getAvg());
System.out.println("HC i=" + i);
}
else if (dataList.get(i).getAlgo().equals("P3")){
series2.add(i, dataList.get(i).getAvg());
System.out.println("P3 i=" + i);
}
}
/*
for (int i = 0; i < dataList.size(); i++){
if (dataList.get(i).getAlgo().equals("HC")){
System.out.println("i = " + i);
series1.add(i, dataList.get(i).getAvg());
}
}
for (int j = 0; j < dataList.size(); j++){
if (dataList.get(j).getAlgo().equals("P3")){
System.out.println("j = " + j);
series2.add(j, dataList.get(j).getAvg());
}
}*/
/*
series1.add(1.0, 2.0);
series1.add(2.0, 3.0);
series1.add(3.0, 2.5);
series1.add(3.5, 2.8);
series1.add(4.2, 6.0);
series2.add(2.0, 1.0);
series2.add(2.5, 2.4);
series2.add(3.2, 1.2);
series2.add(3.9, 2.8);
series2.add(4.6, 3.0); */
dataset.addSeries(series1);
dataset.addSeries(series2);
return dataset;
}
public static ArrayList<PlotData2> readData(){
ArrayList<PlotData2> dataList = new ArrayList<PlotData2>();
try {
BufferedReader in = new BufferedReader( new FileReader("outputAvgGen.txt") );
String str;
while ( (str = in.readLine() )!= null ) {
String[] data = str.split( "," );
double avg = Double.parseDouble(data[0]);
String algo = data[1];
// int gen = Integer.parseInt(data[2]);
dataList.add(new PlotData2(algo,avg));
}
in.close();
} catch ( IOException ex ) {
System.err.println( "Error: Can't open the file for reading." );
}
return dataList;
}
}
Actually my original data being computed are in pairs of HC and P3 in a textfile like this:
15426.35,HC
38903.93,P3
13777.49,HC
34480.21,P3
15199.38,HC
38559.36,P3
13399.15,HC
32931.49,P3
.
.
and so on..
but I sorted it to make the graph being plotted ascendingly but when sorted it doesn't plot according to the pairs.
Can someone please help with the code at least to make it start at zero and end at max range for both lines to make it look simultaneous. Thank you.
The major issue with your code is that you are incrementing the x values for both series simultaneously. You need to do that separately. Furthermore, you are using hardcoded strings in your createDataset method.
Try this approach instead:
public static HashMap<String, List<Double>> readData() {
HashMap<String, List<Double>> dataList = new HashMap<String, List<Double>>();
try {
BufferedReader in = new BufferedReader(new FileReader("outputAvgGen.txt"));
String str;
while ((str = in.readLine()) != null) {
String[] data = str.split(",");
String algo = data[1];
if (dataList.get(algo) == null) {
dataList.put(algo, new ArrayList<Double>());
}
dataList.get(algo).add(Double.parseDouble(data[0]));
}
in.close();
}
catch (IOException ex) {
System.err.println("Error: Can't open the file for reading.");
}
return dataList
}
private XYDataset createDataset() {
HashMap<String, List<Double>> dataList = readData();
XYSeriesCollection dataset = new XYSeriesCollection();
Set<String> keys = dataList.keySet();
for (String key : keys) {
XYSeries series = new XYSeries(key);
List<Double> numbers = dataList.get(key);
for (int i = 0; i < numbers.size() - 1; i++) {
series.add(i, numbers.get(i), false);
}
series.add(numbers.size() - 1, numbers.get(numbers.size() - 1), true);
dataset.addSeries(series);
}
return dataset;
}