I am wondering if it is possible to configure epplus in such a way that when the excel file is opened the table data can be clicked on and a graph will be displayed based on the row of the table clicked. (I realize this is super easy to do in excel I would just rather have everything taken care of before it gets to certain people)
Currently I just have one data table and a graph for each row but it would be better if there was just one graph that changed based on what row is clicked in excel. I also tried a pivot table but that doesn't help me with the dynamic chart.
For anyone trying to figure this out as well. I ended up using a data validation drop down list and making a dynamic table row (outside the base table) that the dynamic chart is based on. The dynamic table row changes based on the value of the data validation dropdown list (you kinda need a feel for excel to be able to do this which I didn't have):
class Program
{
static void Main(string[] args)
{
// Creating an instance
// of ExcelPackage
ExcelPackage excel = new ExcelPackage();
// name of the sheet
var workSheet = excel.Workbook.Worksheets.Add("testSheet");
//init table
var randTable = new DataTable();
randTable.TableName = "randTable";
//init columns
var countColumn = new DataColumn()
{
DataType = typeof(int),
ColumnName = "Count",
ReadOnly = true,
Unique = true
};
var randomColumn0 = new DataColumn()
{
DataType = typeof(int),
ColumnName = "Random-0",
ReadOnly = true,
Unique = false
};
var randomColumn1 = new DataColumn()
{
DataType = typeof(int),
ColumnName = "Random-1",
ReadOnly = true,
Unique = false
};
//add columns to table
randTable.Columns.AddRange(new DataColumn[] { countColumn, randomColumn0, randomColumn1 });
//init data validation
ExcelRange dropdownRange = workSheet.Cells[12, 1, 12, 3];
var dropdownValidation = workSheet.DataValidations.AddListValidation(dropdownRange.Address);
workSheet.Names.Add("count", dropdownRange);
//style data validation
dropdownRange.Merge = true;
workSheet.Cells[dropdownRange.Address].Style.Fill.PatternType = ExcelFillStyle.Solid;
workSheet.Cells[dropdownRange.Address].Style.Fill.BackgroundColor.SetColor(Color.Yellow);
workSheet.Cells[dropdownRange.Address].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
var rand = new Random();
for (var i = 0; i < 10; i++)
{
//add table first column values to validation list
dropdownValidation.Formula.Values.Add(i.ToString());
var row = randTable.NewRow();
row[countColumn] = i;
row[randomColumn0] = rand.Next(0, 100);
row[randomColumn1] = rand.Next(0, 100);
randTable.Rows.Add(row);
}
//make the tableIndexer cell. This cell will be used to get the
//table indices for the selected table row cells
ExcelRange randTableIndexer = workSheet.Cells[12, 4, 12, 4];
randTableIndexer.Formula = "MATCH(INDEX(count,1,1), randTable[Count], 0)";
workSheet.Cells[randTableIndexer.Address].Style.Fill.PatternType = ExcelFillStyle.Solid;
workSheet.Cells[randTableIndexer.Address].Style.Fill.BackgroundColor.SetColor(Color.LightGreen);
workSheet.Cells[randTableIndexer.Address].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
workSheet.Names.Add("tableIndex", randTableIndexer);
//make the cells based off the table at row(randTableIndexer.value)
ExcelRange graphCells = workSheet.Cells[13, 1, 13, 3];
graphCells.CreateArrayFormula("INDEX(randTable[], tableIndex, 0)"); //need [] on table names in epplus formulas
workSheet.Cells[graphCells.Address].Style.Fill.PatternType = ExcelFillStyle.Solid;
workSheet.Cells[graphCells.Address].Style.Fill.BackgroundColor.SetColor(Color.LightBlue);
workSheet.Cells[graphCells.Address].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
graphCells.Calculate();
//add table to workSheet
workSheet.Cells[1, 1].LoadFromDataTable(randTable, true, OfficeOpenXml.Table.TableStyles.Medium15);
workSheet.Cells.AutoFitColumns();
//add dynamic chart
var chart = workSheet.Drawings.AddChart("rands", eChartType.Pie) as ExcelPieChart;
chart.Title.Text = "rands";
chart.Series.Add(graphCells.Address, ExcelRange.GetAddress(1, 1, 3, 1));
chart.Legend.Position = eLegendPosition.Bottom;
chart.SetSize(500, 400);
chart.SetPosition(60, 500);
WriteToFile(excel);
}
public static void WriteToFile(ExcelPackage package)
{
// file name with .xlsx extension
string p_strPath = "C:\\your\\file\\path";
if (File.Exists(p_strPath))
File.Delete(p_strPath);
// Create excel file on physical disk
FileStream objFileStrm = File.Create(p_strPath);
objFileStrm.Close();
// Write content to excel file
File.WriteAllBytes(p_strPath, package.GetAsByteArray());
}
}
Related
I need to update a file automatically that already has data in it.
The document is filled with an SQL data base thanks to the code below
However, I want it to update itself everyday without deleting any data that are already in the document and only adding new ones (don't want any duplicates).
function readData(db, queryString) {
//connect to the database
var server = 'your-servername-OR-serverPublicIpAddress';
var username = 'your-sql-username';
var password = 'your-password';
var dbUrl = 'jdbc:sqlserver://' + server + ':1433;databaseName=' + db;
var conn = Jdbc.getConnection(dbUrl, username, password );
//query the data
var stmt = conn.createStatement();
var exec_query = stmt.executeQuery(queryString);
var metaData = exec_query.getMetaData();
var numCols = metaData.getColumnCount();
//save query data to an array
var result=[]; //initiate a blank array
//save the column header
header = []; //initiate the header row
for (var col = 0; col < numCols; col++) {
header.push(metaData.getColumnName(col + 1)); //add the name of each column to the header row
};
result.push(header);//after the header row is formed, put it to the result array
//save the data of each row
while (exec_query.next()) {
row_data = [];
for (var col = 0; col < numCols; col++) {
row_data.push(exec_query.getString(col + 1));//add data of each column to the row data
//Logger.log(row_data);
};
result.push(row_data); // add row data to result
//Logger.log(result);
};
exec_query.close();
return result
};
function pushDataToGoogleSheet(data, SheetName) {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.setActiveSheet(spreadsheet.getSheetByName(SheetName));
var lastRow = sheet.getLastRow();
sheet.getRange(lastRow+1, 1, data.length, data[0].length).setValues(data);
sheet.getDataRange().removeDuplicates();
};
function main() {
db = 'YOUR_DATABASE_NAME'
SQLquery = 'YOUR_SQL_QUERY'
raw_statistics = readData(db, SQLquery); //get raw statistics
pushDataToGoogleSheet(raw_statistics, 'YOUR_SHEET_NAME'); //push to google sheet
};
function main() {
db = 'YOUR_DATABASE_NAME'
SQLquery = 'YOUR_SQL_QUERY'
raw_statistics = readData(db, SQLquery); //get raw statistics
pushDataToGoogleSheet(raw_statistics, 'YOUR_SHEET_NAME'); //push to google sheet
};
However, in the pushDataToGoogleSheet it says that it can't define the length. So, I don't know if I put the right thing for data or not or if there is an issue in my code...
Do you have an idea ?
Thank you for your help !
I have a column with dates and I want to conditionally color any cell that is older that 2 week yellow, and any that is older than 90 days red. I can't figure out how to do that.
Should be able to just add the conditions like any other. You can use the TODAY() function in excel and subtract:
[TestMethod]
public void Conditional_Formatting_Date()
{
//https://stackoverflow.com/questions/56741642/epplus-two-color-conditional-date-format
var file = new FileInfo(#"c:\temp\Conditional_Formatting_Date.xlsx");
if (file.Exists)
file.Delete();
//Throw in some data
var dataTable = new DataTable("tblData");
dataTable.Columns.AddRange(new[] {
new DataColumn("Col1", typeof(DateTime)),
new DataColumn("Col3", typeof(string))
});
var rnd = new Random();
for (var i = 0; i < 100; i++)
{
var row = dataTable.NewRow();
row[0] = DateTime.Now.AddDays(-rnd.Next(1, 100));
row[1] = $"=TODAY() - A{i +1}";
dataTable.Rows.Add(row);
}
//Create a test file
using (var package = new ExcelPackage(file))
{
//Make the stylesheet
var ws = package.Workbook.Worksheets.Add("table");
var range = ws.Cells[1, 1].LoadFromDataTable(dataTable, false);
ws.Column(1).Style.Numberformat.Format = "mm-dd-yy";
ws.Column(1).AutoFit();
//Add the calc check
var count = 0;
foreach (DataRow row in dataTable.Rows)
ws.Cells[++count, 2].Formula = row[1].ToString();
//Add the conditions - order matters
var rangeA = range.Offset(0, 0, count, 1);
var condition90 = ws.ConditionalFormatting.AddExpression(rangeA);
condition90.Style.Font.Color.Color = Color.White;
condition90.Style.Fill.PatternType = ExcelFillStyle.Solid;
condition90.Style.Fill.BackgroundColor.Color = Color.Red;
condition90.Formula = "TODAY() - A1> 90";
condition90.StopIfTrue = true;
var condition14 = ws.ConditionalFormatting.AddExpression(rangeA);
condition14.Style.Font.Color.Color = Color.Black;
condition14.Style.Fill.PatternType = ExcelFillStyle.Solid;
condition14.Style.Fill.BackgroundColor.Color = Color.Yellow;
condition14.Formula = "TODAY() - A1> 14";
package.Save();
}
}
Which gives this in the output:
I am assuming that you have the column number of the date column and number of rows in your records. Also, the following loop is under assumption that the first row is your column header and records begin from second row. Change the loop counter's initialization and assignment accordingly.
int rowsCount; //get your no of rows
int dateColNumber; //Assign column number in excel file of your date column
string cellValue;
DateTime dateValue;
DateTime today = DateTime.Now;
double daysCount;
for(int i=1;i<rowsCount;i++)
{
cellValue = ws.Cells[i + 1, dateColNumber].Text.ToString(); //First row is header start from second
if(DateTime.TryParse(cellValue,out dateValue))
{
daysCount = (today - dateValue).Days;
if(daysCount>90)
{
ws.Cells[i + 1,dateColNumber].Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid;
ws.Cells[i + 1,dateColNumber].Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.Red);
}
else if(daysCount>14)
{
ws.Cells[i + 1, dateColNumber].Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid;
ws.Cells[i + 1, dateColNumber].Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.Yellow);
}
}
}
I want to make an excel chart, using EPPlus, from a list of single cells. Say I want a pie with three pieces getting their values from cells C4, C6 and C8. How?
These two attempts is among those that does not work:
ExcelChart chart = ExcelWorksheet.Drawings.AddChart(myTitle, eChartType.Pie);
ExcelAddress values = myWorkSheet.Cells["C4;C6;C8"]; // => 'Invalid Address format'
ExcelAddress values = myWorkSheet.Cells["C4,C6,C8"]; // => No chart is made
So, is it possible? If so, what's the syntax?
The line with cell names separated by commas is the format you want. Did you specify both the x and y axis range? Maybe show your code where you actually add the series.
You should be using ExcelRange not Address. Like this:
[TestMethod]
public void Chart_From_Cells_Test()
{
//http://stackoverflow.com/questions/29207020/epplus-chart-from-list-of-single-excel-cells-how
var existingFile = new FileInfo(#"c:\temp\temp.xlsx");
if (existingFile.Exists)
existingFile.Delete();
using (var pck = new ExcelPackage(existingFile))
{
var myWorkSheet = pck.Workbook.Worksheets.Add("Content");
var ExcelWorksheet = pck.Workbook.Worksheets.Add("Chart");
//Some data
myWorkSheet.Cells["A1"].Value = "A";
myWorkSheet.Cells["A2"].Value = 100; myWorkSheet.Cells["A3"].Value = 400; myWorkSheet.Cells["A4"].Value = 200; myWorkSheet.Cells["A5"].Value = 300; myWorkSheet.Cells["A6"].Value = 600; myWorkSheet.Cells["A7"].Value = 500;
myWorkSheet.Cells["B1"].Value = "B";
myWorkSheet.Cells["B2"].Value = 300; myWorkSheet.Cells["B3"].Value = 200; myWorkSheet.Cells["B4"].Value = 1000; myWorkSheet.Cells["B5"].Value = 600; myWorkSheet.Cells["B6"].Value = 500; myWorkSheet.Cells["B7"].Value = 200;
ExcelRange values = myWorkSheet.Cells["B2,B4,B6"];
ExcelRange xvalues = myWorkSheet.Cells["A2,A4,A6"];
const string myTitle = "Chart 1";
ExcelChart chart1 = ExcelWorksheet.Drawings.AddChart(myTitle, eChartType.Pie);
chart1.Series.Add(values, xvalues);
pck.Save();
}
}
I want to add a listener to the select button which gets the multiple rows selected in the checklist tableviewer. It then proccedes to check those boxes.
My question is how do I get the list of rows selected in the tableviewer?
Here is the code for the table:
private void createCheckViewer(Composite parent){
tableViewer = CheckboxTableViewer.newCheckList(parent, SWT.MULTI| SWT.BORDER | SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.V_SCROLL);
if ( (GanttFrame.getListOfFunctionTasks()!= null)){
if (!(GanttFrame.getListOfFunctionTasks().isEmpty())){
// Data Rows
for (int i = 0; i < GanttFrame.getListOfFunctionTasks().size(); i++) {
tableViewer.add(GanttFrame.getListOfFunctionTasks().get(i));
GanttFrame.getListOfFunctionTasks().get(i).setCheckId(i);
}
}
}
// flow trace or function trace
String columnHeader;
if (TraceData.getFlowTraceFlag()){
columnHeader = "Flow Traces";
}else{
columnHeader = "Function Traces";
}
// define layout for the viewer
gridData = new GridData(SWT.FILL, SWT.TOP, true, false, 3, 1);
gridData.heightHint = 400;
tableViewer.getControl().setLayoutData(gridData);
tableViewer.addCheckStateListener(this.getCheckListListener());
final Table table = tableViewer.getTable();
TableLayout layout = new TableLayout();
TableViewerColumn col = new TableViewerColumn(tableViewer, SWT.LEAD);
col.getColumn().setText(columnHeader);
layout.addColumnData(new ColumnWeightData(500));
table.setLayout(layout);
table.setHeaderVisible(true);
table.setLinesVisible(true);
}
Use:
IStructuredSelection selection = (IStructuredSelection)tableViewer.getSelection();
You then have various choices for processing the selection:
Object [] selections = selection.toArray();
List<?> selections = selection.toList();
Iterator<?> iterator = selection.iterator();
I am trying to create an spread sheet by open xml with an table. But while opening the created excel file always it returns the error "Excel found unreadable content in test1.xlsx, do u want to recover. Why this error always happens? When the excel is created without table, i didnt get any error. Please find the below sample code which i used to create.
using (SpreadsheetDocument spreadsheetdocument = SpreadsheetDocument.Create(#"c://test.xlsx", SpreadsheetDocumentType.Workbook))
{
// add a workbookpart to the document.
WorkbookPart workbookpart = spreadsheetdocument.AddWorkbookPart();
workbookpart.Workbook = new Workbook();
// add a worksheetpart to the workbookpart.
WorksheetPart worksheetpart = workbookpart.AddNewPart<WorksheetPart>();
worksheetpart.Worksheet = new Worksheet(new SheetData());
// add sheets to the workbook.
Sheets sheets = spreadsheetdocument.WorkbookPart.Workbook.
AppendChild<Sheets>(new Sheets());
// append a new worksheet and associate it with the workbook.
Sheet sheet = new Sheet()
{
Id = spreadsheetdocument.WorkbookPart.
GetIdOfPart(worksheetpart),
SheetId = 1,
Name = "mysheet"
};
sheets.Append(sheet);
TableDefinitionPart tableDefinitionPart = worksheetpart.AddNewPart<TableDefinitionPart>("rId1");
GenerateTablePartContent(ref tableDefinitionPart);
TableParts tableParts1 = new TableParts() { Count = (UInt32Value)2U };
TablePart tablePart1 = new TablePart() { Id = "rId1" };
tableParts1.Append(tablePart1);
worksheetpart.Worksheet.Append(tableParts1);
spreadsheetdocument.Close();
}
//Added spaces to get the code in one block
private void GenerateTablePartContent(TableDefinitionPart part)
{
Table table1 = new Table() { Id = (UInt32Value)1U, Name = "Table1", DisplayName = "Table1", Reference = "A1:C3", TotalsRowShown = false };
AutoFilter autoFilter1 = new AutoFilter() { Reference = "A1:C3" };
TableColumns tableColumns1 = new TableColumns() { Count = (UInt32Value)3U };
TableColumn tableColumn1 = new TableColumn() { Id = (UInt32Value)1U, Name = "Column1" };
TableColumn tableColumn2 = new TableColumn() { Id = (UInt32Value)2U, Name = "Column2" };
TableColumn tableColumn3 = new TableColumn() { Id = (UInt32Value)3U, Name = "Column3" };
tableColumns1.Append(tableColumn1);
tableColumns1.Append(tableColumn2);
tableColumns1.Append(tableColumn3);
TableStyleInfo tableStyleInfo1 = new TableStyleInfo() { Name = "TableStyleMedium2", ShowFirstColumn = false, ShowLastColumn = false, ShowRowStripes = true, ShowColumnStripes = false };
table1.Append(autoFilter1);
table1.Append(tableColumns1);
table1.Append(tableStyleInfo1);
part.Table = table1;
}
use Open XML SDK Productivity Tool for it. Create an excel file using normal way and put same data there as well and compare that file with the file you are creating with your code. You will see the changes there. I am also facing same issue and I am trying to fix the changes using that tool. Lets see....
and If you have solved the issue please guide me how to do it.