From e5304eacb34c5ca11f497151de4226540306c52c Mon Sep 17 00:00:00 2001 From: Mikhail Tikilyaynen Date: Sat, 26 Dec 2015 15:35:53 +0000 Subject: [PATCH 1/5] Exposed access to the underlying System.Windows.Forms.DataVisualization.Charting.Chart object via a "visitor"-esque member method ApplyToChart(...), in order to enable programmatic control over the chart form window (which is already accessible to the user manually via the Properties tab of the chart form). This enables us to use charting with the following example pattern: let inputData = [1;2;3] inputData |> Chart.Line |> fun c -> c.WithLegend() // add legend using the existing method |> fun c -> ( c, c.ShowChart() ) // create the chart form |> fun (c, _) -> (c, c.ApplyToChart( fun c -> c.ChartAreas.[0].CursorX.IsUserSelectionEnabled <- true ) ) // can now modify chart form using all of the available .NET Chart API by chaining lines like this one |> ignore // avoid displaying the chart twice --- src/FSharp.Charting.fs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/FSharp.Charting.fs b/src/FSharp.Charting.fs index 4f617a8..0c5ea27 100644 --- a/src/FSharp.Charting.fs +++ b/src/FSharp.Charting.fs @@ -1166,6 +1166,9 @@ namespace FSharp.Charting member internal x.Margin with get() = margin and set v = margin <- v member internal x.Name with get() = name and set v = name <- v + member x.ApplyToChart ( fn : Chart -> unit ) = + fn x.Chart + /// Ensure the chart has a Title member internal x.ForceTitle() = match title with From 9d1cbbcb236cfb36694aedd617e69014c5575160 Mon Sep 17 00:00:00 2001 From: mt99 Date: Wed, 30 Dec 2015 11:47:15 +0000 Subject: [PATCH 2/5] ApplyToChart() now returns the Chart object, enabling us to chain calls, like in the example below: inputData |> Chart.Line // do things necessary before chart is rendered |> fun c -> c.WithLegend( FontSize = 5.0 ) .WithStyling( Color = System.Drawing.Color.Red ) // create the chart form and render the chart |> fun c -> ( c, c.ShowChart() ) // do things that can only be done after the chart is rendered |> fun ( c, _ ) -> c.ApplyToChart( fun c -> c.ChartAreas.[0].CursorX.IsUserSelectionEnabled <- true ) .ApplyToChart( fun c -> c.ChartAreas.[0].CursorY.IsUserSelectionEnabled <- true ) |> ignore // avoid displaying the chart twice --- src/FSharp.Charting.fs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/FSharp.Charting.fs b/src/FSharp.Charting.fs index 0c5ea27..60d7205 100644 --- a/src/FSharp.Charting.fs +++ b/src/FSharp.Charting.fs @@ -1168,6 +1168,7 @@ namespace FSharp.Charting member x.ApplyToChart ( fn : Chart -> unit ) = fn x.Chart + x /// Ensure the chart has a Title member internal x.ForceTitle() = From 70e72b409da325babe8752aa86381a01311c39f0 Mon Sep 17 00:00:00 2001 From: mt99 Date: Wed, 17 Feb 2016 17:52:46 +0000 Subject: [PATCH 3/5] Implemented the "caching" of functions applid using ApplytoChart() until the point of drawing of the actual chart, as discussed in https://github.com/fslaborg/FSharp.Charting/pull/102#issuecomment-168001058. ApplyToChart() is now usable with the existing simple dot-notation. --- src/FSharp.Charting.fs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/FSharp.Charting.fs b/src/FSharp.Charting.fs index 60d7205..6a2974e 100644 --- a/src/FSharp.Charting.fs +++ b/src/FSharp.Charting.fs @@ -1145,6 +1145,7 @@ namespace FSharp.Charting let mutable data = ChartData.Values (NotifySeq.ignoreReset (NotifySeq.notifyOrOnce []), ChartValueType.Auto, "Item1", "Item2", "") let mutable margin = DefaultMarginForEachChart + let mutable customizationFunctions : (Chart -> unit) list = [] [] override x.GetHashCode() = 0 @@ -1165,9 +1166,10 @@ namespace FSharp.Charting member internal x.Chart with get() = chart.Value and set v = chart <- evalLazy v member internal x.Margin with get() = margin and set v = margin <- v member internal x.Name with get() = name and set v = name <- v + member internal x.CustomizationFunctions with get() = customizationFunctions member x.ApplyToChart ( fn : Chart -> unit ) = - fn x.Chart + customizationFunctions <- ( fn :: customizationFunctions ) x /// Ensure the chart has a Title @@ -3954,6 +3956,7 @@ namespace FSharp.Charting frm.Text <- ProvideTitle ch frm.Controls.Add(ctl) frm.Show() + ch.CustomizationFunctions |> List.map (fun fn -> fn ch.Chart) |> ignore ctl.Focus() |> ignore frm From a1bd7d60618b4c0fcf933872a01ed66ca8e536dc Mon Sep 17 00:00:00 2001 From: mt99 Date: Wed, 17 Feb 2016 19:15:51 +0000 Subject: [PATCH 4/5] Added ApplyToChart to the documentation. --- docs/content/FurtherSamples.fsx | 15 ++++++++++++++- docs/content/fsharpcharting.md | 2 +- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/docs/content/FurtherSamples.fsx b/docs/content/FurtherSamples.fsx index 9a887d3..564d085 100644 --- a/docs/content/FurtherSamples.fsx +++ b/docs/content/FurtherSamples.fsx @@ -188,4 +188,17 @@ Chart.Line(data,Name="SomeData").WithDataPointLabels(PointToolTip="Hello, I am # Chart.Stock(timeHighLowOpenClose) Chart.ThreeLineBreak(data,Name="SomeData").WithDataPointLabels(PointToolTip="Hello, I am #SERIESNAME") -Chart.Histogram([for x in 1 .. 100 -> rand()*10.],LowerBound=0.,UpperBound=10.,Intervals=10.) \ No newline at end of file +Chart.Histogram([for x in 1 .. 100 -> rand()*10.],LowerBound=0.,UpperBound=10.,Intervals=10.) + +// Example of .ApplyToChart() used to alter the settings on the window chart and to access the chart child objects. +// This can normally be done manually, in the chart property grid (right click the chart, then "Show Property Grid"). +// This is useful when you want to try out carious settings first. But once you know what you want, .ApplyToChart() +// allows programmatic access to the window properties. The two examples below are: IsUserSelectionEnabled essentially +// allows zooming in and out along the given axes, and the longer fiddly example below does the same work as .WithDataPointLabels() +// but across all series objects. +[ Chart.Column(data); + Chart.Column(data2) |> Chart.WithSeries.AxisType( YAxisType = Windows.Forms.DataVisualization.Charting.AxisType.Secondary ) ] +|> Chart.Combine +|> fun c -> c.WithLegend() + .ApplyToChart( fun c -> c.ChartAreas.[0].CursorX.IsUserSelectionEnabled <- true ) + .ApplyToChart( fun c -> let _ = [0 .. c.Series.Count-1] |> List.map ( fun s -> c.Series.[ s ].ToolTip <- "#SERIESNAME (#VALX, #VAL{0:00000})" ) in () ) \ No newline at end of file diff --git a/docs/content/fsharpcharting.md b/docs/content/fsharpcharting.md index 64eff13..95098f9 100644 --- a/docs/content/fsharpcharting.md +++ b/docs/content/fsharpcharting.md @@ -41,7 +41,7 @@ The following methods are used to style chart objects: * `WithTitle` * `WithXAxis` * `WithYAxis` - + * `ApplyToChart` Please [contribute](contributing.html) more documentation on the following topics: From 9ecca19a986a1588bcc4da88386bc9615570ce21 Mon Sep 17 00:00:00 2001 From: Mikhail Tikilyaynen Date: Thu, 14 Apr 2016 23:02:16 +0100 Subject: [PATCH 5/5] CustomizationFunctions need to be applied in the order they were added, if only for the sake of clarity. This was noticed by @simra. --- src/FSharp.Charting.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FSharp.Charting.fs b/src/FSharp.Charting.fs index 6a2974e..59e05cd 100644 --- a/src/FSharp.Charting.fs +++ b/src/FSharp.Charting.fs @@ -3956,7 +3956,7 @@ namespace FSharp.Charting frm.Text <- ProvideTitle ch frm.Controls.Add(ctl) frm.Show() - ch.CustomizationFunctions |> List.map (fun fn -> fn ch.Chart) |> ignore + ch.CustomizationFunctions |> List.rev |> List.map (fun fn -> fn ch.Chart) |> ignore ctl.Focus() |> ignore frm