Skip to content

Commit af4a5a8

Browse files
committed
Add subplots
1 parent c62ea0d commit af4a5a8

File tree

5 files changed

+142
-6
lines changed

5 files changed

+142
-6
lines changed

docs/content/errorbars.fsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,5 @@ Chart.Line([1; 2; 3; 4],[90; 110; 190; 120],Name="anchor 2")
5353

5454
// Simple Subplot
5555

56+
57+

docs/content/multiple-charts.fsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,14 @@ Chart.Line([1; 2; 3; 4],[90; 110; 190; 120],Name="anchor 2")
5252

5353

5454
// Simple Subplot
55+
[for i=1 to 8 do yield (Chart.Scatter ([1; 2; 3; 4],[12; 9; 15; 12],StyleParam.Mode.Lines_Markers) |> Chart.withY_AxisStyle("y-title") )]
56+
57+
|> Chart.stackHorizontal(Col=2,Space=0.15)
58+
|> Chart.Combine
59+
|> Chart.Show
60+
61+
//|> Chart.withX_AxisStyle("Title1")
62+
//|> Chart.withX_AxisStyle(sprintf "Title%i" 3,Id=3)
63+
//|> Chart.Show
64+
5565

src/FSharp.Plotly/ChartExtensions.fs

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ module ChartExtensions =
1313
open Trace
1414
//open StyleParam
1515

16+
//open ChartExtensions
17+
18+
//open StyleParam
19+
1620
/// Provides a set of static methods for creating charts.
1721
type Chart with
1822

@@ -122,7 +126,7 @@ module ChartExtensions =
122126
let layout =
123127
let id = if Id.IsSome then StyleParam.AxisId.X Id.Value else StyleParam.AxisId.X 1
124128
GenericChart.getLayout ch
125-
|> Layout.AddLinearAxis(id,axis=xAxis)
129+
|> Layout.UpdateLinearAxisById(id,axis=xAxis)
126130
GenericChart.setLayout layout ch
127131
| true ->
128132
let layout =
@@ -157,7 +161,7 @@ module ChartExtensions =
157161
let layout =
158162
let id = if Id.IsSome then StyleParam.AxisId.Y Id.Value else StyleParam.AxisId.Y 1
159163
GenericChart.getLayout ch
160-
|> Layout.AddLinearAxis(id,axis=yAxis)
164+
|> Layout.UpdateLinearAxisById(id,axis=yAxis)
161165
GenericChart.setLayout layout ch
162166
| true ->
163167
let layout =
@@ -275,8 +279,7 @@ module ChartExtensions =
275279
let margin =
276280
Margin.init ( ?Left=Left,?Right=Right,?Top=Top,?Bottom=Bottom,?Pad=Pad,?Autoexpand=Autoexpand )
277281
Chart.withMargin(margin)
278-
279-
282+
280283

281284
// TODO: Include withLegend & withLegendStyle
282285

@@ -304,6 +307,70 @@ module ChartExtensions =
304307
static member Combine(gCharts:seq<GenericChart>) =
305308
GenericChart.combine gCharts
306309

310+
311+
/// Create a combined chart with the given charts merged
312+
static member Stack (?ColCount:int, ?Space) =
313+
(fun (charts:#seq<GenericChart>) ->
314+
315+
let col = defaultArg ColCount 2
316+
let len = charts |> Seq.length
317+
let colWidth = 1. / float col
318+
let rowWidth =
319+
let tmp = float len / float col |> ceil
320+
1. / tmp
321+
let space =
322+
let s = defaultArg Space 0.05
323+
if s < 0. || s > 1. then
324+
printfn "Space should be between 0.0 - 1.0. Automaticaly set to default (0.05)"
325+
0.05
326+
else
327+
s
328+
329+
charts
330+
|> Seq.mapi (fun i ch ->
331+
let colI,rowI,index = (i%col+1), (i/col+1),(i+1)
332+
let xdomain = (colWidth * float (colI-1), (colWidth * float colI) - space )
333+
let ydomain = (1. - ((rowWidth * float rowI) - space ),1. - (rowWidth * float (rowI-1)))
334+
let xaxis,yaxis,layout =
335+
let layout = GenericChart.getLayout ch
336+
let xName, yName = StyleParam.AxisId.X 1 |> StyleParam.AxisId.toString, StyleParam.AxisId.Y 1 |> StyleParam.AxisId.toString
337+
match (layout.TryGetTypedValue<Axis.LinearAxis> xName),(layout.TryGetTypedValue<Axis.LinearAxis> yName) with
338+
| Some x, Some y ->
339+
// remove axis
340+
DynObj.remove layout xName
341+
DynObj.remove layout yName
342+
343+
x |> Axis.LinearAxis.style(Anchor=StyleParam.AxisAnchorId.Y index,Domain=StyleParam.Range.MinMax xdomain),
344+
y |> Axis.LinearAxis.style(Anchor=StyleParam.AxisAnchorId.X index,Domain=StyleParam.Range.MinMax ydomain),
345+
layout
346+
| Some x, None ->
347+
// remove x - axis
348+
DynObj.remove layout xName
349+
x |> Axis.LinearAxis.style(Anchor=StyleParam.AxisAnchorId.Y index,Domain=StyleParam.Range.MinMax xdomain),
350+
Axis.LinearAxis.init(Anchor=StyleParam.AxisAnchorId.X index,Domain=StyleParam.Range.MinMax ydomain),
351+
layout
352+
| None, Some y ->
353+
// remove y - axis
354+
DynObj.remove layout yName
355+
Axis.LinearAxis.init(Anchor=StyleParam.AxisAnchorId.Y index,Domain=StyleParam.Range.MinMax xdomain),
356+
y |> Axis.LinearAxis.style(Anchor=StyleParam.AxisAnchorId.X index,Domain=StyleParam.Range.MinMax ydomain),
357+
layout
358+
| None, None ->
359+
Axis.LinearAxis.init(Anchor=StyleParam.AxisAnchorId.Y index,Domain=StyleParam.Range.MinMax xdomain),
360+
Axis.LinearAxis.init(Anchor=StyleParam.AxisAnchorId.X index,Domain=StyleParam.Range.MinMax ydomain),
361+
layout
362+
363+
ch
364+
|> GenericChart.setLayout layout
365+
|> Chart.withAxisAnchor(X=index,Y=index)
366+
|> Chart.withX_Axis(xaxis,index)
367+
|> Chart.withY_Axis(yaxis,index)
368+
)
369+
370+
|> Chart.Combine
371+
)
372+
373+
307374
/// Save chart as html single page
308375
static member SaveHtmlAs pathName (ch:GenericChart,?Verbose) =
309376
let html = GenericChart.toEmbeddedHTML ch

src/FSharp.Plotly/DynamicObj.fs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,17 @@ module ReflectionHelper =
9999
tryUpdatePropertyValue o expr f |> ignore
100100

101101

102+
/// Removes property
103+
let removeProperty (o:obj) (propName:string) =
104+
match tryGetPropertyInfo o propName with
105+
| Some property ->
106+
try
107+
property.SetValue(o, null, null)
108+
true
109+
with
110+
| :? System.ArgumentException -> false
111+
| :? System.NullReferenceException -> false
112+
| None -> false
102113

103114

104115

@@ -118,6 +129,17 @@ type DynamicObj internal (dict:Dictionary<string, obj>) =
118129
| true,value -> Some value
119130
// Next check for Public properties via Reflection
120131
| _ -> ReflectionHelper.tryGetPropertyValue this name
132+
133+
134+
/// Gets property value
135+
member this.TryGetTypedValue<'a> name =
136+
match (this.TryGetValue name) with
137+
| None -> None
138+
| Some o ->
139+
match o with
140+
| :? 'a -> o :?> 'a |> Some
141+
| _ -> None
142+
121143

122144
/// Sets property value, creating a new property if none exists
123145
member this.SetValue (name,value) = // private
@@ -142,6 +164,12 @@ type DynamicObj internal (dict:Dictionary<string, obj>) =
142164
| true,_ -> properties.[name] <- value
143165
| _ -> properties.Add(name,value)
144166

167+
member this.Remove name =
168+
match ReflectionHelper.removeProperty this name with
169+
| true -> true
170+
// Maybe in map
171+
| false -> properties.Remove(name)
172+
145173

146174
override this.TryGetMember(binder:GetMemberBinder,result:obj byref ) =
147175
match this.TryGetValue binder.Name with
@@ -177,6 +205,8 @@ type DynamicObj internal (dict:Dictionary<string, obj>) =
177205
static member GetValue (lookup:DynamicObj,name) =
178206
lookup.TryGetValue(name).Value
179207

208+
static member Remove (lookup:DynamicObj,name) =
209+
lookup.Remove(name)
180210

181211

182212
// ###############################
@@ -207,7 +237,7 @@ module DynObj =
207237
new DynamicObj(dict)
208238

209239

210-
// /// Merges two DynamicObj (Warning: In case of dublicate property names the second member override the first)
240+
//
211241
// let rec merge (first:#DynamicObj) (second:#DynamicObj) =
212242
// let dict = new Dictionary<string, obj>()
213243

@@ -225,8 +255,11 @@ module DynObj =
225255
// new DynamicObj(dict)
226256

227257
//let rec combine<'t when 't :> DynamicObj > (first:'t) (second:'t) =
258+
259+
260+
/// Merges two DynamicObj (Warning: In case of dublicate property names the second member override the first)
228261
let rec combine (first:DynamicObj) (second:DynamicObj) =
229-
printfn "Type %A" (first.GetType())
262+
//printfn "Type %A" (first.GetType())
230263
/// Consider deep-copy of first
231264
for kv in (second.GetProperties true) do
232265
match kv.Value with
@@ -259,3 +292,9 @@ module DynObj =
259292
match dyn.TryGetMember name with
260293
| true,value -> Some value
261294
| _ -> None
295+
296+
let remove (dyn:DynamicObj) propName =
297+
DynamicObj.Remove (dyn, propName) |> ignore
298+
299+
300+

src/FSharp.Plotly/Layout.fs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,4 +255,22 @@ type Layout() =
255255
layout
256256
)
257257

258+
// Updates the style of current axis with given AxisId
259+
static member UpdateLinearAxisById
260+
(
261+
id : StyleParam.AxisId,
262+
axis : Axis.LinearAxis
263+
) =
264+
(fun (layout:Layout) ->
265+
266+
let axis' =
267+
match layout.TryGetValue (StyleParam.AxisId.toString id) with
268+
| Some a -> DynObj.combine (unbox a) axis
269+
| None -> axis :> DynamicObj
270+
271+
axis' |> DynObj.setValue layout (StyleParam.AxisId.toString id)
272+
273+
layout
274+
)
275+
258276

0 commit comments

Comments
 (0)