working through charts

This commit is contained in:
Greg DiCristofaro 2021-03-19 15:33:27 -04:00
parent fa66011ec1
commit 189580df63
8 changed files with 346 additions and 121 deletions

View File

@ -128,6 +128,7 @@ TypesPanel_fileMimeTypesChart_notAnalyzed_title=Not Analyzed
TypesPanel_fileMimeTypesChart_other_title=Other
TypesPanel_fileMimeTypesChart_title=File Types
TypesPanel_fileMimeTypesChart_unknown_title=Unknown
TypesPanel_fileMimeTypesChart_valueLabel=Count
TypesPanel_fileMimeTypesChart_videos_title=Videos
TypesPanel_filesByCategoryTable_allocatedRow_title=Allocated Files
TypesPanel_filesByCategoryTable_directoryRow_title=Directories

View File

@ -40,9 +40,9 @@ import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.DailyActivityAmount;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.TimelineSummary.TimelineSummaryData;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel.BarChartItem;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel.BarChartSeries;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartPanel.OrderedKey;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries.BarChartItem;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents;

View File

@ -65,6 +65,7 @@ import org.sleuthkit.datamodel.TskCoreException;
"TypesPanel_filesByCategoryTable_slackRow_title=Slack Files",
"TypesPanel_filesByCategoryTable_directoryRow_title=Directories",
"TypesPanel_fileMimeTypesChart_title=File Types",
"TypesPanel_fileMimeTypesChart_valueLabel=Count",
"TypesPanel_fileMimeTypesChart_audio_title=Audio",
"TypesPanel_fileMimeTypesChart_documents_title=Documents",
"TypesPanel_fileMimeTypesChart_executables_title=Executables",
@ -198,6 +199,8 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
private final DataFetcher<DataSource, String> osFetcher;
private final DataFetcher<DataSource, Long> sizeFetcher;
private final DataFetcher<DataSource, TypesPieChartData> typesFetcher;
private final DataFetcher<DataSource, Long> allocatedFetcher;
private final DataFetcher<DataSource, Long> unallocatedFetcher;
private final DataFetcher<DataSource, Long> slackFetcher;
@ -262,6 +265,8 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
this.osFetcher = containerData::getOperatingSystems;
this.sizeFetcher = (dataSource) -> dataSource == null ? null : dataSource.getSize();
this.typesFetcher = (dataSource) -> getMimeTypeCategoriesModel(mimeTypeData, dataSource);
this.allocatedFetcher = (dataSource) -> typeData.getCountOfAllocatedFiles(dataSource);
this.unallocatedFetcher = (dataSource) -> typeData.getCountOfUnallocatedFiles(dataSource);
@ -275,9 +280,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
(sizeResult) -> sizeLabel.showDataFetchResult(
DataFetchResult.getSubResult(sizeResult,
size -> SizeRepresentationUtil.getSizeString(size, INTEGER_SIZE_FORMAT, false)))),
new DataFetchWorker.DataFetchComponents<>(
(dataSource) -> getMimeTypeCategoriesModel(mimeTypeData, dataSource),
this::showMimeTypeCategories),
new DataFetchWorker.DataFetchComponents<>(typesFetcher, this::showMimeTypeCategories),
new DataFetchWorker.DataFetchComponents<>(allocatedFetcher,
countRes -> allocatedLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> getStringOrZero(count)))),
new DataFetchWorker.DataFetchComponents<>(unallocatedFetcher,
@ -443,6 +446,15 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
if (dataSource == null) {
return Collections.emptyList();
}
TypesPieChartData typesData = this.getFetchResult(typesFetcher, "Types", dataSource);
PieChartExport typesChart = (typesData == null || !typesData.isUsefulContent()) ? null :
new PieChartExport(
Bundle.TypesPanel_fileMimeTypesChart_title(),
Bundle.TypesPanel_fileMimeTypesChart_valueLabel(),
"#,###",
Bundle.TypesPanel_fileMimeTypesChart_title(),
typesData.getPieSlices());
return Arrays.asList(new ExcelSpecialFormatExport(Bundle.TypesPanel_excelTabName(),
Stream.of(
@ -450,10 +462,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
getStrExportable(osFetcher, Bundle.TypesPanel_osLabel_title(), dataSource),
new KeyValueItemExportable(Bundle.TypesPanel_sizeLabel_title(),
SizeRepresentationUtil.getBytesCell(getFetchResult(sizeFetcher, "Types", dataSource))),
new PieChartExport(String keyColumnHeader,
String valueColumnHeader, String valueFormatString,
String chartTitle,
List<PieChartItem> slices),
typesChart,
getCountExportable(allocatedFetcher, Bundle.TypesPanel_filesByCategoryTable_allocatedRow_title(), dataSource),
getCountExportable(unallocatedFetcher, Bundle.TypesPanel_filesByCategoryTable_unallocatedRow_title(), dataSource),
getCountExportable(slackFetcher, Bundle.TypesPanel_filesByCategoryTable_slackRow_title(), dataSource),

View File

@ -0,0 +1,187 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.sleuthkit.autopsy.datasourcesummary.uiutils;
import com.google.cloud.Tuple;
import java.awt.Color;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xddf.usermodel.XDDFColor;
import org.apache.poi.xddf.usermodel.XDDFShapeProperties;
import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
import org.apache.poi.xddf.usermodel.chart.AxisPosition;
import org.apache.poi.xddf.usermodel.chart.BarDirection;
import org.apache.poi.xddf.usermodel.chart.BarGrouping;
import org.apache.poi.xddf.usermodel.chart.ChartTypes;
import org.apache.poi.xddf.usermodel.chart.LegendPosition;
import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFCategoryAxis;
import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
import org.apache.poi.xddf.usermodel.chart.XDDFPieChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
import org.apache.poi.xssf.usermodel.XSSFChart;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelExportException;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelExport.ExcelSheetExport;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.ExcelItemExportable;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.ItemDimensions;
/**
*
* @author gregd
*/
public class BarChartExport implements ExcelItemExportable, ExcelSheetExport {
private final ExcelTableExport<BarChartSeries, ? extends ExcelCellModel> tableExport;
private final int colOffset;
private final int rowPadding;
private final int colSize;
private final int rowSize;
private final String chartTitle;
private final String sheetName;
private final List<BarChartSeries> categories;
private final String keyColumnHeader;
public BarChartExport(String keyColumnHeader,
String valueFormatString,
String chartTitle,
List<BarChartSeries> categories) {
this(keyColumnHeader, valueFormatString, chartTitle, chartTitle, categories, 1, 1, 8, 10);
}
public BarChartExport(String keyColumnHeader, String valueFormatString,
String chartTitle, String sheetName,
List<BarChartSeries> categories,
int colOffset, int rowPadding, int colSize, int rowSize) {
this.keyColumnHeader = keyColumnHeader;
List<BarChartSeries> categoryKeys = categories.stream()
.filter(cat -> cat != null && cat.getKey() != null)
.sorted((c1, c2) -> c1.getKey().compareTo(c2.getKey()))
.collect(Collectors.toList());
List<Comparable<?>> rowKeys = categories.stream()
.filter(cat -> cat != null && cat.getItems() != null)
.flatMap(cat -> cat.getItems().stream().map(item -> item.getKey()))
.filter(i -> i != null)
.distinct()
.sorted()
.collect(Collectors.toList());
Map<Tuple<Comparable<?>, Comparable<?>>, Double> valueMap = categories.stream()
.flatMap((cat) -> cat.getItems().stream().map((item) -> Tuple.of(Tuple.of(cat.getKey(), item.getKey()), item.getValue())))
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue(), (v1, v2) -> v1));
List<Pair<Comparable<?>, List<Double>>> values = rowKeys.stream()
.map((rowValue))
this.tableExport = new ExcelTableExport<>(chartTitle,
Stream.concat(Stream.of(new ColumnModel<>(keyColumnHeader, (category) -> new DefaultCellModel<>(category.getLabel()))), )
Arrays.asList(
,
new ColumnModel<>(valueColumnHeader, (category) -> new DefaultCellModel<>(category.getValue(), null, valueFormatString))
),
categories);
this.colOffset = colOffset;
this.rowPadding = rowPadding;
this.colSize = colSize;
this.rowSize = rowSize;
this.chartTitle = chartTitle;
this.sheetName = sheetName;
this.categories = categories;
}
@Override
public String getSheetName() {
return sheetName;
}
@Override
public void renderSheet(Sheet sheet, ExcelExport.WorksheetEnv env) throws ExcelExport.ExcelExportException {
write(sheet, 0, 0, env);
}
@Override
public ItemDimensions write(Sheet sheet, int rowStart, int colStart, ExcelExport.WorksheetEnv env) throws ExcelExportException {
if (!(sheet instanceof XSSFSheet)) {
throw new ExcelExportException("Sheet must be an XSSFSheet in order to write.");
}
XSSFSheet xssfSheet = (XSSFSheet) sheet;
// write pie chart table data
ItemDimensions tableDimensions = tableExport.write(xssfSheet, rowStart + rowPadding, colStart, env);
XSSFDrawing drawing = xssfSheet.createDrawingPatriarch();
int chartColStart = colStart + 2 + colOffset;
//createAnchor(int dx1, int dy1, int dx2, int dy2, int col1, int row1, int col2, int row2);
XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, chartColStart, rowStart + rowPadding, chartColStart + colSize, rowStart + rowSize);
XSSFChart chart = drawing.createChart(anchor);
chart.setTitleText(chartTitle);
chart.setTitleOverlay(false);
XDDFChartLegend legend = chart.getOrAddLegend();
legend.setPosition(LegendPosition.BOTTOM);
// Use a category axis for the bottom axis.
XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
bottomAxis.setTitle(keyColumnHeader);
XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
// leftAxis.setTitle(valHeader);
leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
leftAxis.setVisible(false);
XDDFBarChartData data = (XDDFBarChartData) chart.createData(ChartTypes.BAR, bottomAxis, leftAxis);
data.setBarGrouping(BarGrouping.STACKED);
XDDFDataSource<String> headerSource = XDDFDataSourcesFactory.fromStringCellRange(sheet, new CellRangeAddress(1, keyVals.size(), 0, 0));
data.setBarDirection(BarDirection.COL);
for (int i = 0; i < categories.size(); i++) {
XDDFChartData.Series series = data.addSeries(headerSource,
XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(1, keyVals.size(), i + 1, i + 1)));
series.setTitle(categories.size() > i && categories.get(i).getIdentifier() != null ? categories.get(i).getIdentifier() : "", null);
if (categories.get(i).getColor() != null) {
Color color = categories.get(i).getColor();
byte[] colorArrARGB = ByteBuffer.allocate(4).putInt(color.getRGB()).array();
byte[] colorArrRGB = new byte[]{colorArrARGB[1], colorArrARGB[2], colorArrARGB[3]};
XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(colorArrRGB)); // XDDFColor.from(color.getRed(), color.getGreen(), color.getBlue()));
XDDFShapeProperties properties = series.getShapeProperties();
if (properties == null) {
properties = new XDDFShapeProperties();
}
properties.setFillProperties(fill);
series.setShapeProperties(properties);
}
}
chart.plot(data);
return new ItemDimensions(rowStart, colStart, Math.max(tableDimensions.getRowEnd(), rowStart + rowSize) + rowPadding, chartColStart + colSize);
}
}

View File

@ -19,9 +19,7 @@
package org.sleuthkit.autopsy.datasourcesummary.uiutils;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.util.Collections;
import java.util.List;
import javax.swing.JLabel;
import org.apache.commons.collections4.CollectionUtils;
@ -34,90 +32,13 @@ import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.renderer.category.StandardBarPainter;
import org.jfree.data.category.DefaultCategoryDataset;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.BarChartSeries.BarChartItem;
/**
* A bar chart panel.
*/
public class BarChartPanel extends AbstractLoadableComponent<List<BarChartPanel.BarChartSeries>> {
public class BarChartPanel extends AbstractLoadableComponent<List<BarChartSeries>> {
/**
* Represents a series in a bar chart where all items pertain to one
* category.
*/
public static class BarChartSeries {
private final Comparable<?> key;
private final Color color;
private final List<BarChartItem> items;
/**
* Main constructor.
*
* @param key The key.
* @param color The color for this series.
* @param items The bars to be displayed for this series.
*/
public BarChartSeries(Comparable<?> key, Color color, List<BarChartItem> items) {
this.key = key;
this.color = color;
this.items = (items == null) ? Collections.emptyList() : Collections.unmodifiableList(items);
}
/**
* @return The color for this series.
*/
public Color getColor() {
return color;
}
/**
* @return The bars to be displayed for this series.
*/
public List<BarChartItem> getItems() {
return items;
}
/**
* @return The key for this item.
*/
public Comparable<?> getKey() {
return key;
}
}
/**
* An individual bar to be displayed in the bar chart.
*/
public static class BarChartItem {
private final Comparable<?> key;
private final double value;
/**
* Main constructor.
*
* @param key The key.
* @param value The value for this item.
*/
public BarChartItem(Comparable<?> key, double value) {
this.key = key;
this.value = value;
}
/**
* @return The key for this item.
*/
public Comparable<?> getKey() {
return key;
}
/**
* @return The value for this item.
*/
public double getValue() {
return value;
}
}
/**
* JFreeChart bar charts don't preserve the order of bars provided to the
@ -285,12 +206,12 @@ public class BarChartPanel extends AbstractLoadableComponent<List<BarChartPanel.
}
@Override
protected void setResults(List<BarChartPanel.BarChartSeries> data) {
protected void setResults(List<BarChartSeries> data) {
this.dataset.clear();
if (CollectionUtils.isNotEmpty(data)) {
for (int s = 0; s < data.size(); s++) {
BarChartPanel.BarChartSeries series = data.get(s);
BarChartSeries series = data.get(s);
if (series != null && CollectionUtils.isNotEmpty(series.getItems())) {
if (series.getColor() != null) {
this.plot.getRenderer().setSeriesPaint(s, series.getColor());

View File

@ -0,0 +1,102 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.datasourcesummary.uiutils;
import java.awt.Color;
import java.util.Collections;
import java.util.List;
/**
* Represents a series in a bar chart where all items pertain to one
* category.
*/
public class BarChartSeries {
/**
* An individual bar to be displayed in the bar chart.
*/
public static class BarChartItem {
private final Comparable<?> key;
private final double value;
/**
* Main constructor.
*
* @param key The key.
* @param value The value for this item.
*/
public BarChartItem(Comparable<?> key, double value) {
this.key = key;
this.value = value;
}
/**
* @return The key for this item.
*/
public Comparable<?> getKey() {
return key;
}
/**
* @return The value for this item.
*/
public double getValue() {
return value;
}
}
private final Comparable<?> key;
private final Color color;
private final List<BarChartItem> items;
/**
* Main constructor.
*
* @param key The key.
* @param color The color for this series.
* @param items The bars to be displayed for this series.
*/
public BarChartSeries(Comparable<?> key, Color color, List<BarChartItem> items) {
this.key = key;
this.color = color;
this.items = (items == null) ? Collections.emptyList() : Collections.unmodifiableList(items);
}
/**
* @return The color for this series.
*/
public Color getColor() {
return color;
}
/**
* @return The bars to be displayed for this series.
*/
public List<BarChartItem> getItems() {
return items;
}
/**
* @return The key for this item.
*/
public Comparable<?> getKey() {
return key;
}
}

View File

@ -81,6 +81,8 @@ public class ExcelTableExport<T, C extends ExcelCellModel> implements ExcelSheet
sheet.autoSizeColumn(i);
}
// freeze header row
sheet.createFreezePane(0, 1);
}
@Override
@ -119,8 +121,7 @@ public class ExcelTableExport<T, C extends ExcelCellModel> implements ExcelSheet
cell.setCellValue(columns.get(i).getHeaderTitle());
cell.setCellStyle(worksheetEnv.getHeaderStyle());
}
// freeze header row
sheet.createFreezePane(0, 1);
// Create Cell Style for each column (if one is needed)
for (int rowNum = 0; rowNum < safeData.size(); rowNum++) {

View File

@ -9,11 +9,16 @@ import java.util.Arrays;
import java.util.List;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xddf.usermodel.chart.AxisPosition;
import org.apache.poi.xddf.usermodel.chart.ChartTypes;
import org.apache.poi.xddf.usermodel.chart.LegendPosition;
import org.apache.poi.xddf.usermodel.chart.XDDFCategoryAxis;
import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
import org.apache.poi.xddf.usermodel.chart.XDDFPieChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
import org.apache.poi.xssf.usermodel.XSSFChart;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
@ -28,6 +33,7 @@ import org.sleuthkit.autopsy.datasourcesummary.uiutils.ExcelSpecialFormatExport.
* @author gregd
*/
public class PieChartExport implements ExcelItemExportable, ExcelSheetExport {
private final ExcelTableExport<PieChartItem, ? extends ExcelCellModel> tableExport;
private final int colOffset;
private final int rowPadding;
@ -35,26 +41,25 @@ public class PieChartExport implements ExcelItemExportable, ExcelSheetExport {
private final int rowSize;
private final String chartTitle;
private final String sheetName;
private final List<PieChartItem> slices;
public PieChartExport(String keyColumnHeader,
public PieChartExport(String keyColumnHeader,
String valueColumnHeader, String valueFormatString,
String chartTitle,
List<PieChartItem> slices) {
this(keyColumnHeader, valueColumnHeader, valueFormatString, chartTitle, chartTitle, slices, 1, 1, 8, 10);
this(keyColumnHeader, valueColumnHeader, valueFormatString, chartTitle, chartTitle, slices, 1, 1, 8, 14);
}
public PieChartExport(String keyColumnHeader,
public PieChartExport(String keyColumnHeader,
String valueColumnHeader, String valueFormatString,
String chartTitle, String sheetName,
List<PieChartItem> slices,
String chartTitle, String sheetName,
List<PieChartItem> slices,
int colOffset, int rowPadding, int colSize, int rowSize) {
this.tableExport = new ExcelTableExport<>(chartTitle,
Arrays.asList(
new ColumnModel<>(keyColumnHeader, (slice) -> new DefaultCellModel<>(slice.getLabel())),
new ColumnModel<>(valueColumnHeader, (slice) -> new DefaultCellModel<>(slice.getValue(), null, valueFormatString))
),
),
slices);
this.colOffset = colOffset;
this.rowPadding = rowPadding;
@ -62,11 +67,8 @@ public class PieChartExport implements ExcelItemExportable, ExcelSheetExport {
this.rowSize = rowSize;
this.chartTitle = chartTitle;
this.sheetName = sheetName;
this.slices = slices;
}
@Override
public String getSheetName() {
return sheetName;
@ -82,35 +84,39 @@ public class PieChartExport implements ExcelItemExportable, ExcelSheetExport {
if (!(sheet instanceof XSSFSheet)) {
throw new ExcelExportException("Sheet must be an XSSFSheet in order to write.");
}
XSSFSheet xssfSheet = (XSSFSheet) sheet;
// write pie chart table data
ItemDimensions tableDimensions = tableExport.write(xssfSheet, rowStart + rowPadding, colStart, env);
XSSFDrawing drawing = xssfSheet.createDrawingPatriarch();
int chartColStart = colStart + 2 + colOffset;
//createAnchor(int dx1, int dy1, int dx2, int dy2, int col1, int row1, int col2, int row2);
XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, chartColStart, rowStart + rowPadding, chartColStart + colSize, rowStart + rowSize);
XSSFChart chart = drawing.createChart(anchor);
chart.setTitleText(chartTitle);
chart.setTitleOverlay(false);
// XDDFChartLegend legend = chart.getOrAddLegend();
// legend.setPosition(LegendPosition.BOTTOM);
XDDFChartLegend legend = chart.getOrAddLegend();
legend.setPosition(LegendPosition.RIGHT);
// (int firstRow, int lastRow, int firstCol, int lastCol)
XDDFDataSource<String> cat = XDDFDataSourcesFactory.fromStringCellRange(xssfSheet,
new CellRangeAddress(tableDimensions.getRowStart(), tableDimensions.getRowEnd(),
new CellRangeAddress(tableDimensions.getRowStart() + 1, tableDimensions.getRowEnd(),
tableDimensions.getColStart(), tableDimensions.getColStart()));
XDDFNumericalDataSource<Double> val = XDDFDataSourcesFactory.fromNumericCellRange(xssfSheet,
new CellRangeAddress(tableDimensions.getRowStart(), tableDimensions.getRowEnd(),
new CellRangeAddress(tableDimensions.getRowStart() + 1, tableDimensions.getRowEnd(),
tableDimensions.getColStart() + 1, tableDimensions.getColStart() + 1));
XDDFPieChartData data = (XDDFPieChartData) chart.createData(ChartTypes.PIE, null, null);
// NOTE: these can be null parameters to chart.createData in poi >= 4.1.1
XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
XDDFPieChartData data = (XDDFPieChartData) chart.createData(ChartTypes.PIE, bottomAxis, leftAxis);
data.setVaryColors(true);
data.addSeries(cat, val);
@ -124,13 +130,11 @@ public class PieChartExport implements ExcelItemExportable, ExcelSheetExport {
chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowSerName().setVal(false);
chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowCatName().setVal(true);
chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowPercent().setVal(true);
//chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowLegendKey().setVal(false);
chart.getCTChart().getPlotArea().getPieChartArray(0).getSerArray(0).getDLbls().addNewShowLegendKey().setVal(false);
chart.plot(data);
return new ItemDimensions(rowStart, colStart, Math.max(tableDimensions.getRowEnd(), rowStart + rowSize) + rowPadding, chartColStart + colSize);
}
}