@@ -470,6 +470,9 @@ class QgridWidget(widgets.DOMWidget):
470470 _df = Instance (pd .DataFrame )
471471 _df_json = Unicode ('' , sync = True )
472472 _primary_key = List ()
473+ _primary_key_display = Dict ({})
474+ _row_styles = Dict ({}, sync = True )
475+ _disable_grouping = Bool (False )
473476 _columns = Dict ({}, sync = True )
474477 _filter_tables = Dict ({})
475478 _sorted_column_cache = Dict ({})
@@ -762,17 +765,21 @@ def should_be_stringified(col_series):
762765 for idx , cur_level in enumerate (df .index .levels ):
763766 if cur_level .name :
764767 col_name = cur_level .name
768+ self ._primary_key_display [col_name ] = col_name
765769 else :
766770 col_name = 'level_%s' % idx
771+ self ._primary_key_display [col_name ] = ""
767772 self ._primary_key .append (col_name )
768773 if should_be_stringified (cur_level ):
769774 self ._string_columns .append (col_name )
770775 else :
771776 self ._multi_index = False
772777 if df .index .name :
773778 col_name = df .index .name
779+ self ._primary_key_display [col_name ] = col_name
774780 else :
775781 col_name = 'index'
782+ self ._primary_key_display [col_name ] = ""
776783 self ._primary_key = [col_name ]
777784
778785 if should_be_stringified (df .index ):
@@ -786,10 +793,50 @@ def should_be_stringified(col_series):
786793 series_to_set = df [sort_column_name ]
787794 else :
788795 series_to_set = self ._get_col_series_from_df (
789- col_name , df
796+ col_name , df , level_vals = True
790797 ).map (str )
791798 self ._set_col_series_on_df (col_name , df , series_to_set )
792799
800+ if type (df .index ) == pd .core .index .MultiIndex and \
801+ not self ._disable_grouping :
802+ previous_value = None
803+ row_styles = {}
804+ row_styles_idx = 0
805+ for index , row in df .iterrows ():
806+ row_style = {}
807+ row_loc = self ._df .index .get_loc (index )
808+ last_row = row_loc == (len (self ._df ) - 1 )
809+ prev_idx = row_loc - 1
810+ for idx , index_val in enumerate (index ):
811+ col_name = self ._primary_key [idx ]
812+ if previous_value == None :
813+ row_style [col_name ] = 'group-top'
814+ continue
815+ elif index_val == previous_value [idx ]:
816+ if prev_idx < 0 :
817+ row_style [col_name ] = 'group-top'
818+ continue
819+ if row_styles [prev_idx ][col_name ] == 'group-top' :
820+ row_style [col_name ] = 'group-middle'
821+ elif row_styles [prev_idx ][col_name ] == 'group-bottom' :
822+ row_style [col_name ] = 'group-top'
823+ else :
824+ row_style [col_name ] = 'group-middle'
825+ else :
826+ row_style [col_name ] = 'single' if last_row else 'group-top'
827+ if prev_idx >= 0 :
828+ if row_styles [prev_idx ][col_name ] == 'group-middle' :
829+ row_styles [prev_idx ][col_name ] = 'group-bottom'
830+ elif row_styles [prev_idx ][col_name ] == 'group-top' :
831+ row_styles [prev_idx ][col_name ] = 'group-single'
832+ previous_value = index
833+ row_styles [row_loc ] = row_style
834+ row_styles_idx += 1
835+
836+ self ._row_styles = row_styles
837+ else :
838+ self ._row_styles = {}
839+
793840 df_json = pd_json .to_json (None , df ,
794841 orient = 'table' ,
795842 date_format = 'iso' ,
@@ -825,6 +872,10 @@ def should_be_stringified(col_series):
825872
826873 if col_name in self ._primary_key :
827874 cur_column ['is_index' ] = True
875+ cur_column ['index_display_text' ] = \
876+ self ._primary_key_display [col_name ]
877+ if len (self ._primary_key ) > 0 :
878+ cur_column ['level' ] = self ._primary_key .index (col_name )
828879
829880 cur_column ['position' ] = i
830881 columns [col_name ] = cur_column
@@ -836,7 +887,9 @@ def should_be_stringified(col_series):
836887 # json that has interval columns replaced with text columns
837888 if len (self ._interval_columns ) > 0 :
838889 for col_name in self ._interval_columns :
839- col_series = self ._get_col_series_from_df (col_name , df )
890+ col_series = self ._get_col_series_from_df (col_name ,
891+ df ,
892+ level_vals = True )
840893 col_series_as_strings = col_series .map (lambda x : str (x ))
841894 self ._set_col_series_on_df (col_name , df ,
842895 col_series_as_strings )
@@ -850,7 +903,7 @@ def should_be_stringified(col_series):
850903 series_to_set = df [sort_column_name ]
851904 else :
852905 series_to_set = self ._get_col_series_from_df (
853- col_name , df
906+ col_name , df , level_vals = True
854907 ).to_timestamp ()
855908 self ._set_col_series_on_df (col_name , df , series_to_set )
856909
@@ -882,6 +935,7 @@ def _update_sort(self):
882935 try :
883936 if self ._sort_field is None :
884937 return
938+ self ._disable_grouping = False
885939 if self ._sort_field in self ._primary_key :
886940 if len (self ._primary_key ) == 1 :
887941 self ._df .sort_index (
@@ -890,19 +944,23 @@ def _update_sort(self):
890944 )
891945 else :
892946 level_id = self ._sort_field
947+ level_index = self ._primary_key .index (level_id )
893948 if self ._sort_field .startswith ('level_' ):
894949 level_id = int (self ._sort_field [6 :])
895950 self ._df .sort_index (
896951 level = level_id ,
897952 ascending = self ._sort_ascending ,
898953 inplace = True
899954 )
955+ if level_index > 0 :
956+ self ._disable_grouping = True
900957 else :
901958 self ._df .sort_values (
902959 self ._sort_field ,
903960 ascending = self ._sort_ascending ,
904961 inplace = True
905962 )
963+ self ._disable_grouping = True
906964 except TypeError :
907965 self .log .info ('TypeError occurred, assuming mixed data type '
908966 'column' )
@@ -1114,15 +1172,18 @@ def get_value_from_filter_table(k):
11141172 })
11151173
11161174 # get any column from a dataframe, including index columns
1117- def _get_col_series_from_df (self , col_name , df ):
1175+ def _get_col_series_from_df (self , col_name , df , level_vals = False ):
11181176 sort_column_name = self ._sort_helper_columns .get (col_name )
11191177 if sort_column_name :
11201178 return df [sort_column_name ]
11211179
11221180 if col_name in self ._primary_key :
11231181 if len (self ._primary_key ) > 1 :
11241182 key_index = self ._primary_key .index (col_name )
1125- return df .index .levels [key_index ]
1183+ if level_vals :
1184+ return df .index .levels [key_index ]
1185+
1186+ return df .index .get_level_values (key_index )
11261187 else :
11271188 return df .index
11281189 else :
0 commit comments