@@ -352,6 +352,46 @@ module ChartExtensions =
352
352
|> Layout.SetLayoutGrid layoutGrid
353
353
GenericChart.setLayout layout ch)
354
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
+
355
395
[<CompiledName( " WithConfig" ) >]
356
396
static member withConfig ( config : Config ) =
357
397
( fun ( ch : GenericChart ) ->
@@ -450,41 +490,71 @@ module ChartExtensions =
450
490
static member Combine ( gCharts : seq < GenericChart >) =
451
491
GenericChart.combine gCharts
452
492
453
-
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.
454
506
[<CompiledName( " Grid" ) >]
455
507
static member Grid (( gCharts : seq < #seq < GenericChart >>),
456
- sharedAxes : bool
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
457
512
) =
458
513
459
- let nRows = Seq.length gCharts
460
- let rowWidth = 1. / float nRows
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
461
518
519
+ let nRows = Seq.length gCharts
462
520
let nCols = gCharts |> Seq.maxBy Seq.length |> Seq.length
463
- let colWidth = 1. / float nCols
464
-
465
521
let pattern = if sharedAxes then StyleParam.LayoutGridPattern.Coupled else StyleParam.LayoutGridPattern.Independent
466
- let grid =
467
- LayoutGrid.init(
468
- Rows= nRows, Columns= nCols, Pattern= pattern
469
- )
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
+
470
540
gCharts
471
541
|> Seq.mapi ( fun rowIndex row ->
472
542
row |> Seq.mapi ( fun colIndex gChart ->
473
- let xdomain = ( colWidth * float ( colIndex-1 ), ( colWidth * float colIndex ))
474
- let ydomain = ( 1. - (( rowWidth * float rowIndex)), 1. - ( rowWidth * float ( rowIndex -1 )))
543
+ let xdomain = xDomains .[ colIndex]
544
+ let ydomain = yDomains .[ rowIndex]
475
545
476
546
let newXIndex , newYIndex =
477
- ( if sharedAxes then colIndex + 1 else ( rowIndex + colIndex + 1 )),
478
- ( if sharedAxes then rowIndex + 1 else ( rowIndex + colIndex + 1 ))
547
+ ( if sharedAxes then colIndex + 1 else (( nRows * rowIndex) + ( colIndex + 1 ) )),
548
+ ( if sharedAxes then rowIndex + 1 else (( nRows * rowIndex) + ( colIndex + 1 ) ))
479
549
480
550
481
551
let xaxis , yaxis , layout =
482
552
let layout = GenericChart.getLayout gChart
483
553
let xAxisName , yAxisName = StyleParam.AxisId.X 1 |> StyleParam.AxisId.toString, StyleParam.AxisId.Y 1 |> StyleParam.AxisId.toString
484
-
554
+
485
555
let updateXAxis index domain axis =
486
556
axis |> Axis.LinearAxis.style( Anchor= StyleParam.AxisAnchorId.X index, Domain= StyleParam.Range.MinMax domain)
487
-
557
+
488
558
let updateYAxis index domain axis =
489
559
axis |> Axis.LinearAxis.style( Anchor= StyleParam.AxisAnchorId.Y index, Domain= StyleParam.Range.MinMax domain)
490
560
match ( layout.TryGetTypedValue< Axis.LinearAxis> xAxisName),( layout.TryGetTypedValue< Axis.LinearAxis> yAxisName) with
@@ -526,9 +596,30 @@ module ChartExtensions =
526
596
)
527
597
|> Seq.map Chart.Combine
528
598
|> Chart.Combine
529
- |> Chart.withLayoutGrid grid
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)
530
620
531
621
/// 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." ) >]
532
623
[<CompiledName( " Stack" ) >]
533
624
static member Stack ( [<Optional; DefaultParameterValue( null ) >] ? Columns : int ,
534
625
[<Optional; DefaultParameterValue( null ) >] ? Space ) =
0 commit comments