Skip to content

Commit 4e460d4

Browse files
StartAutomatingStartAutomating
authored andcommitted
feat: Turtle.PieGraph ( Fixes PoshWeb#239 )
1 parent 783a324 commit 4e460d4

File tree

1 file changed

+186
-0
lines changed

1 file changed

+186
-0
lines changed

Turtle.types.ps1xml

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1944,6 +1944,192 @@ $null = @(
19441944
$this.Rotate($OppositeAngle)
19451945
)
19461946

1947+
return $this
1948+
</Script>
1949+
</ScriptMethod>
1950+
<ScriptMethod>
1951+
<Name>PieGraph</Name>
1952+
<Script>
1953+
&lt;#
1954+
.SYNOPSIS
1955+
Draws a pie graph using turtle graphics.
1956+
.DESCRIPTION
1957+
This script uses turtle graphics to draw a pie graph based on the provided data.
1958+
.EXAMPLE
1959+
turtle PieGraph 400 400 80 20 save ./80-20.svg
1960+
.EXAMPLE
1961+
turtle PieGraph 400 400 5 10 15 20 15 10 5 | Save-Turtle ./PieGraph.svg
1962+
.EXAMPLE
1963+
turtle width 400 height 400 PieGraph 400 400 @{value=20;fill='red'} @{value=40;fill='blue'} save ./PieGraphColor.svg
1964+
.EXAMPLE
1965+
turtle PieGraph 400 400 @(
1966+
5,10,15,20,15,10,5 | Sort-Object -Descending
1967+
) | Save-Turtle ./PieGraphDescending.svg
1968+
.EXAMPLE
1969+
turtle rotate (Get-Random -Max 360) PieGraph 400 400 @(
1970+
5,10,15,20,15,10,5 | Sort-Object -Descending
1971+
) | Save-Turtle ./PieGraphDescendingRotated.svg
1972+
.EXAMPLE
1973+
turtle PieGraph 200 200 (
1974+
@(1..50) |
1975+
Get-Random -Count (Get-Random -Minimum 5 -Maximum 20)
1976+
) save ./RandomPieGraph.svg
1977+
.EXAMPLE
1978+
$n = Get-Random -Min 5 -Max 10
1979+
turtle width 200 height 200 morph @(
1980+
turtle PieGraph 200 200 @(1..50 | Get-Random -Count $n)
1981+
turtle PieGraph 200 200 @(1..50 | Get-Random -Count $n)
1982+
turtle PieGraph 200 200 @(1..50 | Get-Random -Count $n)
1983+
) save ./RandomPieGraphMorph.svg
1984+
.EXAMPLE
1985+
turtle PieGraph 200 200 (
1986+
@(1..50;-1..-50) |
1987+
Get-Random -Count (Get-Random -Minimum 5 -Maximum 20)
1988+
) save ./RandomPieGraphWithNegative.svg
1989+
.EXAMPLE
1990+
$randomNegativePie = turtle PieGraph 200 200 (
1991+
@(1..50;-1..-50) |
1992+
Get-Random -Count 10
1993+
)
1994+
turtle width 200 height 200 morph @(
1995+
$randomNegativePie
1996+
turtle PieGraph 200 200 (
1997+
@(1..50;-1..-50) |
1998+
Get-Random -Count 10
1999+
)
2000+
$randomNegativePie
2001+
) save ./RandomPieGraphWithNegativeMorph.svg
2002+
#&gt;
2003+
param(
2004+
# The radius of the bar graph
2005+
[double]$Radius,
2006+
2007+
# The points in the bar graph.
2008+
# Each point will be turned into a relative number and turned into an equal-width bar.
2009+
[Parameter(ValueFromRemainingArguments)]
2010+
[PSObject[]]
2011+
$GraphData
2012+
)
2013+
2014+
2015+
# If there were no points, we are drawing nothing, so return ourself.
2016+
if (-not $GraphData) { return $this}
2017+
2018+
filter IsPrimitive {$_.GetType -and $_.GetType().IsPrimitive}
2019+
2020+
# To make a pie graph we need to know the total, and thus we need to make a couple of passes
2021+
[double]$Total = 0.0
2022+
2023+
$sliceObjects = [Ordered]@{}
2024+
$richSlices = $false
2025+
$Slices = @(
2026+
$dataPointIndex = 0
2027+
foreach ($dataPoint in $GraphData)
2028+
{
2029+
$sliceObjects["slice$($sliceObjects.Count)"] = $dataPoint
2030+
# If the data point is a number (or other primitive data)
2031+
if ($dataPoint | IsPrimitive)
2032+
{
2033+
$Total += $dataPoint # add it to the total
2034+
$dataPoint -as [double] # and output it
2035+
}
2036+
# Otherwise, if the data point has a value that is a number
2037+
elseif ($dataPoint.value | IsPrimitive)
2038+
{
2039+
$Total += $dataPoint.value # add it to the total
2040+
$dataPoint.value -as [double] # and output that
2041+
$richSlices = $true
2042+
}
2043+
elseif ($dataPoint -is [Collections.IDictionary]) {
2044+
foreach ($key in $dataPoint.Keys) {
2045+
if ($dataPoint[$key] | IsPrimitive) {
2046+
$Total += $dataPoint[$key] # add it to the total
2047+
$dataPoint[$key] -as [double] # and output that
2048+
}
2049+
}
2050+
$richSlices = $true
2051+
}
2052+
}
2053+
)
2054+
2055+
# Turn each numeric slice into a ratio
2056+
$relativeSlices =
2057+
foreach ($slice in $Slices) { $slice/ $total }
2058+
2059+
# If we have no ratios, we have nothing to graph, and we are done here.
2060+
if (-not $relativeSlices) { return $this }
2061+
2062+
# Next let's figure out the maximum delta x and delta y
2063+
$dx = $this.X + ($Radius * 2)
2064+
$dy = $this.Y + ($Radius * 2)
2065+
# and resize our viewbox with respect to our radius
2066+
$null = $this.ResizeViewBox($Radius)
2067+
2068+
# Calulate the midpoint of the circle
2069+
$midX = $this.X + $dx/2
2070+
$midY = $this.Y + $dy/2
2071+
2072+
# and teleport to it
2073+
$null = $this.Teleport($midX, $midY)
2074+
2075+
# If we are not rendering "rich" slices, we can draw the arcs as one path.
2076+
if (-not $richSlices) {
2077+
for ($sliceNumber =0 ; $sliceNumber -lt $Slices.Length; $sliceNumber++) {
2078+
# Turn each ratio into an angle
2079+
$Angle = $relativeSlices[$sliceNumber] * 360
2080+
$this = $this.
2081+
# Draw an arc of that angle,
2082+
CircleArc($Radius, $Angle).
2083+
# then rotate by the angle.
2084+
Rotate($angle)
2085+
}
2086+
}
2087+
else {
2088+
# Otherwise, we are making multiple turtles
2089+
$nestedTurtles = [Ordered]@{}
2090+
# The idea is the same, but the implementation is more complicated
2091+
$heading = $this.Heading
2092+
if (-not $heading) { $heading = 0.0 }
2093+
for ($sliceNumber =0 ; $sliceNumber -lt $Slices.Length; $sliceNumber++) {
2094+
$Angle = $relativeSlices[$sliceNumber] * 360
2095+
$sliceName = "slice$sliceNumber"
2096+
# created a nested turtle at the midpoint
2097+
$nestedTurtles["slice$sliceNumber"] = turtle teleport $midX $midY
2098+
# with the current heading
2099+
$nestedTurtles["slice$sliceNumber"].Heading = $this.Heading
2100+
# and arc by the angle
2101+
$null = $nestedTurtles["slice$sliceNumber"].CircleArc($Radius, $Angle)
2102+
2103+
# If the slice was of a dictionary
2104+
if ($sliceObjects[$sliceName] -is [Collections.IDictionary])
2105+
{
2106+
# set any settable properties on the turtle
2107+
foreach ($key in $sliceObjects[$sliceName].Keys) {
2108+
# that exist in both the turtle and the dictionary
2109+
if ($nestedTurtles[$sliceName].psobject.properties[$key].SetterScript) {
2110+
$nestedTurtles[$sliceName].$key = $sliceObjects[$sliceName][$key]
2111+
}
2112+
}
2113+
}
2114+
# If the slice was not a string
2115+
elseif ($sliceObjects[$sliceName] -isnot [string])
2116+
{
2117+
# Set any settable properties on the turlte
2118+
foreach ($property in $sliceObjects[$sliceName].Keys) {
2119+
# that exist in both the turtle and the slice object.
2120+
if ($nestedTurtles[$sliceName].psobject.properties[$key].SetterScript) {
2121+
$nestedTurtles[$sliceName].$key = $sliceObjects[$sliceName][$key]
2122+
}
2123+
}
2124+
}
2125+
2126+
# Now rotate our own heading, even though we are not drawing anything.
2127+
$null = $this.Rotate($angle)
2128+
}
2129+
# and set our nested turtles.
2130+
$this.Turtles = $nestedTurtles
2131+
}
2132+
19472133
return $this
19482134
</Script>
19492135
</ScriptMethod>

0 commit comments

Comments
 (0)