Skip to content

issue 14: Multi dims horizontal labels #63

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 53 additions & 35 deletions larray_editor/arrayadapter.py
Original file line number Diff line number Diff line change
@@ -6,13 +6,15 @@


class LArrayDataAdapter(object):
def __init__(self, axes_model, xlabels_model, ylabels_model, data_model,
data=None, changes=None, current_filter=None, bg_gradient=None, bg_value=None):
def __init__(self, axes_model, hlabels_model, vlabels_model, data_model, data=None,
changes=None, current_filter=None, nb_dims_hlabels=1, bg_gradient=None, bg_value=None):
# set models
self.axes_model = axes_model
self.xlabels_model = xlabels_model
self.ylabels_model = ylabels_model
self.hlabels_model = hlabels_model
self.vlabels_model = vlabels_model
self.data_model = data_model
# set number of dims of hlabels
self.nb_dims_hlabels = nb_dims_hlabels
# set current filter
if current_filter is None:
current_filter = {}
@@ -31,38 +33,49 @@ def set_changes(self, changes=None):
assert isinstance(changes, dict)
self.changes = changes

def update_nb_dims_hlabels(self, nb_dims_hlabels):
self.nb_dims_hlabels = nb_dims_hlabels
self.update_axes_and_labels()

def get_axes_names(self):
return self.filtered_data.axes.display_names

def get_axes(self):
axes = self.filtered_data.axes
axes_names = self.filtered_data.axes.display_names
# test self.filtered_data.size == 0 is required in case an instance built as LArray([]) is passed
# test len(axes) == 0 is required when a user filters until to get a scalar
if self.filtered_data.size == 0 or len(axes) == 0:
if self.filtered_data.size == 0 or len(axes_names) == 0:
return None
elif len(axes_names) == 1:
return [axes_names]
else:
axes_names = axes.display_names
if len(axes_names) >= 2:
axes_names = axes_names[:-2] + [axes_names[-2] + '\\' + axes_names[-1]]
return [[axis_name] for axis_name in axes_names]
nb_dims_vlabels = len(axes_names) - self.nb_dims_hlabels
# axes corresponding to horizontal labels are set to the last column
res = [['' for c in range(nb_dims_vlabels-1)] + [axis_name] for axis_name in axes_names[nb_dims_vlabels:]]
# axes corresponding to vertical labels are set to the last row
res = res + [[axis_name for axis_name in axes_names[:nb_dims_vlabels]]]
return res

def get_xlabels(self):
def get_labels(self):
axes = self.filtered_data.axes
if self.filtered_data.size == 0 or len(axes) == 0:
return None
vlabels = None
hlabels = None
else:
return [[label] for label in axes.labels[-1]]

def get_ylabels(self):
axes = self.filtered_data.axes
if self.filtered_data.size == 0 or len(axes) == 0:
return None
elif len(axes) == 1:
return [['']]
else:
labels = axes.labels[:-1]
prod = Product(labels)
return [_LazyDimLabels(prod, i) for i in range(len(labels))]
nb_dims_vlabels = len(axes) - self.nb_dims_hlabels
def get_labels_product(axes, extra_row=False):
if len(axes) == 0:
return [[' ']]
else:
# XXX: appends a fake axis instead of using _LazyNone because
# _LazyNone mess up with LabelsArrayModel.get_values (in which slices are used)
if extra_row:
axes.append(la.Axis([' ']))
prod = Product(axes.labels)
return [_LazyDimLabels(prod, i) for i in range(len(axes.labels))]
vlabels = get_labels_product(axes[:nb_dims_vlabels])
hlabels = get_labels_product(axes[nb_dims_vlabels:], nb_dims_vlabels > 0)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems odd. I would have thought vlabels would get the extra/fake axis instead of hlabels and that the condition would be nb_dims_vlabels == 0, not nb_dims_vlabels > 0???

return vlabels, hlabels

def get_2D_data(self):
"""Returns Numpy 2D ndarray"""
@@ -109,24 +122,29 @@ def set_data(self, data, bg_value=None, current_filter=None):
self.bg_value = la.aslarray(bg_value) if bg_value is not None else None
self.update_filtered_data(current_filter, reset_minmax=True)

def update_axes_and_labels(self):
axes = self.get_axes()
vlabels, hlabels = self.get_labels()
self.axes_model.set_data(axes)
self.hlabels_model.set_data(hlabels)
self.vlabels_model.set_data(vlabels)

def update_data_2D(self, reset_minmax=False):
data_2D = self.get_2D_data()
changes_2D = self.get_changes_2D()
bg_value_2D = self.get_bg_value_2D(data_2D.shape)
self.data_model.set_data(data_2D, changes_2D, reset_minmax=reset_minmax)
self.data_model.set_bg_value(bg_value_2D)

def update_filtered_data(self, current_filter=None, reset_minmax=False):
if current_filter is not None:
assert isinstance(current_filter, dict)
self.current_filter = current_filter
self.filtered_data = self.la_data[self.current_filter]
if np.isscalar(self.filtered_data):
self.filtered_data = la.aslarray(self.filtered_data)
axes = self.get_axes()
xlabels = self.get_xlabels()
ylabels = self.get_ylabels()
data_2D = self.get_2D_data()
changes_2D = self.get_changes_2D()
bg_value_2D = self.get_bg_value_2D(data_2D.shape)
self.axes_model.set_data(axes)
self.xlabels_model.set_data(xlabels)
self.ylabels_model.set_data(ylabels)
self.data_model.set_data(data_2D, changes_2D, reset_minmax=reset_minmax)
self.data_model.set_bg_value(bg_value_2D)
self.update_axes_and_labels()
self.update_data_2D(reset_minmax=reset_minmax)

def get_data(self):
return self.la_data
38 changes: 25 additions & 13 deletions larray_editor/arraymodel.py
Original file line number Diff line number Diff line change
@@ -125,7 +125,8 @@ class LabelsArrayModel(AbstractArrayModel):
font : QFont, optional
Font. Default is `Calibri` with size 11.
"""
def __init__(self, parent=None, data=None, readonly=False, font=None):
def __init__(self, parent=None, data=None, readonly=False, font=None, orientation=Qt.Horizontal):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it turns out to be indeed necessary to differentiate on the orientation (I am unsure about this), then having two different subclasses of LabelsArrayModel depending on the orientation would make things cleaner.

self.orientation = orientation
AbstractArrayModel.__init__(self, parent, data, readonly, font)
self.font.setBold(True)

@@ -136,28 +137,39 @@ def _set_data(self, data, changes=None):
QMessageBox.critical(self.dialog, "Error", "Expected list or tuple.")
data = [[]]
self._data = data
self.total_rows = len(data[0])
self.total_cols = len(data) if self.total_rows > 0 else 0
if self.orientation == Qt.Horizontal:
self.total_rows = len(data) if self.total_cols > 0 else 0
self.total_cols = len(data[0])
else:
self.total_rows = len(data[0])
self.total_cols = len(data) if self.total_rows > 0 else 0
self._compute_rows_cols_loaded()

def flags(self, index):
"""Set editable flag"""
return Qt.ItemIsEnabled

def get_value(self, index):
i = index.row()
j = index.column()
# we need to inverse column and row because of the way ylabels are generated
return str(self._data[j][i])
if self.orientation == Qt.Horizontal:
i, j = index.row(), index.column()
else:
i, j = index.column(), index.row()
return str(self._data[i][j])

# XXX: I wonder if we shouldn't return a 2D Numpy array of strings?
def get_values(self, left=0, top=0, right=None, bottom=None):
if right is None:
right = self.total_rows
if bottom is None:
bottom = self.total_cols
values = [list(line[left:right]) for line in self._data[top:bottom]]
return values
if self.orientation == Qt.Horizontal:
if right is None:
right = self.total_cols
if bottom is None:
bottom = self.total_rows
return [list(line[left:right]) for line in self._data[top:bottom]]
else:
if right is None:
right = self.total_rows
if bottom is None:
bottom = self.total_cols
return [list(line[top:bottom]) for line in self._data[left:right]]

def data(self, index, role=Qt.DisplayRole):
# print('data', index.column(), index.row(), self.rowCount(), self.columnCount(), '\n', self._data)
172 changes: 97 additions & 75 deletions larray_editor/arraywidget.py
Original file line number Diff line number Diff line change
@@ -536,33 +536,33 @@ def __init__(self, parent, data=None, readonly=False, bg_value=None, bg_gradient
self.model_axes = LabelsArrayModel(parent=self, readonly=readonly)
self.view_axes = LabelsView(parent=self, model=self.model_axes, position=(TOP, LEFT))

self.model_xlabels = LabelsArrayModel(parent=self, readonly=readonly)
self.view_xlabels = LabelsView(parent=self, model=self.model_xlabels, position=(TOP, RIGHT))
self.model_hlabels = LabelsArrayModel(parent=self, readonly=readonly)
self.view_hlabels = LabelsView(parent=self, model=self.model_hlabels, position=(TOP, RIGHT))

self.model_ylabels = LabelsArrayModel(parent=self, readonly=readonly)
self.view_ylabels = LabelsView(parent=self, model=self.model_ylabels, position=(BOTTOM, LEFT))
self.model_vlabels = LabelsArrayModel(parent=self, readonly=readonly, orientation=Qt.Vertical)
self.view_vlabels = LabelsView(parent=self, model=self.model_vlabels, position=(BOTTOM, LEFT))

self.model_data = DataArrayModel(parent=self, readonly=readonly, minvalue=minvalue, maxvalue=maxvalue)
self.view_data = DataView(parent=self, model=self.model_data, dtype=data.dtype, shape=data.shape)

self.data_adapter = LArrayDataAdapter(axes_model=self.model_axes, xlabels_model=self.model_xlabels,
ylabels_model=self.model_ylabels, data_model=self.model_data, data=data,
self.data_adapter = LArrayDataAdapter(axes_model=self.model_axes, hlabels_model=self.model_hlabels,
vlabels_model=self.model_vlabels, data_model=self.model_data, data=data,
bg_value=bg_value, bg_gradient=bg_gradient)

# Create vertical and horizontal scrollbars
self.vscrollbar = ScrollBar(self, self.view_data.verticalScrollBar())
self.hscrollbar = ScrollBar(self, self.view_data.horizontalScrollBar())

# Synchronize resizing
self.view_axes.horizontalHeader().sectionResized.connect(self.view_ylabels.updateSectionWidth)
self.view_axes.verticalHeader().sectionResized.connect(self.view_xlabels.updateSectionHeight)
self.view_xlabels.horizontalHeader().sectionResized.connect(self.view_data.updateSectionWidth)
self.view_ylabels.verticalHeader().sectionResized.connect(self.view_data.updateSectionHeight)
self.view_axes.horizontalHeader().sectionResized.connect(self.view_vlabels.updateSectionWidth)
self.view_axes.verticalHeader().sectionResized.connect(self.view_hlabels.updateSectionHeight)
self.view_hlabels.horizontalHeader().sectionResized.connect(self.view_data.updateSectionWidth)
self.view_vlabels.verticalHeader().sectionResized.connect(self.view_data.updateSectionHeight)
# Synchronize auto-resizing
self.view_axes.horizontalHeader().sectionHandleDoubleClicked.connect(self.resize_axes_column_to_contents)
self.view_xlabels.horizontalHeader().sectionHandleDoubleClicked.connect(self.resize_xlabels_column_to_contents)
self.view_hlabels.horizontalHeader().sectionHandleDoubleClicked.connect(self.resize_hlabels_column_to_contents)
self.view_axes.verticalHeader().sectionHandleDoubleClicked.connect(self.resize_axes_row_to_contents)
self.view_ylabels.verticalHeader().sectionHandleDoubleClicked.connect(self.resize_ylabels_row_to_contents)
self.view_vlabels.verticalHeader().sectionHandleDoubleClicked.connect(self.resize_vlabels_row_to_contents)

# synchronize specific methods
self.view_axes.allSelected.connect(self.view_data.selectAll)
@@ -572,18 +572,18 @@ def __init__(self, parent, data=None, readonly=False, bg_value=None, bg_gradient
self.view_data.signal_plot.connect(self.plot)

# Synchronize scrolling
# data <--> xlabels
self.view_data.horizontalScrollBar().valueChanged.connect(self.view_xlabels.horizontalScrollBar().setValue)
self.view_xlabels.horizontalScrollBar().valueChanged.connect(self.view_data.horizontalScrollBar().setValue)
# data <--> ylabels
self.view_data.verticalScrollBar().valueChanged.connect(self.view_ylabels.verticalScrollBar().setValue)
self.view_ylabels.verticalScrollBar().valueChanged.connect(self.view_data.verticalScrollBar().setValue)
# data <--> hlabels
self.view_data.horizontalScrollBar().valueChanged.connect(self.view_hlabels.horizontalScrollBar().setValue)
self.view_hlabels.horizontalScrollBar().valueChanged.connect(self.view_data.horizontalScrollBar().setValue)
# data <--> vlabels
self.view_data.verticalScrollBar().valueChanged.connect(self.view_vlabels.verticalScrollBar().setValue)
self.view_vlabels.verticalScrollBar().valueChanged.connect(self.view_data.verticalScrollBar().setValue)

# Synchronize selecting columns(rows) via hor.(vert.) header of x(y)labels view
self.view_xlabels.horizontalHeader().sectionPressed.connect(self.view_data.selectColumn)
self.view_xlabels.horizontalHeader().sectionEntered.connect(self.view_data.selectNewColumn)
self.view_ylabels.verticalHeader().sectionPressed.connect(self.view_data.selectRow)
self.view_ylabels.verticalHeader().sectionEntered.connect(self.view_data.selectNewRow)
self.view_hlabels.horizontalHeader().sectionPressed.connect(self.view_data.selectColumn)
self.view_hlabels.horizontalHeader().sectionEntered.connect(self.view_data.selectNewColumn)
self.view_vlabels.verticalHeader().sectionPressed.connect(self.view_data.selectRow)
self.view_vlabels.verticalHeader().sectionEntered.connect(self.view_data.selectNewRow)

# following lines are required to keep usual selection color
# when selecting rows/columns via headers of label views.
@@ -598,17 +598,17 @@ def __init__(self, parent, data=None, readonly=False, bg_value=None, bg_gradient
array_frame.setFrameStyle(QFrame.StyledPanel)
# remove borders of internal tables
self.view_axes.setFrameStyle(QFrame.NoFrame)
self.view_xlabels.setFrameStyle(QFrame.NoFrame)
self.view_ylabels.setFrameStyle(QFrame.NoFrame)
self.view_hlabels.setFrameStyle(QFrame.NoFrame)
self.view_vlabels.setFrameStyle(QFrame.NoFrame)
self.view_data.setFrameStyle(QFrame.NoFrame)
# Set layout of table views:
# [ axes ][xlabels]|V|
# [ylabels][ data ]|s|
# [ axes ][vlabels]|V|
# [hlabels][ data ]|s|
# | H. scrollbar |
array_layout = QGridLayout()
array_layout.addWidget(self.view_axes, 0, 0)
array_layout.addWidget(self.view_xlabels, 0, 1)
array_layout.addWidget(self.view_ylabels, 1, 0)
array_layout.addWidget(self.view_hlabels, 0, 1)
array_layout.addWidget(self.view_vlabels, 1, 0)
self.view_data.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
array_layout.addWidget(self.view_data, 1, 1)
array_layout.addWidget(self.vscrollbar, 0, 2, 2, 1)
@@ -662,6 +662,13 @@ def __init__(self, parent, data=None, readonly=False, bg_value=None, bg_gradient
btn_layout.addWidget(gradient_chooser)
self.gradient_chooser = gradient_chooser

label = QLabel("Horizontal Dimensions")
btn_layout.addWidget(label)
spin = QSpinBox(self)
spin.valueChanged.connect(self.nb_horizontal_dims_changed)
self.nb_horizontal_dims_spinbox = spin
btn_layout.addWidget(spin)

# Set widget layout
layout = QVBoxLayout()
layout.addLayout(self.filters_layout)
@@ -675,6 +682,8 @@ def __init__(self, parent, data=None, readonly=False, bg_value=None, bg_gradient
# See http://doc.qt.io/qt-4.8/qt-draganddrop-fridgemagnets-dragwidget-cpp.html for an example
self.setAcceptDrops(True)

self._raw_data_selection = None

def gradient_changed(self, index):
gradient = self.gradient_chooser.itemData(index) if index > 0 else None
self.model_data.set_bg_gradient(gradient)
@@ -760,8 +769,9 @@ def set_data(self, data=None, bg_value=None):
axes = la_data.axes
display_names = axes.display_names

# update data format and bgcolor
self._update_digits_scientific(la_data)
# update data format and bgcolor + dim spinbox
self._update_digits_scientific_dims(la_data)
self.nb_horizontal_dims_spinbox.setValue(1)

# update filters
filters_layout = self.filters_layout
@@ -777,11 +787,11 @@ def set_data(self, data=None, bg_value=None):

# reset default size
self.view_axes.set_default_size()
self.view_ylabels.set_default_size()
self.view_xlabels.set_default_size()
self.view_hlabels.set_default_size()
self.view_vlabels.set_default_size()
self.view_data.set_default_size()

def _update_digits_scientific(self, data):
def _update_digits_scientific_dims(self, data):
"""
data : LArray
"""
@@ -810,6 +820,9 @@ def _update_digits_scientific(self, data):

self.gradient_chooser.setEnabled(self.model_data.bgcolor_possible)

self.nb_horizontal_dims_spinbox.setMinimum(1)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move this out of the function (to set_data)

self.nb_horizontal_dims_spinbox.setMaximum(max(1, self.data_adapter.ndim - 1))

def choose_scientific(self, data):
# max_digits = self.get_max_digits()
# default width can fit 8 chars
@@ -902,37 +915,37 @@ def autofit_columns(self):
self.view_axes.autofit_columns()
for column in range(self.model_axes.columnCount()):
self.resize_axes_column_to_contents(column)
self.view_xlabels.autofit_columns()
for column in range(self.model_xlabels.columnCount()):
self.resize_xlabels_column_to_contents(column)
self.view_hlabels.autofit_columns()
for column in range(self.model_hlabels.columnCount()):
self.resize_hlabels_column_to_contents(column)

def resize_axes_column_to_contents(self, column):
# must be connected to view_axes.horizontalHeader().sectionHandleDoubleClicked signal
width = max(self.view_axes.horizontalHeader().sectionSize(column),
self.view_ylabels.sizeHintForColumn(column))
# no need to call resizeSection on view_ylabels (see synchronization lines in init)
self.view_vlabels.sizeHintForColumn(column))
# no need to call resizeSection on view_vlabels (see synchronization lines in init)
self.view_axes.horizontalHeader().resizeSection(column, width)

def resize_xlabels_column_to_contents(self, column):
def resize_hlabels_column_to_contents(self, column):
# must be connected to view_labels.horizontalHeader().sectionHandleDoubleClicked signal
width = max(self.view_xlabels.horizontalHeader().sectionSize(column),
width = max(self.view_hlabels.horizontalHeader().sectionSize(column),
self.view_data.sizeHintForColumn(column))
# no need to call resizeSection on view_data (see synchronization lines in init)
self.view_xlabels.horizontalHeader().resizeSection(column, width)
self.view_hlabels.horizontalHeader().resizeSection(column, width)

def resize_axes_row_to_contents(self, row):
# must be connected to view_axes.verticalHeader().sectionHandleDoubleClicked
height = max(self.view_axes.verticalHeader().sectionSize(row),
self.view_xlabels.sizeHintForRow(row))
# no need to call resizeSection on view_xlabels (see synchronization lines in init)
self.view_hlabels.sizeHintForRow(row))
# no need to call resizeSection on view_hlabels (see synchronization lines in init)
self.view_axes.verticalHeader().resizeSection(row, height)

def resize_ylabels_row_to_contents(self, row):
def resize_vlabels_row_to_contents(self, row):
# must be connected to view_labels.verticalHeader().sectionHandleDoubleClicked
height = max(self.view_ylabels.verticalHeader().sectionSize(row),
height = max(self.view_vlabels.verticalHeader().sectionSize(row),
self.view_data.sizeHintForRow(row))
# no need to call resizeSection on view_data (see synchronization lines in init)
self.view_ylabels.verticalHeader().resizeSection(row, height)
self.view_vlabels.verticalHeader().resizeSection(row, height)

@property
def dirty(self):
@@ -942,7 +955,7 @@ def dirty(self):
def accept_changes(self):
"""Accept changes"""
la_data = self.data_adapter.accept_changes()
self._update_digits_scientific(la_data)
self._update_digits_scientific_dims(la_data)

def reject_changes(self):
"""Reject changes"""
@@ -967,6 +980,9 @@ def digits_changed(self, value):
self.digits = value
self.model_data.set_format(self.cell_format)

def nb_horizontal_dims_changed(self, value):
self.data_adapter.update_nb_dims_hlabels(value)

def create_filter_combo(self, axis):
def filter_changed(checked_items):
self.data_adapter.change_filter(axis, checked_items)
@@ -1001,17 +1017,17 @@ def _selection_data(self, headers=True, none_selects_all=True):
if not self.data_adapter.ndim:
return raw_data
# FIXME: this is extremely ad-hoc.
# TODO: in the future (pandas-based branch) we should use to_string(data[self._selection_filter()])
# TODO: in the future (multi_index supported) we should use to_string(data[self._selection_filter()])
dim_headers = self.model_axes.get_values()
xlabels = self.model_xlabels.get_values(top=col_min, bottom=col_max)
topheaders = [[dim_header[0] for dim_header in dim_headers] + [label[0] for label in xlabels]]
hlabels = self.model_hlabels.get_values(left=col_min, right=col_max)
topheaders = [dims + labels for dims, labels in zip(dim_headers, hlabels)]
if self.data_adapter.ndim == 1:
return chain(topheaders, [chain([''], row) for row in raw_data])
else:
assert self.data_adapter.ndim > 1
ylabels = self.model_ylabels.get_values(left=row_min, right=row_max)
vlabels = self.model_vlabels.get_values(top=row_min, bottom=row_max)
return chain(topheaders,
[chain([ylabels[j][r] for j in range(len(ylabels))], row)
[chain([vlabels[j][r] for j in range(len(vlabels))], row)
for r, row in enumerate(raw_data)])
else:
return raw_data
@@ -1033,6 +1049,8 @@ def vrepr(v):
clipboard = QApplication.clipboard()
clipboard.setText(text)

self._raw_data_selection = self._selection_data(headers=False)

def to_excel(self):
"""View selection in Excel"""
if xw is None:
@@ -1052,22 +1070,25 @@ def paste(self):
if bounds is None:
return
row_min, row_max, col_min, col_max = bounds
clipboard = QApplication.clipboard()
text = str(clipboard.text())
list_data = [line.split('\t') for line in text.splitlines()]
try:
# take the first cell which contains '\'
pos_last = next(i for i, v in enumerate(list_data[0]) if '\\' in v)
except StopIteration:
# if there isn't any, assume 1d array
pos_last = 0
if pos_last:
# ndim > 1
list_data = [line[pos_last + 1:] for line in list_data[1:]]
elif len(list_data) == 2 and list_data[1][0] == '':
# ndim == 1
list_data = [list_data[1][1:]]
new_data = np.array(list_data)
# clipboard = QApplication.clipboard()
# text = str(clipboard.text())
# list_data = [line.split('\t') for line in text.splitlines()]
# try:
# # take the first cell which contains '\'
# pos_last = next(i for i, v in enumerate(list_data[0]) if '\\' in v)
# except StopIteration:
# # if there isn't any, assume 1d array
# pos_last = 0
# if pos_last:
# # ndim > 1
# list_data = [line[pos_last + 1:] for line in list_data[1:]]
# elif len(list_data) == 2 and list_data[1][0] == '':
# # ndim == 1
# list_data = [list_data[1][1:]]
# new_data = np.array(list_data)
if self._raw_data_selection is None:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ouch. This is no good. This prevents copy/paste from other applications!

return
new_data = np.array(self._raw_data_selection)
if new_data.shape[0] > 1:
row_max = row_min + new_data.shape[0]
if new_data.shape[1] > 1:
@@ -1093,12 +1114,13 @@ def plot(self):
row_min, row_max, col_min, col_max = self.view_data._selection_bounds()
dim_names = self.data_adapter.get_axes_names()
# labels
xlabels = [label[0] for label in self.model_xlabels.get_values(top=col_min, bottom=col_max)]
ylabels = self.model_ylabels.get_values(left=row_min, right=row_max)
# transpose ylabels
ylabels = [[str(ylabels[i][j]) for i in range(len(ylabels))] for j in range(len(ylabels[0]))]
# if there is only one dimension, ylabels is empty
if not ylabels:
xlabels = self.model_hlabels.get_values(left=col_min, right=col_max, bottom=self.data_adapter.nb_dims_hlabels)
xlabels = [[str(xlabels[i][j]) for i in range(len(xlabels))] for j in range(len(xlabels[0]))]
if self.data_adapter.ndim > 1:
ylabels = self.model_vlabels.get_values(top=row_min, bottom=row_max)
# transpose ylabels
ylabels = [[str(ylabels[i][j]) for i in range(len(ylabels))] for j in range(len(ylabels[0]))]
else:
ylabels = [[]]

assert data.ndim == 2
@@ -1118,7 +1140,7 @@ def plot(self):
else:
# plot each row as a line
xlabel = dim_names[-1]
xticklabels = [str(label) for label in xlabels]
xticklabels = ['\n'.join(row) for row in xlabels]
xdata = np.arange(col_max - col_min)
for row in range(len(data)):
ax.plot(xdata, data[row], label=' '.join(ylabels[row]))