diff --git a/src/Plotly.NET/ChartAPI/Chart2D.fs b/src/Plotly.NET/ChartAPI/Chart2D.fs index 9ab0c17b..77577ca5 100644 --- a/src/Plotly.NET/ChartAPI/Chart2D.fs +++ b/src/Plotly.NET/ChartAPI/Chart2D.fs @@ -3817,6 +3817,7 @@ module Chart2D = /// Determines whether or not notches are drawn. Notches displays a confidence interval around the median. We compute the confidence interval as median +/- 1.57 " IQR / sqrt(N), where IQR is the interquartile range and N is the sample size. If two boxes' notches do not overlap there is 95% confidence their medians differ. See https://sites.google.com/site/davidsstatistics/home/notched-box-plots for more info. Defaults to "false" unless `notchwidth` or `notchspan` is set. /// Sets the width of the notches relative to the box' width. For example, with 0, the notches are as wide as the box(es). /// Sets the method used to compute the sample's Q1 and Q3 quartiles. The "linear" method uses the 25th percentile for Q1 and 75th percentile for Q3 as computed using method #10 (listed on http://www.amstat.org/publications/jse/v14n3/langford.html). The "exclusive" method uses the median to divide the ordered dataset into two halves if the sample is odd, it does not include the median in either half - Q1 is then the median of the lower half and Q3 the median of the upper half. The "inclusive" method also uses the median to divide the ordered dataset into two halves but if the sample is odd, it includes the median in both halves - Q1 is then the median of the lower half and Q3 the median of the upper half. + /// Sets the upper and lower bound for the boxes quartiles means box is drawn between Q1 and Q3 SD means the box is drawn between Mean +- Standard Deviation Argument sdmultiple (default 1) to scale the box size So it could be drawn 1-stddev, 3-stddev etc /// If set to false, ignore the global default settings set in `Defaults` [] static member BoxPlot @@ -3847,6 +3848,7 @@ module Chart2D = [] ?Notched: bool, [] ?NotchWidth: float, [] ?QuartileMethod: StyleParam.QuartileMethod, + [] ?SizeMode: StyleParam.BoxSizeMode, [] ?UseDefaults: bool ) = @@ -3888,7 +3890,8 @@ module Chart2D = ?OffsetGroup = OffsetGroup, ?Notched = Notched, ?NotchWidth = NotchWidth, - ?QuartileMethod = QuartileMethod + ?QuartileMethod = QuartileMethod, + ?SizeMode = SizeMode ) ) |> GenericChart.ofTraceObject useDefaults @@ -3923,6 +3926,7 @@ module Chart2D = /// Determines whether or not notches are drawn. Notches displays a confidence interval around the median. We compute the confidence interval as median +/- 1.57 " IQR / sqrt(N), where IQR is the interquartile range and N is the sample size. If two boxes' notches do not overlap there is 95% confidence their medians differ. See https://sites.google.com/site/davidsstatistics/home/notched-box-plots for more info. Defaults to "false" unless `notchwidth` or `notchspan` is set. /// Sets the width of the notches relative to the box' width. For example, with 0, the notches are as wide as the box(es). /// Sets the method used to compute the sample's Q1 and Q3 quartiles. The "linear" method uses the 25th percentile for Q1 and 75th percentile for Q3 as computed using method #10 (listed on http://www.amstat.org/publications/jse/v14n3/langford.html). The "exclusive" method uses the median to divide the ordered dataset into two halves if the sample is odd, it does not include the median in either half - Q1 is then the median of the lower half and Q3 the median of the upper half. The "inclusive" method also uses the median to divide the ordered dataset into two halves but if the sample is odd, it includes the median in both halves - Q1 is then the median of the lower half and Q3 the median of the upper half. + /// Sets the upper and lower bound for the boxes quartiles means box is drawn between Q1 and Q3 SD means the box is drawn between Mean +- Standard Deviation Argument sdmultiple (default 1) to scale the box size So it could be drawn 1-stddev, 3-stddev etc /// If set to false, ignore the global default settings set in `Defaults` [] static member BoxPlot @@ -3950,6 +3954,7 @@ module Chart2D = [] ?Notched: bool, [] ?NotchWidth: float, [] ?QuartileMethod: StyleParam.QuartileMethod, + [] ?SizeMode: StyleParam.BoxSizeMode, [] ?UseDefaults: bool ) = @@ -3976,6 +3981,7 @@ module Chart2D = ?Notched = Notched, ?NotchWidth = NotchWidth, ?QuartileMethod = QuartileMethod, + ?SizeMode = SizeMode, ?UseDefaults = UseDefaults ) @@ -4014,6 +4020,7 @@ module Chart2D = /// Determines whether or not notches are drawn. Notches displays a confidence interval around the median. We compute the confidence interval as median +/- 1.57 " IQR / sqrt(N), where IQR is the interquartile range and N is the sample size. If two boxes' notches do not overlap there is 95% confidence their medians differ. See https://sites.google.com/site/davidsstatistics/home/notched-box-plots for more info. Defaults to "false" unless `notchwidth` or `notchspan` is set. /// Sets the width of the notches relative to the box' width. For example, with 0, the notches are as wide as the box(es). /// Sets the method used to compute the sample's Q1 and Q3 quartiles. The "linear" method uses the 25th percentile for Q1 and 75th percentile for Q3 as computed using method #10 (listed on http://www.amstat.org/publications/jse/v14n3/langford.html). The "exclusive" method uses the median to divide the ordered dataset into two halves if the sample is odd, it does not include the median in either half - Q1 is then the median of the lower half and Q3 the median of the upper half. The "inclusive" method also uses the median to divide the ordered dataset into two halves but if the sample is odd, it includes the median in both halves - Q1 is then the median of the lower half and Q3 the median of the upper half. + /// Sets the upper and lower bound for the boxes quartiles means box is drawn between Q1 and Q3 SD means the box is drawn between Mean +- Standard Deviation Argument sdmultiple (default 1) to scale the box size So it could be drawn 1-stddev, 3-stddev etc /// If set to false, ignore the global default settings set in `Defaults` [] static member BoxPlot @@ -4041,6 +4048,7 @@ module Chart2D = [] ?Notched: bool, [] ?NotchWidth: float, [] ?QuartileMethod: StyleParam.QuartileMethod, + [] ?SizeMode: StyleParam.BoxSizeMode, [] ?UseDefaults: bool ) = @@ -4071,6 +4079,7 @@ module Chart2D = ?Notched = Notched, ?NotchWidth = NotchWidth, ?QuartileMethod = QuartileMethod, + ?SizeMode = SizeMode, ?UseDefaults = UseDefaults ) diff --git a/src/Plotly.NET/CommonAbstractions/StyleParams.fs b/src/Plotly.NET/CommonAbstractions/StyleParams.fs index 56a6c8ae..b74e684e 100644 --- a/src/Plotly.NET/CommonAbstractions/StyleParams.fs +++ b/src/Plotly.NET/CommonAbstractions/StyleParams.fs @@ -356,6 +356,23 @@ module StyleParam = member this.Convert() = this |> BoxPoints.convert + /// + /// Sets the upper and lower bound for the boxes quartiles means box is drawn between Q1 and Q3 SD means the box is drawn between Mean +- Standard Deviation + /// + [] + type BoxSizeMode = + | Quartiles + | SD + + static member toString = + function + | Quartiles -> "quartiles" + | SD -> "sd" + + static member convert = BoxSizeMode.toString >> box + override this.ToString() = this |> BoxSizeMode.toString + member this.Convert() = this |> BoxSizeMode.convert + [] diff --git a/src/Plotly.NET/Traces/Trace2D.fs b/src/Plotly.NET/Traces/Trace2D.fs index f4780e36..a6f57446 100644 --- a/src/Plotly.NET/Traces/Trace2D.fs +++ b/src/Plotly.NET/Traces/Trace2D.fs @@ -1090,6 +1090,7 @@ type Trace2DStyle() = /// Sets the legend rank for this trace. Items and groups with smaller ranks are presented on top/left side while with `"reversed" `legend.traceorder` they are on bottom/right side. The default legendrank is 1000, so that you can use ranks less than 1000 to place certain items before all unranked items, and ranks greater than 1000 to go after all unranked items. /// Sets the legend group for this trace. Traces part of the same legend group hide/show at the same time when toggling legend items. /// Sets the legend group title for this trace. + /// Sets the width (in px or fraction) of the legend for this trace. /// Sets the opacity of the trace. /// Assigns id labels to each datum. These ids for object constancy of data points during animation. Should be an array of strings, not numbers or any other type. /// Sets the x sample data or coordinates. See overview for more info. @@ -1129,6 +1130,7 @@ type Trace2DStyle() = /// If "outliers", only the sample points lying outside the whiskers are shown If "suspectedoutliers", the outlier points are shown and points either less than 4"Q1-3"Q3 or greater than 4"Q3-3"Q1 are highlighted (see `outliercolor`) If "all", all sample points are shown If "false", only the box(es) are shown with no sample points Defaults to "suspectedoutliers" when `marker.outliercolor` or `marker.line.outliercolor` is set. Defaults to "all" under the q1/median/q3 signature. Otherwise defaults to "outliers". /// Determines whether or not notches are drawn. Notches displays a confidence interval around the median. We compute the confidence interval as median +/- 1.57 " IQR / sqrt(N), where IQR is the interquartile range and N is the sample size. If two boxes' notches do not overlap there is 95% confidence their medians differ. See https://sites.google.com/site/davidsstatistics/home/notched-box-plots for more info. Defaults to "false" unless `notchwidth` or `notchspan` is set. /// Sets the width of the notches relative to the box' width. For example, with 0, the notches are as wide as the box(es). + /// Determines whether or not whiskers are visible. Defaults to true for `sizemode` "quartiles", false for "sd". /// Sets the width of the whiskers relative to the box' width. For example, with 1, the whiskers are as wide as the box(es). /// Sets the Quartile 1 values. There should be as many items as the number of boxes desired. /// Sets the Quartile 1 values. There should be as many items as the number of boxes desired. @@ -1138,6 +1140,7 @@ type Trace2DStyle() = /// Sets the notch span from the boxes' `median` values. There should be as many items as the number of boxes desired. This attribute has effect only under the q1/median/q3 signature. If `notchspan` is not provided but a sample (in `y` or `x`) is set, we compute it as 1.57 " IQR / sqrt(N), where N is the sample size. /// Sets the mean values. There should be as many items as the number of boxes desired. This attribute has effect only under the q1/median/q3 signature. If `mean` is not provided but a sample (in `y` or `x`) is set, we compute the mean for each box using the sample values. /// Sets the standard deviation values. There should be as many items as the number of boxes desired. This attribute has effect only under the q1/median/q3 signature. If `sd` is not provided but a sample (in `y` or `x`) is set, we compute the standard deviation for each box using the sample values. + /// Scales the box size when sizemode=sd Allowing boxes to be drawn across any stddev range For example 1-stddev, 3-stddev, 5-stddev /// Sets the method used to compute the sample's Q1 and Q3 quartiles. The "linear" method uses the 25th percentile for Q1 and 75th percentile for Q3 as computed using method #10 (listed on http://www.amstat.org/publications/jse/v14n3/langford.html). The "exclusive" method uses the median to divide the ordered dataset into two halves if the sample is odd, it does not include the median in either half - Q1 is then the median of the lower half and Q3 the median of the upper half. The "inclusive" method also uses the median to divide the ordered dataset into two halves but if the sample is odd, it includes the median in both halves - Q1 is then the median of the lower half and Q3 the median of the upper half. /// Array containing integer indices of selected points. Has an effect only for traces that support selections. Note that an empty array means an empty selection where the `unselected` are turned on for all points, whereas, any other non-array values means no selection all where the `selected` and `unselected` styles have no effect. /// Sets the style of selected points of this trace. @@ -1147,6 +1150,7 @@ type Trace2DStyle() = /// Do the hover effects highlight individual boxes or sample points or both? /// Sets the position of the sample points in relation to the box(es). If "0", the sample points are places over the center of the box(es). Positive (negative) values correspond to positions to the right (left) for vertical boxes and above (below) for horizontal boxes /// Sets the amount of jitter in the sample points drawn. If "0", the sample points align along the distribution axis. If "1", the sample points are drawn in a random jitter of width equal to the width of the box(es). + /// Sets the upper and lower bound for the boxes quartiles means box is drawn between Q1 and Q3 SD means the box is drawn between Mean +- Standard Deviation Argument sdmultiple (default 1) to scale the box size So it could be drawn 1-stddev, 3-stddev etc /// Sets the calendar system to use with `x` date data. /// Sets the calendar system to use with `y` date data. /// Controls persistence of some user-driven changes to the trace: `constraintrange` in `parcoords` traces, as well as some `editable: true` modifications such as `name` and `colorbar.title`. Defaults to `layout.uirevision`. Note that other user-driven trace attribute changes are controlled by `layout` attributes: `trace.visible` is controlled by `layout.legend.uirevision`, `selectedpoints` is controlled by `layout.selectionrevision`, and `colorbar.(x|y)` (accessible with `config: {editable: true}`) is controlled by `layout.editrevision`. Trace changes are tracked by `uid`, which only falls back on trace index if no `uid` is provided. So if your app can add/remove traces before the end of the `data` array, such that the same trace has a different index, you can still preserve user-driven changes if you give each trace a `uid` that stays with it as it moves. @@ -1159,6 +1163,7 @@ type Trace2DStyle() = [] ?LegendRank: int, [] ?LegendGroup: string, [] ?LegendGroupTitle: Title, + [] ?LegendWidth: float, [] ?Opacity: float, [] ?Ids: seq<#IConvertible>, [] ?X: seq<#IConvertible>, @@ -1198,6 +1203,7 @@ type Trace2DStyle() = [] ?BoxPoints: StyleParam.BoxPoints, [] ?Notched: bool, [] ?NotchWidth: float, + [] ?ShowWhiskers: bool, [] ?WhiskerWidth: float, [] ?Q1: seq, [] ?Median: seq, @@ -1207,6 +1213,7 @@ type Trace2DStyle() = [] ?NotchSpan: seq, [] ?Mean: seq, [] ?SD: seq, + [] ?SDMultiple: float, [] ?QuartileMethod: StyleParam.QuartileMethod, [] ?SelectedPoints: seq<#IConvertible>, [] ?Selected: TraceSelection, @@ -1216,6 +1223,7 @@ type Trace2DStyle() = [] ?HoverOn: StyleParam.HoverOn, [] ?PointPos: float, [] ?Jitter: float, + [] ?SizeMode: StyleParam.BoxSizeMode, [] ?XCalendar: StyleParam.Calendar, [] ?YCalendar: StyleParam.Calendar, [] ?UIRevision: string @@ -1229,6 +1237,7 @@ type Trace2DStyle() = LegendRank |> DynObj.setValueOpt boxPlot "legendrank" LegendGroup |> DynObj.setValueOpt boxPlot "legendgroup" LegendGroupTitle |> DynObj.setValueOpt boxPlot "legendgrouptitle" + LegendWidth |> DynObj.setValueOpt boxPlot "legendwidth" Opacity |> DynObj.setValueOpt boxPlot "opacity" Ids |> DynObj.setValueOpt boxPlot "ids" (X, MultiX) |> DynObj.setSingleOrMultiOpt boxPlot "x" @@ -1264,6 +1273,7 @@ type Trace2DStyle() = Notched |> DynObj.setValueOpt boxPlot "notched" NotchWidth |> DynObj.setValueOpt boxPlot "notchwidth" WhiskerWidth |> DynObj.setValueOpt boxPlot "whiskerwidth" + ShowWhiskers |> DynObj.setValueOpt boxPlot "showwhiskers" Q1 |> DynObj.setValueOpt boxPlot "q1" Median |> DynObj.setValueOpt boxPlot "median" Q3 |> DynObj.setValueOpt boxPlot "q3" @@ -1272,6 +1282,7 @@ type Trace2DStyle() = NotchSpan |> DynObj.setValueOpt boxPlot "notchspan" Mean |> DynObj.setValueOpt boxPlot "mean" SD |> DynObj.setValueOpt boxPlot "sd" + SDMultiple |> DynObj.setValueOpt boxPlot "sdmultiple" QuartileMethod |> DynObj.setValueOptBy boxPlot "quartilemethod" StyleParam.QuartileMethod.convert SelectedPoints |> DynObj.setValueOpt boxPlot "selectedpoints" Selected |> DynObj.setValueOpt boxPlot "selected" @@ -1281,6 +1292,7 @@ type Trace2DStyle() = HoverOn |> DynObj.setValueOptBy boxPlot "hoveron" StyleParam.HoverOn.convert PointPos |> DynObj.setValueOpt boxPlot "pointpos" Jitter |> DynObj.setValueOpt boxPlot "jitter" + SizeMode |> DynObj.setValueOptBy boxPlot "sizemode" StyleParam.BoxSizeMode.convert XCalendar |> DynObj.setValueOptBy boxPlot "xcalendar" StyleParam.Calendar.convert YCalendar |> DynObj.setValueOptBy boxPlot "ycalendar" StyleParam.Calendar.convert UIRevision |> DynObj.setValueOpt boxPlot "uirevision" diff --git a/tests/Common/FSharpTestBase/TestCharts/UpstreamFeatures/2.26.fs b/tests/Common/FSharpTestBase/TestCharts/UpstreamFeatures/2.26.fs index 1715c7b9..682a662a 100644 --- a/tests/Common/FSharpTestBase/TestCharts/UpstreamFeatures/2.26.fs +++ b/tests/Common/FSharpTestBase/TestCharts/UpstreamFeatures/2.26.fs @@ -149,4 +149,19 @@ module ``AutoRangeOptions`` = MinAllowed = 4, MaxAllowed = 8 ) + ) + +module ``N-sigma (std deviations) box plots`` = + + let ``2-sigma BoxPlot`` = + Chart.BoxPlot( + data = [-20; 1; 2; 3; 1; 2; 3; 3; 3; 3; 3; 1; 5; 20], + orientation = StyleParam.Orientation.Vertical, + SizeMode = StyleParam.BoxSizeMode.SD, + UseDefaults = false + ) + |> GenericChart.mapTrace ( + Trace2DStyle.BoxPlot( + SDMultiple = 2. + ) ) \ No newline at end of file diff --git a/tests/ConsoleApps/FSharpConsole/Program.fs b/tests/ConsoleApps/FSharpConsole/Program.fs index 103f6cdb..02673d24 100644 --- a/tests/ConsoleApps/FSharpConsole/Program.fs +++ b/tests/ConsoleApps/FSharpConsole/Program.fs @@ -11,150 +11,16 @@ open Newtonsoft.Json [] let main argv = - [ - - Chart.Point( - x = [0 .. 10], - y = [0 .. 10], - UseDefaults = false, - ShowLegend = true - ) - |> Chart.withXAxis( - LinearAxis.init( - AutoRangeOptions = AutoRangeOptions.init( - MinAllowed = 4, - ClipMax = 8 - ) - ) - ) - |> Chart.withYAxis( - LinearAxis.init( - AutoRangeOptions = AutoRangeOptions.init( - MinAllowed = 4, - ClipMax = 8 - ) - ) - ) - - - Chart.Point( - x = [0 .. 10], - y = [0 .. 10], - UseDefaults = false, - ShowLegend = true - ) - |> Chart.withXAxis( - LinearAxis.init( - MinAllowed = 4, - MaxAllowed = 8 - ) - ) - |> Chart.withYAxis( - LinearAxis.init( - MinAllowed = 4, - MaxAllowed = 8 - ) - ) - - - - Chart.Point3D( - x = [0 .. 10], - y = [0 .. 10], - z = [0 .. 10], - UseDefaults = false, - ShowLegend = true, - CameraProjectionType = StyleParam.CameraProjectionType.Orthographic - ) - |> Chart.withXAxis( - LinearAxis.init( - AutoRangeOptions = AutoRangeOptions.init( - MinAllowed = 4, - ClipMax = 8 - ) - ), - Id = StyleParam.SubPlotId.Scene 1 - ) - |> Chart.withYAxis( - LinearAxis.init( - AutoRangeOptions = AutoRangeOptions.init( - MinAllowed = 4, - ClipMax = 8 - ) - ), - Id = StyleParam.SubPlotId.Scene 1 - ) - |> Chart.withZAxis( - LinearAxis.init( - AutoRangeOptions = AutoRangeOptions.init( - MinAllowed = 4, - ClipMax = 8 - ) - ) - ) - - - - Chart.Point3D( - x = [0 .. 10], - y = [0 .. 10], - z = [0 .. 10], - UseDefaults = false, - ShowLegend = true, - CameraProjectionType = StyleParam.CameraProjectionType.Orthographic - ) - |> Chart.withXAxis( - LinearAxis.init( - MinAllowed = 4, - MaxAllowed = 8 - ), - Id = StyleParam.SubPlotId.Scene 1 - ) - |> Chart.withYAxis( - LinearAxis.init( - MinAllowed = 4, - MaxAllowed = 8 - ), - Id = StyleParam.SubPlotId.Scene 1 - ) - |> Chart.withZAxis( - LinearAxis.init( - MinAllowed = 4, - MaxAllowed = 8 - ) - ) - - - - Chart.PointPolar( - r = [0 .. 10], - theta = [0 .. 10 .. 100], - UseDefaults = false, - ShowLegend = true - ) - |> Chart.withRadialAxis( - RadialAxis.init( - AutoRangeOptions = AutoRangeOptions.init( - MinAllowed = 4, - MaxAllowed = 8 - ) - ) - ) - - - - Chart.PointPolar( - r = [0 .. 10], - theta = [0 .. 10 .. 100], - UseDefaults = false, - ShowLegend = true - ) - |> Chart.withRadialAxis( - RadialAxis.init( - MinAllowed = 4, - MaxAllowed = 8 - ) - ) - ] - |> Seq.iter Chart.show + Chart.BoxPlot( + data = [-20; 1; 2; 3; 1; 2; 3; 3; 3; 3; 3; 1; 5; 20], + orientation = StyleParam.Orientation.Vertical, + SizeMode = StyleParam.BoxSizeMode.SD, + UseDefaults = false + ) + |> GenericChart.mapTrace ( + Trace2DStyle.BoxPlot( + SDMultiple = 2. + ) + ) + |> Chart.show 0 \ No newline at end of file diff --git a/tests/CoreTests/CoreTests/UpstreamFeatures/2.26.fs b/tests/CoreTests/CoreTests/UpstreamFeatures/2.26.fs index f3bdef3e..b3e7a243 100644 --- a/tests/CoreTests/CoreTests/UpstreamFeatures/2.26.fs +++ b/tests/CoreTests/CoreTests/UpstreamFeatures/2.26.fs @@ -66,4 +66,19 @@ module ``AutoRangeOptions`` = |> chartGeneratedContains AutoRangeOptions.``PointPolar chart with minallowed and maxallowed on radial axis`` ) ] + ] + +module ``N-sigma (std deviations) box plots`` = + [] + let ``Sigma boxplots`` = + testList "UpstreamFeatures.PlotlyJS_2_26" [ + testList "N-sigma (std deviations) box plots" [ + testCase "2-Sigma box plot data" ( fun () -> + """var data = [{"type":"box","marker":{},"line":{},"sizemode":"sd","y":[-20,1,2,3,1,2,3,3,3,3,3,1,5,20],"sdmultiple":2.0}];""" + |> chartGeneratedContains ``N-sigma (std deviations) box plots``.``2-sigma BoxPlot`` + ) + testCase "2-Sigma box plot layout" ( fun () -> + emptyLayout ``N-sigma (std deviations) box plots``.``2-sigma BoxPlot`` + ) + ] ] \ No newline at end of file