コード例 #1
0
    def __init__(self):
        super(ChannelArithmeticDialog, self).__init__()
        # Channel indexes in the arithmetic calculator are denoted using a
        # regular expression: one or more digits in square brackets (e.g. [1234]).
        # First digit is zero and nothing afterwards or first digit is in [1-9] and
        # there are possibly more digits afterwards.
        # Starting index is zero.
        self.channel_pattern = re.compile(r"\[(0|[1-9]\d*)\]")

        # Use QT's global threadpool, documentation says: "This global thread pool
        # automatically maintains an optimal number of threads based on the
        # number of cores in the CPU."
        self.threadpool = QThreadPool.globalInstance()

        # Configure the help dialog.
        self.help_dialog = HelpDialog(w=700, h=500)
        self.help_dialog.setWindowTitle("Channel Arithmetic Help")
        self.help_dialog.set_rst_text(
            inspect.getdoc(self), pygments_css_file_name="pygments_dark.css")

        self.__create_gui()
        self.setWindowTitle("Channel Arithmetic")
        self.processing_error = False

        self.show()
コード例 #2
0
    def __init__(self):
        super().__init__()

        # Create all dialogs
        self.about_dialog = AboutDialog()
        self.tutorial_dialog = HelpDialog()
        self.size_warning = SizeWarning()
        self.source_warning = SourceCodeWarning()
        self.about_dialog.hide()
        self.tutorial_dialog.hide()
        self.size_warning.hide()
        self.source_warning.hide()

        # Read config file to find out if this is first run
        configpath = str(
            Path.home()) + "/.config/codeblock_visual_studio/config"
        configread = configparser.ConfigParser()
        config = configread.read(configpath)
        if len(config) == 0:
            # First Run, open tutorial and autogenerate config
            os.makedirs(os.path.dirname(configpath), exist_ok=True)
            with open(configpath, 'w') as f:
                f.write("")
                self.tutorial_dialog.exec_()

        # Bind buttons to functions and initialize varibales
        self.bind()
        self.classViewFileIndex = {}
        self.lines = []
        self.lint = ()
        self.go_ahead = True
        self.class_list = {}
コード例 #3
0
    def __init__(self):
        super(ExportChannelSettingsDialog, self).__init__()

        # Configure the help dialog.
        self.help_dialog = HelpDialog(w=700, h=500)
        self.help_dialog.setWindowTitle("Export Channel Settings Help")
        self.help_dialog.set_rst_text(
            inspect.getdoc(self), pygments_css_file_name="pygments_dark.css")

        self.__create_gui()
        self.setWindowTitle("Export Channel Settings to csv File")
        self.show()
コード例 #4
0
    def initGui(self):
        """Create the menu entries and toolbar icons inside the QGIS GUI."""

        icon_path = ':/plugins/mainPlug\icon.png'
        about_path = ':/plugins/mainPlug\\about.png'
        """self.add_action(
            icon_path,
            store_val=0,
            text=self.tr(u'PlotData'),
            callback=self.run,
            parent=self.iface.mainWindow())"""
        """self.add_action(
            icon_path,
            store_val=1,
            text=self.tr(u'File_Import_Test'),
            callback=self.run_file_input,
            dialog=FileInputDialog()
        )"""
        self.add_action(about_path,
                        store_val=2,
                        text=self.tr(u'About'),
                        callback=self.runabout,
                        dialog=AboutDialog())

        self.com.log("Add_action: About", 0)
        self.add_action(icon_path,
                        store_val=3,
                        text=self.tr(u'Calculate NDVI'),
                        callback=self.run_calc_ndvi,
                        dialog=ImportExportDialog())
        self.com.log("Add_Action: Calculate NDVI", 0)

        self.add_action(icon_path,
                        store_val=5,
                        text=self.tr(u'Plot Soil data'),
                        callback=self.run_SoilSample,
                        dialog=CsvInputdialog())

        self.add_action(icon_path,
                        store_val=4,
                        text=self.tr(u'Help'),
                        callback=self.run_help,
                        dialog=HelpDialog())

        self.add_action(icon_path,
                        store_val=6,
                        text=self.tr(u'Krig'),
                        callback=self.run_krig,
                        dialog=KrigDialog())
コード例 #5
0
class ChannelArithmeticDialog(ieb.ImarisExtensionBase):
    """
    Channel Arithmetic and Beyond
    =============================
    `View on GitHub <https://github.com/niaid/imaris_extensions>`_

    This program enables one to specify arithmetic expressions which are used to
    create new channels. The basic arithmetic operations are supported: +,-,*,/,**.
    More advanced operations that run short `SimpleITK <https://simpleitk.org/>`_
    code snippets are also supported.

    Channels are referenced using square brackets and the channel index, starting
    at **zero**. To apply an expression to all channels, use the channel index 'i'.

    When creating a single new channel, the arithmetic expression consists of literal
    channel numbers, one can select a name and color for the new channel. When
    creating multiple new channels, the arithmetic expression is applied to all channels,
    the postfix '_modified' is appended to the original channel names and the original
    color is copied over. Note that for all channels created by the program the
    channel description will include the arithmetic expression used to create that
    channel. This transparently supports your efforts to conduct reproducible
    research.

    Because an Imaris image has a specific pixel type (8, 16, 32 bit unsigned integer
    and 32 bit floating point) all computations are performed using a 32 bit floating
    point representation and then clamped to the range of the image's pixel type.

    The program allows you to use the same expression on multiple files. In this
    case literal channel values are limited by the number of shared channels. Thus,
    if working with two files one with three channels and one with four channels,
    the valid literal channel values are limited to 0, 1, 2. We cannot use 3 as it does not
    exist in all files. On the other hand, if our autofluorescence channel is one
    of these channels, e.g. channel 0, we can subtract it from all channels in
    both files, `[i]-[0]`.

    Basic Examples
    --------------

    Multiply channels zero and three:

    .. code-block:: Python

      [0]*[3]

    Multiply channels zero and three and subtract the result from channel four:

    .. code-block:: Python

      [4] - ([0]*[3])

    Duplicate all channels:

    .. code-block:: Python

      [i]

    Subtract channel zero from all channels:

    .. code-block:: Python

      [i]-[0]


    Advanced Examples
    -----------------

    Threshold channel one using a value of 100, resulting image is binary
    values in {0,1}:

    .. code-block:: Python

      [1]>100

    Threshold a specific channel to create a binary result using the Otsu
    filter:

    .. code-block:: Python

      sitk.OtsuThreshold([1], 0, 1)

    Threshold a specific channel retaining the values above the threshold:

    .. code-block:: Python

      sitk.Cast([1]>100, sitk.sitkFloat32)*[1]

    Threshold a specific channel, get all connected components, then
    sort the components according to size, discarding those smaller than a minimum
    size and create a binary mask corresponding to the largest component, which is
    the first label(second largest component label is 2 etc.)

    .. code-block:: Python

      sitk.RelabelComponent(sitk.ConnectedComponent([1]>100), minimumObjectSize = 50)==1

    Create a binary mask representing the colocalization of two channels,
    intensity values below 20 are considred noise:

    .. code-block:: Python

      ([1]>20)*([2]>20)

    Create a binary mask representing the colocalization of two channels.
    We are interested in all pixels in channel 2 that have a value above 20
    and that are less than 1.0um away from pixels in channel 1 that have a value
    above 100 (**note**: this operation yields different results when run using
    a slice-by-slice approach vs. a volumetric approach):

    .. code-block:: Python

        (sitk.Cast([2]>20, sitk.sitkFloat32) *
         sitk.Abs(sitk.SignedMaurerDistanceMap([1]>100, insideIsPositive=False, squaredDistance=False, useImageSpacing=True)))<=1.0

    Create a binary mask using thresholding and then perform morphological
    closing (dilation followed by erosion) with distance maps, useful
    for filling holes:

    .. code-block:: Python

      sitk.SignedMaurerDistanceMap(sitk.SignedMaurerDistanceMap([1]>100, insideIsPositive=False, squaredDistance=False, useImageSpacing=True) < 1.0, insideIsPositive=False, squaredDistance=False, useImageSpacing=True)<-1.0

    Create a binary mask using thresholding and then perform morphological
    opening (erosion followed by dilation) with distance maps, useful
    for removing small islands:

    .. code-block:: Python

      sitk.SignedMaurerDistanceMap(sitk.SignedMaurerDistanceMap([1]>100, insideIsPositive=False, squaredDistance=False, useImageSpacing=True) < -0.2, insideIsPositive=False, squaredDistance=False, useImageSpacing=True)<0.2
    """  # noqa

    def __init__(self):
        super(ChannelArithmeticDialog, self).__init__()
        # Channel indexes in the arithmetic calculator are denoted using a
        # regular expression: one or more digits in square brackets (e.g. [1234]).
        # First digit is zero and nothing afterwards or first digit is in [1-9] and
        # there are possibly more digits afterwards.
        # Starting index is zero.
        self.channel_pattern = re.compile(r"\[(0|[1-9]\d*)\]")

        # Use QT's global threadpool, documentation says: "This global thread pool
        # automatically maintains an optimal number of threads based on the
        # number of cores in the CPU."
        self.threadpool = QThreadPool.globalInstance()

        # Configure the help dialog.
        self.help_dialog = HelpDialog(w=700, h=500)
        self.help_dialog.setWindowTitle("Channel Arithmetic Help")
        self.help_dialog.set_rst_text(
            inspect.getdoc(self), pygments_css_file_name="pygments_dark.css")

        self.__create_gui()
        self.setWindowTitle("Channel Arithmetic")
        self.processing_error = False

        self.show()

    def __create_gui(self):
        menu_bar = self.menuBar()
        # Force menubar to be displayed in the application on OSX/Linux, otherwise it
        # is displayed in the system menubar
        menu_bar.setNativeMenuBar(False)
        self.help_button = QPushButton("Help")
        self.help_button.clicked.connect(self.help_dialog.show)
        menu_bar.setCornerWidget(self.help_button, Qt.TopLeftCorner)

        central_widget = QWidget(self)
        gui_layout = QVBoxLayout()
        central_widget.setLayout(gui_layout)
        self.setCentralWidget(central_widget)

        select_files_widget = self.__create_select_files_widget()
        arithmetic_widget = self.__create_arithmetic_widget()

        self.stack = QStackedWidget(self)
        self.stack.addWidget(select_files_widget)
        self.stack.addWidget(arithmetic_widget)
        gui_layout.addWidget(self.stack)

        self.status_bar = self.statusBar()

    def closeEvent(self, event):
        """
        Override the closeEvent method so that clicking the 'x' button also
        closes all of the dialogs.
        """
        self.help_dialog.close()
        event.accept()

    def __create_arithmetic_widget(self):
        wid = QWidget(self)
        arithmetic_layout = QVBoxLayout()
        wid.setLayout(arithmetic_layout)

        self.valid_indexes_label = QLabel("")
        arithmetic_layout.addWidget(self.valid_indexes_label)

        layout = QHBoxLayout()
        layout.setAlignment(Qt.AlignLeft)
        layout.addWidget(QLabel("Enter new channel arithmetic expression:"))
        arithmetic_layout.addLayout(layout)

        self.arithmetic_expression_text_edit = QTextEdit()
        arithmetic_layout.addWidget(self.arithmetic_expression_text_edit)

        self.slice_by_slice_checkbox = QCheckBox(
            "Slice by slice (smaller memory footprint).")
        arithmetic_layout.addWidget(self.slice_by_slice_checkbox)

        layout = QHBoxLayout()
        layout.addWidget(QLabel("New channel name:"))
        self.new_channel_name_line_edit = QLineEdit()
        layout.addWidget(self.new_channel_name_line_edit)
        arithmetic_layout.addLayout(layout)

        layout = QHBoxLayout()
        layout.addWidget(QLabel("New channel color:"))
        self.new_channel_color_button = QPushButton()
        self.new_channel_color_button.clicked.connect(
            self.__select_color_callback)
        layout.addWidget(self.new_channel_color_button)
        arithmetic_layout.addLayout(layout)

        self.apply_button = QPushButton("Apply")
        self.apply_button.clicked.connect(self.__channel_arithmetic_wrapper)
        arithmetic_layout.addWidget(self.apply_button)

        progress_wid = QWidget()
        self.progress_grid_layout = QGridLayout()
        progress_wid.setLayout(self.progress_grid_layout)
        scroll_area = QScrollArea()
        scroll_area.setWidget(progress_wid)
        scroll_area.setWidgetResizable(True)
        arithmetic_layout.addWidget(scroll_area)

        layout = QHBoxLayout()
        layout.setAlignment(Qt.AlignLeft)
        self.processing_prev_button = QPushButton("Prev")
        self.processing_prev_button.clicked.connect(
            lambda: self.stack.setCurrentIndex(0))
        layout.addWidget(self.processing_prev_button)
        arithmetic_layout.addLayout(layout)

        return wid

    def __configure_and_show_arithmetic_widget(self):
        file_names = self.input_files_edit.toPlainText().split("\n")
        num_channels = []
        problematic_images = []
        for file_name in file_names:
            try:
                meta_data = sio.read_metadata(file_name)
                num_channels.append(len(meta_data["channels_information"]))
            except Exception:
                problematic_images.append(file_name)
        if problematic_images:
            self._error_function(
                "Problem encountered reading the following file(s):\n" +
                "\n".join(problematic_images))
            return
        self.max_channel_index = min(num_channels) - 1
        self.valid_indexes_label.setText(
            f"Valid channel indexes: 0...{self.max_channel_index}, i")
        self.arithmetic_expression_text_edit.clear()
        self.slice_by_slice_checkbox.setChecked(False)
        self.new_channel_name_line_edit.clear()

        # Remove all widgets from layout, done in reverse order because
        # removing from the begining shifts the rest of the items
        for i in reversed(range(self.progress_grid_layout.count())):
            self.progress_grid_layout.itemAt(i).widget().setParent(None)

        for i, file_name in enumerate(file_names):
            self.progress_grid_layout.addWidget(
                QLabel(os.path.basename(file_name)), i, 0)
            progress_bar = QProgressBar()
            progress_bar.setMaximum(100)
            self.progress_grid_layout.addWidget(progress_bar, i, 1)

        self.stack.setCurrentIndex(1)

    def __create_select_files_widget(self):
        wid = QWidget()
        input_layout = QVBoxLayout()
        wid.setLayout(input_layout)

        layout = QHBoxLayout()
        layout.addWidget(QLabel("File names:"))
        layout.setAlignment(Qt.AlignLeft)
        button = QPushButton("Browse")
        button.setToolTip("Select input files for arithmetic operation.")
        button.clicked.connect(self.__browse_select_input_callback)
        layout.addWidget(button)
        input_layout.addLayout(layout)

        self.input_files_edit = QTextEdit()
        self.input_files_edit.setReadOnly(True)
        input_layout.addWidget(self.input_files_edit)

        layout = QHBoxLayout()
        layout.setAlignment(Qt.AlignRight)
        self.input_files_next_button = QPushButton("Next")
        self.input_files_next_button.setEnabled(False)
        self.input_files_next_button.clicked.connect(
            self.__configure_and_show_arithmetic_widget)
        layout.addWidget(self.input_files_next_button)
        input_layout.addLayout(layout)

        return wid

    def __browse_select_input_callback(self):
        file_names, _ = QFileDialog.getOpenFileNames(
            self,
            "QFileDialog.getOpenFileNames()",
            "",
            "Imaris Images (*.ims);;All Files (*)",
        )
        if file_names:
            self.input_files_edit.setText("\n".join(file_names))
            self.input_files_next_button.setEnabled(True)

    def __select_color_callback(self):
        color = QColorDialog.getColor()
        if color.isValid():
            self.new_channel_color_button.setStyleSheet(
                f"background-color :rgb({color.red()},{color.green()},{color.blue()})"
            )

    def __channel_arithmetic_wrapper(self):
        # Get the arithmetic expression after removing all whitespace
        arithmetic_expression = "".join(
            self.arithmetic_expression_text_edit.toPlainText().split())
        color = self.new_channel_color_button.palette().button().color()

        if arithmetic_expression:
            # Get the explicit channel indexes that appear in the expression and
            # check that they are in the valid range.
            channel_indexes = re.findall(self.channel_pattern,
                                         arithmetic_expression)
            invalid_channels = [
                ci for ci in channel_indexes
                if int(ci) not in range(self.max_channel_index + 1)
            ]
            if invalid_channels:
                self._error_function(
                    "The following channels specified in the arithmetic expression"
                    +
                    f" are outside the valid range [0,{self.max_channel_index}]: "
                    + ", ".join(invalid_channels))
                return

            # Disable the UI interaction during computation
            self.arithmetic_expression_text_edit.setReadOnly(True)
            self.slice_by_slice_checkbox.setEnabled(False)
            self.new_channel_name_line_edit.setReadOnly(True)
            self.new_channel_color_button.setEnabled(False)
            self.apply_button.setEnabled(False)
            self.processing_prev_button.setEnabled(False)

            QApplication.setOverrideCursor(Qt.WaitCursor)
            file_names = self.input_files_edit.toPlainText().split("\n")
            self.num_threads_left = len(file_names)
            for i, input_file_name in enumerate(file_names):
                # Configure and perform computation in another thread.
                arithmetic_calculator = ArithmeticCalculator(
                    self.channel_pattern)
                arithmetic_calculator.signals.finished.connect(
                    self.__arithmetic_finished)
                arithmetic_calculator.signals.processing_error.connect(
                    self._processing_error_function)
                arithmetic_calculator.signals.progress_signal.connect(
                    self.progress_grid_layout.itemAtPosition(
                        i, 1).widget().setValue)
                arithmetic_calculator.signals.update_state_signal.connect(
                    self.status_bar.showMessage)
                arithmetic_calculator.input_file_name = input_file_name
                arithmetic_calculator.arithmetic_expression = arithmetic_expression
                arithmetic_calculator.new_channel_color = [
                    color.red() / 255.0,
                    color.green() / 255.0,
                    color.blue() / 255.0,
                ]
                arithmetic_calculator.new_channel_alpha = color.alpha() / 255.0
                arithmetic_calculator.new_channel_name = (
                    self.new_channel_name_line_edit.text().strip())
                arithmetic_calculator.slice_by_slice = (
                    self.slice_by_slice_checkbox.isChecked())
                self.threadpool.start(arithmetic_calculator)
        else:
            self._error_function(
                "No action taken: arithmetic expression not set.")

    def __arithmetic_finished(self):
        self.num_threads_left = self.num_threads_left - 1
        if self.num_threads_left == 0:
            QApplication.restoreOverrideCursor()
            self.status_bar.clearMessage()
            for i in range(self.progress_grid_layout.rowCount()):
                self.progress_grid_layout.itemAtPosition(
                    i, 1).widget().setValue(0)
            # Enable the UI interaction after computation
            self.arithmetic_expression_text_edit.setReadOnly(False)
            self.slice_by_slice_checkbox.setEnabled(True)
            self.new_channel_name_line_edit.setReadOnly(False)
            self.new_channel_color_button.setEnabled(True)
            self.apply_button.setEnabled(True)
            self.processing_prev_button.setEnabled(True)

            # Inform the user that the calculations completed. If processing errors
            # occured then the desired operation may not have happened, but the
            # calculation was completed.
            QMessageBox().information(self, "Message",
                                      "Calculation completed.")
            self.processing_error = False
コード例 #6
0
class Main(MainWindow):
    def __init__(self):
        super().__init__()

        # Create all dialogs
        self.about_dialog = AboutDialog()
        self.tutorial_dialog = HelpDialog()
        self.size_warning = SizeWarning()
        self.source_warning = SourceCodeWarning()
        self.about_dialog.hide()
        self.tutorial_dialog.hide()
        self.size_warning.hide()
        self.source_warning.hide()

        # Read config file to find out if this is first run
        configpath = str(
            Path.home()) + "/.config/codeblock_visual_studio/config"
        configread = configparser.ConfigParser()
        config = configread.read(configpath)
        if len(config) == 0:
            # First Run, open tutorial and autogenerate config
            os.makedirs(os.path.dirname(configpath), exist_ok=True)
            with open(configpath, 'w') as f:
                f.write("")
                self.tutorial_dialog.exec_()

        # Bind buttons to functions and initialize varibales
        self.bind()
        self.classViewFileIndex = {}
        self.lines = []
        self.lint = ()
        self.go_ahead = True
        self.class_list = {}

    def bind(self):
        self.actionOpen.triggered.connect(self.open_file)
        self.actionAbout.triggered.connect(self.about_dialog.show)
        self.actionTutorial.triggered.connect(self.tutorial_dialog.show)
        self.classView.itemDoubleClicked.connect(self.classview_openclass)
        self.size_warning.buttonBox.accepted.connect(self.size_warning.hide)
        self.size_warning.buttonBox.rejected.connect(self.check_size)

    def check_size(self):
        self.size_warning.hide()
        self.go_ahead = False

    def classview_openclass(self):
        # Get the selected class (should be first one selected)
        try:
            selected_item = self.classView.selectedItems()[0].parent().text(0)
        except AttributeError:
            return 0

        # Figure out whether to use package naming or module naming
        if selected_item.split(".")[-1] in ["py", "so"]:
            # Select module naming
            inspect_typed = selected_item.split(".")[0]
        else:
            # Select package naming
            inspect_typed = selected_item

        # Read entire file into self.lines
        try:
            with open(self.class_list[2][inspect_typed]) as f:
                self.lines = []
                for l in f:
                    self.lines.append(l.lstrip())
        except UnicodeDecodeError:
            self.source_warning.show()
            return 0

        if len(self.lines) > 2000:
            self.size_warning.exec_()
            if self.go_ahead == False:
                self.go_ahead = True
                return 0

        # Get output from linter and use the read code to generate the code blocks
        self.lint = error_catcher.get_lint(self.class_list[2][inspect_typed])
        self.create_blocks(
            self.class_list[0][self.class_list[2][inspect_typed]][
                self.classView.selectedItems()[0].text(0)])

    def open_file(self):
        filename = QFileDialog.getOpenFileName(self, 'Open file for reading',
                                               '', "Python files (*.py)")[0]
        self.regenerate_classview(filename)

    def regenerate_classview(self, file):
        try:
            # Get everything in format (classes, lint, imports)
            # classes is in format {file: {class: {functions: {list_of_source}}}}
            # Lint is in format {file: [list_of_lint_warns]}
            # Imports is in format {module: file}
            self.class_list = interpreter.get_classes_all(file)
        except:
            self.class_list = ({}, {}, {})
        class_list_sorted = {}
        for k, v in self.class_list[0].items():
            # Get name of modules
            try:
                filename = list(self.class_list[2].keys())[list(
                    self.class_list[2].values()).index(k)]
            except ValueError:
                filename = file.split("/")[-1]
            if len(filename.split(".")) < 2:
                # Use module-style naming (.py or .so extension)
                filename = filename + "." + k.split(".")[-1]

            class_list_sorted[filename] = {}
            for i, j in v.items():
                class_list_sorted[filename][i] = None
            # for i, j in self.class_list[0].items():
            #     if len(filename.split(".")) > 2:
            #         filecompare = filename
            #     else:
            #         filecompare = filename.split(".")[0]
            #     if filecompare in str(j):
            #         class_list_sorted[filename][i] = j
        class_tree_index = {}
        self.classView.clear()
        ind0 = 0
        # class_list_sorted should be in the format {module_name: {class_name:[arbitrary val]}}
        for k2, v2 in class_list_sorted.items():
            class_tree_index[ind0] = QTreeWidgetItem(self.classView)
            class_tree_index[ind0].setText(0, k2)
            for k3, v3 in v2.items():
                class_tree_index[v3] = QTreeWidgetItem(class_tree_index[ind0])
                class_tree_index[v3].setText(0, k3)
            ind0 = ind0 + 1

    def create_blocks(self, funcs):
        for child in self.codeArea.children():
            child.deleteLater()
        self.codeArea.setUpdatesEnabled(True)
        self.function_blocks = self.generate_function_blocks(funcs)
        self.code_blocks = self.generate_code_blocks(funcs)
        for k, v in self.function_blocks.items():
            v.attach_child(self.code_blocks[k][0])
            v.raiseEvent()
            self.code_blocks[k].append(v)

        # svgWidget = HatBlock("test", self.code_blocks['test'][-1], self.codeArea)
        # self.function_blocks.append(svgWidget)
        # svgWidget.show()
        for c, i in enumerate(self.function_blocks.values()):
            i.move_recurse(sum(self.code_blocks['func-widths'][0:c]),
                           i.geometry().y())
            i.raiseEvent()

        for bar in self.code_blocks['ctrlbar']:
            bar.adjust_bar()
            bar.show()
            bar.raise_()

        for comment in self.code_blocks['comments']:
            comment.adjust()
            comment.show()

    def generate_function_blocks(self, funcs):
        f = 0
        retblocks = {}
        for func, func_def in funcs.items():
            if func != "":
                if func_def[0].startswith("@"):
                    retblocks[func] = CapBlock(func_def[1].strip(),
                                               parent=self.codeArea)
                else:
                    retblocks[func] = CapBlock(func_def[0].strip(),
                                               parent=self.codeArea)
            f = f + 1
        return retblocks

    def generate_code_blocks(self, funcs_list):
        f = 0
        retblocks = {}
        # We need a fresh copy of funcs_list due to mutations that occur during function run
        funcs = copy.deepcopy(funcs_list)
        retblocks['comments'] = []
        retblocks['ctrlbar'] = []
        retblocks['func-widths'] = []
        ctrl_bar_count = 0
        for func, code in funcs.items():
            f = 0
            maxwidth = 0
            retblocks[func] = []
            control_block_map = {}
            not_done = True
            for line in code:
                if code.index(line) == 0:
                    # Skip first line (which, by spec, contains function header)
                    continue
                if func != "":
                    if line.lstrip().startswith("#"):
                        self.lint[2][line.lstrip()] = self.lines.index(
                            line.lstrip()) + 1
                    line_leading_whitespace = len(line) - len(line.lstrip())
                    if line_leading_whitespace in control_block_map.keys():
                        # CtrlBottom detected (must be before ifblock)
                        sorted_keys = list(control_block_map.keys())
                        sorted_keys.sort()
                        if not line_leading_whitespace == \
                                sorted_keys[-1]:
                            line = line.lstrip()
                            for l in range(sorted_keys[-1]):
                                line = " " + line
                        retblocks[func].append(
                            CtrlBottom(line.lstrip(), parent=self.codeArea))
                        code.insert(f + 1, line)
                        retblocks['ctrlbar'].append(
                            CtrlBar(parent=self.codeArea))
                        retblocks['ctrlbar'][ctrl_bar_count].attach_top(
                            control_block_map[len(line) - len(line.lstrip())])
                        retblocks['ctrlbar'][ctrl_bar_count].attach_bottom(
                            retblocks[func][f])
                        ctrl_bar_count = ctrl_bar_count + 1
                        del control_block_map[len(line) - len(line.lstrip())]
                    elif line.strip(
                    )[-1] == ':' and not line.lstrip().startswith("#"):
                        # Indented Block - use CtrlTop block
                        retblocks[func].append(
                            CtrlTop(line.lstrip(), parent=self.codeArea))
                        # Store [whitespace, satisfied] values for ctrltop
                        control_block_map[
                            len(line) -
                            len(line.lstrip())] = retblocks[func][f]
                    else:
                        # Just a regular CodeBlock
                        try:
                            if self.lines.index(
                                    line.lstrip()) + 1 in self.lint[0].values(
                                    ):
                                color = "red"
                                lintline = list(self.lint[0].keys())[list(
                                    self.lint[0].values()).index(
                                        self.lines.index(line.lstrip()) + 1)]
                            elif self.lines.index(
                                    line.lstrip()) + 1 in self.lint[1].values(
                                    ):
                                color = "#FFBB33"
                                lintline = list(self.lint[1].keys())[list(
                                    self.lint[1].values()).index(
                                        self.lines.index(line.lstrip()) + 1)]
                            else:
                                color = "#496BD3"
                                lintline = None
                        except ValueError as v:
                            color = "#496BD3"
                            lintline = None
                        retblocks[func].append(
                            CodeBlock(line.lstrip(),
                                      color,
                                      parent=self.codeArea))
                        if lintline is not None:
                            retblocks['comments'].append(
                                CommentBubble(lintline,
                                              retblocks[func][f],
                                              parent=self.codeArea))
                    if f != 0:
                        retblocks[func][f - 1].attach_child(retblocks[func][f])
                if retblocks[func][f].geometry().width() > maxwidth:
                    maxwidth = retblocks[func][f].geometry().width()
                f = f + 1
                if f == len(code) - 1 and len(
                        control_block_map) > 0 and not_done:
                    # CtrlBottom detected (must be before ifblock)
                    sorted_keys = list(control_block_map.keys())
                    sorted_keys.sort()
                    if not line_leading_whitespace == \
                            sorted_keys[-1]:
                        line = line.lstrip()
                        for l in range(sorted_keys[-1]):
                            line = " " + line

                    retblocks[func].append(
                        CtrlBottom(line, parent=self.codeArea))
                    code.insert(f + 1, line)
                    retblocks['ctrlbar'].append(CtrlBar(parent=self.codeArea))
                    retblocks['ctrlbar'][ctrl_bar_count].attach_top(
                        control_block_map[len(line) - len(line.lstrip())])
                    retblocks['ctrlbar'][ctrl_bar_count].attach_bottom(
                        retblocks[func][f])
                    ctrl_bar_count = ctrl_bar_count + 1
                    del control_block_map[len(line) - len(line.lstrip())]
                    not_done = False
            retblocks['func-widths'].append(maxwidth)

        return retblocks

    def get_imports(self, file):
        finder = ModuleFinder()
        finder.run_script(file)
        im = []
        for name, mod in finder.modules.items():
            im.append(name)
        return im

    def get_functions(self, file, class_name):
        spec = importlib.util.spec_from_file_location("foo", file)
        foo = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(foo)
        dirvar = getattr(foo, class_name)
        functions = {}
        for i in dir(dirvar):
            if inspect.isroutine(getattr(dirvar, i)):
                try:
                    functions[i] = list(
                        filter(
                            None,
                            inspect.getsource(getattr(dirvar,
                                                      i)).splitlines()))
                except TypeError:
                    pass
        return functions

    def get_classes(self, file):
        classes = {}
        try:
            sys.path.append("/".join(file.split("/")[:-1]))
            spec = importlib.util.spec_from_file_location(
                file.split("/")[-1], file)
            foo = importlib.util.module_from_spec(spec)
            spec.loader.exec_module(foo)
            for name, obj in inspect.getmembers(foo):
                if inspect.isclass(obj):
                    classes[name] = obj
                    try:
                        self.classViewFileIndex[str(classes[name]).split(
                            "'")[1::2][0]] = inspect.getfile(obj)
                    except TypeError:
                        self.classViewFileIndex[str(
                            classes[name]).split("'")[1::2][0].replace(
                                ".py", "")] = file
        except FileNotFoundError:
            pass
            # do stuff
        return classes

    def get_vars(self, file):
        defined = []
        try:
            importvar = __import__(file)
            dirvar = importvar
            returnvar = dir(dirvar)
        except ImportError:
            importvar = __import__(file.split(".")[0])
            dirvar = getattr(importvar, file.split(".")[1])
            returnvar = dir(dirvar)
        for attr in returnvar:
            if not callable(getattr(dirvar, attr)):
                defined.append(attr)
        returnvar = defined
        return returnvar
コード例 #7
0
ファイル: main.py プロジェクト: crosslore/cuauv_software
 def help_menu(self):
     dialog = HelpDialog()
     response = dialog.run()
     dialog.destroy()
コード例 #8
0
ファイル: input_view_eat.py プロジェクト: buma/eatToday
 def show_help():
     msg = HelpDialog(self)
     msg.setText("Column help")
     msg.setInformativeText(SQLTransformer.get_column_names())
     #TODO: add serch query help
     msg.show()
コード例 #9
0
class ExportChannelSettingsDialog(ieb.ImarisExtensionBase):
    """
    Export Channel Settings
    =======================
    `View on GitHub <https://github.com/niaid/imaris_extensions>`_

    This program enables you to export the channel settings from an imaris file
    to a comma separated values (csv) file. This is convenient for manual editing.
    Once modified the settings file can be applied to other imaris files using the
    `Configure Channel Settings extension  <http://niaid.github.io/imaris_extensions/XTConfigureChannelSettings.html>`_.

    Note: If the exported settings include color tables, these are exported as additional files that are referenced in
    the csv file.

    Example output csv file content::

        name,description,color,alpha,range,gamma
        Cytoplasm, first channel description,"0.0, 76.5, 0.0",1.0,"22.836, 162.388",1.0
        Nucleus,second channel description,glow_color_table.pal,1.0,"72.272, 158.038",1.0
        Vesicles,third channel description,"255.0,0.0,0.0",1.0,"62.164, 150.97",1.0

    The second channel used a color table instead of a single color. The file containing
    the color table is specified using a relative path. The contents of a color table
    file are triplets, RGB values, in [0,255]. The specific file with 256 entries
    looks like this::

        0.000 0.000 0.000
        0.000 0.000 0.000
        4.080 0.000 0.000
        4.080 0.000 0.000
        7.905 0.000 0.000
        7.905 0.000 0.000
        11.985 0.000 0.000
        11.985 0.000 4.080
        16.065 0.000 4.080
        16.065 0.000 4.080
        19.890 0.000 4.080
        19.890 0.000 4.080
        ...
        ...
        250.920 250.920 235.110
        250.920 250.920 238.935
        250.920 250.920 243.015
        250.920 250.920 243.015
        250.920 250.920 247.095
        255.000 255.000 255.000
    """
    def __init__(self):
        super(ExportChannelSettingsDialog, self).__init__()

        # Configure the help dialog.
        self.help_dialog = HelpDialog(w=700, h=500)
        self.help_dialog.setWindowTitle("Export Channel Settings Help")
        self.help_dialog.set_rst_text(
            inspect.getdoc(self), pygments_css_file_name="pygments_dark.css")

        self.__create_gui()
        self.setWindowTitle("Export Channel Settings to csv File")
        self.show()

    def __error_function(self, message):
        error_dialog = QErrorMessage(self)
        error_dialog.showMessage(message)

    def __create_gui(self):
        menu_bar = self.menuBar()
        # Force menubar to be displayed in the application on OSX/Linux, otherwise it
        # is displayed in the system menubar
        menu_bar.setNativeMenuBar(False)
        self.help_button = QPushButton("Help")
        self.help_button.clicked.connect(self.help_dialog.show)
        menu_bar.setCornerWidget(self.help_button, Qt.TopLeftCorner)

        central_widget = QWidget(self)
        layout = QVBoxLayout()
        central_widget.setLayout(layout)
        self.setCentralWidget(central_widget)

        input_file_layout = QHBoxLayout()
        input_file_layout.addWidget(QLabel("File:"))
        self.input_file_line_edit = QLineEdit()
        self.input_file_line_edit.setReadOnly(True)
        self.input_file_line_edit.setToolTip(
            "Select ims file whose channel information you want to export.")
        input_file_layout.addWidget(self.input_file_line_edit)
        button = QPushButton("Browse")
        button.clicked.connect(self.__browse_callback)
        input_file_layout.addWidget(button)
        layout.addLayout(input_file_layout)

        button = QPushButton("Export")
        button.clicked.connect(self.__export_channel_settings)
        layout.addWidget(button)

    def closeEvent(self, event):
        """
        Override the closeEvent method so that clicking the 'x' button also
        closes all of the dialogs.
        """
        self.help_dialog.close()
        event.accept()

    def __browse_callback(self):
        file_name, _ = QFileDialog.getOpenFileName(
            self, "QFileDialog.getOpenFileName()", "",
            "Imaris (*.ims);;All Files (*)")
        self.input_file_line_edit.setText(file_name)

    def __export_channel_settings(self):
        input_file_name = self.input_file_line_edit.text().strip()
        default_output_file_name = os.path.join(
            os.path.dirname(input_file_name), "channel_settings")
        output_file_name, _ = QFileDialog.getSaveFileName(
            self, "Export Channel Settings", default_output_file_name,
            "csv(*.csv)")
        metadata = sio.read_metadata(input_file_name)
        # Using known metadata dictionary structure from the sitk_ims_file_io module
        channel_settings_headings = [
            "name",
            "description",
            "color",
            "alpha",
            "range",
            "gamma",
        ]
        channel_settings = [None] * len(metadata["channels_information"])
        for i, cs in metadata["channels_information"]:
            current_settings = [cs["name"], cs["description"]]
            if "color" in cs:
                color_settings = ", ".join([str(c * 255) for c in cs["color"]])
            elif "color_table" in cs:
                color_table = "".join([
                    f"{c*255:.3f}\n" if (i % 3) == 0 else f"{c*255:.3f} "
                    for i, c in enumerate(cs["color_table"], 1)
                ])
                color_settings = (os.path.splitext(output_file_name)[0] +
                                  f"_color_table_channel{i}.pal")
                with open(color_settings, "w") as fp:
                    fp.write(color_table)
            current_settings.extend([
                os.path.basename(color_settings),
                cs["alpha"],
                ", ".join([str(v) for v in cs["range"]]),
            ])
            if "gamma" in cs:
                current_settings.append(cs["gamma"])
            channel_settings[i] = current_settings
        df = pd.DataFrame(
            channel_settings,
            columns=channel_settings_headings[0:len(channel_settings[0]
                                                    )  # noqa: E203
                                              ],
        )
        df.to_csv(output_file_name, index=False)
        QMessageBox().information(self, "Message", "Succesfuly Exported")
コード例 #10
0
ファイル: main.py プロジェクト: athityakumar/software
 def help_menu(self):
     dialog = HelpDialog()
     response = dialog.run()
     dialog.destroy()