3 people like it.
Like the snippet!
Gantt Chart Visualization
Shows how to generate a Gantt chart to visualize a schedule.
Note: Requires BinPacking.fs found here: http://fssnip.net/hG
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
|
#load "BinPacking.fs"
#r "System.Windows.Forms.DataVisualization"
[<Measure>] type m //minutes
[<Measure>] type ft //feet
type Machine = {Id:string; ProcessingRate:int<ft/m>}
type Task = {Id:string; Demand:int<ft>}
let rnd = System.Random()
let toRate (x:int) = x*1<ft/m>
let toFeet (x:int) = x*1<ft>
let machines = [for i in 1..5 -> {Id=sprintf "M %d" i; ProcessingRate=rnd.Next(5, 20) |> toRate}]
let tasks = [for i in 1..30 -> {Id=sprintf "J %d" i; Demand=rnd.Next(100,200) |> toFeet }]
open BinPacking
let timeHorizon = 60<m>
let bins = machines |> List.map (fun m -> {Id=m.Id; Size=m.ProcessingRate * timeHorizon |> int; Data=m})
let items = tasks |> List.map (fun j -> {Size=j.Demand |> int; Data=j})
let sortedItems = items |> List.sortBy (fun i -> -i.Size) //sort in decreasing order
let schedule,_,_ = packBestFit bins sortedItems //generate a schedule using best fit heuristics
//let schedule,_,_ = packWorstFit bins sortedItems //generate a schedule using worst fit heuristics
//vizualization
//visualization helper type
type Job = {TaskId:string; MachineId:string; Start:int; End:int; Rate:int }
//list of jobs created from the schedule
let plan =
schedule
|> Map.toSeq
|> Seq.collect (fun (machine,tasks) ->
let _,jobs =
((0,[]),tasks) ||> List.fold (fun (offset,acc) item ->
let taskMinutes = item.Data.Demand / machine.Data.ProcessingRate
let job =
{
TaskId=item.Data.Id
MachineId = machine.Id
Start = offset
End = offset + (taskMinutes |> int)
Rate = machine.Data.ProcessingRate |> int
}
job.End,job::acc)
jobs
)
|> Seq.toList
open System
open System.Windows.Forms
open System.Windows.Forms.DataVisualization.Charting
open System.Drawing
//creates chart
let visualizePlan (plan:Job list) =
//set up the chart window, plot area, titles, etc.
let titleFont = new Font("Arial Black", 12.f, FontStyle.Bold)
let chart = new Chart(Dock = DockStyle.Fill)
chart.Titles.Add ("Job Schedule") |> fun t -> t.Font <- titleFont
chart.BorderSkin.SkinStyle <- BorderSkinStyle.Emboss
chart.BorderlineWidth <- 2
chart.BorderDashStyle <- ChartDashStyle.Solid
chart.BorderlineColor <- Color.DarkBlue
let area = new ChartArea("Main")
area.AxisY.Title <- "Minutes (offset)"
area.AxisX.Title <- "Machines"
area.AxisX.TitleFont <- titleFont
area.AxisY.TitleFont <- titleFont
area.BackColor <- Color.AntiqueWhite
area.BackSecondaryColor <- Color.Yellow
area.BorderColor <- Color.Blue
area.BorderWidth <- 1
area.ShadowOffset <- 5
// area.Area3DStyle.Enable3D <- true
chart.ChartAreas.Add(area)
let mainForm = new Form(Visible = true, TopMost = true, Width = 700, Height = 500)
mainForm.Controls.Add(chart)
//get the unique list of machines in the plan
let machines = plan |> List.map (fun p -> p.MachineId,p.Rate) |> Seq.distinct |> Map.ofSeq
//color each job according to machine rate
let rates = machines |> Map.toList |> List.map(fun (_,r) -> r)
let rMax,rMin = List.max rates |> float, List.min rates |> float
let mColors =
machines |> Map.map (fun m rate ->
let greenness = if rMax=rMin then 0 else 190 - int( ((float rate - rMin) / (rMax - rMin)) * 190.)
Color.FromArgb(210,255, greenness, 50))
let series = new Series("Jobs", ChartType = SeriesChartType.RangeBar, BorderWidth = 4)
chart.Series.Add(series)
//using the list of machines, fill in the data series points
machines
|> Map.toSeq
|> Seq.iteri (fun i (mchn, _) ->
plan
|> List.filter (fun p -> p.MachineId = mchn)
|> List.iter (fun job ->
let idx = series.Points.AddXY(i, job.Start, job.End)
//set other visualization attributes of the point just added
let pt = series.Points.[idx]
pt.Color <- mColors.[mchn]
pt.AxisLabel <- job.MachineId
pt.Label <- job.TaskId
pt.ToolTip <- sprintf "%s, Time: %dm, M.Rate=%d" job.TaskId (job.End-job.Start) job.Rate
pt.LabelForeColor <- Color.Gray
pt.LabelBackColor <- Color.AntiqueWhite
pt.BorderWidth <- 2
pt.BorderColor <- Color.AntiqueWhite
)
)
mainForm
visualizePlan plan
|
Multiple items
type MeasureAttribute =
inherit Attribute
new : unit -> MeasureAttribute
Full name: Microsoft.FSharp.Core.MeasureAttribute
--------------------
new : unit -> MeasureAttribute
[<Measure>]
type m
Full name: Script.m
[<Measure>]
type ft
Full name: Script.ft
type Machine =
{Id: string;
ProcessingRate: int<ft/m>;}
Full name: Script.Machine
Machine.Id: string
Multiple items
val string : value:'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = System.String
Full name: Microsoft.FSharp.Core.string
Machine.ProcessingRate: int<ft/m>
Multiple items
val int : value:'T -> int (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.int
--------------------
type int = int32
Full name: Microsoft.FSharp.Core.int
--------------------
type int<'Measure> = int
Full name: Microsoft.FSharp.Core.int<_>
type Task =
{Id: string;
Demand: int<ft>;}
Full name: Script.Task
Task.Id: string
Task.Demand: int<ft>
val rnd : System.Random
Full name: Script.rnd
namespace System
Multiple items
type Random =
new : unit -> Random + 1 overload
member Next : unit -> int + 2 overloads
member NextBytes : buffer:byte[] -> unit
member NextDouble : unit -> float
Full name: System.Random
--------------------
System.Random() : unit
System.Random(Seed: int) : unit
val toRate : x:int -> int<ft/m>
Full name: Script.toRate
val x : int
val toFeet : x:int -> int<ft>
Full name: Script.toFeet
val machines : Machine list
Full name: Script.machines
val i : int
val sprintf : format:Printf.StringFormat<'T> -> 'T
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
System.Random.Next() : int
System.Random.Next(maxValue: int) : int
System.Random.Next(minValue: int, maxValue: int) : int
val tasks : Task list
Full name: Script.tasks
val timeHorizon : int<m>
Full name: Script.timeHorizon
val bins : obj list
Full name: Script.bins
Multiple items
module List
from Microsoft.FSharp.Collections
--------------------
type List<'T> =
| ( [] )
| ( :: ) of Head: 'T * Tail: 'T list
interface IEnumerable
interface IEnumerable<'T>
member Head : 'T
member IsEmpty : bool
member Item : index:int -> 'T with get
member Length : int
member Tail : 'T list
static member Cons : head:'T * tail:'T list -> 'T list
static member Empty : 'T list
Full name: Microsoft.FSharp.Collections.List<_>
val map : mapping:('T -> 'U) -> list:'T list -> 'U list
Full name: Microsoft.FSharp.Collections.List.map
val m : Machine
Multiple items
val m : Machine
--------------------
[<Measure>]
type m
Full name: Script.m
namespace Microsoft.FSharp.Data
val items : obj list
Full name: Script.items
val j : Task
val sortedItems : obj list
Full name: Script.sortedItems
val sortBy : projection:('T -> 'Key) -> list:'T list -> 'T list (requires comparison)
Full name: Microsoft.FSharp.Collections.List.sortBy
val i : obj
val schedule : Map<Task,obj list>
Full name: Script.schedule
type Job =
{TaskId: string;
MachineId: string;
Start: int;
End: int;
Rate: int;}
Full name: Script.Job
Job.TaskId: string
Job.MachineId: string
Job.Start: int
Job.End: int
Job.Rate: int
val plan : Job list
Full name: Script.plan
Multiple items
module Map
from Microsoft.FSharp.Collections
--------------------
type Map<'Key,'Value (requires comparison)> =
interface IEnumerable
interface IComparable
interface IEnumerable<KeyValuePair<'Key,'Value>>
interface ICollection<KeyValuePair<'Key,'Value>>
interface IDictionary<'Key,'Value>
new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
member Add : key:'Key * value:'Value -> Map<'Key,'Value>
member ContainsKey : key:'Key -> bool
override Equals : obj -> bool
member Remove : key:'Key -> Map<'Key,'Value>
...
Full name: Microsoft.FSharp.Collections.Map<_,_>
--------------------
new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
val toSeq : table:Map<'Key,'T> -> seq<'Key * 'T> (requires comparison)
Full name: Microsoft.FSharp.Collections.Map.toSeq
module Seq
from Microsoft.FSharp.Collections
val collect : mapping:('T -> #seq<'U>) -> source:seq<'T> -> seq<'U>
Full name: Microsoft.FSharp.Collections.Seq.collect
val machine : Task
val tasks : obj list
val jobs : Job list
val fold : folder:('State -> 'T -> 'State) -> state:'State -> list:'T list -> 'State
Full name: Microsoft.FSharp.Collections.List.fold
val offset : int
val acc : Job list
val item : obj
val taskMinutes : int
val job : Job
val toList : source:seq<'T> -> 'T list
Full name: Microsoft.FSharp.Collections.Seq.toList
namespace System.Windows
namespace System.Windows.Forms
namespace System.Windows.Forms.DataVisualization
namespace System.Windows.Forms.DataVisualization.Charting
namespace System.Drawing
val visualizePlan : plan:Job list -> Form
Full name: Script.visualizePlan
val plan : Job list
type 'T list = List<'T>
Full name: Microsoft.FSharp.Collections.list<_>
val titleFont : Font
Multiple items
type Font =
inherit MarshalByRefObject
new : prototype:Font * newStyle:FontStyle -> Font + 12 overloads
member Bold : bool
member Clone : unit -> obj
member Dispose : unit -> unit
member Equals : obj:obj -> bool
member FontFamily : FontFamily
member GdiCharSet : byte
member GdiVerticalFont : bool
member GetHashCode : unit -> int
member GetHeight : unit -> float32 + 2 overloads
...
Full name: System.Drawing.Font
--------------------
Font(prototype: Font, newStyle: FontStyle) : unit
(+0 other overloads)
Font(family: FontFamily, emSize: float32) : unit
(+0 other overloads)
Font(familyName: string, emSize: float32) : unit
(+0 other overloads)
Font(family: FontFamily, emSize: float32, style: FontStyle) : unit
(+0 other overloads)
Font(family: FontFamily, emSize: float32, unit: GraphicsUnit) : unit
(+0 other overloads)
Font(familyName: string, emSize: float32, style: FontStyle) : unit
(+0 other overloads)
Font(familyName: string, emSize: float32, unit: GraphicsUnit) : unit
(+0 other overloads)
Font(family: FontFamily, emSize: float32, style: FontStyle, unit: GraphicsUnit) : unit
(+0 other overloads)
Font(familyName: string, emSize: float32, style: FontStyle, unit: GraphicsUnit) : unit
(+0 other overloads)
Font(family: FontFamily, emSize: float32, style: FontStyle, unit: GraphicsUnit, gdiCharSet: byte) : unit
(+0 other overloads)
type FontStyle =
| Regular = 0
| Bold = 1
| Italic = 2
| Underline = 4
| Strikeout = 8
Full name: System.Drawing.FontStyle
field FontStyle.Bold = 1
val chart : Chart
Multiple items
type Chart =
inherit Control
new : unit -> Chart
member AlignDataPointsByAxisLabel : unit -> unit + 3 overloads
member Annotations : AnnotationCollection
member AntiAliasing : AntiAliasingStyles with get, set
member ApplyPaletteColors : unit -> unit
member BackColor : Color with get, set
member BackGradientStyle : GradientStyle with get, set
member BackHatchStyle : ChartHatchStyle with get, set
member BackImage : string with get, set
member BackImageAlignment : ChartImageAlignmentStyle with get, set
...
Full name: System.Windows.Forms.DataVisualization.Charting.Chart
--------------------
Chart() : unit
type DockStyle =
| None = 0
| Top = 1
| Bottom = 2
| Left = 3
| Right = 4
| Fill = 5
Full name: System.Windows.Forms.DockStyle
field DockStyle.Fill = 5
property Chart.Titles: TitleCollection
Collections.ObjectModel.Collection.Add(item: Title) : unit
TitleCollection.Add(name: string) : Title
val t : Title
property Title.Font: Font
property Chart.BorderSkin: BorderSkin
property BorderSkin.SkinStyle: BorderSkinStyle
type BorderSkinStyle =
| None = 0
| Emboss = 1
| Raised = 2
| Sunken = 3
| FrameThin1 = 4
| FrameThin2 = 5
| FrameThin3 = 6
| FrameThin4 = 7
| FrameThin5 = 8
| FrameThin6 = 9
...
Full name: System.Windows.Forms.DataVisualization.Charting.BorderSkinStyle
field BorderSkinStyle.Emboss = 1
property Chart.BorderlineWidth: int
property Chart.BorderDashStyle: ChartDashStyle
type ChartDashStyle =
| NotSet = 0
| Dash = 1
| DashDot = 2
| DashDotDot = 3
| Dot = 4
| Solid = 5
Full name: System.Windows.Forms.DataVisualization.Charting.ChartDashStyle
field ChartDashStyle.Solid = 5
property Chart.BorderlineColor: Color
type Color =
struct
member A : byte
member B : byte
member Equals : obj:obj -> bool
member G : byte
member GetBrightness : unit -> float32
member GetHashCode : unit -> int
member GetHue : unit -> float32
member GetSaturation : unit -> float32
member IsEmpty : bool
member IsKnownColor : bool
...
end
Full name: System.Drawing.Color
property Color.DarkBlue: Color
val area : ChartArea
Multiple items
type ChartArea =
inherit ChartNamedElement
new : unit -> ChartArea + 1 overload
member AlignWithChartArea : string with get, set
member AlignmentOrientation : AreaAlignmentOrientations with get, set
member AlignmentStyle : AreaAlignmentStyles with get, set
member Area3DStyle : ChartArea3DStyle with get, set
member Axes : Axis[] with get, set
member AxisX : Axis with get, set
member AxisX2 : Axis with get, set
member AxisY : Axis with get, set
member AxisY2 : Axis with get, set
...
Full name: System.Windows.Forms.DataVisualization.Charting.ChartArea
--------------------
ChartArea() : unit
ChartArea(name: string) : unit
property ChartArea.AxisY: Axis
property Axis.Title: string
property ChartArea.AxisX: Axis
property Axis.TitleFont: Font
property ChartArea.BackColor: Color
property Color.AntiqueWhite: Color
property ChartArea.BackSecondaryColor: Color
property Color.Yellow: Color
property ChartArea.BorderColor: Color
property Color.Blue: Color
property ChartArea.BorderWidth: int
property ChartArea.ShadowOffset: int
property Chart.ChartAreas: ChartAreaCollection
Collections.ObjectModel.Collection.Add(item: ChartArea) : unit
ChartAreaCollection.Add(name: string) : ChartArea
val mainForm : Form
Multiple items
type Form =
inherit ContainerControl
new : unit -> Form
member AcceptButton : IButtonControl with get, set
member Activate : unit -> unit
member ActiveMdiChild : Form
member AddOwnedForm : ownedForm:Form -> unit
member AllowTransparency : bool with get, set
member AutoScale : bool with get, set
member AutoScaleBaseSize : Size with get, set
member AutoScroll : bool with get, set
member AutoSize : bool with get, set
...
nested type ControlCollection
Full name: System.Windows.Forms.Form
--------------------
Form() : unit
property Control.Controls: Control.ControlCollection
Control.ControlCollection.Add(value: Control) : unit
val machines : Map<string,int>
val p : Job
val distinct : source:seq<'T> -> seq<'T> (requires equality)
Full name: Microsoft.FSharp.Collections.Seq.distinct
val ofSeq : elements:seq<'Key * 'T> -> Map<'Key,'T> (requires comparison)
Full name: Microsoft.FSharp.Collections.Map.ofSeq
val rates : int list
val toList : table:Map<'Key,'T> -> ('Key * 'T) list (requires comparison)
Full name: Microsoft.FSharp.Collections.Map.toList
val r : int
val rMax : float
val rMin : float
val max : list:'T list -> 'T (requires comparison)
Full name: Microsoft.FSharp.Collections.List.max
Multiple items
val float : value:'T -> float (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.float
--------------------
type float = Double
Full name: Microsoft.FSharp.Core.float
--------------------
type float<'Measure> = float
Full name: Microsoft.FSharp.Core.float<_>
val min : list:'T list -> 'T (requires comparison)
Full name: Microsoft.FSharp.Collections.List.min
val mColors : Map<string,Color>
val map : mapping:('Key -> 'T -> 'U) -> table:Map<'Key,'T> -> Map<'Key,'U> (requires comparison)
Full name: Microsoft.FSharp.Collections.Map.map
val m : string
val rate : int
val greenness : int
Color.FromArgb(argb: int) : Color
Color.FromArgb(alpha: int, baseColor: Color) : Color
Color.FromArgb(red: int, green: int, blue: int) : Color
Color.FromArgb(alpha: int, red: int, green: int, blue: int) : Color
val series : Series
Multiple items
type Series =
inherit DataPointCustomProperties
new : unit -> Series + 2 overloads
member AxisLabel : string with get, set
member ChartArea : string with get, set
member ChartType : SeriesChartType with get, set
member ChartTypeName : string with get, set
member EmptyPointStyle : DataPointCustomProperties with get, set
member Enabled : bool with get, set
member IsXValueIndexed : bool with get, set
member Legend : string with get, set
member MarkerStep : int with get, set
...
Full name: System.Windows.Forms.DataVisualization.Charting.Series
--------------------
Series() : unit
Series(name: string) : unit
Series(name: string, yValues: int) : unit
type SeriesChartType =
| Point = 0
| FastPoint = 1
| Bubble = 2
| Line = 3
| Spline = 4
| StepLine = 5
| FastLine = 6
| Bar = 7
| StackedBar = 8
| StackedBar100 = 9
...
Full name: System.Windows.Forms.DataVisualization.Charting.SeriesChartType
field SeriesChartType.RangeBar = 23
property Chart.Series: SeriesCollection
Collections.ObjectModel.Collection.Add(item: Series) : unit
SeriesCollection.Add(name: string) : Series
val iteri : action:(int -> 'T -> unit) -> source:seq<'T> -> unit
Full name: Microsoft.FSharp.Collections.Seq.iteri
val mchn : string
val filter : predicate:('T -> bool) -> list:'T list -> 'T list
Full name: Microsoft.FSharp.Collections.List.filter
val iter : action:('T -> unit) -> list:'T list -> unit
Full name: Microsoft.FSharp.Collections.List.iter
val idx : int
property Series.Points: DataPointCollection
DataPointCollection.AddXY(xValue: obj, [<ParamArray>] yValue: obj []) : int
DataPointCollection.AddXY(xValue: float, yValue: float) : int
val pt : DataPoint
property DataPointCustomProperties.Color: Color
property DataPointCustomProperties.AxisLabel: string
property DataPointCustomProperties.Label: string
property DataPointCustomProperties.ToolTip: string
property DataPointCustomProperties.LabelForeColor: Color
property Color.Gray: Color
property DataPointCustomProperties.LabelBackColor: Color
property DataPointCustomProperties.BorderWidth: int
property DataPointCustomProperties.BorderColor: Color
More information