Skip to content

Commit 1864341

Browse files
authored
Merge pull request #41 from muehlhaus/GridChart
Refactor Chart.Stack
2 parents 735e6bb + 0a66156 commit 1864341

File tree

9 files changed

+600
-8
lines changed

9 files changed

+600
-8
lines changed

Diff for: docsrc/tools/generate.fsx

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ let rec copyRecursive dir1 dir2 =
3333
copyRecursive subdir1 subdir2
3434
for file in Directory.EnumerateFiles dir1 do
3535
File.Copy(file, file.Replace(dir1, dir2), true)
36+
3637
// Web site location for the generated documentation
3738
let website = "https://muehlhaus.github.io/FSharp.Plotly/"
3839

Diff for: src/FSharp.Plotly.WPF/AssemblyInfo.fs

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ open System.Reflection
55
[<assembly: AssemblyTitleAttribute("FSharp.Plotly.WPF")>]
66
[<assembly: AssemblyProductAttribute("FSharp.Plotly")>]
77
[<assembly: AssemblyDescriptionAttribute("A F# interactive charting library using plotly.js")>]
8-
[<assembly: AssemblyVersionAttribute("1.2.2")>]
9-
[<assembly: AssemblyFileVersionAttribute("1.2.2")>]
8+
[<assembly: AssemblyVersionAttribute("1.2.3")>]
9+
[<assembly: AssemblyFileVersionAttribute("1.2.3")>]
1010
do ()
1111

1212
module internal AssemblyVersionInformation =
1313
let [<Literal>] AssemblyTitle = "FSharp.Plotly.WPF"
1414
let [<Literal>] AssemblyProduct = "FSharp.Plotly"
1515
let [<Literal>] AssemblyDescription = "A F# interactive charting library using plotly.js"
16-
let [<Literal>] AssemblyVersion = "1.2.2"
17-
let [<Literal>] AssemblyFileVersion = "1.2.2"
16+
let [<Literal>] AssemblyVersion = "1.2.3"
17+
let [<Literal>] AssemblyFileVersion = "1.2.3"

Diff for: src/FSharp.Plotly/AssemblyInfo.fs

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ open System.Reflection
55
[<assembly: AssemblyTitleAttribute("FSharp.Plotly")>]
66
[<assembly: AssemblyProductAttribute("FSharp.Plotly")>]
77
[<assembly: AssemblyDescriptionAttribute("A F# interactive charting library using plotly.js")>]
8-
[<assembly: AssemblyVersionAttribute("1.2.2")>]
9-
[<assembly: AssemblyFileVersionAttribute("1.2.2")>]
8+
[<assembly: AssemblyVersionAttribute("1.2.3")>]
9+
[<assembly: AssemblyFileVersionAttribute("1.2.3")>]
1010
do ()
1111

1212
module internal AssemblyVersionInformation =
1313
let [<Literal>] AssemblyTitle = "FSharp.Plotly"
1414
let [<Literal>] AssemblyProduct = "FSharp.Plotly"
1515
let [<Literal>] AssemblyDescription = "A F# interactive charting library using plotly.js"
16-
let [<Literal>] AssemblyVersion = "1.2.2"
17-
let [<Literal>] AssemblyFileVersion = "1.2.2"
16+
let [<Literal>] AssemblyVersion = "1.2.3"
17+
let [<Literal>] AssemblyFileVersion = "1.2.3"

Diff for: src/FSharp.Plotly/ChartExtensions.fs

+177
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,55 @@ module ChartExtensions =
343343
(fun (ch:GenericChart) ->
344344
GenericChart.addLayout layout ch)
345345

346+
// Set the LayoutGrid options of a Chart
347+
[<CompiledName("WithLayoutGrid")>]
348+
static member withLayoutGrid(layoutGrid:LayoutGrid) =
349+
(fun (ch:GenericChart) ->
350+
let layout =
351+
GenericChart.getLayout ch
352+
|> Layout.SetLayoutGrid layoutGrid
353+
GenericChart.setLayout layout ch)
354+
355+
// Set the LayoutGrid options of a Chart
356+
[<CompiledName("WithLayoutGridStyle")>]
357+
static member withLayoutGridStyle([<Optional;DefaultParameterValue(null)>]?SubPlots : StyleParam.AxisId [] [],
358+
[<Optional;DefaultParameterValue(null)>]?XAxes : StyleParam.AxisId [],
359+
[<Optional;DefaultParameterValue(null)>]?YAxes : StyleParam.AxisId [],
360+
[<Optional;DefaultParameterValue(null)>]?Rows : int,
361+
[<Optional;DefaultParameterValue(null)>]?Columns : int,
362+
[<Optional;DefaultParameterValue(null)>]?RowOrder : StyleParam.LayoutGridRowOrder,
363+
[<Optional;DefaultParameterValue(null)>]?Pattern : StyleParam.LayoutGridPattern,
364+
[<Optional;DefaultParameterValue(null)>]?XGap : float,
365+
[<Optional;DefaultParameterValue(null)>]?YGap : float,
366+
[<Optional;DefaultParameterValue(null)>]?Domain : Domain,
367+
[<Optional;DefaultParameterValue(null)>]?XSide : StyleParam.LayoutGridXSide,
368+
[<Optional;DefaultParameterValue(null)>]?YSide : StyleParam.LayoutGridYSide
369+
) =
370+
(fun (ch:GenericChart) ->
371+
let layout = GenericChart.getLayout ch
372+
let updatedGrid =
373+
let currentGrid =
374+
match layout.TryGetTypedValue<LayoutGrid> "grid" with
375+
| Some grid -> grid
376+
| None -> LayoutGrid()
377+
currentGrid
378+
|> LayoutGrid.style(
379+
?SubPlots = SubPlots,
380+
?XAxes = XAxes ,
381+
?YAxes = YAxes ,
382+
?Rows = Rows ,
383+
?Columns = Columns ,
384+
?RowOrder = RowOrder,
385+
?Pattern = Pattern ,
386+
?XGap = XGap ,
387+
?YGap = YGap ,
388+
?Domain = Domain ,
389+
?XSide = XSide ,
390+
?YSide = YSide
391+
)
392+
let updatedLayout = layout |> Layout.SetLayoutGrid updatedGrid
393+
GenericChart.setLayout updatedLayout ch)
394+
346395
[<CompiledName("WithConfig")>]
347396
static member withConfig (config:Config) =
348397
(fun (ch:GenericChart) ->
@@ -441,8 +490,136 @@ module ChartExtensions =
441490
static member Combine(gCharts:seq<GenericChart>) =
442491
GenericChart.combine gCharts
443492

493+
///Creates a Grid containing the given plots as subplots with the dimensions of the input (amount of columns equal to the largest inner sequence).
494+
///
495+
///Parameters:
496+
///
497+
///sharedAxes : Wether the subplots share one xAxis per column and one yAxis per row or not. (default:TopToBottom)
498+
///
499+
///rowOrder : the order in which the rows of the grid will be rendered (default:false)
500+
///
501+
///xGap : The space between columns of the grid relative to the x dimension of the grid
502+
///
503+
///yGap : The space between rows of the grid relative to the y dimension of the grid
504+
///
505+
///Use Chart.withLayoutGridStyle to further style the grid object contained in the returned chart.
506+
[<CompiledName("Grid")>]
507+
static member Grid ((gCharts:seq<#seq<GenericChart>>),
508+
[<Optional;DefaultParameterValue(false)>]?sharedAxes:bool,
509+
[<Optional;DefaultParameterValue(null)>]?rowOrder:StyleParam.LayoutGridRowOrder,
510+
[<Optional;DefaultParameterValue(0.05)>] ?xGap,
511+
[<Optional;DefaultParameterValue(0.05)>] ?yGap
512+
) =
513+
514+
let sharedAxes = defaultArg sharedAxes false
515+
let rowOrder = defaultArg rowOrder StyleParam.LayoutGridRowOrder.TopToBottom
516+
let xGap = defaultArg xGap 0.05
517+
let yGap = defaultArg yGap 0.05
518+
519+
let nRows = Seq.length gCharts
520+
let nCols = gCharts |> Seq.maxBy Seq.length |> Seq.length
521+
let pattern = if sharedAxes then StyleParam.LayoutGridPattern.Coupled else StyleParam.LayoutGridPattern.Independent
522+
523+
let generateDomainRanges (count:int) (gap:float) =
524+
[|0. .. (1. / (float count)) .. 1.|]
525+
|> fun doms ->
526+
doms
527+
|> Array.windowed 2
528+
|> Array.mapi (fun i x ->
529+
if i = 0 then
530+
x.[0], (x.[1] - (gap / 2.))
531+
elif i = (doms.Length - 1) then
532+
(x.[0] + (gap / 2.)),x.[1]
533+
else
534+
(x.[0] + (gap / 2.)) , (x.[1] - (gap / 2.))
535+
)
536+
537+
let yDomains = generateDomainRanges nRows yGap
538+
let xDomains = generateDomainRanges nCols xGap
539+
540+
gCharts
541+
|> Seq.mapi (fun rowIndex row ->
542+
row |> Seq.mapi (fun colIndex gChart ->
543+
let xdomain = xDomains.[colIndex]
544+
let ydomain = yDomains.[rowIndex]
545+
546+
let newXIndex, newYIndex =
547+
(if sharedAxes then colIndex + 1 else ((nRows * rowIndex) + (colIndex + 1))),
548+
(if sharedAxes then rowIndex + 1 else ((nRows * rowIndex) + (colIndex + 1)))
549+
550+
551+
let xaxis,yaxis,layout =
552+
let layout = GenericChart.getLayout gChart
553+
let xAxisName, yAxisName = StyleParam.AxisId.X 1 |> StyleParam.AxisId.toString, StyleParam.AxisId.Y 1 |> StyleParam.AxisId.toString
554+
555+
let updateXAxis index domain axis =
556+
axis |> Axis.LinearAxis.style(Anchor=StyleParam.AxisAnchorId.X index,Domain=StyleParam.Range.MinMax domain)
557+
558+
let updateYAxis index domain axis =
559+
axis |> Axis.LinearAxis.style(Anchor=StyleParam.AxisAnchorId.Y index,Domain=StyleParam.Range.MinMax domain)
560+
match (layout.TryGetTypedValue<Axis.LinearAxis> xAxisName),(layout.TryGetTypedValue<Axis.LinearAxis> yAxisName) with
561+
| Some x, Some y ->
562+
// remove axis
563+
DynObj.remove layout xAxisName
564+
DynObj.remove layout yAxisName
565+
566+
x |> updateXAxis newXIndex xdomain,
567+
y |> updateYAxis newYIndex ydomain,
568+
layout
569+
570+
| Some x, None ->
571+
// remove x - axis
572+
DynObj.remove layout xAxisName
573+
574+
x |> updateXAxis newXIndex xdomain,
575+
Axis.LinearAxis.init(Anchor=StyleParam.AxisAnchorId.Y newYIndex ,Domain=StyleParam.Range.MinMax ydomain),
576+
layout
577+
578+
| None, Some y ->
579+
// remove y - axis
580+
DynObj.remove layout yAxisName
581+
582+
Axis.LinearAxis.init(Anchor=StyleParam.AxisAnchorId.X newXIndex,Domain=StyleParam.Range.MinMax xdomain),
583+
y |> updateYAxis newYIndex ydomain,
584+
layout
585+
| None, None ->
586+
Axis.LinearAxis.init(Anchor=StyleParam.AxisAnchorId.X newXIndex,Domain=StyleParam.Range.MinMax xdomain),
587+
Axis.LinearAxis.init(Anchor=StyleParam.AxisAnchorId.Y newYIndex,Domain=StyleParam.Range.MinMax ydomain),
588+
layout
589+
590+
gChart
591+
|> GenericChart.setLayout layout
592+
|> Chart.withAxisAnchor(X=newXIndex,Y=newYIndex)
593+
|> Chart.withX_Axis(xaxis,newXIndex)
594+
|> Chart.withY_Axis(yaxis,newYIndex)
595+
)
596+
)
597+
|> Seq.map Chart.Combine
598+
|> Chart.Combine
599+
|> Chart.withLayoutGrid(
600+
LayoutGrid.init(
601+
Rows=nRows,Columns=nCols,XGap= xGap,YGap= yGap,Pattern=pattern,RowOrder=rowOrder
602+
)
603+
)
604+
605+
///Creates a chart stack from the input charts by stacking them on top of each other starting from the first chart.
606+
///
607+
///Parameters:
608+
///
609+
///sharedAxis : wether the stack has a shared x axis (default:true)
610+
[<CompiledName("SingleStack")>]
611+
static member SingleStack (charts:#seq<GenericChart>,
612+
[<Optional;DefaultParameterValue(true)>] ?sharedXAxis:bool) =
613+
614+
let sharedAxis = defaultArg sharedXAxis true
615+
let singleCol = seq {
616+
for i = 0 to ((Seq.length charts) - 1) do
617+
yield seq {Seq.item i charts}
618+
}
619+
Chart.Grid(gCharts = singleCol, sharedAxes = sharedAxis, rowOrder = StyleParam.LayoutGridRowOrder.BottomToTop)
444620

445621
/// Create a combined chart with the given charts merged
622+
[<Obsolete("Use Chart.Grid for multi column grid charts or singleStack for one-column stacked charts.")>]
446623
[<CompiledName("Stack")>]
447624
static member Stack ( [<Optional;DefaultParameterValue(null)>] ?Columns:int,
448625
[<Optional;DefaultParameterValue(null)>] ?Space) =

Diff for: src/FSharp.Plotly/FSharp.Plotly.fsproj

+2
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
<Compile Include="Table.fs" />
5050
<Compile Include="Trace.fs" />
5151
<Compile Include="Trace3d.fs" />
52+
<Compile Include="LayoutGrid.fs" />
5253
<Compile Include="Layout.fs" />
5354
<Compile Include="Config.fs" />
5455
<Compile Include="GenericChart.fs" />
@@ -57,6 +58,7 @@
5758
<Compile Include="CandelstickExtension.fs" />
5859
<Compile Include="SankeyExtension.fs" />
5960
<Compile Include="Templates.fs" />
61+
<None Include="Playground.fsx" />
6062
<None Include="TestScript.fsx" />
6163
<None Include="paket.references" />
6264
<None Include="paket.template" />

Diff for: src/FSharp.Plotly/Layout.fs

+19
Original file line numberDiff line numberDiff line change
@@ -388,4 +388,23 @@ type Layout() =
388388
layout
389389
)
390390

391+
static member SetLayoutGrid
392+
(
393+
grid: LayoutGrid
394+
) =
395+
(fun (layout:Layout) ->
396+
grid |> DynObj.setValue layout "grid"
397+
layout
398+
)
399+
400+
401+
static member GetLayoutGrid
402+
(
403+
grid: LayoutGrid
404+
) =
405+
(fun (layout:Layout) ->
406+
grid |> DynObj.setValue layout "grid"
407+
layout
408+
)
409+
391410

0 commit comments

Comments
 (0)