@@ -539,7 +539,7 @@ def __init__(self, parent, data=None, readonly=False, bg_value=None, bg_gradient
539
539
self .model_hlabels = LabelsArrayModel (parent = self , readonly = readonly )
540
540
self .view_hlabels = LabelsView (parent = self , model = self .model_hlabels , position = (TOP , RIGHT ))
541
541
542
- self .model_vlabels = LabelsArrayModel (parent = self , readonly = readonly )
542
+ self .model_vlabels = LabelsArrayModel (parent = self , readonly = readonly , orientation = Qt . Vertical )
543
543
self .view_vlabels = LabelsView (parent = self , model = self .model_vlabels , position = (BOTTOM , LEFT ))
544
544
545
545
self .model_data = DataArrayModel (parent = self , readonly = readonly , minvalue = minvalue , maxvalue = maxvalue )
@@ -662,6 +662,13 @@ def __init__(self, parent, data=None, readonly=False, bg_value=None, bg_gradient
662
662
btn_layout .addWidget (gradient_chooser )
663
663
self .gradient_chooser = gradient_chooser
664
664
665
+ label = QLabel ("Horizontal Dimensions" )
666
+ btn_layout .addWidget (label )
667
+ spin = QSpinBox (self )
668
+ spin .valueChanged .connect (self .nb_horizontal_dims_changed )
669
+ self .nb_horizontal_dims_spinbox = spin
670
+ btn_layout .addWidget (spin )
671
+
665
672
# Set widget layout
666
673
layout = QVBoxLayout ()
667
674
layout .addLayout (self .filters_layout )
@@ -675,6 +682,8 @@ def __init__(self, parent, data=None, readonly=False, bg_value=None, bg_gradient
675
682
# See http://doc.qt.io/qt-4.8/qt-draganddrop-fridgemagnets-dragwidget-cpp.html for an example
676
683
self .setAcceptDrops (True )
677
684
685
+ self ._raw_data_selection = None
686
+
678
687
def gradient_changed (self , index ):
679
688
gradient = self .gradient_chooser .itemData (index ) if index > 0 else None
680
689
self .model_data .set_bg_gradient (gradient )
@@ -760,8 +769,9 @@ def set_data(self, data=None, bg_value=None):
760
769
axes = la_data .axes
761
770
display_names = axes .display_names
762
771
763
- # update data format and bgcolor
764
- self ._update_digits_scientific (la_data )
772
+ # update data format and bgcolor + dim spinbox
773
+ self ._update_digits_scientific_dims (la_data )
774
+ self .nb_horizontal_dims_spinbox .setValue (1 )
765
775
766
776
# update filters
767
777
filters_layout = self .filters_layout
@@ -781,7 +791,7 @@ def set_data(self, data=None, bg_value=None):
781
791
self .view_vlabels .set_default_size ()
782
792
self .view_data .set_default_size ()
783
793
784
- def _update_digits_scientific (self , data ):
794
+ def _update_digits_scientific_dims (self , data ):
785
795
"""
786
796
data : LArray
787
797
"""
@@ -810,6 +820,9 @@ def _update_digits_scientific(self, data):
810
820
811
821
self .gradient_chooser .setEnabled (self .model_data .bgcolor_possible )
812
822
823
+ self .nb_horizontal_dims_spinbox .setMinimum (1 )
824
+ self .nb_horizontal_dims_spinbox .setMaximum (max (1 , self .data_adapter .ndim - 1 ))
825
+
813
826
def choose_scientific (self , data ):
814
827
# max_digits = self.get_max_digits()
815
828
# default width can fit 8 chars
@@ -942,7 +955,7 @@ def dirty(self):
942
955
def accept_changes (self ):
943
956
"""Accept changes"""
944
957
la_data = self .data_adapter .accept_changes ()
945
- self ._update_digits_scientific (la_data )
958
+ self ._update_digits_scientific_dims (la_data )
946
959
947
960
def reject_changes (self ):
948
961
"""Reject changes"""
@@ -967,6 +980,9 @@ def digits_changed(self, value):
967
980
self .digits = value
968
981
self .model_data .set_format (self .cell_format )
969
982
983
+ def nb_horizontal_dims_changed (self , value ):
984
+ self .data_adapter .update_nb_dims_hlabels (value )
985
+
970
986
def create_filter_combo (self , axis ):
971
987
def filter_changed (checked_items ):
972
988
self .data_adapter .change_filter (axis , checked_items )
@@ -1001,15 +1017,15 @@ def _selection_data(self, headers=True, none_selects_all=True):
1001
1017
if not self .data_adapter .ndim :
1002
1018
return raw_data
1003
1019
# FIXME: this is extremely ad-hoc.
1004
- # TODO: in the future (pandas-based branch ) we should use to_string(data[self._selection_filter()])
1020
+ # TODO: in the future (multi_index supported ) we should use to_string(data[self._selection_filter()])
1005
1021
dim_headers = self .model_axes .get_values ()
1006
- hlabels = self .model_hlabels .get_values (top = col_min , bottom = col_max )
1007
- topheaders = [[ dim_header [ 0 ] for dim_header in dim_headers ] + [ label [ 0 ] for label in hlabels ] ]
1022
+ hlabels = self .model_hlabels .get_values (left = col_min , right = col_max )
1023
+ topheaders = [dims + labels for dims , labels in zip ( dim_headers , hlabels ) ]
1008
1024
if self .data_adapter .ndim == 1 :
1009
1025
return chain (topheaders , [chain (['' ], row ) for row in raw_data ])
1010
1026
else :
1011
1027
assert self .data_adapter .ndim > 1
1012
- vlabels = self .model_vlabels .get_values (left = row_min , right = row_max )
1028
+ vlabels = self .model_vlabels .get_values (top = row_min , bottom = row_max )
1013
1029
return chain (topheaders ,
1014
1030
[chain ([vlabels [j ][r ] for j in range (len (vlabels ))], row )
1015
1031
for r , row in enumerate (raw_data )])
@@ -1033,6 +1049,8 @@ def vrepr(v):
1033
1049
clipboard = QApplication .clipboard ()
1034
1050
clipboard .setText (text )
1035
1051
1052
+ self ._raw_data_selection = self ._selection_data (headers = False )
1053
+
1036
1054
def to_excel (self ):
1037
1055
"""View selection in Excel"""
1038
1056
if xw is None :
@@ -1052,22 +1070,25 @@ def paste(self):
1052
1070
if bounds is None :
1053
1071
return
1054
1072
row_min , row_max , col_min , col_max = bounds
1055
- clipboard = QApplication .clipboard ()
1056
- text = str (clipboard .text ())
1057
- list_data = [line .split ('\t ' ) for line in text .splitlines ()]
1058
- try :
1059
- # take the first cell which contains '\'
1060
- pos_last = next (i for i , v in enumerate (list_data [0 ]) if '\\ ' in v )
1061
- except StopIteration :
1062
- # if there isn't any, assume 1d array
1063
- pos_last = 0
1064
- if pos_last :
1065
- # ndim > 1
1066
- list_data = [line [pos_last + 1 :] for line in list_data [1 :]]
1067
- elif len (list_data ) == 2 and list_data [1 ][0 ] == '' :
1068
- # ndim == 1
1069
- list_data = [list_data [1 ][1 :]]
1070
- new_data = np .array (list_data )
1073
+ # clipboard = QApplication.clipboard()
1074
+ # text = str(clipboard.text())
1075
+ # list_data = [line.split('\t') for line in text.splitlines()]
1076
+ # try:
1077
+ # # take the first cell which contains '\'
1078
+ # pos_last = next(i for i, v in enumerate(list_data[0]) if '\\' in v)
1079
+ # except StopIteration:
1080
+ # # if there isn't any, assume 1d array
1081
+ # pos_last = 0
1082
+ # if pos_last:
1083
+ # # ndim > 1
1084
+ # list_data = [line[pos_last + 1:] for line in list_data[1:]]
1085
+ # elif len(list_data) == 2 and list_data[1][0] == '':
1086
+ # # ndim == 1
1087
+ # list_data = [list_data[1][1:]]
1088
+ # new_data = np.array(list_data)
1089
+ if self ._raw_data_selection is None :
1090
+ return
1091
+ new_data = np .array (self ._raw_data_selection )
1071
1092
if new_data .shape [0 ] > 1 :
1072
1093
row_max = row_min + new_data .shape [0 ]
1073
1094
if new_data .shape [1 ] > 1 :
@@ -1093,12 +1114,13 @@ def plot(self):
1093
1114
row_min , row_max , col_min , col_max = self .view_data ._selection_bounds ()
1094
1115
dim_names = self .data_adapter .get_axes_names ()
1095
1116
# labels
1096
- xlabels = [label [0 ] for label in self .model_hlabels .get_values (top = col_min , bottom = col_max )]
1097
- ylabels = self .model_vlabels .get_values (left = row_min , right = row_max )
1098
- # transpose ylabels
1099
- ylabels = [[str (ylabels [i ][j ]) for i in range (len (ylabels ))] for j in range (len (ylabels [0 ]))]
1100
- # if there is only one dimension, ylabels is empty
1101
- if not ylabels :
1117
+ xlabels = self .model_hlabels .get_values (left = col_min , right = col_max , bottom = self .data_adapter .nb_dims_hlabels )
1118
+ xlabels = [[str (xlabels [i ][j ]) for i in range (len (xlabels ))] for j in range (len (xlabels [0 ]))]
1119
+ if self .data_adapter .ndim > 1 :
1120
+ ylabels = self .model_vlabels .get_values (top = row_min , bottom = row_max )
1121
+ # transpose ylabels
1122
+ ylabels = [[str (ylabels [i ][j ]) for i in range (len (ylabels ))] for j in range (len (ylabels [0 ]))]
1123
+ else :
1102
1124
ylabels = [[]]
1103
1125
1104
1126
assert data .ndim == 2
@@ -1118,7 +1140,7 @@ def plot(self):
1118
1140
else :
1119
1141
# plot each row as a line
1120
1142
xlabel = dim_names [- 1 ]
1121
- xticklabels = [str ( label ) for label in xlabels ]
1143
+ xticklabels = [' \n ' . join ( row ) for row in xlabels ]
1122
1144
xdata = np .arange (col_max - col_min )
1123
1145
for row in range (len (data )):
1124
1146
ax .plot (xdata , data [row ], label = ' ' .join (ylabels [row ]))
0 commit comments