3 people like it.

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
Raw view Test code New version

More information

Link:http://fssnip.net/hK
Posted:11 years ago
Author:Faisal Waris
Tags: visualization