Math.NET Numerics
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

187 lines
6.9 KiB

namespace Microsoft.FSharp.Plot
open System
open System.Drawing
open System.Windows.Forms
// Abstract objects that represent "plottable" items
type IPlot =
abstract BasePlot : IPlot // extend to array of IPlot (for compound plots)
// Control which can accept selected IPlot objects.
type IChart =
abstract Control : Control
abstract Accepts : IPlot -> bool
abstract Add : IPlot -> unit
abstract Context : MenuItem[]
// Each
type IChartFactory =
abstract Name : string
abstract Accepts : IPlot -> bool
abstract Create : unit -> IChart
// The window management functions for charts/plots.
module Interactive =
let menuItem str handler =
let item = new MenuItem(str:string)
item.Click.Add(fun _ -> handler())
item
// should be a property for dynamic load
let factories = ref [] : IChartFactory list ref
let addFactory f = factories := !factories @ [f]
// Frames are container Controls in which to add ChartControls.
// Focus is the current/last IChart - where to add next plots where possible.
// naive next frame
// let nextFrame() = let form = new Form(Visible=true,Title="F# Plot Window") in form :> Control
// tabbing next frame
// 1. tabControl
let mutable tabControl = null : TabControl
let ensureTabControl() =
if tabControl <> null && not tabControl.IsDisposed then
tabControl
else
let form = new Form(TopMost=true,Width=400,Height=400,Text="F# Plot Window")
let tab = new TabControl()
tabControl <- tab
form.Controls.Add(tab)
form.Show()
tab.Dock <- DockStyle.Fill
let deleteSelected _ = tab.SelectedTab.Dispose()
let deleteNonSelected _ = let keep = tab.SelectedTab
let pages = tab.Controls |> Seq.cast : TabPage seq
pages |> Seq.to_array |> Array.iter (fun page -> if page <> keep then page.Dispose())
tab.ContextMenu <- new ContextMenu [| menuItem "Delete selected tab" deleteSelected;
menuItem "Delete un-selected tab" deleteNonSelected;
|]
tab
type myTabPage(chart : IChart) =
inherit TabPage()
let mutable m_chart = chart
member this.Chart
with get() = m_chart
and set ch = m_chart <- ch
let mutable pageNumber = 0
let nextFrame (ch) =
let tab2 = ensureTabControl()
let page = new myTabPage(ch)
pageNumber <- pageNumber + 1
page.Text <- sprintf "P%d" pageNumber
let () = tab2.Controls.Add(page)
tab2.SelectTab(page)
(page :> Control)
//let mutable focus = ((new TextChartControl() :>IChart) : IChart) // dummy value
//do focus.Control.Dispose()
let setFocus x = () // focus <- x
let plot(pl:'a :> IPlot) =
let p = pl.BasePlot
match !factories |> List.tryFind (fun fac -> fac.Accepts p) with
| None -> printf "Sorry, not accepted by a registered charting engine\n"; failwith "unknown plot"
| Some fac -> let chart = fac.Create()
let frame = nextFrame(chart)
frame.Controls.Add(chart.Control)
chart.Control.Dock <- DockStyle.Fill
chart.Add p
let items =
[| new MenuItem("-");
menuItem "Delete" (fun _ -> frame.Dispose())
|]
frame.ContextMenu <- new ContextMenu(Array.append chart.Context items)
setFocus chart
(pl : 'a)
open System.Windows.Forms
let chart(ch : 'a :> IChart) =
let frame = nextFrame(ch)
frame.Controls.Add(ch.Control)
ch.Control.Dock <- DockStyle.Fill
let items =
[| new MenuItem("-");
menuItem "Delete" (fun _ -> frame.Dispose())
|]
frame.ContextMenu <- new ContextMenu(Array.append ch.Context items)
setFocus ch
(ch : 'a)
let multiplot(parray : IPlot array) =
let myTab = ensureTabControl()
for p in parray do
let tabPageList : myTabPage list = myTab.Controls |> Seq.cast |> Seq.to_list
let existingTab = tabPageList |> List.tryFind(fun c -> c.Chart.Accepts p)
match existingTab with
| Some(c) -> c.Chart.Add p
| _ -> plot p |> ignore; ()
let replot(p:'a :> IPlot) =
let myTab = ensureTabControl()
if myTab.TabCount > 0 then
let page = myTab.Controls.Item(myTab.SelectedIndex) :?> myTabPage
if page.Chart.Accepts p then
page.Chart.Add p
(p:'a)
else
plot p
else plot p
type MultiChartControl(tc : TableLayoutPanel) =
let table = tc
interface IChart with
override this.Control = table :> Control
override this.Accepts(x) = false // denies all
override this.Add(x:IPlot) = ()
override this.Context = [| |]
let subplot(parray : IPlot array) =
let calcRowsColumns len =
let rows = int (sqrt (float len) )
let cols = if (len % rows) > 0 then (len / rows) + 1
else len / rows
rows,cols
let r, c = calcRowsColumns parray.Length
let myTab = ensureTabControl()
let table = new TableLayoutPanel()
table.Dock <- DockStyle.Fill
table.RowCount <- r
table.ColumnCount <- c
let arrangeRowsCols (tbl : TableLayoutPanel)=
tbl.RowStyles.Clear()
tbl.ColumnStyles.Clear()
let rows = tbl.RowCount
let cols = tbl.ColumnCount
for i=0 to tbl.RowCount - 1 do
tbl.RowStyles.Add(new RowStyle(SizeType.Percent, float32 (100/rows))) |>ignore
for i=0 to tbl.ColumnCount - 1 do
tbl.ColumnStyles.Add(new ColumnStyle(SizeType.Percent , float32 (100 / cols))) |>ignore
arrangeRowsCols table
let multiChart = new MultiChartControl(table)
let frame = nextFrame(multiChart)
frame.Controls.Add table
Array.iter (fun p ->
match !factories |> List.tryFind (fun fac -> fac.Accepts p) with
| None -> printf "Sorry, %A not accepted by a registered charting engine\n" p
| Some fac -> let chart = fac.Create()
chart.Control.Dock <- DockStyle.Fill
chart.Add p
table.Controls.Add chart.Control
setFocus chart) parray