GraphicalEngine/Show-Graph.ps1
Function Show-Graph { [cmdletbinding()] Param( [int[]] $Datapoints, [String] $GraphTitle, [ValidateScript({ if( $_ -le 5 ){ Throw "Can not set XAxisStep less than or equals to 5" } else { return $true } })] [Int] $XAxisStep = 10, [Int] $YAxisStep = 10, [Int] $yAxisMaxRows = 10, [ValidateSet("Bar","Scatter","Line")] [String] $Type = 'Bar', [Hashtable] $ColorMap ) # graph boundary marks $TopLeft = [char]9484 # ┌ $BottomLeft = [char]9492 # └ $TopRight = [char]9488 # ┐ $BottomRight = [char]9496 # ┘ $VerticalEdge = [char]9474 # │ $TopEdge = $BottomEdge = [char]9472 # ─ # Calculate Max, Min and Range of Y axis $NumOfDatapoints = $Datapoints.Count $Metric = $Datapoints | Measure-Object -Maximum -Minimum $EndofRange = $Metric.Maximum + ($YAxisStep - $Metric.Maximum % $YAxisStep) $StartOfRange = $Metric.Minimum - ($Metric.Minimum % $YAxisStep) $difference = $EndofRange - $StartOfRange $NumOfRows = $difference/($YAxisStep) # Calculate label lengths $LengthOfMaxYAxisLabel = [Math]::Max(1, (($Datapoints | Measure-Object -Maximum).Maximum).tostring().length) # Cap number of rows to yAxisMaxRows for better readability if ( $NumOfRows -gt $yAxisMaxRows ) { $NumOfRows = $yAxisMaxRows } # Create a 2D Array to save datapoints in a 2D format switch( $Type ){ 'Bar' { $Array = Get-BarPlot -Datapoints $Datapoints -Step $YAxisStep -StartOfRange $StartOfRange -EndofRange $EndofRange -yAxisMaxRows $yAxisMaxRows } 'Scatter' { $Array = Get-ScatterPlot -Datapoints $Datapoints -Step $YAxisStep -StartOfRange $StartOfRange -EndofRange $EndofRange -yAxisMaxRows $yAxisMaxRows } 'Line' { $Array = Get-LinePlot -Datapoints $Datapoints -Step $YAxisStep -StartOfRange $StartOfRange -EndofRange $EndofRange -yAxisMaxRows $yAxisMaxRows } } # Preparing the step markings on the X-Axis (reversed for time series) $Increment = $XAxisStep $XAxisLabel = " " * ($LengthOfMaxYAxisLabel + 4) $XAxis = " " * ($LengthOfMaxYAxisLabel + 3) + [char]9492 # └ For ( $Label = 1; $Label -le $NumOfDatapoints; $Label++ ) { if ( [math]::floor($Label/$XAxisStep) ){ $TimeLabel = $NumOfDatapoints - $Label + 1 $XAxisLabel += $TimeLabel.tostring().PadLeft($Increment) $XAxis += ([char]9516).ToString() $XAxisStep += $Increment } else { $XAxis += [Char]9472 # ─ } } # calculate boundaries of the graph $TopBoundaryLength = [Math]::Max(0, $XAxis.Length - $GraphTitle.Length) $BottomBoundaryLength = $XAxis.Length + 2 # draw top boundary Write-Host ([string]::Concat($TopLeft," ",$GraphTitle," ",$([string]$TopEdge * $TopBoundaryLength),$TopRight)) Write-Host ([String]::Concat($VerticalEdge,$(" "*$($XAxis.length+2)),$VerticalEdge)) # extra line to add space between top-boundary and the graph # draw the graph For( $i = $NumOfRows; $i -gt 0; $i-- ) { $Row = '' For( $j = 0; $j -lt $NumOfDatapoints; $j++ ) { $Cell = $Array[$i,$j] if( [String]::IsNullOrWhiteSpace($Cell) ){ if( $AddHorizontalLines ) { $String = [Char]9472 # ─ } else { $String = ' ' } } else { $String = $Cell } $Row = [string]::Concat($Row, $String) } $YAxisLabel = $StartOfRange + $i * $YAxisStep If( $ColorMap ) { $Keys = $ColorMap.Keys | Sort-Object $LowerBound = $StartOfRange $Map = @() $Map += For( $k = 0; $k -lt $Keys.count; $k++ ) { [PSCustomObject]@{ LowerBound = $LowerBound UpperBound = $Keys[$k] Color = $ColorMap[$Keys[$k]] } $LowerBound = $Keys[$k] + 1 } $Color = $Map.ForEach({ if( $YAxisLabel -ge $_.LowerBound -and $YAxisLabel -le $_.UpperBound ) { $_.Color } }) # if out of bounds, use the last color if ( [String]::IsNullOrEmpty($Color) ) { $Map = $Map | sort-object -Property UpperBound -Descending $Color = $Map[0].Color } Write-Graph ' ' $YAxisLabel $Row $Color 'DarkYellow' $LengthOfMaxYAxisLabel } else { THROW "ColorMap is not defined. Please provide a valid ColorMap hashtable." } } # draw bottom boundary $XAxisLabel +=" "*([Math]::Max(0, $XAxis.Length-$XAxisLabel.Length)) # to match x-axis label length with x-axis length Write-Host([String]::Concat($VerticalEdge,$XAxis," ",$VerticalEdge)) # Prints X-Axis horizontal line Write-Host([string]::Concat($VerticalEdge,$XAxisLabel," ",$VerticalEdge)) # Prints X-Axis step labels # bottom boundary Write-Host([string]::Concat($BottomLeft,$([string]$BottomEdge * $BottomBoundaryLength),$BottomRight)) } |