Skip to content

Commit

Permalink
Added sample editing in straditizers axes
Browse files Browse the repository at this point in the history
  • Loading branch information
Chilipp committed May 7, 2018
1 parent 04fd3e2 commit 85b3709
Show file tree
Hide file tree
Showing 5 changed files with 687 additions and 109 deletions.
5 changes: 3 additions & 2 deletions straditize/binary.py
Original file line number Diff line number Diff line change
Expand Up @@ -1889,13 +1889,14 @@ def _update_rough_locs(self):
rough = np.tile(missing[:, np.newaxis], (1, len(df.columns) * 2))
rough[:, 1::2] += 1
new = pd.DataFrame(
rough, index=missing,
rough.astype(int), index=missing,
columns=pd.MultiIndex.from_product(
[df.columns, ['vmin', 'vmax']]))
if self._rough_locs is None:
self.rough_locs = new
else:
self.rough_locs = new.combine_first(self.rough_locs)
self.rough_locs = new.combine_first(
self.rough_locs).astype(int)

def _add_samples_from_array(self, samples):
df = self.sample_locs
Expand Down
98 changes: 45 additions & 53 deletions straditize/straditizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ def indexes(self):
@property
def column_indexes(self):
"""The horizontal indexes for each column"""
bounds = self.data_reader.column_bounds + self.data_xlim[0]
bounds = self.data_reader.all_column_bounds + self.data_xlim[0]
return [
pd.Index(np.arange(se)) for se in bounds]
pd.Index(np.arange(*se)) for se in bounds]

#: The :class:`straditize.binary.DataReader` instance to digitize the
#: data
Expand Down Expand Up @@ -752,47 +752,51 @@ def marks_for_samples(self):
def _new_mark(pos, artists=[]):
return cm.CrossMarks(
pos, zorder=2, idx_v=idx_v, idx_h=idx_h,
xlim=xlim, ylim=ylim, c='g', alpha=0.5,
linewidth=0.5, selectable=['h'], auto_hide=True,
marker='o', connected_artists=artists,
ax=ax)
xlim=xlim, ylim=ylim, alpha=0.5,
linewidth=1.5, selectable=['h'], marker='x',
select_props={'c': 'r', 'lw': 2.0},
connected_artists=artists, ax=ax)

def new_mark(pos):
return _new_mark(
return [_new_mark(
[starts + full_df.loc[np.round(pos[-1] - ylim[0])],
np.round(pos[-1])])
np.round(pos[-1])])]

def new_mark_and_range(key, row):
def new_mark_and_range(key, row, row_indices):
artists = []
try:
indices = reader.rough_locs.loc[key]
except KeyError:
pass
else:
for i, l in enumerate(indices):
if l:
for (col, val), s in zip(row.items(), starts):
try:
imin, imax = row_indices[2*col:2*col+2]
except KeyError:
pass
else:
if imin >= 0:
artists.extend(ax.plot(
starts[i] + full_df.loc[l, i],
np.array(l) + ylim[0], c='0.5', lw=0, marker='+'))
return _new_mark([starts + row.tolist(), key + ylim[0]],
artists=artists)
s + full_df.iloc[imin:imax, col],
ylim[0] + np.arange(imin, imax), c='0.5', lw=0,
marker='+'))
return [_new_mark([starts + np.array(row), min(ylim) + key],
artists)]

reader = self.data_reader
if reader.full_df is None:
reader.digitize()
df = reader.sample_locs()
full_df = reader.full_df
df = reader.sample_locs
full_df = reader._full_df
self.remove_marks()
ax = self.ax
idx_v = self.indexes['y']
idx_h = self.column_indexes
xlim = self.data_xlim
ylim = self.data_ylim
starts = reader._get_column_starts() + xlim[0]
self.marks = marks = [
new_mark_and_range(key, row)
for key, row in df.iterrows()]

starts = reader.all_column_starts + xlim[0]
if not len(df):
self.marks = marks = []
else:
self.marks = marks = list(chain.from_iterable(
new_mark_and_range(key, row, indices)
for (key, row), (key2, indices) in zip(
df.iterrows(), reader.rough_locs.iterrows())))
if marks:
marks[0].connect_marks(marks)
self.create_magni_marks(marks)
Expand All @@ -801,33 +805,21 @@ def new_mark_and_range(key, row):
self.mark_cids.add(self.fig.canvas.mpl_connect(
'button_press_event', self._remove_mark_event))

def update_samples(self):
index = np.array(np.ceil([mark.y for mark in self.marks]))
data = np.array(np.ceil([mark.x for mark in self.marks]))
df = pd.DataFrame(data, index=index)
def update_samples(self, remove=True):
y0 = min(self.data_ylim)
x0 = min(self.data_xlim)
starts = self.data_reader.all_column_starts[np.newaxis] + x0
index = np.array(np.ceil([mark.y for mark in self.marks])) - y0
data = np.array(np.ceil([mark.xa for mark in self.marks])) - starts
df = pd.DataFrame(data, index=index.astype(int)).sort_index()
self.data_reader.sample_locs = df
# set the rough locations equal to the samples if they have not
# already been set, otherwise update
if self.data_reader.rough_locs is None:
self.data_reader.rough_locs = pd.DataFrame(
data.reshape(data.shape + (1, )),
index=index)
else:
old = self.data_reader.rough_locs
old['in_old'] = True
new = df[[]]
new['in_new'] = True
joined = old.join(new, how='right')
missing_idx = joined[
joined['in_old'].isnull().values &
joined['in_new'].notnull().values].index.values
missing = df.loc[missing_idx, :].values
joined[missing_idx, :] = missing.reshape(
missing.shape + (1, ))
joined.drop(['in_old', 'in_new'], axis=1, inplace=True)
joined.sort_index(inplace=True)
self.data_reader.rough_locs = joined
self.remove_marks()
self.data_reader._update_rough_locs()
if remove:
self.remove_marks()
try:
del self._plotted_full_df
except AttributeError:
pass

def marks_for_samples_sep(self, nrows=3):
def _new_mark(pos, ax, artists=[]):
Expand Down
80 changes: 61 additions & 19 deletions straditize/widgets/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,17 @@ def __init__(self, straditizer_widgets):
self.btn_reset_samples = QPushButton('Reset')
self.btn_reset_samples.setToolTip('Reset the samples')

self.cb_edit_separate = QCheckBox('In separate figure')
self.cb_edit_separate.setToolTip(
'Edit the samples in a separate figure where you have one '
'plot for each column')
self.txt_edit_rows = QLineEdit()
self.txt_edit_rows.setValidator(QIntValidator(1, 1000))
self.txt_edit_rows.setToolTip(
'The number of plot rows in the editing figure?')
self.txt_edit_rows.setText('3')
self.txt_edit_rows.setEnabled(False)

self.txt_min_len = QLineEdit()
self.txt_min_len.setToolTip(
'Minimum length of a potential sample to include')
Expand Down Expand Up @@ -378,6 +389,7 @@ def __init__(self, straditizer_widgets):
self.btn_new_exaggeration.clicked.connect(self.init_exaggerated_reader)
self.btn_select_exaggerations.clicked.connect(
self.select_exaggerated_features)
self.cb_edit_separate.stateChanged.connect(self.toggle_txt_edit_rows)

# disable warning if bars cannot be separated
warnings.filterwarnings('ignore', 'Could not separate bars',
Expand Down Expand Up @@ -410,6 +422,9 @@ def refresh(self):
def toggle_txt_fromlast(self, state):
self.txt_fromlast.setEnabled(state == Qt.Checked)

def toggle_txt_edit_rows(self, state):
self.txt_edit_rows.setEnabled(state == Qt.Checked)

def toggle_txt_from0(self, state):
self.txt_from0.setEnabled(state == Qt.Checked)

Expand Down Expand Up @@ -473,7 +488,7 @@ def toggle_txt_tolerance(self, s):
self.straditizer.data_reader is not None):
self.txt_tolerance.setText(str(getattr(
self.straditizer.data_reader, 'tolerance', '')))
# otherwise use a default value of 10 for rounded bars
# otherwise use a default value of 10 for roundedtt bars
elif enable and int(self.txt_tolerance.text() or 2) == 2:
self.txt_tolerance.setText('10')
# and 2 for rectangular bars
Expand Down Expand Up @@ -833,6 +848,16 @@ def setup_children(self, item):

self.tree.setItemWidget(edit_child, 0, w)

edit_child2 = QTreeWidgetItem(0)
samples_box = QGridLayout()
samples_box.addWidget(self.cb_edit_separate, 0, 0, 1, 2)
samples_box.addWidget(QLabel('Number of rows:'), 1, 0)
samples_box.addWidget(self.txt_edit_rows, 1, 1)
w = QWidget()
w.setLayout(samples_box)
edit_child.addChild(edit_child2)
self.tree.setItemWidget(edit_child2, 0, w)

def init_reader(self):
"""Initialize the reader"""
# make sure, the StackedReader is registered
Expand Down Expand Up @@ -979,21 +1004,28 @@ def load_samples(self, fname=None):

def edit_samples(self):
from psyplot_gui.main import mainwindow
from straditize.widgets.samples_table import MultiCrossMarksEditor
fig, axes = self.straditizer.marks_for_samples_sep()
self._samples_fig = fig
if mainwindow.figures: # using psyplot backend
fig_dock = self._samples_fig.canvas.manager.window
stradi_dock = self.straditizer.ax.figure.canvas.manager.window
mainwindow.tabifyDockWidget(stradi_dock, fig_dock)
a = fig_dock.toggleViewAction()
if not a.isChecked():
a.trigger()
fig_dock.raise_()
self._samples_editor = editor = MultiCrossMarksEditor(
self.straditizer, axes=axes)
from straditize.widgets.samples_table import (
MultiCrossMarksEditor, SingleCrossMarksEditor)
draw_sep = self.cb_edit_separate.isChecked()
if draw_sep:
fig, axes = self.straditizer.marks_for_samples_sep()
self._samples_fig = fig
if mainwindow.figures: # using psyplot backend
fig_dock = self._samples_fig.canvas.manager.window
stradi_dock = self.straditizer.ax.figure.canvas.manager.window
mainwindow.tabifyDockWidget(stradi_dock, fig_dock)
a = fig_dock.toggleViewAction()
if not a.isChecked():
a.trigger()
fig_dock.raise_()
self._samples_editor = editor = MultiCrossMarksEditor(
self.straditizer, axes=axes)
else:
self.straditizer.marks_for_samples()
self._samples_editor = editor = SingleCrossMarksEditor(
self.straditizer)
dock = editor.to_dock(
mainwindow, title='samples editor')
mainwindow, title='Samples editor')
editor.show_plugin()
editor.maybe_tabify()
editor.raise_()
Expand All @@ -1003,24 +1035,34 @@ def edit_samples(self):
editor.table.zoom_to_cells(
chain.from_iterable([i] * ncols for i in range(nrows)),
list(range(ncols)) * nrows)
args = (self.straditizer.draw_figure, ) if not draw_sep else ()
self.connect2apply(lambda: self.straditizer.update_samples_sep(),
self._close_samples_fig,
dock.close,
self.straditizer_widgets.refresh)
self.straditizer_widgets.refresh, *args)
self.connect2cancel(self.straditizer.remove_marks,
self._close_samples_fig,
dock.close)
dock.close, *args)
self.maybe_show_btn_reset_samples()

def _close_samples_fig(self):
import matplotlib.pyplot as plt
plt.close(self._samples_fig)
for l in self._samples_editor.table.model().lines:
try:
l.remove()
except ValueError:
pass
try:
plt.close(self._samples_fig)
except AttributeError:
pass
else:
del self._samples_fig
del self._samples_editor
try:
del self.straditizer._plotted_full_df
except AttributeError:
pass
del self._samples_fig

def digitize(self):
reader = self.reader
Expand Down

0 comments on commit 85b3709

Please sign in to comment.