Types/Turtle/BarGraph.ps1

<#
.SYNOPSIS
    Draws a bar graph using turtle graphics.
.DESCRIPTION
    This script uses turtle graphics to draw a bar graph based on the provided data.
.EXAMPLE
    turtle barGraph 100 100 5 10 15 20 15 10 5
.EXAMPLE
    turtle barGraph 200 200 (
        @(1..50;-1..-50) |
            Get-Random -Count (Get-Random -Minimum 5 -Maximum 20)
    ) save ./RandomBarGraph.svg
.EXAMPLE
    turtle rotate 90 barGraph 200 200 (
        @(1..50;-1..-50) |
            Get-Random -Count (Get-Random -Minimum 5 -Maximum 20)
    ) save ./RandomVerticalBarGraph.svg
.EXAMPLE
    turtle rotate 45 barGraph 200 200 (
        @(1..50;-1..-50) |
            Get-Random -Count (Get-Random -Minimum 5 -Maximum 20)
    ) save ./RandomDiagonalBarGraph.svg
.EXAMPLE
    $sourceData = @(1..50;-1..-50)
    $itemCount = (Get-Random -Minimum 5 -Maximum 20)
    $points = $sourceData | Get-Random -Count $itemCount
    turtle bargraph 200 200 $points morph @(
        turtle bargraph 200 200 $points
        turtle bargraph 200 200 ( $sourceData | Get-Random -Count $itemCount )
        turtle bargraph 200 200 $points
    ) save ./RandomBarGraphMorph.svg
#>

param(
# The width of the bar graph
[double]$Width,
# The height of the bar graph.
# Please note that in the case of negative values, the effective height is twice this number.
[double]$Height,

# The points in the bar graph.
# Each point will be turned into a relative number and turned into an equal-width bar.
[Parameter(ValueFromRemainingArguments)]
[double[]]$Points
)


# If there were no points, we are drawing nothing, so return ourself.
if (-not $points) { return $this}

# Divide the width by the number of points to get a very snug bar graph
$barWidth = $width / $points.Length

# Find the maximum and minimum values in the points
$min, $max = 0, 0
foreach ($point in $points) {
    if ($point -gt $max) { $max = $point}
    if ($point -lt $min) { $min = $point}
}

# This gives us the range.
$range = $max - $min

# If the range is zero, we're drawing a flatline.
if ($range -eq 0) {
    # so just draw that line and return.
    return $this.Forward($width)
}

# Now that we've normalized the range, we can draw the bars.
for ($pointIndex =0 ; $pointIndex -lt $points.Length; $pointIndex++) {
    # Each point is essentially telling us the height
    $point = $points[$pointIndex]
    # which we can turn into a relative value
    $relativeHeight = (
        # by subtracting the minimum and dividing by the range
        (($point - $min) / $range)
    ) * $height
    # If the point was negative, we need to flip the height
    if ($point -lt 0) { $relativeHeight *= -1}
    # Now we can draw the bar
    $this = $this.
        # Turn outward and draw the side
        Rotate(-90).Forward($relativeHeight).
        # Turn and draw the top
        Rotate(90).Forward($barWidth).
        # Turn and draw the other side
        Rotate(90).Forward($relativeHeight).
        # Turn back to the original direction
        Rotate(-90)
}
return $this