mirror of
https://github.com/dfinke/ImportExcel.git
synced 2025-12-06 00:23:20 +00:00
Merge pull request #501 from jhoneill/master
Added Pivot table grouping
This commit is contained in:
@@ -674,6 +674,7 @@
|
||||
|
||||
$row = $ws.Dimension.End.Row
|
||||
Write-Debug -Message ("Appending: headers are " + ($script:Header -join ", ") + " Start row is $row")
|
||||
if ($Title) {Write-Warning -Message "-Title Parameter is ignored when appending."}
|
||||
}
|
||||
elseif ($Title) {
|
||||
#Can only add a title if not appending!
|
||||
|
||||
@@ -38,7 +38,51 @@
|
||||
but here -Address is specified to place it beside the data. The Add-Pivot table is given the chart definition and told to create a tale
|
||||
using the City field to create rows, the Product field to create columns and the data should be the sum of the gross field and the sum of the net field;
|
||||
grand totals for both gross and net are included for rows (Cities) and columns (product) and the data is explicitly formatted as a currency.
|
||||
Not that in the chart definition the number format for the axis does not include any fraction part.
|
||||
Note that in the chart definition the number format for the axis does not include any fraction part.
|
||||
.Example
|
||||
>
|
||||
$excel = Convertfrom-csv @"
|
||||
Location,OrderDate,quantity
|
||||
Boston,1/1/2017,100
|
||||
New York,1/21/2017,200
|
||||
Boston,1/11/2017,300
|
||||
New York,1/9/2017,400
|
||||
Boston,1/18/2017,500
|
||||
Boston,2/1/2017,600
|
||||
New York,2/21/2017,700
|
||||
New York,2/11/2017,800
|
||||
Boston,2/9/2017,900
|
||||
Boston,2/18/2017,1000
|
||||
New York,1/1/2018,100
|
||||
Boston,1/21/2018,200
|
||||
New York,1/11/2018,300
|
||||
Boston,1/9/2018,400
|
||||
New York,1/18/2018,500
|
||||
Boston,2/1/2018,600
|
||||
Boston,2/21/2018,700
|
||||
New York,2/11/2018,800
|
||||
New York,2/9/2018,900
|
||||
Boston,2/18/2018,1000
|
||||
"@ | Select-Object -Property @{n="OrderDate";e={[datetime]::ParseExact($_.OrderDate,"M/d/yyyy",(Get-Culture))}},
|
||||
Location, Quantity | Export-Excel "test2.xlsx" -PassThru -AutoSize
|
||||
|
||||
Set-ExcelColumn -Worksheet $excel.sheet1 -Column 1 -NumberFormat 'Short Date'
|
||||
|
||||
$pt = Add-PivotTable -PassThru -PivotTableName "ByDate" -Address $excel.Sheet1.cells["F1"] -SourceWorkSheet $excel.Sheet1 -PivotRows location,orderdate -PivotData @{'quantity'='sum'} -GroupDateRow orderdate -GroupDatePart 'Months,Years' -PivotTotals None
|
||||
$pt.RowFields[0].SubtotalTop=$false
|
||||
$pt.RowFields[0].Compact=$false
|
||||
Close-ExcelPackage $excel -Show
|
||||
|
||||
Here the data contains dates formatted as strings using US format. These
|
||||
are converted to DateTime objects before being exported to Excel; the
|
||||
"OrderDate" column is formatted with the local short-date style. Then
|
||||
the PivotTable is added; it groups information by date and location, the
|
||||
date is split into years and then months. No grand totals are displayed.
|
||||
The Pivot table object is caught in a variable, and the "Location"
|
||||
column has its subtotal moved from the top to the bottom of each location
|
||||
section, and the "Compact" option is disabled to prevent "Year" moving
|
||||
into the same column as location.
|
||||
Finally the workbook is saved and shown in Excel.
|
||||
#>
|
||||
[cmdletbinding(defaultParameterSetName='ChartbyParams')]
|
||||
[OutputType([OfficeOpenXml.Table.PivotTable.ExcelPivotTable])]
|
||||
@@ -71,6 +115,18 @@
|
||||
[String]$PivotTotals = "Both",
|
||||
#Included for compatibility - equivalent to -PivotTotals "None".
|
||||
[Switch]$NoTotalsInPivot,
|
||||
#The name of a row field which should be grouped by parts of the date/time (ignored if GroupDateRow is not specified)
|
||||
[String]$GroupDateRow,
|
||||
#The Part(s) of the date to use in the grouping (ignored if GroupDateRow is not specified)
|
||||
[OfficeOpenXml.Table.PivotTable.eDateGroupBy[]]$GroupDatePart,
|
||||
#The name of a row field which should be grouped by Number (e.g 0-99, 100-199, 200-299 )
|
||||
[String]$GroupNumericRow,
|
||||
#The starting point for grouping
|
||||
[double]$GroupNumbericMin = 0 ,
|
||||
#The endpoint for grouping
|
||||
[double]$GroupNumbericMax = [Double]::MaxValue ,
|
||||
#The interval for grouping
|
||||
[double]$GroupNumbericInterval = 100 ,
|
||||
#Number format to apply to the data cells in the PivotTable.
|
||||
[string]$PivotNumberFormat,
|
||||
#Apply a table style to the PivotTable.
|
||||
@@ -198,7 +254,17 @@
|
||||
if ($PivotTotals -eq "None" -or $PivotTotals -eq "Rows") { $pivotTable.ColumGrandTotals = $false } # Epplus spelling mistake, not mine!
|
||||
elseif ($PivotTotals -eq "Both" -or $PivotTotals -eq "Columns") { $pivotTable.ColumGrandTotals = $true }
|
||||
if ($PivotDataToColumn ) { $pivotTable.DataOnRows = $false }
|
||||
if ($PivotTableStyle) { $pivotTable.TableStyle = $PivotTableStyle}
|
||||
if ($PivotTableStyle) { $pivotTable.TableStyle = $PivotTableStyle}
|
||||
if ($GroupNumericRow) {
|
||||
$r =$pivotTable.RowFields.Where({$_.name -eq $GroupNumericRow })
|
||||
if (-not $r ) {Write-Warning -Message "Could not find a Row field named '$GroupNumericRow'; no numeric grouping will be done."}
|
||||
else {$r.AddNumericGrouping($GroupNumbericMin,$GroupNumbericMax,$GroupNumbericInterval)}
|
||||
}
|
||||
if ($GroupDateRow -and $PSBoundParameters.ContainsKey("GroupDatePart")) {
|
||||
$r =$pivotTable.RowFields.Where({$_.name -eq $GroupDateRow })
|
||||
if (-not $r ) {Write-Warning -Message "Could not find a Row field named '$GroupDateRow'; no date grouping will be done."}
|
||||
else {$r.AddDateGrouping($GroupDatePart)}
|
||||
}
|
||||
}
|
||||
catch {Write-Warning -Message "Failed adding PivotTable '$pivotTableName': $_"}
|
||||
}
|
||||
@@ -271,6 +337,18 @@ function New-PivotTableDefinition {
|
||||
[String]$PivotTotals = "Both",
|
||||
#Included for compatibility - equivalent to -PivotTotals "None"
|
||||
[Switch]$NoTotalsInPivot,
|
||||
#The name of a row field which should be grouped by parts of the date/time (ignored if GroupDateRow is not specified)
|
||||
[String]$GroupDateRow,
|
||||
#The Part(s) of the date to use in the grouping (ignored if GroupDateRow is not specified)
|
||||
[OfficeOpenXml.Table.PivotTable.eDateGroupBy[]]$GroupDatePart,
|
||||
#The name of a row field which should be grouped by Number (e.g 0-99, 100-199, 200-299 )
|
||||
[String]$GroupNumericRow,
|
||||
#The starting point for grouping
|
||||
[double]$GroupNumbericMin = 0 ,
|
||||
#The endpoint for grouping
|
||||
[double]$GroupNumbericMax = [Double]::MaxValue ,
|
||||
#The interval for grouping
|
||||
[double]$GroupNumbericInterval = 100 ,
|
||||
#Number format to apply to the data cells in the PivotTable
|
||||
[string]$PivotNumberFormat,
|
||||
#Apply a table style to the PivotTable
|
||||
|
||||
@@ -55,6 +55,9 @@ Install-Module ImportExcel
|
||||
|
||||
# What's new
|
||||
- Set-ExcelRow and Set-ExcelColumn now check that the worksheet name they passed exists in the workbook.
|
||||
- Added parameters -GroupDateRow and -GroupDatePart & -GroupNumericRow, -GroupNumbericMin, -GroupNumbericMax and -GroupNumbericInterval
|
||||
to Add-PivotTable and New-PivotTableDefinition. The date ones gather dates of the same year and/or quarter and/or month and/or day etc.
|
||||
the number ones group numbers into bands, starting at Min, and going up steps specified by Interval. Added tests and help for these.
|
||||
|
||||
# What's new 5.4
|
||||
|
||||
|
||||
@@ -156,10 +156,11 @@
|
||||
if ($PSBoundParameters.ContainsKey('Value')) { foreach ($row in ($StartRow..$endRow)) {
|
||||
if ($Value -is [scriptblock]) { #re-create the script block otherwise variables from this function are out of scope.
|
||||
$cellData = & ([scriptblock]::create( $Value ))
|
||||
Write-Verbose -Message $cellData
|
||||
if ($null -eq $cellData) {Write-Verbose -Message "Script block evaluates to null."}
|
||||
else {Write-Verbose -Message "Script block evaluates to '$cellData'"}
|
||||
}
|
||||
else { $cellData = $Value}
|
||||
if ($cellData -match "^=") { $Worksheet.Cells[$Row, $Column].Formula = ($cellData -replace '^=','') } #EPPlus likes formulas with no = sign; Excel doesn't care
|
||||
if ($cellData -match "^=") { $Worksheet.Cells[$Row, $Column].Formula = ($cellData -replace '^=','') } #EPPlus likes formulas with no = sign; Excel doesn't care
|
||||
elseif ( [System.Uri]::IsWellFormedUriString($cellData , [System.UriKind]::Absolute)) {
|
||||
# Save a hyperlink : internal links can be in the form xl://sheet!E419 (use A1 as goto sheet), or xl://RangeName
|
||||
if ($cellData -match "^xl://internal/") {
|
||||
@@ -168,13 +169,13 @@
|
||||
$h = New-Object -TypeName OfficeOpenXml.ExcelHyperLink -ArgumentList $referenceAddress , $display
|
||||
$Worksheet.Cells[$Row, $Column].HyperLink = $h
|
||||
}
|
||||
else {$Worksheet.Cells[$Row, $Column].HyperLink = $cellData }
|
||||
$Worksheet.Cells[$Row, $Column].Style.Font.Color.SetColor([System.Drawing.Color]::Blue)
|
||||
else {$Worksheet.Cells[$Row, $Column].HyperLink = $cellData }
|
||||
$Worksheet.Cells[$Row, $Column].Style.Font.UnderLine = $true
|
||||
$Worksheet.Cells[$Row, $Column].Style.Font.Color.SetColor([System.Drawing.Color]::Blue)
|
||||
}
|
||||
else { $Worksheet.Cells[$Row, $Column].Value = $cellData }
|
||||
if ($cellData -is [datetime]) { $Worksheet.Cells[$Row, $Column].Style.Numberformat.Format = 'm/d/yy h:mm' } # This is not a custom format, but a preset recognized as date and localized.
|
||||
if ($cellData -is [timespan]) { $Worksheet.Cells[$Row, $Column].Style.Numberformat.Format = '[h]:mm:ss' }
|
||||
else { $Worksheet.Cells[$Row, $Column].Value = $cellData }
|
||||
if ($cellData -is [datetime]) { $Worksheet.Cells[$Row, $Column].Style.Numberformat.Format = 'm/d/yy h:mm' } # This is not a custom format, but a preset recognized as date and localized.
|
||||
if ($cellData -is [timespan]) { $Worksheet.Cells[$Row, $Column].Style.Numberformat.Format = '[h]:mm:ss' }
|
||||
}}
|
||||
|
||||
#region Apply formatting
|
||||
|
||||
@@ -147,7 +147,8 @@
|
||||
if ($Value -is [scriptblock] ) {
|
||||
#re-create the script block otherwise variables from this function are out of scope.
|
||||
$cellData = & ([scriptblock]::create( $Value ))
|
||||
Write-Verbose -Message $cellData
|
||||
if ($null -eq $cellData) {Write-Verbose -Message "Script block evaluates to null."}
|
||||
else {Write-Verbose -Message "Script block evaluates to '$cellData'"}
|
||||
}
|
||||
else{$cellData = $Value}
|
||||
if ($cellData -match "^=") { $Worksheet.Cells[$Row, $column].Formula = ($cellData -replace '^=','') } #EPPlus likes formulas with no = sign; Excel doesn't care
|
||||
|
||||
@@ -6,7 +6,9 @@ Describe "Creating small named ranges with hyperlinks" {
|
||||
$path = "$env:TEMP\Results.xlsx"
|
||||
Remove-Item -Path $path -ErrorAction SilentlyContinue
|
||||
#Read race results, and group by race name : export 1 row to get headers, leaving enough rows aboce to put in a link for each race
|
||||
$results = Import-Csv -Path $dataPath | Group-Object -Property RACE
|
||||
$results = Import-Csv -Path $dataPath |
|
||||
Select-Object Race,@{n="Date";e={[datetime]::ParseExact($_.date,"dd/MM/yyyy",(Get-Culture))}}, FinishPosition, Driver, GridPosition, Team,Points |
|
||||
Group-Object -Property RACE
|
||||
$topRow = $lastDataRow = 1 + $results.Count
|
||||
$excel = $results[0].Group[0] | Export-Excel -Path $path -StartRow $TopRow -BoldTopRow -PassThru
|
||||
|
||||
@@ -39,8 +41,16 @@ Describe "Creating small named ranges with hyperlinks" {
|
||||
$ct = New-ConditionalText -Text "Ferrari"
|
||||
$ct2 = New-ConditionalText -Range $worksheet.Names["FinishPosition"].Address -ConditionalType LessThanOrEqual -Text 3 -ConditionalText ([System.Drawing.Color]::Red) -Background ([System.Drawing.Color]::White) #Test new-conditionalText in shortest and longest forms.
|
||||
#Create links for each group name (race) and Export them so they start at Cell A1; create a pivot table with definition just created, save the file and open in Excel
|
||||
$results | ForEach-Object {(New-Object -TypeName OfficeOpenXml.ExcelHyperLink -ArgumentList "Sheet1!$($_.Name)" , "$($_.name) GP")} | #Test Exporting Hyperlinks with display property.
|
||||
Export-Excel -ExcelPackage $excel -AutoSize -PivotTableDefinition $pt -Calculate -ConditionalFormat $ct,$ct2 #Test conditional text rules in conditional format (orignally icon sets only )
|
||||
$excel = $results | ForEach-Object {(New-Object -TypeName OfficeOpenXml.ExcelHyperLink -ArgumentList "Sheet1!$($_.Name)" , "$($_.name) GP")} | #Test Exporting Hyperlinks with display property.
|
||||
Export-Excel -ExcelPackage $excel -AutoSize -PivotTableDefinition $pt -Calculate -ConditionalFormat $ct,$ct2 -PassThru #Test conditional text rules in conditional format (orignally icon sets only )
|
||||
|
||||
$null = Add-WorkSheet -ExcelPackage $excel -WorksheetName "Points1"
|
||||
Add-PivotTable -PivotTableName "Points1" -Address $excel.Points1.Cells["A1"] -ExcelPackage $excel -SourceWorkSheet sheet1 -SourceRange $excel.Sheet1.Tables[0].Address.Address -PivotRows Driver,Date -PivotData @{Points="SUM"} -GroupDateRow Date -GroupDatePart Years, Months
|
||||
|
||||
$null = Add-WorkSheet -ExcelPackage $excel -WorksheetName "Places1"
|
||||
$newpt = Add-PivotTable -PivotTableName "Places1" -Address $excel.Places1.Cells["A1"] -ExcelPackage $excel -SourceWorkSheet sheet1 -SourceRange $excel.Sheet1.Tables[0].Address.Address -PivotRows Driver,FinishPosition -PivotData @{Date="Count"} -GroupNumericRow FinishPosition -GroupNumbericMin 1 -GroupNumbericMax 25 -GroupNumbericInterval 3 -PassThru
|
||||
$newpt.RowFields[0].SubTotalFunctions = [OfficeOpenXml.Table.PivotTable.eSubTotalFunctions]::None
|
||||
Close-ExcelPackage -ExcelPackage $excel
|
||||
|
||||
$excel = Open-ExcelPackage $path
|
||||
$sheet = $excel.Workbook.Worksheets[1]
|
||||
@@ -98,4 +108,32 @@ Describe "Creating small named ranges with hyperlinks" {
|
||||
$sheet.Tables[0].ShowRowStripes | should not be $true
|
||||
}
|
||||
}
|
||||
Context "Adding Pivot tables" {
|
||||
it "Added a worksheet with a pivot table grouped by date " {
|
||||
$excel.Points1 | should not beNullOrEmpty
|
||||
$excel.Points1.PivotTables.Count | should be 1
|
||||
$pt = $excel.Points1.PivotTables[0]
|
||||
$pt.RowFields.Count | should be 3
|
||||
$pt.RowFields[0].name | should be "Driver"
|
||||
$pt.RowFields[0].Grouping | should benullorEmpty
|
||||
$pt.RowFields[1].name | should be "years"
|
||||
$pt.RowFields[1].Grouping | should not benullorEmpty
|
||||
$pt.RowFields[2].name | should be "date"
|
||||
$pt.RowFields[2].Grouping | should not benullorEmpty
|
||||
}
|
||||
it "Added a worksheet with a pivot table grouped by Number " {
|
||||
$excel.Places1 | should not beNullOrEmpty
|
||||
$excel.Places1.PivotTables.Count | should be 1
|
||||
$pt = $excel.Places1.PivotTables[0]
|
||||
$pt.RowFields.Count | should be 2
|
||||
$pt.RowFields[0].name | should be "Driver"
|
||||
$pt.RowFields[0].Grouping | should benullorEmpty
|
||||
$pt.RowFields[0].SubTotalFunctions.ToString() | should be "None"
|
||||
$pt.RowFields[1].name | should be "FinishPosition"
|
||||
$pt.RowFields[1].Grouping | should not benullorEmpty
|
||||
$pt.RowFields[1].Grouping.Start | should be 1
|
||||
$pt.RowFields[1].Grouping.End | should be 25
|
||||
$pt.RowFields[1].Grouping.Interval | should be 3
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user