22# -*- coding: utf-8; -*-
33# Copyright (c) 2023 Oracle and/or its affiliates.
44# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
5+ from typing import List
56
67from ads .common .decorator .runtime_dependency import OptionalDependency
78from ads .feature_store .statistics .charts .abstract_feature_stat import AbsFeatureStat
9+ from ads .feature_store .statistics .charts .frequency_distribution import (
10+ FrequencyDistribution ,
11+ )
812from ads .feature_store .statistics .generic_feature_value import GenericFeatureValue
913
1014try :
@@ -23,6 +27,8 @@ class BoxPlot(AbsFeatureStat):
2327 CONST_SD = "StandardDeviation"
2428 CONST_MEAN = "Mean"
2529 CONST_BOX_PLOT_TITLE = "Box Plot"
30+ CONST_IQR = "IQR"
31+ CONST_FREQUENCY_DISTRIBUTION = "FrequencyDistribution"
2632
2733 class Quartiles :
2834 CONST_Q1 = "q1"
@@ -52,16 +58,15 @@ def __init__(
5258 sd : float ,
5359 q1 : float ,
5460 q3 : float ,
55- min : float ,
56- max : float ,
61+ boxpoints : List [float ],
5762 ):
5863 self .mean = mean
5964 self .median = median
6065 self .q1 = q1
6166 self .q3 = q3
6267 self .sd = sd
63- self .min = min
64- self .max = max
68+ self .iqr = self . q3 - self . q1
69+ self .boxpoints = boxpoints
6570
6671 def add_to_figure (self , fig : Figure , xaxis : int , yaxis : int ):
6772 xaxis_str , yaxis_str , x_str , y_str = self .get_x_y_str_axes (xaxis , yaxis )
@@ -71,14 +76,30 @@ def add_to_figure(self, fig: Figure, xaxis: int, yaxis: int):
7176 q1 = [self .q1 ],
7277 q3 = [self .q3 ],
7378 sd = [self .sd ],
74- upperfence = [self .max ],
75- lowerfence = [self .min ],
79+ y = [self .boxpoints ],
80+ upperfence = [self .q3 + 1.5 * self .iqr ],
81+ lowerfence = [self .q1 - 1.5 * self .iqr ],
7682 xaxis = x_str ,
7783 yaxis = y_str ,
84+ name = "" ,
85+ jitter = 0 ,
7886 )
7987 fig .layout .annotations [xaxis ].text = self .CONST_BOX_PLOT_TITLE
8088 fig .layout [yaxis_str ]["title" ] = "Values"
8189
90+ @staticmethod
91+ def get_boxpoints_from_frequency_distribution (
92+ frequency_distribution : FrequencyDistribution ,
93+ ) -> List [float ]:
94+ boxpoints = []
95+ if frequency_distribution is not None :
96+ for frequency , bin in zip (
97+ frequency_distribution .frequency , frequency_distribution .bins
98+ ):
99+ boxpoints .extend ([bin ] * frequency )
100+
101+ return boxpoints
102+
82103 @classmethod
83104 def from_json (cls , json_dict : dict ) -> "BoxPlot" :
84105 if type (json_dict ) is dict and json_dict .get (cls .CONST_QUARTILES ) is not None :
@@ -89,8 +110,11 @@ def from_json(cls, json_dict: dict) -> "BoxPlot":
89110 sd = GenericFeatureValue .from_json (json_dict .get (cls .CONST_SD )).val ,
90111 q1 = quartiles .q1 ,
91112 q3 = quartiles .q3 ,
92- min = GenericFeatureValue .from_json (json_dict .get (cls .CONST_MIN )).val ,
93- max = GenericFeatureValue .from_json (json_dict .get (cls .CONST_MAX )).val ,
113+ boxpoints = cls .get_boxpoints_from_frequency_distribution (
114+ FrequencyDistribution .from_json (
115+ json_dict .get (cls .CONST_FREQUENCY_DISTRIBUTION )
116+ )
117+ ),
94118 )
95119 else :
96120 return None
0 commit comments