# Author: Carsten Sachse 29-Aug-2011
# Copyright: EMBL (2010 - 2018), Forschungszentrum Juelich (2019 - 2021)
# License: see license.txt for details
"""
Program to interactively explore grid searches according to different criteria
"""
from functools import partial
import os
import shutil
from spring.csinfrastr.csdatabase import SpringDataBase, GridRefineTable, GridTable, grid_base
from spring.csinfrastr.csfeatures import Features
from spring.csinfrastr.csgui import QTabWidgetCloseable
from spring.csinfrastr.cslogger import Logger
from spring.csinfrastr.csproductivity import ExtLauncher
from spring.csinfrastr.csreadinput import OptHandler
from spring.segment3d.segclassreconstruct import SegClassReconstruct
from spring.springgui.springdataexplore import SpringDataExplore, SpringDataExploreTablePane, SpringDataExploreDraw, \
SpringDataExplore3d, SpringCommon
import sys
from EMAN2 import EMData
from PyQt5.QtCore import Qt
##from PyQt5.QtCore import pyqtSignal as SIGNAL
from PyQt5.QtWidgets import QApplication, QWidget, QStackedWidget, QPushButton, QComboBox, QSplitter, QTableWidget, \
QFileDialog, QGridLayout
from sqlalchemy.sql.expression import desc, asc
import numpy as np
[docs]class SegGridExplorePar(object):
"""
Class to initiate default dictionary with input parameters including help and range values and status dictionary
"""
def __init__(self):
# package/program identity
self.package = 'emspring'
self.progname = 'seggridexplore'
self.proginfo = __doc__
self.code_files = [self.progname]
self.seggridexplore_features = Features()
self.feature_set = self.seggridexplore_features.setup(self)
self.define_parameters_and_their_properties()
self.define_program_states()
[docs] def define_parameters_and_their_properties(self):
self.feature_set = self.seggridexplore_features.set_grid_database(self.feature_set, singular=False)
self.feature_set = self.set_subgrid_merge_option(self.feature_set)
self.feature_set = self.set_reconstitute_grid(self.feature_set)
self.feature_set = self.seggridexplore_features.set_interactive_vs_batch_mode(self.feature_set)
self.feature_set = self.set_file_prefix_symmetry_grid(self.feature_set)
self.feature_set = self.set_parameter_pair_to_be_extracted(self.feature_set)
[docs] def define_program_states(self):
self.feature_set.program_states['extract_desired_em_files']='Extract desired EM files'
self.program_states['launch_seggridexplore_gui']='Explore different grid combinations interactively'
[docs] def set_file_prefix_symmetry_grid(self, feature_set):
inp9 = 'EM name'
feature_set.parameters[inp9]='recvol.hdf'
feature_set.properties[inp9]=feature_set.file_properties(1,['hdf'],'saveFile')
feature_set.hints[inp9]='Template output name for associated EM files from grid search: accepted image file ' +\
'formats ({0})'.format(', '.join(feature_set.properties[inp9].ext))
feature_set.level[inp9]='beginner'
feature_set.relatives[inp9]='Batch mode'
return feature_set
[docs] def set_subgrid_merge_option(self, feature_set):
inp8 = 'Subgrid merge option'
feature_set.parameters[inp8] = False
feature_set.hints[inp8] = 'Merge subgrids from multiple grid searches. Either these subgrids were ' + \
'generated using the subgrid option in segrefine3drid or they originate from adjacent grids with the ' + \
'same grid spacing. Enter subgrids using wildcards * or ?? can be used to specify multiple input files.'
feature_set.level[inp8]='expert'
return feature_set
[docs] def set_reconstitute_grid(self, feature_set):
inp1 = 'Reconstitute Grid'
feature_set.parameters[inp1]=bool(True)
feature_set.hints[inp1]='In case subgrids are merged reconstitute entire grid by reproducing directory tree ' + \
'in one place and generate symbolic links to associated original files.'
feature_set.relatives[inp1]='Subgrid merge option'
feature_set.level[inp1]='expert'
return feature_set
[docs]class SegGridExplorePreparation(object):
def __init__(self, parset = None):
self.log = Logger()
if parset is not None:
self.feature_set = parset
p = self.feature_set.parameters
self.grid_database = p['Grid database']
self.infile = self.grid_database
self.outfile = p['EM name']
self.batch_mode = p['Batch mode']
self.parameter_pair = p['Parameter pair']
self.reconstitute_grid = p['Reconstitute Grid']
self.subgrid_merge = p['Subgrid merge option']
if self.subgrid_merge:
self.subgrid_files = Features().convert_list_of_files_from_entry_string(self.grid_database)
[docs]class SegGridExploreSupport(object):
[docs] def convert_None2nan(self, x):
"""
Converts None objects to nan, for use in
NumPy arrays. Returns an array.
>>> from spring.segment3d.seggridexplore import SegGridExploreSupport
>>> SegGridExploreSupport().convert_None2nan(5*[None])
[nan, nan, nan, nan, nan]
"""
newlist = []
for i in x:
if i is not None:
newlist.append(i)
else:
newlist.append(np.nan)
return newlist
[docs] def get_general_grid_parameters(self, grid_file):
grid_session = SpringDataBase().setup_sqlite_db(grid_base, grid_file)
grid_combinations = grid_session.query(GridRefineTable).order_by(asc(GridRefineTable.id)).all()
grid_parameters = grid_session.query(GridTable).filter(GridTable.id == grid_combinations[0].grid_id).first()
return grid_session, grid_combinations, grid_parameters
[docs] def get_rises_and_rotations_and_entered_symmetry_grid(self, grid_combinations):
rise_or_pitches = np.array([each_grid_combination.primary_value for each_grid_combination in grid_combinations])
rotation_or_unit_numbers = np.array([each_grid_combination.secondary_value for each_grid_combination in \
grid_combinations])
entered_symmetry_grid = SegClassReconstruct().convert_rise_rotation_or_pitch_unitnumber_series_to_grid_of_tuples\
(np.unique(rise_or_pitches), np.unique(rotation_or_unit_numbers))
return rise_or_pitches, rotation_or_unit_numbers, entered_symmetry_grid
[docs] def get_all_attr_from_search_result(self, all_grid_combinations, db_attr, filtered_attr, grid_data, zlabels, table):
list_of_val = [getattr(each_grid_combination, db_attr) for each_grid_combination in \
all_grid_combinations]
if set(list_of_val) != set([None]):
conv_values = self.convert_None2nan(list_of_val)
grid_data.append(conv_values)
zlabels += SpringDataBase().get_labels_from_table(table, db_attr)
filtered_attr += [db_attr]
return grid_data, zlabels, filtered_attr
[docs] def get_common_criterias(self):
return ['fsc_0143', 'fsc_05', 'xshift_error', 'inplane_error', 'outofplane_error', 'mean_peak',
'amp_corr_quarter_nyquist', 'amp_corr_half_nyquist', 'amp_corr_3quarter_nyquist',
'amp_correlation', 'helical_ccc_error', 'mean_helical_ccc', 'out_of_plane_dev',
'variance', 'asym_unit_count', 'avg_azimuth_sampling', 'dev_azimuth_sampling']
[docs] def get_criterias(self):
additional_criteria = ['phase_residual', 'diff_noise_ccc', 'diff_noise_amp_ccc', 'cross_correlation',
'diff_noise_pr','excluded_inplane_ratio', 'excluded_out_of_plane_ratio', 'excluded_total_ratio',
'noise_ccc', 'noise_amp_ccc', 'noise_pr', 'precision', 'recall', 'f1_measure', 'f05_measure']
combined_criteria = self.get_common_criterias() + additional_criteria
return combined_criteria
[docs]class SegGridExploreGuiPane(QWidget):
def __init__(self, grid, grid_pairs, zxy_labels, files_2d, files_3d, parent = None):
QWidget.__init__(self, parent)
self.tabWidget = QTabWidgetCloseable()
self.grid = grid
self.grid_pairs = grid_pairs
self.zxy_labels = zxy_labels
self.files_2d = files_2d
self.files_3d = files_3d
self.layout = QGridLayout()
if self.grid.shape[0] == 1 or self.grid.shape[-1] == 1:
self.add_1d_plot(((0, 0)), self.zxy_labels[1])
else:
self.setup_matrix_image_plot()
self.table_matrix = self.prepare_table_matrix_from_symmetry_grid_pairs(self.grid, self.grid_pairs)
self.table_pane = SpringDataExploreTablePane(self.table_matrix, ['GridID'] + list(self.zxy_labels))
self.table_pane.data_table.primary_id_signal.connect(partial(self.launch_external_viewer_from_index))
self.table_pane.data_table.setSelectionBehavior(QTableWidget.SelectRows)
self.table_pane.data_table.setToolTip('Open connected data point by clicking on beginning of row.')
self.splitter = QSplitter(Qt.Horizontal)
self.splitter.addWidget(self.table_pane)
self.splitter.addWidget(self.tabWidget)
self.layout.addWidget(self.splitter, 0, 0, 2, 5)
self.setLayout(self.layout)
self.external_launcher = ExtLauncher()
[docs] def setup_matrix_image_plot(self):
self.seggridexplore2d_tab = SpringDataExplore()
self.seggridexplore2d_tab.on_draw(np.array(self.grid), self.grid_pairs, self.zxy_labels, '2d')
self.seggridexplore2d_tab.picked_left_point.connect(partial(self.launch_external_viewers_from_index_pair))
self.seggridexplore2d_tab.picked_middle_point.connect(partial(self.add_additional_1d_tab))
self.seggridexplore2d_tab.main_frame.setToolTip('Left mouse button to open associated reprojections and ' + \
'power spectrum (and reconstruction if provided).\nMiddle mouse button to open 1D profile of associated ' + \
'{rise_pitch} and {rot_number}.'.format(rise_pitch=self.zxy_labels[1], rot_number=self.zxy_labels[2]))
self.tabWidget.addTab(self.seggridexplore2d_tab, '2D grid')
self.button3d = QPushButton()
self.button3d.setText('Explore3d')
##self.connect(self.button3d, SIGNAL('clicked()'), self.add_3d_surface_tab)
self.button3d.clicked.connect(self.add_3d_surface_tab)
self.pull_down3d = QComboBox()
self.pull_down3d.addItems(['Vispy (fast)', 'Matplotlib (slow)'])
self.pull_down3d.setToolTip('Choose between fast PyOpenGL (Vispy) display with less navigation options ' + \
'for large data grids or \nslow display with many navigation options for small data grids (matplotlib)')
self.layout.addWidget(self.pull_down3d, 2, 3, 1, 1)
self.layout.addWidget(self.button3d, 2, 4, 1, 1)
[docs] def get_corresponding_symmetry_pair_from_picked_indices(self, index_pair):
x_index, y_index = index_pair
symmetry_pair = self.grid_pairs[int(y_index)][int(x_index)]
return symmetry_pair, x_index, y_index
[docs] def add_1d_plot(self, index_pair, symmetry_pair):
self.seggridexplore1d_tab = SpringDataExplore()
self.seggridexplore1d_tab.on_draw(self.grid, self.grid_pairs, self.zxy_labels, '1d', index_pair)
self.tabWidget.addTab(self.seggridexplore1d_tab, '1D: ' + \
'{0}'.format(symmetry_pair.__str__().strip(')').strip('(')))
self.tabWidget.setCurrentIndex(self.tabWidget.indexOf(self.seggridexplore1d_tab))
self.seggridexplore1d_tab.picked_left_point.connect(partial(self.launch_external_viewers_from1d))
self.seggridexplore1d_tab.picked_label.connect(partial(self.define_labels_for_1d_profile))
self.seggridexplore1d_tab.index_2d.connect(partial(self.define_2d_index_for_1d_profile))
[docs] def add_additional_1d_tab(self, index_pair):
symmetry_pair, x_index, y_index = self.get_corresponding_symmetry_pair_from_picked_indices(index_pair)
self.add_1d_plot(index_pair, symmetry_pair)
[docs] def add_3d_surface_tab(self):
if str(str(self.pull_down3d.currentText())) == 'Vispy (fast)':
self.seggridexplore3d_tab = SpringDataExplore3d()
self.seggridexplore3d_tab.canvas.set_data(self.grid, self.grid_pairs, self.zxy_labels)
self.tabWidget.addTab(self.seggridexplore3d_tab, '3D surface (vp)')
elif str(str(self.pull_down3d.currentText())) == 'Matplotlib (slow)':
self.seggridexplore3d_tab = SpringDataExplore()
self.seggridexplore3d_tab.on_draw(self.grid, self.grid_pairs, self.zxy_labels, '3d')
self.tabWidget.addTab(self.seggridexplore3d_tab, '3D surface (mpl)')
self.tabWidget.setCurrentIndex(self.tabWidget.indexOf(self.seggridexplore3d_tab))
[docs] def define_labels_for_1d_profile(self, label):
self.label = label
[docs] def define_2d_index_for_1d_profile(self, index_pair):
self.index_2dpair = index_pair
[docs] def launch_external_viewers_from1d(self, picked_pair_from1d):
helical_rises, helical_rotations = \
SpringDataExploreDraw().extract_rise_rotation_from_symmetry_grid(self.grid_pairs)
if self.label == self.zxy_labels[1]:
previous_rotation_index = self.index_2dpair[0]
adjusted_rise = picked_pair_from1d[0]
matched_indices = np.where(np.array(helical_rises) == adjusted_rise)
y_index = matched_indices[0][0]
x_index = int(previous_rotation_index)
elif self.label == self.zxy_labels[2]:
previous_rise_index = self.index_2dpair[1]
adjusted_rotation = picked_pair_from1d[0]
matched_indices = np.where(np.array(helical_rotations) == adjusted_rotation)
y_index = int(previous_rise_index)
x_index = matched_indices[0][0]
stack_index = self.get_stack_index_from_rise_and_rotation_index(x_index, y_index)
self.launch_external_viewers(stack_index)
[docs] def launch_external_viewers(self, index):
if self.files_2d[index] is not None:
img = EMData()
if not hasattr(self, 'opened'):
self.opened = []
else:
[os.remove(each_opened) for each_opened in self.opened]
self.opened = []
for (each_file, stack_id) in self.files_2d[index]:
if each_file.endswith('hdf'):
print(each_file, stack_id)
img.read_image(each_file, stack_id)
file_name = '{0}_{1:05}{2}'.format(os.path.splitext(each_file)[0], stack_id, os.path.splitext(each_file)[1])
img.write_image(file_name)
self.external_launcher.qlaunch_open_file(os.path.abspath(file_name))
self.opened.append(file_name)
else:
self.external_launcher.qlaunch_open_file(each_file)
if self.files_3d[index] is not None:
self.external_launcher.qlaunch_open_file(self.files_3d[index][0])
[docs] def launch_external_viewer_from_index(self, stack_index):
self.launch_external_viewers(stack_index)
[docs] def launch_external_viewers_from_index_pair(self, index_pair):
x_index, y_index = index_pair
stack_index = self.get_stack_index_from_rise_and_rotation_index(x_index, y_index)
self.launch_external_viewers(stack_index)
[docs] def get_stack_index_from_rise_and_rotation_index(self, x_index, y_index):
x_count, y_count = self.grid_pairs.shape
stack_index = int(x_index + y_count * y_index)
return stack_index
[docs] def exitApp(self):
self.close()
[docs] def prepare_table_matrix_from_symmetry_grid_pairs(self, symmetry_grid_np, symmetry_grid_pairs):
sym_id = np.arange(symmetry_grid_np.size)
symmetry_grid_cc_seq = symmetry_grid_np.ravel()
rises_seq, rotation_seq = list(zip(*symmetry_grid_pairs.ravel()))
table_matrix = np.vstack([sym_id, symmetry_grid_cc_seq, rises_seq, rotation_seq])
return table_matrix
[docs]class SegGridExploreGui(SegGridExploreSupport, QWidget):
def __init__(self, feature_set, parent = None):
QWidget.__init__(self, parent)
self.feature_set = feature_set
self.properties = feature_set.properties
# self.grid_database = self.feature_set.parameters['Grid database']
self.grid_database = 'grid.db'
self = SpringCommon().setup_spring_page_top(self, feature_set)
self.grids, self.grid_pairs, self.zxy_labels, self.files_2d, self.files_3d, hints = \
self.get_grid_information_from_database(self.grid_database)
self.stackedPane = QStackedWidget()
self.currentPaneIndex = 0
self.panes = []
for pane_id, each_grid in enumerate(self.grids):
self.pane = SegGridExploreGuiPane(self.grids[pane_id], self.grid_pairs[pane_id], self.zxy_labels[pane_id],
self.files_2d[pane_id], self.files_3d[pane_id])
self.stackedPane.addWidget(self.pane)
self.panes.append(self.pane)
self.layout.addWidget(self.stackedPane, 1, 0, 2, 5)
self.stackedPane.setCurrentIndex(self.currentPaneIndex)
self.z_labels = [each_label[0] for each_label in self.zxy_labels ]
self.pull_down_panes = QComboBox()
self.pull_down_panes.addItems(self.z_labels)
self.pull_down_panes.setToolTip(hints)
##self.connect(self.pull_down_panes, SIGNAL('currentIndexChanged(int)'), self.update_panes)
self.pull_down_panes.currentIndexChanged.connect(self.update_panes)
self.layout.addWidget(self.pull_down_panes, 0, 3, 1, 1)
self.pull_down_pairs = QComboBox()
self.items = []
for each_grid in self.grid_pairs:
self.items.append([ 'Grid ID:{0}: {1}'.format(each_grid_id, str(each_pair).strip(')').strip('(')) for \
each_grid_id, each_pair in enumerate(each_grid.ravel())])
self.pull_down_pairs.addItems(self.items[self.currentPaneIndex])
self.layout.addWidget(self.pull_down_pairs, 3, 3, 1, 1)
self.save_button = QPushButton()
self.save_button.setText('Save')
self.save_button.setToolTip('Save associated EM files.')
self.save_button.setShortcut('Ctrl+S')
##self.connect(self.save_button, SIGNAL('clicked()'), self.saveEmFile)
self.save_button.clicked.connect(self.saveEmFile)
self.layout.addWidget(self.save_button, 3, 4, 1, 1)
self.setLayout(self.layout)
[docs] def update_panes(self, value):
self.currentPaneIndex = value
self.stackedPane.setCurrentIndex(self.currentPaneIndex)
[docs] def saveEmFile(self):
fname, _filter = QFileDialog.getSaveFileName(self , 'Save EM file', '.', 'Files ({0})'.\
format('*.' + ' *.'.join(list(self.properties.values())[1].ext)))
fname = str(fname)
index = self.pull_down_pairs.currentIndex()
files = self.files_2d[self.currentPaneIndex][index]
img = EMData()
for each_file_id, (each_file_name, each_stack_id) in enumerate(files):
img.read_image(each_file_name, each_stack_id)
img.write_image(os.path.splitext(fname)[0] + '2d' + os.path.splitext(fname)[-1], each_file_id)
volume_name = self.files_3d[self.currentPaneIndex][index][0]
if volume_name is not None:
img.read_image(volume_name)
img.write_image(os.path.splitext(fname)[0] + '3d' + os.path.splitext(fname)[-1])
[docs]class SegGridExploreMerge(SegGridExplorePreparation):
[docs] def check_whether_seamless_grid_merging_is_possible(self, primary_min, primary_max, primary_inc):
"""
>>> from spring.segment3d.seggridexplore import SegGridExplore
>>> s = SegGridExplore()
>>> s.check_whether_seamless_grid_merging_is_possible([16.25, 16.36], [16.35, 16.45], [0.01])
>>> s.check_whether_seamless_grid_merging_is_possible([16.25, 16.38], [16.35, 16.45], [0.01])
Traceback (most recent call last):
File '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/doctest.py', line 1254, in __run
compileflags, 1) in test.globs
File '<doctest spring.segment3d.seggridexplore.SegGridExploreMerge.check_whether_seamless_grid_merging_is_possible[3]>', line 1, in <module>
s.check_whether_seamless_grid_merging_is_possible([16.25, 16.38], [16.35, 16.45], [0.01])
File '/Users/sachse/Documents/en_casa/EMBL/08_python/26_springbox/develop-eggs/spring-dev/spring/segment3d/seggridexplore.py', line 517, in check_whether_seamless_grid_merging_is_possible
raise ValueError(msg)
ValueError: You have specified grid datbases to be merged that can not be merged seamlessly without gaps into a continuous grid.
"""
primary_min = [abs(each_min) for each_min in list(primary_min)]
primary_max = [abs(each_max) for each_max in list(primary_max)]
primary_inc = [abs(each_inc) for each_inc in list(primary_inc)]
primary_min.sort()
primary_max.sort()
for each_ext_id, each_max in enumerate(primary_max[:-1]):
next_min = primary_min[each_ext_id + 1]
computed_next_min = each_max + primary_inc[0]
if abs(computed_next_min - next_min) > primary_inc[0]/100.0:
msg = 'You have specified grid datbases to be merged that can not be merged seamlessly without ' + \
'gaps into a continuous grid.'
raise ValueError(msg)
[docs] def update_new_grid_min_and_max_after_merge(self, primary_min, primary_max, second_min, second_max, merged_session):
grid = merged_session.query(GridTable).first()
grid.primary_min = min(primary_min)
grid.primary_max = max(primary_max)
grid.second_min = min(second_min)
grid.second_max = max(second_max)
merged_session.merge(grid)
merged_session.commit()
return merged_session
[docs] def merge_grids_from_files(self, sorted_subgrid_files, primary_min, primary_max, second_min, second_max,
primary_inc, second_inc, same_increments):
same_max_and_mins = len(primary_min) + len(primary_max) + len(second_min) + len(second_max)
if same_max_and_mins == 4 and same_increments == 2:
merged_session = self.perform_simple_additive_merge(sorted_subgrid_files)
if not same_max_and_mins == 4 and same_increments == 2:
if 0 in second_inc or 0 in primary_inc:
pass
else:
self.check_whether_seamless_grid_merging_is_possible(primary_min, primary_max, primary_inc)
self.check_whether_seamless_grid_merging_is_possible(second_min, second_max, second_inc)
merged_session = self.perform_simple_additive_merge(sorted_subgrid_files)
merged_session = self.update_new_grid_min_and_max_after_merge(primary_min, primary_max, second_min,
second_max, merged_session)
os.rename('grid.db', 'grid_not_sorted.db')
tmp_session = SpringDataBase().setup_sqlite_db(grid_base, 'grid_not_sorted.db')
grid = tmp_session.query(GridRefineTable).\
order_by(GridRefineTable.primary_value.asc()).\
order_by(GridRefineTable.secondary_value.asc()).all()
shutil.copy('grid_not_sorted.db', 'grid.db')
merged_session = SpringDataBase().setup_sqlite_db(grid_base, 'grid.db')
columns = SpringDataBase().get_columns_from_table(GridRefineTable)
for each_grid_id, each_grid_point in enumerate(grid):
data = SpringDataBase().get_data_from_entry(columns, each_grid_point)
data['id'] = each_grid_id + 1
merged_session.merge(GridRefineTable(**data))
merged_session.commit()
os.remove('grid_not_sorted.db')
return merged_session
[docs] def merge_subgrids_into_single_grid_file(self, subgrid_files):
split_files = [os.path.split(each_file)[-1] for each_file in subgrid_files]
sorted_subgrid_files = [subgrid_files[each_ind] for each_ind in np.argsort(split_files)]
file_grid_parameters = []
for each_subgrid_file in sorted_subgrid_files:
each_grid = SpringDataBase().setup_sqlite_db(grid_base, each_subgrid_file)
grid_entries = each_grid.query(GridTable).first()
file_grid_parameters.append(grid_entries)
primary_var = set([each_file_grid.primary_variable for each_file_grid in file_grid_parameters])
secondary_var = set([each_file_grid.secondary_variable for each_file_grid in file_grid_parameters])
primary_min = set([each_file_grid.primary_min for each_file_grid in file_grid_parameters])
primary_max = set([each_file_grid.primary_max for each_file_grid in file_grid_parameters])
second_min = set([each_file_grid.second_min for each_file_grid in file_grid_parameters])
second_max = set([each_file_grid.second_max for each_file_grid in file_grid_parameters])
primary_inc = set([each_file_grid.primary_inc for each_file_grid in file_grid_parameters])
second_inc = set([each_file_grid.second_inc for each_file_grid in file_grid_parameters])
same_variables = len(primary_var) + len(secondary_var)
same_increments = len(primary_inc) + len(second_inc)
for each_inc in list(primary_inc) + list(second_inc):
if each_inc == 0:
same_variables = 2
same_increments = 2
entities = []
if not same_variables == 2:
entities.append('variables')
if not same_increments == 2:
entities.append('increments')
if not same_variables == 2 or not same_increments == 2:
msg = ''
for each_entity in entities:
msg += 'You have specified grid databases to be merged that do not match in their primary or ' + \
'secondary {0}. This way they cannot be merged. Double-check the specified files. '.format(each_entity)
raise ValueError(msg)
merged_session = self.merge_grids_from_files(sorted_subgrid_files, primary_min, primary_max, second_min,
second_max, primary_inc, second_inc, same_increments)
return merged_session
[docs] def write_symbolic_links_to_have_merged_data_in_one_place(self, grid_session):
grid_points = grid_session.query(GridRefineTable).all()
for each_grid_point in grid_points:
for each_entry in each_grid_point.em_files_2d + each_grid_point.em_files_3d:
if type(each_entry) is tuple:
each_file = each_entry[0]
else:
each_file = each_entry
local_dir = os.path.split(os.path.dirname(each_file))[-1]
if not os.path.isdir(local_dir):
os.mkdir(local_dir)
os.chdir(local_dir)
os.symlink(os.path.relpath(each_file), os.path.basename(each_file))
os.chdir(os.pardir)
[docs]class SegGridExplore(SegGridExploreMerge):
[docs] def launch_seggridexplore_gui(self, feature_set):
self.log.fcttolog()
app = QApplication(sys.argv)
gridexplor = SegGridExploreGui(feature_set)
gridexplor.show()
app.exec_()
[docs] def launch_seggridexplore(self):
if self.subgrid_merge:
grid_session = self.merge_subgrids_into_single_grid_file(self.subgrid_files)
if self.reconstitute_grid:
self.write_symbolic_links_to_have_merged_data_in_one_place(grid_session)
else:
shutil.copy(self.grid_database, 'grid.db')
self.log.plog(10)
if not self.batch_mode:
self.launch_seggridexplore_gui(self.feature_set)
else:
self.extract_desired_em_files()
self.log.endlog(self.feature_set)
[docs]def main():
# Option handling
parset = SegGridExplorePar()
mergeparset = OptHandler(parset)
######## Program
sseg = SegGridExplore(mergeparset)
sseg.launch_seggridexplore()
if __name__ == '__main__':
main()