Beispiel #1
0
           Item("title_font", label="Font", style="simple"),
           Item("title_color", label="Color", style="custom"),
           Item("tick_interval",
                label="Interval",
                editor=TextEditor(evaluate=float_or_auto)),
           show_border=True,
           label="Main"),
     Group(
         Item("tick_color", label="Color", style="custom"),
         # editor=EnableRGBAColorEditor()),
         Item("tick_weight", label="Thickness"),
         # Item("tick_label_font", label="Font"),
         Item("tick_label_color", label="Label color", style="custom"),
         # editor=EnableRGBAColorEditor()),
         HGroup(
             Item("tick_in", label="Tick in"),
             Item("tick_out", label="Tick out"),
         ),
         Item("tick_visible", label="Visible"),
         show_border=True,
         label="Ticks"),
     Group(
         Item("axis_line_color", label="Color", style="custom"),
         # editor=EnableRGBAColorEditor()),
         Item("axis_line_weight", label="Thickness"),
         Item("axis_line_visible", label="Visible"),
         show_border=True,
         label="Line")),
 title='Edit Axis',
 x=50,
 y=50,
 buttons=[
Beispiel #2
0
class UpdateView(HasTraits):
    piksi_hw_rev = String('piksi_multi')
    is_v2 = Bool(False)

    piksi_stm_vers = String('Waiting for Piksi to send settings...',
                            width=COLUMN_WIDTH)
    newest_stm_vers = String('Downloading Latest Firmware info...')
    piksi_nap_vers = String('Waiting for Piksi to send settings...')
    newest_nap_vers = String('Downloading Latest Firmware info...')
    local_console_vers = String('v' + CONSOLE_VERSION)
    newest_console_vers = String('Downloading Latest Console info...')
    download_directory_label = String('Firmware Download Directory:')

    update_stm_firmware = Button(label='Update Firmware')

    updating = Bool(False)
    update_stm_en = Bool(False)

    download_firmware = Button(label='Download Latest Firmware')
    download_directory = String()
    choose_dir = Button(label='...', padding=-1)
    download_stm = Button(label='Download', height=HT)
    downloading = Bool(False)
    download_fw_en = Bool(False)

    stm_fw = Instance(FirmwareFileDialog)

    stream = Instance(OutputStream)

    view = View(
        VGroup(Item('piksi_hw_rev',
                    label='Hardware Revision',
                    editor_args={'enabled': False},
                    resizable=True),
               HGroup(
                   VGroup(Item('piksi_stm_vers',
                               label='Current',
                               resizable=True,
                               editor_args={'enabled': False}),
                          Item('newest_stm_vers',
                               label='Latest',
                               resizable=True,
                               editor_args={
                                   'enabled': False,
                                   'readonly_allow_selection': True
                               }),
                          Item('stm_fw',
                               style='custom',
                               show_label=True,
                               label="Local File"),
                          Item('update_stm_firmware',
                               show_label=False,
                               enabled_when='update_stm_en'),
                          show_border=True,
                          label="Firmware Version"),
                   VGroup(Item('local_console_vers',
                               label='Current',
                               resizable=True,
                               editor_args={'enabled': False}),
                          Item('newest_console_vers',
                               label='Latest',
                               editor_args={'enabled': False}),
                          label="Swift Console Version",
                          show_border=True),
               ),
               HGroup(
                   VGroup(HGroup(
                       Item('download_directory',
                            label="Directory",
                            resizable=True),
                       UItem('choose_dir', width=-0.1),
                   ),
                          HGroup(
                              Spring(width=50, springy=False),
                              Item('download_firmware',
                                   enabled_when='download_fw_en',
                                   show_label=False,
                                   resizable=True,
                                   springy=True)),
                          label="Firmware Download",
                          show_border=True),
                   VGroup(Item(
                       'stream',
                       style='custom',
                       editor=InstanceEditor(),
                       show_label=False,
                   ),
                          show_border=True,
                          label="Firmware Upgrade Status"),
               ),
               show_border=True), )

    def __init__(self,
                 link,
                 download_dir=None,
                 prompt=True,
                 connection_info={'mode': 'unknown'}):
        """
        Traits tab with UI for updating Piksi firmware.

        Parameters
        ----------
        link : sbp.client.handler.Handler
          Link for SBP transfer to/from Piksi.
        prompt : bool
          Prompt user to update console/firmware if out of date.
        """
        self.link = link
        self.connection_info = connection_info
        self.settings = {}
        self.prompt = prompt
        self.python_console_cmds = {'update': self}
        self.download_directory = download_dir
        try:
            self.update_dl = UpdateDownloader(root_dir=self.download_directory)
        except RuntimeError:
            self.update_dl = None
        self.stm_fw = FirmwareFileDialog(self.download_directory)
        self.stm_fw.on_trait_change(self._manage_enables, 'status')
        self.stream = OutputStream()
        self.stream.max_len = 1000
        self.last_call_fw_version = None
        self.link.add_callback(self.log_cb, SBP_MSG_LOG)

    def _choose_dir_fired(self):
        dialog = DirectoryDialog(label='Choose Download location',
                                 action='open',
                                 default_directory=self.download_directory)
        dialog.open()
        if dialog.return_code == OK:
            self.download_directory = dialog.path
        else:
            self._write('Error while selecting firmware download location')

    def _manage_enables(self):
        """ Manages whether traits widgets are enabled in the UI or not. """
        if self.updating or self.downloading:
            self.update_stm_en = False
            self.download_fw_en = False
        else:
            if getattr(self.stm_fw, 'blob', None) is not None:
                self.update_stm_en = True
            else:
                self.update_stm_en = False
            if self.download_directory != '':
                self.download_fw_en = True

    def _download_directory_changed(self):
        if getattr(self, 'update_dl', None):
            self.update_dl.set_root_path(self.download_directory)
        self._manage_enables()

    def _updating_changed(self):
        """ Handles self.updating trait being changed. """
        self._manage_enables()

    def _downloading_changed(self):
        """ Handles self.downloading trait being changed. """
        self._manage_enables()

    def _clear_stream(self):
        self.stream.reset()

    def _write(self, text):
        """
        Stream style write function. Allows flashing debugging messages to be
        routed to embedded text console.

        Parameters
        ----------
        text : string
          Text to be written to screen.
        """
        self.stream.write(text)
        self.stream.write('\n')
        self.stream.flush()

    def _update_stm_firmware_fired(self):
        """
        Handle update_stm_firmware button. Starts thread so as not to block the GUI
        thread.
        """
        ins_settings = self.settings.get('ins', None)
        ins_output_mode = None
        if ins_settings is not None:
            ins_output_mode = ins_settings.get('output_mode').value

        if (ins_output_mode
                is not None) and not (ins_output_mode.startswith('Disabled') or
                                      ins_output_mode.startswith('disabled')):
            ins_disable_prompt = \
                prompt.CallbackPrompt(
                    title="Unsupported Update Request",
                    actions=[prompt.close_button],
                )
            ins_disable_prompt.text = \
                "\n\n" + \
                "Updating firmware is not supported when INS is active.\n\n" + \
                "Please change the 'output mode' INS setting to 'Disabled'\n" + \
                "before updating firmware.\n\n"
            ins_disable_prompt.run(block=False)
            return

        if self.connection_info['mode'] != 'TCP/IP':
            self._write(
                "\n"
                "-----------------------------------------------\n"
                "USB Flashdrive Upgrade Procedure\n"
                "-----------------------------------------------\n"
                "\n"
                "1.\tInsert the USB flash drive provided with your Piksi Multi into your computer.\n"
                "  \tSelect the flash drive root directory as the firmware download destination using the directory chooser above.\n"
                "  \tPress the \"Download Latest Firmware\" button. This will download the latest Piksi Multi firmware file onto\n"
                "  \tthe USB flashdrive.\n"
                "2.\tEject the drive from your computer and plug it into the USB Host port of the Piksi Multi evaluation board.\n"
                "3.\tReset your Piksi Multi and it will upgrade to the version on the USB flash drive.\n"
                "  \tThis should take less than 5 minutes.\n"
                "4.\tWhen the upgrade completes you will be prompted to remove the USB flash drive and reset your Piksi Multi.\n"
                "5.\tVerify that the firmware version has upgraded via inspection of the Current Firmware Version box\n"
                "  \ton the Update Tab of the Swift Console.\n")

            confirm_prompt = prompt.CallbackPrompt(
                title="Update device over serial connection?",
                actions=[
                    prompt.close_button, prompt.continue_via_serial_button
                ],
                callback=self._update_stm_firmware_fn)
            confirm_prompt.text = "\n" \
                                  + "    Upgrading your device via UART / RS232 may take up to 30 minutes.     \n" \
                                  + "                                                                          \n" \
                                  + "    If the device you are upgrading has an accessible USB host port, it   \n" \
                                    "    is recommended to instead  follow the \'USB Flashdrive Upgrade        \n" \
                                    "    Procedure\' that now appears in the Firmware upgrade status box.      \n" \
                                  + "\n" \
                                  + "    Are you sure you want to continue upgrading over serial?"
            confirm_prompt.run(block=False)
        else:
            self._update_stm_firmware_fn()

    def _replace_with_version_2(self):
        self.downloading = True
        self._write('Downloading Multi firmware v2.0.0')
        filepath = self.update_dl._download_file_from_url(V2_LINK)
        self._write('Saved file to %s' % filepath)
        self.stm_fw.load_bin(filepath)
        self.downloading = False

    def _update_stm_firmware_fn(self):
        try:
            if self._firmware_update_thread.is_alive():
                return
        except AttributeError:
            pass

        current_fw_version = parse_version(self.piksi_stm_vers)
        re_result = re.search('[a-zA-Z0-9]*-(v[0-9]*\.[0-9]*\.[0-9])',
                              self.stm_fw.status)
        intended_version = parse_version(re_result.group(1))
        # If the current firmware is not yet beyond 2.0.0, and we are loading beyond 2.0.0
        # warn the user that this upgrade is not possible
        if (current_fw_version < pkparse_version("v2.0.0")
                and intended_version > pkparse_version("v2.0.0")):
            confirm_prompt = prompt.CallbackPrompt(
                title="Update to v2.0.0",
                actions=[prompt.close_button, prompt.ok_button],
                callback=self._replace_with_version_2)
            confirm_prompt.text = "\n" \
                                  + "    Upgrading to firmware v2.1.0 or later requires that the device be     \n" \
                                  + "    running firmware v2.0.0 or later. Please upgrade to firmware          \n" \
                                  + "    version 2.0.0.                                                        \n" \
                                  + "                                                                          \n" \
                                  + "    Would you like to download firmware version v2.0.0 now?               \n" \
                                  + "                                                                          \n"
            confirm_prompt.run(block=False)
            return
        self._firmware_update_thread = Thread(
            target=self.manage_firmware_updates, args=("STM", ))
        self._firmware_update_thread.start()

    def _download_firmware(self):
        """ Download latest firmware from swiftnav.com. """
        self._write('')

        # Check that we received the index file from the website.
        if self.update_dl is None or self.update_dl.index is None:
            self._write("Error: Can't download firmware files")
            return

        self.downloading = True
        status = 'Downloading Latest Firmware...'
        self.stm_fw.clear(status)
        self._write(status)

        # Get firmware files from Swift Nav's website, save to disk, and load.
        if 'fw' in self.update_dl.index[self.piksi_hw_rev]:
            try:
                self._write('Downloading Latest Multi firmware')
                filepath = self.update_dl.download_multi_firmware(
                    self.piksi_hw_rev)
                self._write('Saved file to %s' % filepath)
                self.stm_fw.load_bin(filepath)
            except AttributeError:
                self._write(
                    "Error downloading firmware: index file not downloaded yet"
                )
            except RuntimeError as e:
                self._write(
                    "RunTimeError: unable to download firmware to path {0}: {1}"
                    .format(self.download_directory, e))
            except IOError as e:
                if e.errno == errno.EACCES or e.errno == errno.EPERM:
                    self._write("IOError: unable to write to path %s. "
                                "Verify that the path is writable." %
                                self.download_directory)
                else:
                    raise (e)
            except KeyError:
                self._write(
                    "Error downloading firmware: URL not present in index")
            except URLError:
                self.nap_fw.clear("Error downloading firmware")
                self._write(
                    "Error: Failed to download latest NAP firmware from Swift Navigation's website"
                )
            self.downloading = False
            return

    def _download_firmware_fired(self):
        """
        Handle download_firmware button. Starts thread so as not to block the GUI
        thread.
        """
        try:
            if self._download_firmware_thread.is_alive():
                return
        except AttributeError:
            pass

        self._download_firmware_thread = Thread(target=self._download_firmware)
        self._download_firmware_thread.start()

    def compare_versions(self):
        """
        To be called after latest Piksi firmware info has been received from
        device, to decide if current firmware on Piksi is out of date. Also informs
        user if the firmware was successfully upgraded. Starts a thread so as not
        to block GUI thread.
        """
        try:
            if self._compare_versions_thread.is_alive():
                return
        except AttributeError:
            pass

        self._compare_versions_thread = Thread(target=self._compare_versions)
        self._compare_versions_thread.start()

    def _compare_versions(self):
        """
        Compares version info between received firmware version / current console
        and firmware / console info from website to decide if current firmware or
        console is out of date. Prompt user to update if so. Informs user if
        firmware successfully upgraded.
        """
        # Check that settings received from Piksi contain FW versions.
        try:
            self.piksi_hw_rev = HW_REV_LOOKUP[self.settings['system_info']
                                              ['hw_revision'].value]
            self.piksi_stm_vers = self.settings['system_info'][
                'firmware_version'].value
        except KeyError:
            self._write(
                "\nError: Settings received from Piksi don't contain firmware version keys. Please contact Swift Navigation.\n"
            )
            return

        self.is_v2 = self.piksi_hw_rev.startswith('piksi_v2')

        self._get_latest_version_info()

        # Check that we received the index file from the website.
        if self.update_dl is None:
            self._write(
                "Error: No website index to use to compare versions with local firmware"
            )
            return
        # Get local stm version
        local_stm_version = None
        local_serial_number = None
        try:
            local_stm_version = self.settings['system_info'][
                'firmware_version'].value
            local_serial_number = self.settings['system_info'][
                'serial_number'].value
        except:  # noqa
            pass
        # Check if console is out of date and notify user if so.
        if self.prompt:
            local_console_version = parse_version(CONSOLE_VERSION)
            remote_console_version = parse_version(self.newest_console_vers)
            self.console_outdated = remote_console_version > local_console_version

            # we want to warn users using v2 regardless of version logic
            if self.console_outdated or self.is_v2:
                if not self.is_v2:
                    console_outdated_prompt = \
                        prompt.CallbackPrompt(
                            title="Swift Console Outdated",
                            actions=[prompt.close_button],
                        )
                    console_outdated_prompt.text = \
                        "Your console is out of date and may be incompatible\n" + \
                        "with current firmware. We highly recommend upgrading to\n" + \
                        "ensure proper behavior.\n\n" + \
                        "Please visit http://support.swiftnav.com to\n" + \
                        "download the latest version.\n\n" + \
                        "Local Console Version :\n\t" + \
                        "v" + CONSOLE_VERSION + \
                        "\nLatest Console Version :\n\t" + \
                        self.update_dl.index[self.piksi_hw_rev]['console']['version'] + "\n"
                else:
                    console_outdated_prompt = \
                        prompt.CallbackPrompt(
                            title="Swift Console Incompatible",
                            actions=[prompt.close_button],
                        )
                    console_outdated_prompt.text = \
                        "Your console is incompatible with your hardware revision.\n" + \
                        "We highly recommend using a compatible console version\n" + \
                        "to ensure proper behavior.\n\n" + \
                        "Please visit http://support.swiftnav.com to\n" + \
                        "download the latest compatible version.\n\n" + \
                        "Current Hardware revision :\n\t" + \
                        self.piksi_hw_rev + \
                        "\nLast supported Console Version: \n\t" + \
                        self.update_dl.index[self.piksi_hw_rev]['console']['version'] + "\n"

                console_outdated_prompt.run()

            # For timing aesthetics between windows popping up.
            sleep(0.5)

            # Check if firmware is out of date and notify user if so.
            remote_stm_version = self.newest_stm_vers

            self.fw_outdated = remote_stm_version > local_stm_version
            if local_stm_version.startswith('DEV'):
                self.fw_outdated = False

            if self.fw_outdated:
                fw_update_prompt = \
                    prompt.CallbackPrompt(
                        title='Firmware Update',
                        actions=[prompt.close_button]
                    )

                if 'fw' in self.update_dl.index[self.piksi_hw_rev]:
                    fw_update_prompt.text = \
                        "New Piksi firmware available.\n\n" + \
                        "Please use the Update tab to update.\n\n" + \
                        "Newest Firmware Version :\n\t%s\n\n" % \
                        self.update_dl.index[self.piksi_hw_rev]['fw']['version']
                else:
                    fw_update_prompt.text = \
                        "New Piksi firmware available.\n\n" + \
                        "Please use the Update tab to update.\n\n" + \
                        "Newest STM Version :\n\t%s\n\n" % \
                        self.update_dl.index[self.piksi_hw_rev]['stm_fw']['version'] + \
                        "Newest SwiftNAP Version :\n\t%s\n\n" % \
                        self.update_dl.index[self.piksi_hw_rev]['nap_fw']['version']

                fw_update_prompt.run()

        # Check if firmware successfully upgraded and notify user if so.
        if ((self.last_call_fw_version is not None
             and self.last_call_fw_version != local_stm_version)
                and (self.last_call_sn is None or local_serial_number is None
                     or self.last_call_sn == local_serial_number)):
            fw_success_str = "Firmware successfully upgraded from %s to %s." % \
                             (self.last_call_fw_version, local_stm_version)
            print(fw_success_str)
            self._write(fw_success_str)

        # Record firmware version reported each time this callback is called.
        self.last_call_fw_version = local_stm_version
        self.last_call_sn = local_serial_number

    def _get_latest_version_info(self):
        """ Get latest firmware / console version from website. """
        try:
            self.update_dl = UpdateDownloader(root_dir=self.download_directory)
        except RuntimeError:
            self._write(
                "\nError: Failed to download latest file index from Swift Navigation's website. Please visit our website to check that you're running the latest Piksi firmware and Piksi console.\n"
            )
            self.update_dl = None
            return

        # Make sure index contains all keys we are interested in.
        try:
            if 'fw' in self.update_dl.index[self.piksi_hw_rev]:
                self.newest_stm_vers = self.update_dl.index[
                    self.piksi_hw_rev]['fw']['version']
            else:
                self.newest_stm_vers = self.update_dl.index[
                    self.piksi_hw_rev]['stm_fw']['version']
                self.newest_nap_vers = self.update_dl.index[
                    self.piksi_hw_rev]['nap_fw']['version']
            self.newest_console_vers = self.update_dl.index[
                self.piksi_hw_rev]['console']['version']
        except KeyError:
            self._write(
                "\nError: Index downloaded from Swift Navigation's website (%s) doesn't contain all keys. Please contact Swift Navigation.\n"
                % INDEX_URL)
            return

    def file_transfer_progress_cb(self, arg):
        new_pcent = float(arg) / float(self.blob_size) * 100
        if new_pcent - self.pcent_complete > 0.1:
            self.pcent_complete = new_pcent
            self.stream.scrollback_write(
                "{:2.1f} % of {:2.1f} MB transferred.".format(
                    self.pcent_complete, self.blob_size * 1e-6))

    def log_cb(self, msg, **kwargs):
        for regex in UPGRADE_WHITELIST:
            if re.match(regex, msg.text):
                text = msg.text.replace("\r", "\n").strip().split("\n")
                if len(text) > 1:
                    # upgrade tool deliminates lines in stoud with \r, we want penultimate line that is complete to show
                    text = text[-2]
                else:
                    # If there is only one line, we show that
                    text = text[-1]
                self.stream.scrollback_write(text)

    def manage_multi_firmware_update(self):
        self.blob_size = float(len(self.stm_fw.blob))
        self.pcent_complete = 0
        # Set up progress dialog and transfer file to Piksi using SBP FileIO
        self._clear_stream()
        self._write(
            "Transferring image to device...\n\n00.0 of {:2.1f} MB trasnferred"
            .format(self.blob_size * 1e-6))
        try:
            FileIO(self.link).write("upgrade.image_set.bin",
                                    self.stm_fw.blob,
                                    progress_cb=self.file_transfer_progress_cb)
        except Exception as e:
            self._write("Failed to transfer image file to Piksi: %s\n" % e)
            self._write("Upgrade Aborted.")
            import traceback
            print(traceback.format_exc())
            return -1

        self.stream.scrollback_write(
            "Image transfer complete: {:2.1f} MB transferred.\n".format(
                self.blob_size * 1e-6))
        # Setup up pulsed progress dialog and commit to flash
        self._write("Committing file to Flash...\n")
        self.link.add_callback(self.log_cb, SBP_MSG_LOG)
        code = shell_command(self.link, "upgrade_tool upgrade.image_set.bin",
                             200)
        self.link.remove_callback(self.log_cb, SBP_MSG_LOG)

        if code != 0:
            self._write('Failed to perform upgrade (code = %d)' % code)
            if code == -255:
                self._write('Shell command timed out.  Please try again.')
            return
        self._write("Upgrade Complete.")
        self._write('Resetting Piksi...')
        self.link(MsgReset(flags=0))

    # Executed in GUI thread, called from Handler.
    def manage_firmware_updates(self, device):
        """
        Update Piksi firmware. Erase entire STM flash (other than bootloader)
        if so directed. Flash NAP only if new firmware is available.
        """
        self.updating = True
        self._write('')
        if not self.is_v2:
            self.manage_multi_firmware_update()
        else:
            self._write(
                'Unable to upgrade piksi v2; please use the last supported v2 console version.'
            )
            self._write("")
        self.updating = False
Beispiel #3
0
class PolygonPlotDemo(HasTraits):

    # The main plot container.
    plot = Instance(Plot)

    # Data holder for `plot`.
    apd = Instance(ArrayPlotData)

    # The polygon plot renderer.
    polygon_plot = Instance(PolygonPlot)

    # Assorted styles that will be set on `polygon_plot`.
    edge_style = LineStyle
    edge_width = Range(value=1, low=0, high=8)
    edge_alpha = Range(value=1.0, low=0.0, high=1.0)
    face_alpha = Range(value=0.4, low=0.0, high=1.0)
    alpha = Range(value=1.0, low=0.0, high=1.0)

    traits_view = \
        View(
            VGroup(
                Group(
                    UItem('plot', editor=ComponentEditor(), style='custom'),
                ),
                VGroup(
                    HGroup(
                        Item('edge_style'),
                        spring,
                    ),
                    Item('edge_width'),
                    Item('edge_alpha'),
                    Item('face_alpha'),
                    Item('alpha'),
                ),
            ),
            resizable=True,
        )

    #----------------------------------------------------------------------
    # Default values
    #----------------------------------------------------------------------

    def _apd_default(self):
        # Create the data to plot.
        px = np.array([0.5, 1.0, 2.0, 2.5, 2.0, 1.5, 0.5, 0.0])
        py = np.array([0.0, 0.8, 0.5, 3.0, 3.5, 2.0, 3.0, 0.5])

        # Create the ArrayPlotData container used by the Plot.
        apd = ArrayPlotData(px=px, py=py)
        return apd

    def _plot_default(self):
        plot = Plot(self.apd, title='PolygonPlot Demo')
        return plot

    def _polygon_plot_default(self):
        p = self.plot.plot(('px', 'py'),
                           type='polygon',
                           face_color=(0, 0.8, 1) + (self.face_alpha, ),
                           edge_color=(0, 0, 0) + (self.edge_alpha, ),
                           edge_style=self.edge_style,
                           alpha=self.alpha)
        return p[0]

    #----------------------------------------------------------------------
    # Trait change handlers
    #----------------------------------------------------------------------

    def _edge_style_changed(self):
        self.polygon_plot.edge_style = self.edge_style

    def _edge_width_changed(self):
        self.polygon_plot.edge_width = self.edge_width

    def _edge_alpha_changed(self):
        self.polygon_plot.edge_color = self.polygon_plot.edge_color[:3] + (
            self.edge_alpha, )

    def _face_alpha_changed(self):
        self.polygon_plot.face_color = self.polygon_plot.face_color[:3] + (
            self.face_alpha, )

    def _alpha_changed(self):
        self.polygon_plot.alpha = self.alpha
Beispiel #4
0
    def traits_view(self):
        irrad_grp = VGroup(
            HGroup(UItem('irradiation_enabled',
                         tooltip='Enable Irradiation filter'),
                   UItem('irradiation',
                         enabled_when='irradiation_enabled',
                         editor=EnumEditor(name='irradiations'))),
            UItem('level',
                  enabled_when='irradiation_enabled',
                  editor=EnumEditor(name='levels')),
            visible_when='irradiation_visible',
            show_border=True,
            label='Irradiations')

        pgrp = UItem('projects',
                     height=-150,
                     editor=FilterTabularEditor(editable=False,
                                                enabled_cb='project_enabled',
                                                refresh='refresh_needed',
                                                selected='selected_projects',
                                                adapter=ProjectAdapter(),
                                                multi_select=True))

        project_grp = Group(pgrp,
                            springy=False,
                            visible_when='project_visible',
                            show_border=True,
                            label='Projects')

        analysis_type_group = HGroup(
            UItem('use_analysis_type_filtering',
                  tooltip='Enable Analysis Type filter',
                  label='Enabled'),
            spring,
            UItem('_analysis_include_types',
                  enabled_when='use_analysis_type_filtering',
                  style='custom',
                  editor=CheckListEditor(cols=5,
                                         name='available_analysis_types')),
            visible_when='analysis_types_visible',
            show_border=True,
            label='Analysis Types')

        date_grp = HGroup(UItem('use_low_post'),
                          UItem('low_post', enabled_when='use_low_post'),
                          UItem('use_high_post'),
                          UItem('high_post', enabled_when='use_high_post'),
                          UItem('use_named_date_range'),
                          UItem('named_date_range'),
                          icon_button_editor('date_configure_button', 'calendar'),
                          label='Date',
                          visible_when='date_visible',
                          show_border=True)

        ms_grp = HGroup(UItem('use_mass_spectrometers',
                              tooltip='Enable Mass Spectrometer filter'),
                        spring,
                        UItem('mass_spectrometer_includes',
                              style='custom',
                              enabled_when='use_mass_spectrometers',
                              editor=CheckListEditor(name='available_mass_spectrometers',
                                                     cols=10)),
                        visible_when='mass_spectrometer_visible',
                        label='Mass Spectrometer', show_border=True)
        ln_grp = HGroup(
            UItem('identifier'),
            label='Identifier', show_border=True,
            visible_when='identifier_visible')

        top_level_filter_grp = VGroup(
            CustomLabel('filter_label',
                        style='custom',
                        width=-1.0,
                        visible_when='not filter_focus'),
            HGroup(ms_grp, ln_grp),
            HGroup(project_grp, irrad_grp),
            analysis_type_group,
            date_grp)

        g1 = UItem('controller.tableview', style='custom')
        grp = VGroup(top_level_filter_grp, g1)
        return View(grp)
Beispiel #5
0
class TitleEditorDemo(HasTraits):

    # Define the selection of titles that can be displayed:
    title = Enum(
        'Select a new title from the drop down list below',
        'This is the TitleEditor demonstration',
        'Acme Widgets Sales for Each Quarter',
        'This is Not Intended to be a Real Application'
    )

    # A user settable version of the title:
    title_2 = Str('Type into the text field below to change this title')

    # A title driven by the result of a calculation:
    title_3 = Property(depends_on='value')

    # The number used to drive the calculation:
    value = Float

    # Define the test view:
    view = View(
        VGroup(
            VGroup(
                HGroup(
                    Item('title',
                         show_label=False,
                         springy=True,
                         editor=TitleEditor()
                         )
                ),
                Item('title'),
                show_border=True
            ),
            VGroup(
                HGroup(
                    Item('title_2',
                         show_label=False,
                         springy=True,
                         editor=TitleEditor()
                         )
                ),
                Item('title_2', label='Title'),
                show_border=True
            ),
            VGroup(
                HGroup(
                    Item('title_3',
                         show_label=False,
                         springy=True,
                         editor=TitleEditor()
                         )
                ),
                Item('value'),
                show_border=True
            )
        ),
        width=0.4
    )

    #-- Property Implementations ---------------------------------------------

    @cached_property
    def _get_title_3(self):
        try:
            return ('The square root of %s is %s' %
                    (self.value, self.value ** 0.5))
        except:
            return ('The square root of %s is %si' %
                    (self.value, (-self.value) ** 0.5))
Beispiel #6
0
class ViewHandlerMixin(HasTraits):
    """
    Useful bits for view handlers. 
    """
    
    # the view for the current plot
    current_plot_view = \
        View(
            HGroup(
                Item('plot_names_by',
                     editor = TextEditor(),
                     style = "readonly",
                     show_label = False),
                Item('current_plot',
                     editor = TabListEditor(name = 'plot_names'),
                     style = 'custom',
                     show_label = False)))
        
    plot_params_traits = View(Item('plot_params',
                                   editor = InstanceEditor(),
                                   style = 'custom',
                                   show_label = False))
    
    context = Instance(WorkflowItem)
    
    conditions_names = Property(depends_on = "context.conditions")
    previous_conditions_names = Property(depends_on = "context.previous_wi.conditions")
    statistics_names = Property(depends_on = "context.statistics")
    numeric_statistics_names = Property(depends_on = "context.statistics")
    
    # MAGIC: gets value for property "conditions_names"
    def _get_conditions_names(self):
        if self.context and self.context.conditions:
            return sorted(list(self.context.conditions.keys()))
        else:
            return []
    
    # MAGIC: gets value for property "previous_conditions_names"
    def _get_previous_conditions_names(self):
        if self.context and self.context.previous_wi and self.context.previous_wi.conditions:
            return sorted(list(self.context.previous_wi.conditions.keys()))
        else:
            return []
        
    # MAGIC: gets value for property "statistics_names"
    def _get_statistics_names(self):
        if self.context and self.context.statistics:
            return sorted(list(self.context.statistics.keys()))
        else:
            return []

    # MAGIC: gets value for property "numeric_statistics_names"
    def _get_numeric_statistics_names(self):
        if self.context and self.context.statistics:
            return sorted([x for x in list(self.context.statistics.keys())
                                 if util.is_numeric(self.context.statistics[x])])
        else:
            return []

    @on_trait_change('context.view_error_trait', 
                     dispatch = 'ui', 
                     post_init = True)
    def _view_trait_error(self):
        
        # check if we're getting called on the local or remote process
        if self.info is None or self.info.ui is None:
            return
        
        for ed in self.info.ui._editors:  
                          
            if ed.name == self.context.view_error_trait:
                err_state = True
            else:
                err_state = False

            if not ed.label_control:
                continue
            
            item = ed.label_control
            
            if not err_state and not hasattr(item, '_ok_color'):
                continue
            
            pal = QtGui.QPalette(item.palette())  # @UndefinedVariable
            
            if err_state:
                setattr(item, 
                        '_ok_color', 
                        QtGui.QColor(pal.color(item.backgroundRole())))  # @UndefinedVariable
                pal.setColor(item.backgroundRole(), QtGui.QColor(255, 145, 145))  # @UndefinedVariable
                item.setAutoFillBackground(True)
                item.setPalette(pal)
            else:
                pal.setColor(item.backgroundRole(), item._ok_color)
                delattr(item, '_ok_color')
                item.setAutoFillBackground(False)
                item.setPalette(pal)
Beispiel #7
0
class VolumeSlicer(HasTraits):
    # The data to plot
    data = Array()

    # The 4 views displayed
    scene3d = Instance(MlabSceneModel, ())
    scene_x = Instance(MlabSceneModel, ())
    scene_y = Instance(MlabSceneModel, ())
    scene_z = Instance(MlabSceneModel, ())

    # The data source
    data_src3d = Instance(Source)

    # The image plane widgets of the 3D scene
    ipw_3d_x = Instance(PipelineBase)
    ipw_3d_y = Instance(PipelineBase)
    ipw_3d_z = Instance(PipelineBase)

    _axis_names = dict(x=0, y=1, z=2)

    #---------------------------------------------------------------------------
    def __init__(self, **traits):
        super(VolumeSlicer, self).__init__(**traits)
        # Force the creation of the image_plane_widgets:
        self.ipw_3d_x
        self.ipw_3d_y
        self.ipw_3d_z

    #---------------------------------------------------------------------------
    # Default values
    #---------------------------------------------------------------------------
    def _data_src3d_default(self):
        return mlab.pipeline.scalar_field(self.data,
                                          figure=self.scene3d.mayavi_scene)

    def make_ipw_3d(self, axis_name):
        ipw = mlab.pipeline.image_plane_widget(
            self.data_src3d,
            figure=self.scene3d.mayavi_scene,
            plane_orientation='%s_axes' % axis_name)
        return ipw

    def _ipw_3d_x_default(self):
        return self.make_ipw_3d('x')

    def _ipw_3d_y_default(self):
        return self.make_ipw_3d('y')

    def _ipw_3d_z_default(self):
        return self.make_ipw_3d('z')

    #---------------------------------------------------------------------------
    # Scene activation callbaks
    #---------------------------------------------------------------------------
    @on_trait_change('scene3d.activated')
    def display_scene3d(self):
        outline = mlab.pipeline.outline(
            self.data_src3d,
            figure=self.scene3d.mayavi_scene,
        )
        self.scene3d.mlab.view(40, 50)
        # Interaction properties can only be changed after the scene
        # has been created, and thus the interactor exists
        for ipw in (self.ipw_3d_x, self.ipw_3d_y, self.ipw_3d_z):
            # Turn the interaction off
            ipw.ipw.interaction = 0
        self.scene3d.scene.background = (0, 0, 0)
        # Keep the view always pointing up
        self.scene3d.scene.interactor.interactor_style = \
                                 tvtk.InteractorStyleTerrain()

    def make_side_view(self, axis_name):
        scene = getattr(self, 'scene_%s' % axis_name)

        # To avoid copying the data, we take a reference to the
        # raw VTK dataset, and pass it on to mlab. Mlab will create
        # a Mayavi source from the VTK without copying it.
        # We have to specify the figure so that the data gets
        # added on the figure we are interested in.
        outline = mlab.pipeline.outline(
            self.data_src3d.mlab_source.dataset,
            figure=scene.mayavi_scene,
        )
        ipw = mlab.pipeline.image_plane_widget(outline,
                                               plane_orientation='%s_axes' %
                                               axis_name)
        setattr(self, 'ipw_%s' % axis_name, ipw)

        # Synchronize positions between the corresponding image plane
        # widgets on different views.
        ipw.ipw.sync_trait('slice_position',
                           getattr(self, 'ipw_3d_%s' % axis_name).ipw)

        # Make left-clicking create a crosshair
        ipw.ipw.left_button_action = 0

        # Add a callback on the image plane widget interaction to
        # move the others
        def move_view(obj, evt):
            position = obj.GetCurrentCursorPosition()
            for other_axis, axis_number in self._axis_names.items():
                if other_axis == axis_name:
                    continue
                ipw3d = getattr(self, 'ipw_3d_%s' % other_axis)
                ipw3d.ipw.slice_position = position[axis_number]

        ipw.ipw.add_observer('InteractionEvent', move_view)
        ipw.ipw.add_observer('StartInteractionEvent', move_view)

        # Center the image plane widget
        ipw.ipw.slice_position = 0.5 * self.data.shape[
            self._axis_names[axis_name]]

        # Position the view for the scene
        views = dict(
            x=(0, 90),
            y=(90, 90),
            z=(0, 0),
        )
        scene.mlab.view(*views[axis_name])
        # 2D interaction: only pan and zoom
        scene.scene.interactor.interactor_style = \
                                 tvtk.InteractorStyleImage()
        scene.scene.background = (0, 0, 0)

    @on_trait_change('scene_x.activated')
    def display_scene_x(self):
        return self.make_side_view('x')

    @on_trait_change('scene_y.activated')
    def display_scene_y(self):
        return self.make_side_view('y')

    @on_trait_change('scene_z.activated')
    def display_scene_z(self):
        return self.make_side_view('z')

    #---------------------------------------------------------------------------
    # The layout of the dialog created
    #---------------------------------------------------------------------------
    view = View(
        HGroup(
            Group(
                Item('scene_y',
                     editor=SceneEditor(scene_class=Scene),
                     height=250,
                     width=300),
                Item('scene_z',
                     editor=SceneEditor(scene_class=Scene),
                     height=250,
                     width=300),
                show_labels=False,
            ),
            Group(
                Item('scene_x',
                     editor=SceneEditor(scene_class=Scene),
                     height=250,
                     width=300),
                Item('scene3d',
                     editor=SceneEditor(scene_class=MayaviScene),
                     height=250,
                     width=300),
                show_labels=False,
            ),
        ),
        resizable=True,
        title='Volume Slicer',
    )
class FunctionPlotter(HasTraits):
    figure = Instance(Figure, ())  #❶
    code = Code()  #❷
    points = List(Instance(Point), [])  #❸
    draw_button = Button("Plot")

    view = View(
        VSplit(
            Item("figure",
                 editor=MPLFigureEditor(toolbar=True),
                 show_label=False),  #❶
            HSplit(
                VGroup(
                    Item("code", style="custom"),  #❷
                    HGroup(Item("draw_button", show_label=False), ),
                    show_labels=False),
                Item("points", editor=point_table_editor, show_label=False)  #❸
            )),
        width=800,
        height=600,
        title="Function Plotter",
        resizable=True)

    ###2###
    ###3###
    def __init__(self, **kw):
        super(FunctionPlotter, self).__init__(**kw)
        self.figure.canvas_events = [  #❶
            ("button_press_event", self.memory_location),
            ("button_release_event", self.update_location)
        ]
        self.button_press_status = None  #保存鼠标按键按下时的状态
        self.lines = []  #保存所有曲线
        self.functions = []  #保存所有的曲线函数
        self.env = {}  #代码的执行环境

        self.axe = self.figure.add_subplot(1, 1, 1)
        self.axe.callbacks.connect('xlim_changed', self.update_data)  #❷
        self.axe.set_xlim(0, 1)
        self.axe.set_ylim(0, 1)
        self.points_line, = self.axe.plot([], [], "kx", ms=8,
                                          zorder=1000)  #数据点
###3###
###6###

    def update_data(self, axe):
        xmin, xmax = axe.get_xlim()
        x = np.linspace(xmin, xmax, 500)
        for line, func in zip(self.lines, self.functions):
            y = func(x)
            line.set_data(x, y)
        self.update_figure()
###6###
###4###

    def memory_location(self, evt):
        if evt.button in (1, 3):
            self.button_press_status = time.clock(), evt.x, evt.y
        else:
            self.button_press_status = None

    def update_location(self, evt):
        if evt.button in (1, 3) and self.button_press_status is not None:
            last_clock, last_x, last_y = self.button_press_status
            if time.clock() - last_clock > 0.5:  #❶
                return
            if ((evt.x - last_x)**2 + (evt.y - last_y)**2)**0.5 > 4:  #❷
                return

        if evt.button == 1:
            if evt.xdata is not None and evt.ydata is not None:
                point = Point(x=evt.xdata, y=evt.ydata)  #❸
                self.points.append(point)
        elif evt.button == 3:
            if self.points:
                self.points.pop()  #❹
###4###
###5###

    @on_trait_change("points[]")
    def _points_changed(self, obj, name, new):
        for point in new:
            point.on_trait_change(self.update_points, name="x, y")  #❶
        self.update_points()

    def update_points(self):  #❷
        arr = np.array([(point.x, point.y) for point in self.points])
        if arr.shape[0] > 0:
            self.points_line.set_data(arr[:, 0], arr[:, 1])
        else:
            self.points_line.set_data([], [])
        self.update_figure()

    def update_figure(self):  #❸
        if self.figure.canvas is not None:  #❹
            self.figure.canvas.draw_idle()
###5###
###7###

    def _draw_button_fired(self):
        self.plot_lines()

    def plot_lines(self):
        xmin, xmax = self.axe.get_xlim()  #❶
        x = np.linspace(xmin, xmax, 500)
        self.env = {
            "points": np.array([(point.x, point.y) for point in self.points])
        }  #❷
        exec self.code in self.env

        results = []
        for line in self.lines:
            line.remove()
        self.axe.set_color_cycle(None)  #重置颜色循环
        self.functions = []
        self.lines = []
        for name, value in self.env.items():  #❸
            if name.startswith("_"):  #忽略以_开头的名字
                continue
            if callable(value):
                try:
                    y = value(x)
                    if y.shape != x.shape:  #输出数组应该与输入数组的形状一致
                        raise ValueError(
                            "the return shape is not the same as x")
                except Exception as ex:
                    import traceback
                    print "failed when call function {}\n".format(name)
                    traceback.print_exc()
                    continue

                results.append((name, y))
                self.functions.append(value)

        for (name, y), function in zip(results, self.functions):
            #如果函数有plot_parameters属性,则用其作为plot()的参数
            kw = getattr(function, "plot_parameters", {})  #❹
            label = kw.get("label", name)
            line, = self.axe.plot(x, y, label=label, **kw)
            self.lines.append(line)

        points = self.env.get("points", None)  #❺
        if points is not None:
            self.points = [
                Point(x=x, y=y) for x, y in np.asarray(points).tolist()
            ]

        self.axe.legend()
        self.update_figure()
Beispiel #9
0
class ResultViewer(HasTraits):

    sensor_graph = Instance(TravelsensorGraph, ())

    result_options = Instance(Combobox, ())

    show_result = Button("Show")

    show_index = Int()

    cur_image = Image()

    logger = getLogger("Application")

    def __init__(self, recorder):
        self.recorder = recorder
        self.result_options.add_item('recorded_image',
                                     self.show_recorded_image)
        self.result_options.add_item('strain-exx', self.show_strain_exx)
        self.result_options.add_item('strain-exy', self.show_strain_exy)
        self.result_options.add_item('strain-eyy', self.show_strain_eyy)
        self.result_options.selected_key = 'recorded_image'

    def show_recorded_image(self, index):
        if not self.recorder.show_images:
            self.result_options.add_listener(self)
            self.recorder.show_images = True
            self.show_images = True
        try:
            fname = self.recorder.images[index]
        except IndexError:
            fname = 'None'
        self.fpath = join(images_dir, fname)
        self.cur_image = ImageResource(join(resized_images_dir, fname))

    def show_strain_exx(self, index):
        fname = strain_exx_img_file.format(convert_number(index))
        self.fpath = join(result_normal_dir, fname)
        self.cur_image = ImageResource(join(result_resized_dir, fname))

    def show_strain_exy(self, index):
        fname = strain_exy_img_file.format(convert_number(index))
        self.fpath = join(result_normal_dir, fname)
        self.cur_image = ImageResource(join(result_resized_dir, fname))

    def show_strain_eyy(self, index):
        fname = strain_eyy_img_file.format(convert_number(index))
        self.fpath = join(result_normal_dir, fname)
        self.cur_image = ImageResource(join(result_resized_dir, fname))

    def update_image(self, index):
        self.index = index
        self.result_options.get_selected_value()(index)

    def selected_changed(self, selected_key):
        for key in self.result_options.values:
            if key == selected_key:
                self.update_image(self.index)

    def _sensor_fired(self):
        files = get_all_files(travel_sensor_sensors_dir)
        sensors = []
        for f in files:
            if ".npy" in f:
                sensor = Sensor.load(join(travel_sensor_sensors_dir, f))
                sensors.append(sensor)
        self.sensor_graph.update_sensors(sensors)
        self.sensor_graph.plot(0)

    def _show_result_fired(self):
        img = imread(self.fpath)
        namedWindow('image', WINDOW_NORMAL)
        imshow('image', img)
        waitKey(0)
        destroyAllWindows()

    sensor = Button('Show Sensors')

    show_images = Bool(False)

    view = View(
        VGroup(VGroup(
            UItem('cur_image', width=300, height=225),
            label="Recorded image:",
        ),
               HGroup(
                   UItem('result_options', style='custom'),
                   UItem('show_result', label='Show details'),
                   UItem('sensor'),
               ),
               visible_when='show_images'))
Beispiel #10
0
    mrk_out_wildcard = ["Tab separated values file (*.txt)|*.txt"]
else:
    mrk_wildcard = ["*.sqd;*.mrk;*.txt;*.pickled"]
    mrk_out_wildcard = "*.txt"
out_ext = '.txt'


use_editor_v = CheckListEditor(cols=1, values=[(i, str(i)) for i in range(5)])
use_editor_h = CheckListEditor(cols=5, values=[(i, str(i)) for i in range(5)])

mrk_view_editable = View(
    VGroup('file',
           Item('name', show_label=False, style='readonly'),
           HGroup(
               Item('use', editor=use_editor_v, enabled_when="enabled",
                    style='custom'),
               'points',
           ),
           HGroup(Item('clear', enabled_when="can_save", show_label=False),
                  Item('save_as', enabled_when="can_save",
                       show_label=False)),
           ))

mrk_view_basic = View(
    VGroup('file',
           Item('name', show_label=False, style='readonly'),
           Item('use', editor=use_editor_h, enabled_when="enabled",
                style='custom'),
           HGroup(Item('clear', enabled_when="can_save", show_label=False),
                  Item('edit', show_label=False),
                  Item('save_as', enabled_when="can_save",
Beispiel #11
0
 Group(
     Item(name='number_of_labels'),
     enabled_when='show_scalar_bar==True',
 ),
 Group(
     Item(name='shadow'),
     Item(name='use_default_name'),
     Item(name='data_name',
          enabled_when='not object.use_default_name'),
     HGroup(
         Item(name='_title_text_property',
              show_label=False,
              editor=InstanceEditor(
                  label='Edit bar Title',
                  id='mayavi.core.lut_manager.bar_title_text')),
         Item(name='_label_text_property',
              show_label=False,
              editor=InstanceEditor(
                  label='Edit bar Text',
                  id='mayavi.core.lut_manager.bar_label_text'),
              label='Edit bar Text'),
     ),
     HGroup(
         Item(
             name='scalar_bar',
             show_label=False,
             editor=InstanceEditor(
                 label='Edit bar Actor',
                 id='mayavi.core.lut_manager.bar_actor'),
         ),
         Item(
class SolutionView(HasTraits):
  python_console_cmds = Dict()
  pdop = Float()
  gdop = Float()
  tdop = Float()
  hdop = Float()
  vdop = Float()
  pos_llh = Array(dtype=float, shape=(3,))
  pos_ned = Array(dtype=float, shape=(3,))
  ns = List()
  mean_ns = Float()
  es = List()
  mean_es = Float()
  ds = List()
  mean_ds = Float()
  mean_len = Int(50)
  mean_dist = Float()
  n_used = Int()
  dist = Float()

  plot = Instance(Plot)
  plot_data = Instance(ArrayPlotData)
  clear = Button()

  pr_plot = Instance(Plot)
  pr_plot_data = Instance(ArrayPlotData)
  prs = List()
  pred_prs = List()

  traits_view = View(
    HGroup(
      Item('pdop', label='PDOP', format_str='%.1f'),
      Item('gdop', label='GDOP', format_str='%.1f'),
      Item('tdop', label='TDOP', format_str='%.1f'),
      Item('hdop', label='HDOP', format_str='%.1f'),
      Item('vdop', label='VDOP', format_str='%.1f'),
    ),
    Item('clear'),
    HGroup(
      Item('pos_llh'),
      Item('pos_ned'),
      VGroup(
        Item('dist'),
        Item('mean_len'),
        Item('mean_dist'),
      ),
      VGroup(
        Item('mean_ns'),
        Item('mean_es'),
        Item('mean_ds'),
      ),
      Item('n_used')
    ),
    Item(
      'plot',
      editor = ComponentEditor(bgcolor = (0.8,0.8,0.8)),
    )
  )

  prs_view = View(
    Item(
      'pr_plot',
      editor = ComponentEditor(bgcolor = (0.8,0.8,0.8)),
      show_label = False,
    )
  )


  def _clear_fired(self):
    self.ns = []
    self.es = []
    self.ds = []

  def prs_callback(self, data):
    fmt = '<' + str(TRACK_N_CHANNELS) + 'd'
    self.prs.append(struct.unpack(fmt, data))
    prs = np.transpose(self.prs[-500:])
    t = range(len(prs[0]))
    self.pr_plot_data.set_data('t', t)
    for n in range(TRACK_N_CHANNELS):
      self.pr_plot_data.set_data('prs'+str(n), prs[n])

  def pred_prs_callback(self, data):
    return
    fmt = '<' + str(TRACK_N_CHANNELS) + 'd'
    self.pred_prs.append(struct.unpack(fmt, data))
    pred_prs = np.array(np.transpose(self.pred_prs[-500:]))
    prs = np.array(np.transpose(self.prs[-500:]))
    t = range(len(pred_prs[0]))
    self.pr_plot_data.set_data('t', t)
    for n in range(TRACK_N_CHANNELS):
      err = prs[n]-pred_prs[n]
      #err = err - (sum(err)/len(err))
      self.pr_plot_data.set_data('pred_prs'+str(n), err)

  def solution_callback(self, data):
    soln = struct.unpack('<3d3d3d3d3d7ddBB', data)
    self.pos_llh = [soln[0]*(180/math.pi), soln[1]*(180/math.pi), soln[2]]
    pos_xyz = soln[3:6]
    self.pos_ned = soln[6:9]
    vel_xyz = soln[9:12]
    vel_ned = soln[12:15]
    err_cov = soln[15:22]
    time = soln[22]
    soln_valid = soln[23]
    self.n_used = soln[24]

    self.dist = math.sqrt(self.pos_ned[0]**2 + self.pos_ned[1]**2 + self.pos_ned[2]**2)

    if self.dist < 3000:
      self.ns.append(self.pos_ned[0])
      self.es.append(self.pos_ned[1])
      self.ds.append(self.pos_ned[2])
    else:
      print "Whacky solution detected!"
    
    self.mean_ns = sum(self.ns[:self.mean_len])/len(self.ns[:self.mean_len])
    self.mean_es = sum(self.es[:self.mean_len])/len(self.es[:self.mean_len])
    self.mean_ds = sum(self.ds[:self.mean_len])/len(self.ds[:self.mean_len])
    self.mean_dist = math.sqrt(self.mean_ns**2 + self.mean_es**2 + self.mean_ds**2)

    self.plot_data.set_data('n', self.ns)
    self.plot_data.set_data('e', self.es)
    self.plot_data.set_data('h', self.ds)
    self.plot_data.set_data('ref_n', [0.0, self.mean_ns])
    self.plot_data.set_data('ref_e', [0.0, self.mean_es])
    t = range(len(self.ds))
    self.plot_data.set_data('t', t)

  def dops_callback(self, data):
    self.pdop, self.dgop, self.tdop, self.hdop, self.vdop = struct.unpack('<ddddd', data)

  def __init__(self, link):
    super(SolutionView, self).__init__()

    self.link = link
    self.link.add_callback(MSG_SOLUTION, self.solution_callback)
    self.link.add_callback(MSG_SOLUTION_DOPS, self.dops_callback)
    self.link.add_callback(MSG_SOLUTION_PRS, self.prs_callback)
    self.link.add_callback(MSG_SOLUTION_PRED_PRS, self.pred_prs_callback)

    self.plot_data = ArrayPlotData(n=[0.0], e=[0.0], h=[0.0], t=[0.0], ref_n=[0.0], ref_e=[0.0])
    self.plot = Plot(self.plot_data) #, auto_colors=colours_list)
    self.plot.plot(('n', 'e'), type='scatter', color='blue', marker='plus')
    self.plot.plot(('ref_n', 'ref_e'),
        type='scatter',
        color='red',
        marker='cross',
        marker_size=10,
        line_width=1.5
    )
    #self.plot.plot(('h', 'e'), type='line', color='red')

    self.pr_plot_data = ArrayPlotData(t=[0.0])
    self.pr_plot = Plot(self.pr_plot_data, auto_colors=colours_list)
    self.pr_plot.value_range.tight_bounds = False
    #self.pr_plot.value_range.low_setting = 0.0
    for n in range(TRACK_N_CHANNELS):
      self.pr_plot_data.set_data('prs'+str(n), [0.0])
      self.pr_plot.plot(('t', 'prs'+str(n)), type='line', color='auto')
      #self.pr_plot_data.set_data('pred_prs'+str(n), [0.0])
      #self.pr_plot.plot(('t', 'pred_prs'+str(n)), type='line', color='auto')

    self.python_console_cmds = {
      'solution': self
    }
Beispiel #13
0
 HGroup(
     VGroup(
         HGroup(  # Simulation Control
             VGroup(
                 Item(
                     name="bit_rate",
                     label="Bit Rate (Gbps)",
                     tooltip="bit rate",
                     show_label=True,
                     enabled_when="True",
                     editor=TextEditor(auto_set=False, enter_set=True, evaluate=float),
                 ),
                 Item(
                     name="nbits",
                     label="Nbits",
                     tooltip="# of bits to run",
                     editor=TextEditor(auto_set=False, enter_set=True, evaluate=int),
                 ),
                 Item(
                     name="nspb",
                     label="Nspb",
                     tooltip="# of samples per bit",
                     editor=TextEditor(auto_set=False, enter_set=True, evaluate=int),
                 ),
                 Item(
                     name="mod_type",
                     label="Modulation",
                     tooltip="line signalling/modulation scheme",
                     editor=CheckListEditor(values=[(0, "NRZ"), (1, "Duo-binary"), (2, "PAM-4")]),
                 ),
             ),
             VGroup(
                 Item(name="do_sweep", label="Do Sweep", tooltip="Run parameter sweeps."),
                 Item(
                     name="sweep_aves",
                     label="SweepAves",
                     tooltip="# of trials, per sweep, for averaging.",
                     enabled_when="do_sweep == True",
                 ),
                 Item(
                     name="pattern_len",
                     label="PatLen",
                     tooltip="length of random pattern to use to construct bit stream",
                     editor=TextEditor(auto_set=False, enter_set=True, evaluate=int),
                 ),
                 Item(
                     name="eye_bits",
                     label="EyeBits",
                     tooltip="# of bits to use to form eye diagrams",
                     editor=TextEditor(auto_set=False, enter_set=True, evaluate=int),
                 ),
             ),
             VGroup(
                 Item(name="vod", label="Vod (V)", tooltip="Tx output voltage into matched load"),
                 Item(name="rn", label="Rn (V)", tooltip="standard deviation of random noise"),
                 Item(name="pn_mag", label="Pn (V)", tooltip="peak magnitude of periodic noise"),
                 Item(name="pn_freq", label="f(Pn) (MHz)", tooltip="frequency of periodic noise"),
             ),
         ),
         label="Simulation Control",
         show_border=True,
     ),
     VGroup(
         Item(
             name="thresh",
             label="Pj Threshold (sigma)",
             tooltip="Threshold for identifying periodic jitter spectral elements. (sigma)",
         ),
         Item(
             name="impulse_length",
             label="Impulse Response Length (ns)",
             tooltip="Manual impulse response length override",
         ),
         Item(name="debug", label="Debug", tooltip="Enable to log extra information to console."),
         label="Analysis Parameters",
         show_border=True,
     ),
 ),
Beispiel #14
0
class PandasPlot(HasTraits):
    '''Plot to interface a pandas df'''

    ### For testing
    rnd_cols = Bool(False)
    samecols = Bool(False)
    transpose = Bool(False)

    ### Traits of the actual plot and plotdatasource handler ###
    _dffull = Instance(DataFrame)  #Any?
    plot = Instance(Plot)
    plotdata = Instance(
        PandasPlotData)  #Data stored at any given time in the plot
    df = Instance(DataFrame)

    ### Axis traits
    idxname = Str('Index')
    colname = Str('Column')
    idxorient = DefaultEnum('top', 'bottom', 'left', 'right', default='bottom')
    colorient = DefaultEnum('top', 'bottom', 'left', 'right', default='top')
    selection_axis = DefaultEnum(
        'index', 'value',
        default='index')  #Which axis does selection tool sample

    ### Aesthetic traits
    title = Str('Title')  #Defaults from df name
    linecolor = Str('yellow')
    pointcolor = Str('red')
    linestyle = Enum('line', 'scatter', 'both')
    markersize = Range(low=1, high=5)

    sampling = Range(low=0.0, high=100., value=100.0)
    _spacing = Property(depends_on='sampling')

    ### _Event Handlers

    def _rnd_cols_changed(self):

        x = np.linspace(0, 100, 100)  #Index generator
        y = np.linspace(0, 100, 100)  #Column generator

        scale = randint(1, 1000)

        self.df = DataFrame((np.random.rand(len(x), len(y))),
                            columns=(scale / 2.0) * y,
                            index=scale * x)

    def _samecols_changed(self):
        self.df = DataFrame((np.random.rand(100, 100)))

    def _transpose_changed(self):
        self.df = self.df.transpose()

    ### Axis Aesthetics
    @on_trait_change('idxname', 'idxcolumn', 'idxorient', 'colorient')
    def _axis_changed(self, trait, new):
        '''Change plot axis name or orientation'''
        setattr(self, trait, new)
        self._update_axis()
        self.plot.request_redraw(
        )  #Necessary but how do I only call axis redraw?

    def _title_changed(self, old, new):
        if old != new:
            self.plot.title = new
            self.plot.request_redraw(
            )  #HOW TO PREVENT COLLISION WITH TOP OVERLAY

    def _selection_axis_changed(self, old, new):
        if old != new:
            self._update_lines()

    def _df_changed(self, old, new):
        ''' Handles how updates occur when df changes.  Evaluates if columns or columnlabels
        have been changed.  Provides entry condition as well.

        Note: New automatically sets self.df, so when I refer to new, I am actually
        referring to self.df.  Using "new" instead of self.df is just for readability'''

        ### Initialize plot first time df is passed into the class.  Boolean listeners
        ### for df behave oddly, so uses self.plotdata for entry condition.

        if not self.plotdata:
            self.plotdata = PandasPlotData(df=new)

            self._dffull = new

            ### Try to infer plot title from df name ###
            try:
                self.title = new.name  #Turn into a "transfer" method where I pass list of attributes i want look for
            except AttributeError:
                pass

            ### Draw barebones of plot
            self._plot_default()
            self._update_lines()

        ### Decide to update columns or completely redraw df.
        else:
            changed = self.plotdata.set_df(new)

            ### If 'event changed', don't bother updaing lines
            if not changed:
                self._update_lines()

    ### Plot spacing

    def _get__spacing(self):
        '''Integer spacing given % sampling'''
        samp = self.sampling / 100.0
        colsize = df.shape[0]
        return colsize - int(round(colsize * samp, 0))

    def _sampling_changed(self, old, new):
        if old != new:
            self._update_samples()

    def _update_samples(self):
        '''Updates the list of line plots shown or hidden based on plot sampling.'''
        if self._spacing == 0:
            return

        ### Hide all plots
        to_hide = self.plot.plots.keys()
        self.plot.hideplot(*to_hide)

        ### Show only plots in samples
        to_show = self.plot.plots.keys()[::self._spacing]
        self.plot.showplot(*to_show)
        self.plot.request_redraw()

    def _update_rangeselect(self):
        ''' Overwrites range selection tool in current plot.'''

        #### Remove current overlay
        self.plot.overlays = [
            obj for obj in self.plot.overlays
            if not isinstance(obj, RangeSelectionOverlay)
        ]

        mycomp = self.plot.plots.itervalues().next()[
            0]  #Quick wayt to get first value in dictionary

        inds = range(len(self.df.index))
        idx = ArrayDataSource(inds)
        vals = ArrayDataSource(df.index.values)

        index_range = DataRange1D(idx)
        val_range = DataRange1D(vals)
        imap = LinearMapper(
            range=index_range)  #,stretch_data=self.index_mapper.stretch_data)
        vmap = LinearMapper(range=val_range)
        #   mycomp.index_range.refresh()

        mycomp.index_mapper = imap
        mycomp.value_mapper = vmap

        self.rangeselect = RangeSelection(mycomp, axis=self.selection_axis)
        self.plot.active_tool = self.rangeselect
        self.plot.overlays.append(RangeSelectionOverlay(component=mycomp))
        self.rangeselect.on_trait_change(self.on_selection_changed,
                                         "selection")

    def _update_lines(self):
        ''' Redraws lines, plots and reapplies line selection.'''

        oldplots = self.plot.plots.keys()
        newplots = [name for name in self.plotdata.list_data(as_strings=True)]

        to_remove = [p for p in oldplots if p not in newplots]
        to_add = [p for p in newplots if p not in oldplots]

        if to_remove:
            for p in to_remove:
                self.plot.delplot(p)

        if to_add:
            for name in to_add:
                self.plot.plot(('index', name),
                               name=name,
                               color=self.linecolor)

        self._update_axis()
        self._update_samples()
        self._update_rangeselect()

    def on_selection_changed(self, selection):
        if selection != None:
            self.rangeXMin, self.rangeXMax = selection
            print selection

    def _update_axis(self):
        ''' Forces a label axis onto the plot. '''

        print 'updaing axis', self.idxname

        indexlabels = [str(round(i, 1)) for i in self.df.index]
        columnlabels = [str(round(i, 1)) for i in self.df.columns]

        index_axis = LabelAxis(
            self.plot,
            orientation=self.idxorient,
            positions=range(int(float(indexlabels[0])),
                            int(float(indexlabels[-1]))),
            labels=indexlabels,  #, resizable='hv',
            title=self.idxname)

        col_axis = LabelAxis(
            self.plot,
            orientation=self.colorient,
            positions=range(int(float(columnlabels[0])),
                            int(float(columnlabels[-1]))),
            labels=columnlabels,  #, resizable='hv',
            title=self.colname)

        ### Remove underlays
        self.plot.underlays = [
            obj for obj in self.plot.underlays
            if not isinstance(obj, PlotAxis)
        ]
        self.plot.underlays = [
            obj for obj in self.plot.underlays
            if not isinstance(obj, LabelAxis)
        ]

        self.plot.underlays.append(index_axis)
        self.plot.underlays.append(col_axis)

    def _plot_default(self, toolbar=True, **pltkwds):
        ''' Draw bare plot, including main plotting area, toolbar, etc...
         either at initialization or global redo'''

        if toolbar:
            self.plot = ToolbarPlot(self.plotdata, **pltkwds)
        else:
            self.plot = Plot(self.plotdata, **pltkwds)

        self.plot.title = self.title
        self.plot.padding = 50
        self.plot.legend.visible = False

        self.plot.tools.append(PanTool(self.plot))
        zoom = BetterSelectingZoom(component=self.plot,
                                   tool_mode="box",
                                   always_on=False)
        self.plot.overlays.append(zoom)

    def _overwrite_plotdata(self):
        '''When a new instance of PandasPlotData is created, this overwrites the
        data source and updates the axis values.'''
        self.plotdata = PandasPlotData(df=self.df)
        self._plot_default()  #CAN THIS JUST DRAW LINES

    ### Traits View

    main_group = Group(
        HGroup(
            Item('rnd_cols'),
            Item('samecols'),
            Item('transpose'),
        ),
        Item('plot', editor=ComponentEditor(), show_label=False),
        Item('idxname'),
        Item('idxorient'),
        Item('selection_axis'),
        Item('title'),
        Item('sampling'),

        #   Item('df_new'), Item('df_change'),
        #Include('sample_group'),
        #Include('axis_traits_group')
    )

    traits_view = View(Include('main_group'), height=600, width=800)
Beispiel #15
0
class UpdateView(HasTraits):
    piksi_hw_rev = String('piksi_multi')
    is_v2 = Bool(False)

    piksi_stm_vers = String('Waiting for Piksi to send settings...',
                            width=COLUMN_WIDTH)
    newest_stm_vers = String('Downloading Latest Firmware info...')
    piksi_nap_vers = String('Waiting for Piksi to send settings...')
    newest_nap_vers = String('Downloading Latest Firmware info...')
    local_console_vers = String('v' + CONSOLE_VERSION)
    newest_console_vers = String('Downloading Latest Console info...')

    erase_stm = Bool(True)
    erase_en = Bool(True)

    update_stm_firmware = Button(label='Update FW')
    update_nap_firmware = Button(label='Update NAP')
    update_full_firmware = Button(label='Update Piksi STM and NAP Firmware')

    updating = Bool(False)
    update_stm_en = Bool(False)
    update_nap_en = Bool(False)
    update_en = Bool(False)
    serial_upgrade = Bool(False)
    upgrade_steps = String("Firmware upgrade steps:")

    download_firmware = Button(label='Download Latest Firmware')
    download_directory = Directory(
        "  Please choose a directory for downloaded firmware files...")
    download_stm = Button(label='Download', height=HT)
    download_nap = Button(label='Download', height=HT)
    downloading = Bool(False)
    download_fw_en = Bool(True)

    stm_fw = Instance(FirmwareFileDialog)
    nap_fw = Instance(FirmwareFileDialog)

    stream = Instance(OutputStream)

    view = View(
        VGroup(
            Item('piksi_hw_rev',
                 label='Hardware Revision',
                 editor_args={'enabled': False},
                 resizable=True),
            HGroup(
                VGroup(Item('piksi_stm_vers',
                            label='Current',
                            resizable=True,
                            editor_args={'enabled': False}),
                       Item('newest_stm_vers',
                            label='Latest',
                            resizable=True,
                            editor_args={
                                'enabled': False,
                                'readonly_allow_selection': True
                            }),
                       Item('stm_fw',
                            style='custom',
                            show_label=True,
                            label="Local File",
                            enabled_when='download_fw_en',
                            visible_when='serial_upgrade',
                            editor_args={'enabled': False}),
                       HGroup(
                           Item('update_stm_firmware',
                                show_label=False,
                                enabled_when='update_stm_en',
                                visible_when='serial_upgrade'),
                           Item('erase_stm',
                                label='Erase STM flash\n(recommended)',
                                enabled_when='erase_en',
                                show_label=True,
                                visible_when='is_v2')),
                       show_border=True,
                       label="Firmware Version"),
                VGroup(Item('piksi_nap_vers',
                            label='Current',
                            resizable=True,
                            editor_args={'enabled': False}),
                       Item('newest_nap_vers',
                            label='Latest',
                            resizable=True,
                            editor_args={'enabled': False}),
                       Item('nap_fw',
                            style='custom',
                            show_label=True,
                            label="Local File",
                            enabled_when='download_fw_en',
                            editor_args={'enabled': False}),
                       HGroup(
                           Item('update_nap_firmware',
                                show_label=False,
                                enabled_when='update_nap_en',
                                visible_when='serial_upgrade'),
                           Item(width=50, label="                  ")),
                       show_border=True,
                       label="NAP Version",
                       visible_when='is_v2'),
                VGroup(Item('local_console_vers',
                            label='Current',
                            resizable=True,
                            editor_args={'enabled': False}),
                       Item('newest_console_vers',
                            label='Latest',
                            editor_args={'enabled': False}),
                       label="Swift Console Version",
                       show_border=True),
            ), UItem('download_directory', enabled_when='download_fw_en'),
            UItem('download_firmware', enabled_when='download_fw_en'),
            UItem('update_full_firmware',
                  enabled_when='update_en',
                  visible_when='is_v2'),
            VGroup(
                UItem('upgrade_steps',
                      visible_when='not serial_upgrade',
                      style='readonly'),
                Item(
                    'stream',
                    style='custom',
                    editor=InstanceEditor(),
                    show_label=False,
                ),
                show_border=True,
            )))

    def __init__(self,
                 link,
                 download_dir=None,
                 prompt=True,
                 serial_upgrade=False):
        """
        Traits tab with UI for updating Piksi firmware.

        Parameters
        ----------
        link : sbp.client.handler.Handler
          Link for SBP transfer to/from Piksi.
        prompt : bool
          Prompt user to update console/firmware if out of date.
        """
        self.link = link
        self.settings = {}
        self.prompt = prompt
        self.python_console_cmds = {'update': self}
        try:
            self.update_dl = UpdateDownloader()
            if download_dir:
                self.update_dl.set_root_path(download_dir)
        except URLError:
            self.update_dl = None
        self.erase_en = True
        self.stm_fw = FirmwareFileDialog('bin')
        self.stm_fw.on_trait_change(self._manage_enables, 'status')
        self.nap_fw = FirmwareFileDialog('M25')
        self.nap_fw.on_trait_change(self._manage_enables, 'status')
        self.stream = OutputStream()
        self.serial_upgrade = serial_upgrade
        self.last_call_fw_version = None
        if not self.serial_upgrade:
            self._write(
                "1. Insert the USB flash drive provided with your Piki Multi into "
                "your computer.  Select the flash drive root directory as the "
                "firmware download destination using the \"Please "
                "choose a directory for downloaded firmware files\" directory "
                "chooser above.  Press the \"Download Latest Firmware\" button.  "
                "This will download the latest Piksi Multi firmware file onto the "
                "USB flashdrive.\n"
                "2. Eject the drive from your computer and plug it "
                "into the Piksi Multi evaluation board.\n"
                "3. Reset your Piksi Multi and it will upgrade to the version "
                "on the USB flash drive. This should take less than 5 minutes.\n"
                "4. When the upgrade completes you will be prompted to remove the "
                "USB flash drive and reset your Piksi Multi.\n"
                "5. Verify that the firmware version has upgraded via inspection "
                "of the Current Firmware Version box on the Firmware Update Tab "
                "of the Swift Console.\n")

    def _manage_enables(self):
        """ Manages whether traits widgets are enabled in the UI or not. """
        if self.updating or self.downloading:
            self.update_stm_en = False
            self.update_nap_en = False
            self.update_en = False
            self.download_fw_en = False
            self.erase_en = False
        else:
            self.download_fw_en = True
            self.erase_en = True
            if self.stm_fw.ihx is not None or self.stm_fw.blob is not None:
                self.update_stm_en = True
            else:
                self.update_stm_en = False
                self.update_en = False
            if self.nap_fw.ihx is not None:
                self.update_nap_en = True
            else:
                self.update_nap_en = False
                self.update_en = False
            if self.nap_fw.ihx is not None and self.stm_fw.ihx is not None:
                self.update_en = True

    def _download_directory_changed(self):
        if self.update_dl:
            self.update_dl.set_root_path(self.download_directory)

    def _updating_changed(self):
        """ Handles self.updating trait being changed. """
        self._manage_enables()

    def _downloading_changed(self):
        """ Handles self.downloading trait being changed. """
        self._manage_enables()

    def _write(self, text):
        """
        Stream style write function. Allows flashing debugging messages to be
        routed to embedded text console.

        Parameters
        ----------
        text : string
          Text to be written to screen.
        """
        self.stream.write(text)
        self.stream.write('\n')
        self.stream.flush()

    def _update_stm_firmware_fired(self):
        """
        Handle update_stm_firmware button. Starts thread so as not to block the GUI
        thread.
        """
        try:
            if self._firmware_update_thread.is_alive():
                return
        except AttributeError:
            pass

        self._firmware_update_thread = Thread(
            target=self.manage_firmware_updates, args=("STM", ))
        self._firmware_update_thread.start()

    def _update_nap_firmware_fired(self):
        """
        Handle update_nap_firmware button. Starts thread so as not to block the GUI
        thread.
        """
        try:
            if self._firmware_update_thread.is_alive():
                return
        except AttributeError:
            pass

        self._firmware_update_thread = Thread(
            target=self.manage_firmware_updates, args=("M25", ))
        self._firmware_update_thread.start()

    def _update_full_firmware_fired(self):
        """
        Handle update_full_firmware button. Starts thread so as not to block the GUI
        thread.
        """
        try:
            if self._firmware_update_thread.is_alive():
                return
        except AttributeError:
            pass

        self._firmware_update_thread = Thread(
            target=self.manage_firmware_updates, args=("ALL", ))
        self._firmware_update_thread.start()

    def _download_firmware(self):
        """ Download latest firmware from swiftnav.com. """
        self._write('')

        # Check that we received the index file from the website.
        if self.update_dl is None:
            self._write("Error: Can't download firmware files")
            return

        self.downloading = True
        status = 'Downloading Latest Firmware...'
        self.nap_fw.clear(status)
        self.stm_fw.clear(status)
        self._write(status)

        # Get firmware files from Swift Nav's website, save to disk, and load.
        if 'fw' in self.update_dl.index[self.piksi_hw_rev]:
            try:
                self._write('Downloading Latest Multi firmware')
                filepath = self.update_dl.download_multi_firmware(
                    self.piksi_hw_rev)
                self._write('Saved file to %s' % filepath)
                self.stm_fw.load_bin(filepath)
            except AttributeError:
                self.nap_fw.clear("Error downloading firmware")
                self._write(
                    "Error downloading firmware: index file not downloaded yet"
                )
            except IOError:
                self.nap_fw.clear(
                    "IOError: unable to write to path %s. "
                    "Verify that the path exists and is writable." %
                    self.download_directory)
                self._write("IOError: unable to write to path %s. "
                            "Verify that the path exists and is writable." %
                            self.download_directory)
            except KeyError:
                self.nap_fw.clear("Error downloading firmware")
                self._write(
                    "Error downloading firmware: URL not present in index")
            except URLError:
                self.nap_fw.clear("Error downloading firmware")
                self._write(
                    "Error: Failed to download latest NAP firmware from Swift Navigation's website"
                )
            self.downloading = False
            return

    def _download_firmware_fired(self):
        """
        Handle download_firmware button. Starts thread so as not to block the GUI
        thread.
        """
        try:
            if self._download_firmware_thread.is_alive():
                return
        except AttributeError:
            pass

        self._download_firmware_thread = Thread(target=self._download_firmware)
        self._download_firmware_thread.start()

    def compare_versions(self):
        """
        To be called after latest Piksi firmware info has been received from
        device, to decide if current firmware on Piksi is out of date. Also informs
        user if the firmware was successfully upgraded. Starts a thread so as not
        to block GUI thread.
        """
        try:
            if self._compare_versions_thread.is_alive():
                return
        except AttributeError:
            pass

        self._compare_versions_thread = Thread(target=self._compare_versions)
        self._compare_versions_thread.start()

    def _compare_versions(self):
        """
        Compares version info between received firmware version / current console
        and firmware / console info from website to decide if current firmware or
        console is out of date. Prompt user to update if so. Informs user if
        firmware successfully upgraded.
        """
        # Check that settings received from Piksi contain FW versions.
        try:
            self.piksi_hw_rev = \
                HW_REV_LOOKUP[self.settings['system_info']
                              ['hw_revision'].value]
            self.piksi_stm_vers = \
                self.settings['system_info']['firmware_version'].value
        except KeyError:
            self._write(
                "\nError: Settings received from Piksi don't contain firmware version keys. Please contact Swift Navigation.\n"
            )
            return

        self.is_v2 = self.piksi_hw_rev.startswith('piksi_v2')
        if self.is_v2:
            self.stm_fw.set_flash_type('STM')
            self.serial_upgrade = True
        else:
            self.stm_fw.set_flash_type('bin')

        self._get_latest_version_info()

        # Check that we received the index file from the website.
        if self.update_dl is None:
            self._write(
                "Error: No website index to use to compare versions with local firmware"
            )
            return
        # Get local stm version
        local_stm_version = None
        try:
            local_stm_version = self.settings['system_info'][
                'firmware_version'].value
        except:
            pass
        # Check if console is out of date and notify user if so.
        if self.prompt:
            local_console_version = parse_version(CONSOLE_VERSION)
            remote_console_version = parse_version(self.newest_console_vers)
            self.console_outdated = remote_console_version > local_console_version

            # we want to warn users using v2 regardless of version logic
            if self.console_outdated or self.is_v2:
                if not self.is_v2:
                    console_outdated_prompt = \
                        prompt.CallbackPrompt(
                            title="Swift Console Outdated",
                            actions=[prompt.close_button],
                        )
                    console_outdated_prompt.text = \
                        "Your console is out of date and may be incompatible\n" + \
                        "with current firmware. We highly recommend upgrading to\n" + \
                        "ensure proper behavior.\n\n" + \
                        "Please visit http://support.swiftnav.com to\n" + \
                        "download the latest version.\n\n" + \
                        "Local Console Version :\n\t" + \
                        "v" + CONSOLE_VERSION + \
                        "\nLatest Console Version :\n\t" + \
                        self.update_dl.index[self.piksi_hw_rev]['console']['version'] + "\n"
                else:
                    console_outdated_prompt = \
                        prompt.CallbackPrompt(
                            title="Swift Console Incompatible",
                            actions=[prompt.close_button],
                        )
                    console_outdated_prompt.text = \
                        "Your console is incompatible with your hardware revision.\n" + \
                        "We highly recommend using a compatible console version\n" + \
                        "to ensure proper behavior.\n\n" + \
                        "Please visit http://support.swiftnav.com to\n" + \
                        "download the latest compatible version.\n\n" + \
                        "Current Hardware revision :\n\t" + \
                        self.piksi_hw_rev + \
                        "\nLast supported Console Version: \n\t" + \
                        self.update_dl.index[self.piksi_hw_rev]['console']['version'] + "\n"

                console_outdated_prompt.run()

            # For timing aesthetics between windows popping up.
            sleep(0.5)

            # Check if firmware is out of date and notify user if so.
            remote_stm_version = self.newest_stm_vers

            self.fw_outdated = remote_stm_version > local_stm_version

            if self.fw_outdated:
                fw_update_prompt = \
                    prompt.CallbackPrompt(
                        title='Firmware Update',
                        actions=[prompt.close_button]
                    )

                if 'fw' in self.update_dl.index[self.piksi_hw_rev]:
                    fw_update_prompt.text = \
                        "New Piksi firmware available.\n\n" + \
                        "Please use the Firmware Update tab to update.\n\n" + \
                        "Newest Firmware Version :\n\t%s\n\n" % \
                        self.update_dl.index[self.piksi_hw_rev]['fw']['version']
                else:
                    fw_update_prompt.text = \
                        "New Piksi firmware available.\n\n" + \
                        "Please use the Firmware Update tab to update.\n\n" + \
                        "Newest STM Version :\n\t%s\n\n" % \
                        self.update_dl.index[self.piksi_hw_rev]['stm_fw']['version'] + \
                        "Newest SwiftNAP Version :\n\t%s\n\n" % \
                        self.update_dl.index[self.piksi_hw_rev]['nap_fw']['version']

                fw_update_prompt.run()

        # Check if firmware successfully upgraded and notify user if so.
        if self.last_call_fw_version is not None and \
                self.last_call_fw_version != local_stm_version:
            fw_success_str = "Firmware successfully upgraded from %s to %s." % \
                             (self.last_call_fw_version, local_stm_version)
            print(fw_success_str)
            self._write(fw_success_str)

        # Record firmware version reported each time this callback is called.
        self.last_call_fw_version = local_stm_version

    def _get_latest_version_info(self):
        """ Get latest firmware / console version from website. """
        try:
            self.update_dl = UpdateDownloader()
        except URLError:
            self._write(
                "\nError: Failed to download latest file index from Swift Navigation's website. Please visit our website to check that you're running the latest Piksi firmware and Piksi console.\n"
            )
            return

        # Make sure index contains all keys we are interested in.
        try:
            if 'fw' in self.update_dl.index[self.piksi_hw_rev]:
                self.newest_stm_vers = self.update_dl.index[
                    self.piksi_hw_rev]['fw']['version']
            else:
                self.newest_stm_vers = self.update_dl.index[
                    self.piksi_hw_rev]['stm_fw']['version']
                self.newest_nap_vers = self.update_dl.index[
                    self.piksi_hw_rev]['nap_fw']['version']
            self.newest_console_vers = self.update_dl.index[
                self.piksi_hw_rev]['console']['version']
        except KeyError:
            self._write(
                "\nError: Index downloaded from Swift Navigation's website (%s) doesn't contain all keys. Please contact Swift Navigation.\n"
                % INDEX_URL)
            return

    def manage_stm_firmware_update(self):
        # Erase all of STM's flash (other than bootloader) if box is checked.
        if self.erase_stm:
            text = "Erasing STM"
            self._write(text)
            self.create_flash("STM")
            sectors_to_erase = set(range(self.pk_flash.n_sectors)).difference(
                set(self.pk_flash.restricted_sectors))
            progress_dialog = PulsableProgressDialog(len(sectors_to_erase),
                                                     False)
            progress_dialog.title = text
            GUI.invoke_later(progress_dialog.open)
            erase_count = 0
            for s in sorted(sectors_to_erase):
                progress_dialog.progress(erase_count)
                self._write('Erasing %s sector %d' %
                            (self.pk_flash.flash_type, s))
                self.pk_flash.erase_sector(s)
                erase_count += 1
            self.stop_flash()
            self._write("")
            try:
                progress_dialog.close()
            except AttributeError:
                pass
        # Flash STM.
        text = "Updating STM"
        self._write(text)
        self.create_flash("STM")
        stm_n_ops = self.pk_flash.ihx_n_ops(self.stm_fw.ihx,
                                            erase=not self.erase_stm)
        progress_dialog = PulsableProgressDialog(stm_n_ops, True)
        progress_dialog.title = text
        GUI.invoke_later(progress_dialog.open)
        # Don't erase sectors if we've already done so above.
        self.pk_flash.write_ihx(self.stm_fw.ihx,
                                self.stream,
                                mod_print=0x40,
                                elapsed_ops_cb=progress_dialog.progress,
                                erase=not self.erase_stm)
        self.stop_flash()
        self._write("")
        try:
            progress_dialog.close()
        except AttributeError:
            pass

    def manage_nap_firmware_update(self, check_version=False):
        # Flash NAP if out of date.
        try:
            local_nap_version = parse_version(
                self.settings['system_info']['nap_version'].value)
            remote_nap_version = parse_version(self.newest_nap_vers)
            nap_out_of_date = local_nap_version != remote_nap_version
        except KeyError:
            nap_out_of_date = True
        if nap_out_of_date or not check_version:
            text = "Updating NAP"
            self._write(text)
            self.create_flash("M25")
            nap_n_ops = self.pk_flash.ihx_n_ops(self.nap_fw.ihx)
            progress_dialog = PulsableProgressDialog(nap_n_ops, True)
            progress_dialog.title = text
            GUI.invoke_later(progress_dialog.open)
            self.pk_flash.write_ihx(self.nap_fw.ihx,
                                    self.stream,
                                    mod_print=0x40,
                                    elapsed_ops_cb=progress_dialog.progress)
            self.stop_flash()
            self._write("")
            try:
                progress_dialog.close()
            except AttributeError:
                pass
            return True
        else:
            text = "NAP is already to latest version, not updating!"
            self._write(text)
            self._write("")
            return False

    def manage_multi_firmware_update(self):
        # Set up progress dialog and transfer file to Piksi using SBP FileIO
        progress_dialog = PulsableProgressDialog(len(self.stm_fw.blob))
        progress_dialog.title = "Transferring image file"
        GUI.invoke_later(progress_dialog.open)
        self._write("Transferring image file...")
        try:
            FileIO(self.link).write("upgrade.image_set.bin",
                                    self.stm_fw.blob,
                                    progress_cb=progress_dialog.progress)
        except Exception as e:
            self._write("Failed to transfer image file to Piksi: %s\n" % e)
            progress_dialog.close()
            return
        try:
            progress_dialog.close()
        except AttributeError:
            pass

        # Setup up pulsed progress dialog and commit to flash
        progress_dialog = PulsableProgressDialog(100, True)
        progress_dialog.title = "Committing to flash"
        GUI.invoke_later(progress_dialog.open)
        self._write("Committing file to flash...")

        def log_cb(msg, **kwargs):
            self._write(msg.text)

        self.link.add_callback(log_cb, SBP_MSG_LOG)
        code = shell_command(self.link,
                             "upgrade_tool upgrade.image_set.bin",
                             600,
                             progress_cb=progress_dialog.progress)
        self.link.remove_callback(log_cb, SBP_MSG_LOG)
        progress_dialog.close()

        if code != 0:
            self._write('Failed to perform upgrade (code = %d)' % code)
            if code == -255:
                self._write('Shell command timed out.  Please try again.')
            return
        self._write('Resetting Piksi...')
        self.link(MsgReset(flags=0))

    # Executed in GUI thread, called from Handler.
    def manage_firmware_updates(self, device):
        """
        Update Piksi firmware. Erase entire STM flash (other than bootloader)
        if so directed. Flash NAP only if new firmware is available.
        """
        self.updating = True
        update_nap = False
        self._write('')
        if not self.is_v2:
            self.manage_multi_firmware_update()
            self.updating = False
            return
        elif device == "STM":
            self.manage_stm_firmware_update()
        elif device == "M25":
            update_nap = self.manage_nap_firmware_update()
        else:
            self.manage_stm_firmware_update()
            update_nap = self.manage_nap_firmware_update(check_version=True)

        # Must tell Piksi to jump to application after updating firmware.
        if device == "STM" or update_nap:
            self.link(MsgBootloaderJumpToApp(jump=0))
            self._write("Firmware update finished.")
            self._write("")

        self.updating = False

    def create_flash(self, flash_type):
        """
        Create flash.Flash instance and set Piksi into bootloader mode, prompting
        user to reset if necessary.

        Parameter
        ---------
        flash_type : string
          Either "STM" or "M25".
        """
        # Reset device if the application is running to put into bootloader mode.
        self.link(MsgReset(flags=0))

        self.pk_boot = bootload.Bootloader(self.link)

        self._write("Waiting for bootloader handshake message from Piksi ...")
        reset_prompt = None
        handshake_received = self.pk_boot.handshake(1)

        # Prompt user to reset Piksi if we don't receive the handshake message
        # within a reasonable amount of tiime (firmware might be corrupted).
        while not handshake_received:
            reset_prompt = \
                prompt.CallbackPrompt(
                    title="Please Reset Piksi",
                    actions=[prompt.close_button],
                )

            reset_prompt.text = \
                "You must press the reset button on your Piksi in order\n" + \
                "to update your firmware.\n\n" + \
                "Please press it now.\n\n"

            reset_prompt.run(block=False)

            while not reset_prompt.closed and not handshake_received:
                handshake_received = self.pk_boot.handshake(1)

            reset_prompt.kill()
            reset_prompt.wait()

        self._write("received bootloader handshake message.")
        self._write("Piksi Onboard Bootloader Version: " +
                    self.pk_boot.version)

        self.pk_flash = flash.Flash(self.link, flash_type,
                                    self.pk_boot.sbp_version)

    def stop_flash(self):
        """
        Stop Flash and Bootloader instances (removes callback from SerialLink).
        """
        self.pk_flash.stop()
        self.pk_boot.stop()
Beispiel #16
0
class TravelsensorGraph(HasTraits):

    plotview = Instance(PlotView, ())

    checkable_sensors = List()

    cycol = cycle('bgrcmky')

    force = []

    x_axis = Instance(Combobox, ())

    y_axis = Instance(Combobox, ())

    def update_sensors(self, sensors):
        del self.checkable_sensors[:]
        for s in sensors:
            c = next(self.cycol)
            s.parent = self
            s.plot_color = c
            self.checkable_sensors.append(s)

    def plot(self, index):
        self.update_axis_properties()
        self.update_plot()
        self.configure_traits()

    def get_recorded_values(self, axis):
        res = []
        for i in range(len(self.recorded_values)):
            val = self.recorded_values[i]
            if axis.selected_key == val:
                arr = load(join(recorder_dir, recording_file))
                res.append((None, arr[:, i]))
                return res

    def get_dic_values(self, axis):
        res = []
        for i in range(len(self.dic_properties)):
            val = self.dic_properties[i]
            if axis.selected_key == val:
                for t in self.checkable_sensors:
                    if t.is_checked:
                        arr = load(
                            join(travel_sensor_sensors_dir, t.name + ".npy"))
                        res.append((t, arr[:, i]))
                return res

    def update_axis_properties(self):
        self.recorded_values = ["Time [s]"]
        ports = MeasuringCard.load_input_ports_as_dict()
        for key in ports:
            self.recorded_values.append(key)
        for val in self.recorded_values:
            self.x_axis.add_item(val, self.get_recorded_values)
            self.y_axis.add_item(val, self.get_recorded_values)
        self.dic_properties = [
            "U-displacement [mm]", "V-displacement [mm]", "Strain exx",
            "Strain exy", "Strain eyy"
        ]
        for dic in self.dic_properties:
            self.x_axis.add_item(dic, self.get_dic_values)
            self.y_axis.add_item(dic, self.get_dic_values)
        self.x_axis.selected_key = self.recorded_values[0]
        self.y_axis.selected_key = self.dic_properties[0]

    def update_plot(self):
        self.x_arr = self.x_axis.get_selected_value()(self.x_axis)
        self.y_arr = self.y_axis.get_selected_value()(self.y_axis)
        self.plotview.reset_subplots("SmartRecord")
        self.plotview.set_labels(self.x_axis.selected_key,
                                 self.y_axis.selected_key, "SmartRecord")
        for x_val in self.x_arr:
            xt, xvals = x_val
            for y_val in self.y_arr:
                yt, yvals = y_val
                if xt == None:
                    self.plotview.plot_graph(0, xvals, yvals, yt.plot_color)
                else:
                    self.plotview.plot_graph(0, xvals, yvals, xt.plot_color)

    icon = Image(ImageResource("../../../../icons/smrc_icon.png"))

    smrc = Str("SmartRecord")

    update_button = Button("Update plot")

    def _update_button_fired(self):
        self.update_plot()

    view = View(VGroup(
        HGroup(
            UItem('smrc',
                  style_sheet="*{font: bold; font-size:32px;\
                              color:" + toolbar_background + ";}",
                  style='readonly'), UItem('icon')),
        HGroup(
            VGroup(
                VGroup(Item('x_axis', style='custom'),
                       Item('y_axis', style='custom'),
                       UItem('update_button'),
                       label="Axis"),
                VGroup(
                    UItem('checkable_sensors',
                          style='readonly',
                          editor=ListEditor(editor=InstanceEditor(),
                                            style='custom')),
                    label='Sensors',
                ),
            ), UItem('plotview', style='custom'))),
                title="Sensors",
                resizable=True,
                handler=GraphHandler())
Beispiel #17
0
class FirmwareFileDialog(HasTraits):

    file_wildcard = String("Intel HEX File (*.hex)|*.hex|All files|*")

    status = String('Please choose a file')
    choose_fw = Button(label='...', padding=-1)
    view = View(
        HGroup(UItem('status', resizable=True), UItem('choose_fw',
                                                      width=-0.1)), )

    def __init__(self, flash_type):
        """
        Pop-up file dialog to choose an IntelHex file, with status and button to
        display in traitsui window.
        """
        self.set_flash_type(flash_type)

    def set_flash_type(self, flash_type):
        """
        Parameters
        ----------
        flash_type : string
          Which Piksi flash to interact with ("M25" or "STM").
        """
        if flash_type not in ('bin', 'M25', 'STM'):
            raise ValueError("flash_type must be 'bin', 'M25' or 'STM'")
        if flash_type == 'bin':
            self.file_wildcard = "Binary image set (*.bin)|*.bin|All files|*"
        else:
            self.file_wildcard = "Intel HEX File (*.hex)|*.hex|All files|*"
        self._flash_type = flash_type
        self.ihx = None
        self.blob = None

    def clear(self, status):
        """
        Set text of status box and clear IntelHex file.

        Parameters
        ----------
        status : string
          Error text to replace status box text with.
        """
        self.ihx = None
        self.blob = None
        self.status = status

    def load_ihx(self, filepath):
        """
        Load IntelHex file and set status to indicate if file was
        successfully loaded.

        Parameters
        ----------
        filepath : string
          Path to IntelHex file.
        """
        if self._flash_type not in ('M25', 'STM'):
            self.clear("Error: Can't load Intel HEX File as image set binary")
            return

        try:
            self.ihx = IntelHex(filepath)
            self.status = os.path.split(filepath)[1]
        except HexRecordError:
            self.clear('Error: File is not a valid Intel HEX File')

        # Check that address ranges are valid for self._flash_type.
        ihx_addrs = flash.ihx_ranges(self.ihx)
        if self._flash_type == "M25":
            try:
                sectors = flash.sectors_used(ihx_addrs,
                                             flash.m25_addr_sector_map)
            except IndexError:
                self.clear('Error: HEX File contains restricted address ' +
                           '(STM Firmware File Chosen?)')
        elif self._flash_type == "STM":
            try:
                sectors = flash.sectors_used(ihx_addrs,
                                             flash.stm_addr_sector_map)
            except:
                self.clear('Error: HEX File contains restricted address ' +
                           '(NAP Firmware File Chosen?)')

    def load_bin(self, filepath):
        if self._flash_type != 'bin':
            self.clear("Error: Can't load binary file for M25 or STM flash")
            return

        try:
            self.blob = open(filepath, 'rb').read()
            self.status = os.path.split(filepath)[1]
        except:
            self.clear('Error: Failed to read binary file')

    def _choose_fw_fired(self):
        """ Activate file dialog window to choose IntelHex firmware file. """
        dialog = FileDialog(label='Choose Firmware File',
                            action='open',
                            wildcard=self.file_wildcard)
        dialog.open()
        if dialog.return_code == OK:
            filepath = os.path.join(dialog.directory, dialog.filename)
            if self._flash_type == 'bin':
                self.load_bin(filepath)
            else:
                self.load_ihx(filepath)
        else:
            self.clear('Error while selecting file')
Beispiel #18
0
class SolutionView(HasTraits):
    python_console_cmds = Dict()
    # we need to doubleup on Lists to store the psuedo absolutes separately
    # without rewriting everything
    lats = List()
    lngs = List()
    alts = List()
    """
  logging_v : toggle logging for velocity files
  directory_name_v : location and name of velocity files
  logging_p : toggle logging for position files
  directory_name_p : location and name of velocity files
  """

    logging_v = Bool(False)
    directory_name_v = File

    logging_p = Bool(False)
    directory_name_p = File

    lats_psuedo_abs = List()
    lngs_psuedo_abs = List()
    alts_psuedo_abs = List()

    table_spp = List()
    table_psuedo_abs = List()
    dops_table = List()
    pos_table_spp = List()
    vel_table = List()

    rtk_pos_note = Str(
        "It is necessary to enter the \"Surveyed Position\" settings for the base station in order to view the psuedo-absolute RTK Positions in this tab."
    )

    plot = Instance(Plot)
    plot_data = Instance(ArrayPlotData)
    # Store plots we care about for legend

    running = Bool(True)
    zoomall = Bool(False)
    position_centered = Bool(False)

    clear_button = SVGButton(label='',
                             tooltip='Clear',
                             filename=os.path.join(determine_path(), 'images',
                                                   'iconic', 'x.svg'),
                             width=16,
                             height=16)
    zoomall_button = SVGButton(label='',
                               tooltip='Zoom All',
                               toggle=True,
                               filename=os.path.join(determine_path(),
                                                     'images', 'iconic',
                                                     'fullscreen.svg'),
                               width=16,
                               height=16)
    center_button = SVGButton(label='',
                              tooltip='Center on Solution',
                              toggle=True,
                              filename=os.path.join(determine_path(), 'images',
                                                    'iconic', 'target.svg'),
                              width=16,
                              height=16)
    paused_button = SVGButton(label='',
                              tooltip='Pause',
                              toggle_tooltip='Run',
                              toggle=True,
                              filename=os.path.join(determine_path(), 'images',
                                                    'iconic', 'pause.svg'),
                              toggle_filename=os.path.join(
                                  determine_path(), 'images', 'iconic',
                                  'play.svg'),
                              width=16,
                              height=16)

    traits_view = View(
        HSplit(
            Tabbed(
                VGroup(Item('',
                            label='Single Point Position (SPP)',
                            emphasized=True),
                       Item('table_spp',
                            style='readonly',
                            editor=TabularEditor(adapter=SimpleAdapter()),
                            show_label=False,
                            width=0.3),
                       label='Single Point Position'),
                VGroup(Item('', label='RTK Position', emphasized=True),
                       Item('table_psuedo_abs',
                            style='readonly',
                            editor=TabularEditor(adapter=SimpleAdapter()),
                            show_label=False,
                            width=0.3,
                            height=0.9),
                       Item('rtk_pos_note',
                            show_label=False,
                            resizable=True,
                            editor=MultilineTextEditor(
                                TextEditor(multi_line=True)),
                            style='readonly',
                            width=0.3,
                            height=-40),
                       label='RTK Position')),
            VGroup(
                HGroup(
                    Item('paused_button', show_label=False),
                    Item('clear_button', show_label=False),
                    Item('zoomall_button', show_label=False),
                    Item('center_button', show_label=False),
                ),
                Item('plot',
                     show_label=False,
                     editor=ComponentEditor(bgcolor=(0.8, 0.8, 0.8))),
            )))

    def _zoomall_button_fired(self):
        self.zoomall = not self.zoomall

    def _center_button_fired(self):
        self.position_centered = not self.position_centered

    def _paused_button_fired(self):
        self.running = not self.running

    def _clear_button_fired(self):
        self.lats = []
        self.lngs = []
        self.alts = []
        self.lats_psuedo_abs = []
        self.lngs_psuedo_abs = []
        self.alts_psuedo_abs = []
        self.plot_data.set_data('lat', [])
        self.plot_data.set_data('lng', [])
        self.plot_data.set_data('alt', [])
        self.plot_data.set_data('t', [])
        self.plot_data.set_data('lat_ps', [])
        self.plot_data.set_data('lng_ps', [])
        self.plot_data.set_data('alt_ps', [])
        self.plot_data.set_data('t_ps', [])

    def _pos_llh_callback(self, sbp_msg, **metadata):
        # Updating an ArrayPlotData isn't thread safe (see chaco issue #9), so
        # actually perform the update in the UI thread.
        if self.running:
            GUI.invoke_later(self.pos_llh_callback, sbp_msg)

    def mode_string(self, msg):
        if msg:
            if (msg.flags & 0xff) == 0:
                return 'SPP (single point position)'
            elif (msg.flags & 0xff) == 1:
                return 'Fixed RTK'
            elif (msg.flags & 0xff) == 2:
                return 'Float RTK'
        return 'None'

    def update_table(self):
        self._table_list = self.table_spp.items()

    def auto_survey(self):
        if self.counter < 1000:
            self.counter = self.counter + 1
        self.latitude_list.append(self.last_soln.lat)
        self.longitude_list.append(self.last_soln.lon)
        self.altitude_list.append(self.last_soln.height)
        self.latitude_list = self.latitude_list[-1000:]
        self.longitude_list = self.longitude_list[-1000:]
        self.altitude_list = self.altitude_list[-1000:]
        self.latitude = (sum(self.latitude_list)) / self.counter
        self.altitude = (sum(self.altitude_list)) / self.counter
        self.longitude = (sum(self.longitude_list)) / self.counter

    def pos_llh_callback(self, sbp_msg, **metadata):
        self.last_stime_update = time.time()
        soln = MsgPosLLH(sbp_msg)
        self.last_soln = soln
        masked_flag = soln.flags & 0x7
        if masked_flag == 0:
            psuedo_absolutes = False
        else:
            psuedo_absolutes = True
        pos_table = []

        tow = soln.tow * 1e-3
        if self.nsec is not None:
            tow += self.nsec * 1e-9

        if self.week is not None:
            t = datetime.datetime(1980, 1, 6) + \
                datetime.timedelta(weeks=self.week) + \
                datetime.timedelta(seconds=tow)
            pos_table.append(('GPS Time', t))
            pos_table.append(('GPS Week', str(self.week)))

            if (self.directory_name_p == ''):
                filepath_p = time.strftime("position_log_%Y%m%d-%H%M%S.csv")
            else:
                filepath_p = os.path.join(
                    self.directory_name_p,
                    time.strftime("position_log_%Y%m%d-%H%M%S.csv"))

            if self.logging_p == False:
                self.log_file = None

            if self.logging_p:
                if self.log_file is None:
                    self.log_file = open(filepath_p, 'w')
                    self.log_file.write(
                        "time,latitude(degrees),longitude(degrees),altitude(meters),n_sats,flags\n"
                    )

                self.log_file.write('%s,%.10f,%.10f,%.4f,%d,%d\n' %
                                    (str(t), soln.lat, soln.lon, soln.height,
                                     soln.n_sats, soln.flags))
                self.log_file.flush()

        pos_table.append(('GPS ToW', tow))

        pos_table.append(('Num. sats', soln.n_sats))

        pos_table.append(('Lat', soln.lat))
        pos_table.append(('Lng', soln.lon))
        pos_table.append(('Alt', soln.height))
        pos_table.append(('Flags', '0x%02x' % soln.flags))

        pos_table.append(('Mode', self.mode_string(soln)))

        self.auto_survey()

        if psuedo_absolutes:
            # setup_plot variables
            self.lats_psuedo_abs.append(soln.lat)
            self.lngs_psuedo_abs.append(soln.lon)
            self.alts_psuedo_abs.append(soln.height)

            self.lats_psuedo_abs = self.lats_psuedo_abs[-1000:]
            self.lngs_psuedo_abs = self.lngs_psuedo_abs[-1000:]
            self.alts_psuedo_abs = self.alts_psuedo_abs[-1000:]

            self.plot_data.set_data('lat_ps', self.lats_psuedo_abs)
            self.plot_data.set_data('lng_ps', self.lngs_psuedo_abs)
            self.plot_data.set_data('alt_ps', self.alts_psuedo_abs)
            self.plot_data.set_data('cur_lat_ps', [soln.lat])
            self.plot_data.set_data('cur_lng_ps', [soln.lon])
            t_psuedo_abs = range(len(self.lats))
            if t is not None:
                self.plot_data.set_data('t', t)
            self.plot_data.set_data('t_ps', t_psuedo_abs)
            # set-up table variables
            self.table_psuedo_abs = pos_table

        else:
            # setup_plot variables
            self.lats.append(soln.lat)
            self.lngs.append(soln.lon)
            self.alts.append(soln.height)

            self.lats = self.lats[-1000:]
            self.lngs = self.lngs[-1000:]
            self.alts = self.alts[-1000:]

            self.plot_data.set_data('lat', self.lats)
            self.plot_data.set_data('lng', self.lngs)
            self.plot_data.set_data('alt', self.alts)
            self.plot_data.set_data('cur_lat', [soln.lat])
            self.plot_data.set_data('cur_lng', [soln.lon])
            t = range(len(self.lats))
            self.plot_data.set_data('t', t)

            # set-up table variables
            self.pos_table_spp = pos_table
            self.table_spp = self.pos_table_spp + self.vel_table + self.dops_table
            # TODO: figure out how to center the graph now that we have two separate messages
            # when we selectivtely send only SPP, the centering function won't work anymore
            if self.position_centered:
                d = (self.plot.index_range.high -
                     self.plot.index_range.low) / 2.
                self.plot.index_range.set_bounds(soln.lon - d, soln.lon + d)
                d = (self.plot.value_range.high -
                     self.plot.value_range.low) / 2.
                self.plot.value_range.set_bounds(soln.lat - d, soln.lat + d)
        if self.zoomall:
            plot_square_axes(self.plot, 'lng', 'lat')

    def dops_callback(self, sbp_msg, **metadata):
        dops = MsgDops(sbp_msg)
        self.dops_table = [('PDOP', '%.1f' % (dops.pdop * 0.01)),
                           ('GDOP', '%.1f' % (dops.gdop * 0.01)),
                           ('TDOP', '%.1f' % (dops.tdop * 0.01)),
                           ('HDOP', '%.1f' % (dops.hdop * 0.01)),
                           ('VDOP', '%.1f' % (dops.vdop * 0.01))]
        self.table_spp = self.pos_table_spp + self.vel_table + self.dops_table

    def vel_ned_callback(self, sbp_msg, **metadata):
        vel_ned = MsgVelNED(sbp_msg)

        tow = vel_ned.tow * 1e-3
        if self.nsec is not None:
            tow += self.nsec * 1e-9

        if self.week is not None:
            t = datetime.datetime(1980, 1, 6) + \
                datetime.timedelta(weeks=self.week) + \
                datetime.timedelta(seconds=tow)

            if self.directory_name_v == '':
                filepath_v = time.strftime("velocity_log_%Y%m%d-%H%M%S.csv")
            else:
                filepath_v = os.path.join(
                    self.directory_name_v,
                    time.strftime("velocity_log_%Y%m%d-%H%M%S.csv"))

            if self.logging_v == False:
                self.vel_log_file = None

            if self.logging_v:

                if self.vel_log_file is None:
                    self.vel_log_file = open(filepath_v, 'w')
                    self.vel_log_file.write(
                        'time,north(m/s),east(m/s),down(m/s),speed(m/s),num_sats\n'
                    )

                self.vel_log_file.write(
                    '%s,%.6f,%.6f,%.6f,%.6f,%d\n' %
                    (str(t), vel_ned.n * 1e-3, vel_ned.e * 1e-3,
                     vel_ned.d * 1e-3,
                     math.sqrt(vel_ned.n * vel_ned.n + vel_ned.e * vel_ned.e) *
                     1e-3, vel_ned.n_sats))
                self.vel_log_file.flush()

        self.vel_table = [
            ('Vel. N', '% 8.4f' % (vel_ned.n * 1e-3)),
            ('Vel. E', '% 8.4f' % (vel_ned.e * 1e-3)),
            ('Vel. D', '% 8.4f' % (vel_ned.d * 1e-3)),
        ]
        self.table_spp = self.pos_table_spp + self.vel_table + self.dops_table

    def gps_time_callback(self, sbp_msg, **metadata):
        self.week = MsgGPSTime(sbp_msg).wn
        self.nsec = MsgGPSTime(sbp_msg).ns

    def __init__(self, link, dirname=''):
        super(SolutionView, self).__init__()

        self.log_file = None
        self.directory_name_v = dirname
        self.directory_name_p = dirname
        self.vel_log_file = None
        self.last_stime_update = 0
        self.last_soln = None

        self.counter = 0
        self.latitude_list = []
        self.longitude_list = []
        self.altitude_list = []
        self.altitude = 0
        self.longitude = 0
        self.latitude = 0

        self.plot_data = ArrayPlotData(lat=[],
                                       lng=[],
                                       alt=[],
                                       t=[],
                                       cur_lat=[],
                                       cur_lng=[],
                                       cur_lat_ps=[],
                                       cur_lng_ps=[],
                                       lat_ps=[],
                                       lng_ps=[],
                                       alt_ps=[],
                                       t_ps=[])
        self.plot = Plot(self.plot_data)

        # 1000 point buffer
        self.plot.plot(('lng', 'lat'),
                       type='line',
                       name='',
                       color=(0, 0, 0.9, 0.1))
        self.plot.plot(('lng', 'lat'),
                       type='scatter',
                       name='',
                       color='blue',
                       marker='dot',
                       line_width=0.0,
                       marker_size=1.0)
        self.plot.plot(('lng_ps', 'lat_ps'),
                       type='line',
                       name='',
                       color=(1, 0.4, 0, 0.1))
        self.plot.plot(('lng_ps', 'lat_ps'),
                       type='scatter',
                       name='',
                       color='orange',
                       marker='diamond',
                       line_width=0.0,
                       marker_size=1.0)
        # current values
        spp = self.plot.plot(('cur_lng', 'cur_lat'),
                             type='scatter',
                             name='SPP',
                             color='blue',
                             marker='plus',
                             line_width=1.5,
                             marker_size=5.0)
        rtk = self.plot.plot(('cur_lng_ps', 'cur_lat_ps'),
                             type='scatter',
                             name='RTK',
                             color='orange',
                             marker='plus',
                             line_width=1.5,
                             marker_size=5.0)
        plot_labels = ['SPP', 'RTK']
        plots_legend = dict(zip(plot_labels, [spp, rtk]))
        self.plot.legend.plots = plots_legend
        self.plot.legend.visible = True

        self.plot.index_axis.tick_label_position = 'inside'
        self.plot.index_axis.tick_label_color = 'gray'
        self.plot.index_axis.tick_color = 'gray'
        self.plot.index_axis.title = 'Longitude (degrees)'
        self.plot.index_axis.title_spacing = 5
        self.plot.value_axis.tick_label_position = 'inside'
        self.plot.value_axis.tick_label_color = 'gray'
        self.plot.value_axis.tick_color = 'gray'
        self.plot.value_axis.title = 'Latitude (degrees)'
        self.plot.value_axis.title_spacing = 5
        self.plot.padding = (25, 25, 25, 25)

        self.plot.tools.append(PanTool(self.plot))
        zt = ZoomTool(self.plot,
                      zoom_factor=1.1,
                      tool_mode="box",
                      always_on=False)
        self.plot.overlays.append(zt)

        self.link = link
        self.link.add_callback(self._pos_llh_callback, SBP_MSG_POS_LLH)
        self.link.add_callback(self.vel_ned_callback, SBP_MSG_VEL_NED)
        self.link.add_callback(self.dops_callback, SBP_MSG_DOPS)
        self.link.add_callback(self.gps_time_callback, SBP_MSG_GPS_TIME)

        self.week = None
        self.nsec = 0

        self.python_console_cmds = {
            'solution': self,
        }
Beispiel #19
0
    def traits_view(self):

        c_grp = VGroup(
                       # HGroup(Item('setpoint'),
                       #        UItem('water_flow_state', editor=LEDEditor(label='H2O Flow')),
                       #        spring, icon_button_editor('pane.disable_button', 'cancel')),
                       VGroup(UItem('output_percent_readback', editor=LCDEditor())),
                       icon_button_editor('start_record_button', 'media-record',
                                          tooltip='Start recording',
                                          enabled_when='not _recording'),
                       icon_button_editor('stop_record_button',
                                          'media-playback-stop',
                                          tooltip='Stop recording',
                                          enabled_when='_recording'),
                       label='Controller', show_border=True)

        power_grp = HGroup(UItem('pane.extract_value',
                                width=50,
                                enabled_when='furnace_enabled',
                                tooltip='Power setting for furnace (0-100%)'),
                          UItem('pane.extract_button',
                                enabled_when='furnace_enabled',
                                tooltip='Send the value to the furnace'),
                          show_border=True, label='Furnace Power')

        # jitter_grp = HGroup(UItem('pane.jitter_button', editor=ButtonEditor(label_value='pane.jitter_label')),
        #                     icon_button_editor('pane.configure_jitter_button', 'cog', tooltip='Configure Jitter'),
        #                     show_border=True, label='Jitter')

        dump_grp = HGroup(UItem('pane.dump_sample_number',
                                width=50,
                                enabled_when='dump_sample_enabled',
                                tooltip='Sample number to dump'),
                          UItem('pane.dump_sample_button',
                                enabled_when='dump_sample_enabled',
                                tooltip='Execute the complete sample loading procedure'),
                          UItem('pane.clear_sample_states_button'),
                          show_border=True, label='Dump')
        # status_grp = HGroup(CustomLabel('status_txt', size=14))
        d1 = VGroup(
                    power_grp, dump_grp)
        d2 = VGroup(
            # UItem('pane.refresh_states_button'),
            UItem('dumper_canvas', editor=ComponentEditor()))
        d_grp = HGroup(d1, d2, label='Dumper', show_border=True)

        # v_grp = VGroup(UItem('video_canvas', editor=VideoComponentEditor()),
        #                visible_when='video_enabled',
        #                label='Camera')

        g_grp = VGroup(Item('graph_scan_width', label='Scan Width (mins)'),
                       HGroup(Item('graph_scale', label='Scale'),
                              Item('graph_y_auto', label='Autoscale Y'),
                              Item('graph_ymax', label='Max', format_str='%0.3f', enabled_when='not graph_y_auto'),
                              Item('graph_ymin', label='Min', format_str='%0.3f', enabled_when='not graph_y_auto')),
                       HGroup(icon_button_editor('clear_button', 'clear',
                                                 tooltip='Clear and reset graph'), spring),
                       HGroup(icon_button_editor('start_record_button', 'media-record',
                                                 tooltip='Start recording',
                                                 enabled_when='not _recording'),
                              icon_button_editor('stop_record_button',
                                                 'media-playback-stop',
                                                 tooltip='Stop recording',
                                                 enabled_when='_recording'),
                              icon_button_editor('add_marker_button', 'flag',
                                                 enabled_when='_recording'),
                              show_border=True,
                              label='Record Scan'),
                       label='Graph')
        v = View(VGroup(c_grp,
                        HGroup(Tabbed(d_grp, g_grp))))
        return v
Beispiel #20
0
class Visualization(HasTraits):
    engine1 = Instance(Engine, args=())
    sceneView1 = Instance(MlabSceneModel, ())  # The scene model
    # Initialize the GUI Values
    GUI_OBJECT_NAME = Str("")
    GUI_ID = Str("")
    GUI_MATERIAL_ID = Str("")
    GUI_MATERIAL_NAME = Str("")
    GUI_CHANGE_REPRESENTATION = Bool
    GUI_CHANGE_MATERIAL = Str
    GUI_MATERIAL_LIBRARY = List([''])

    # Initialize the picker
    @on_trait_change('sceneView1.activated')
    def initializePicker(self):
        picker = self.sceneView1.mayavi_scene.on_mouse_pick(
            self.picker_callback, type='cell')
        picker.tolerance = 0.01

    #  Perform an action depending if an AMF object was picked or not
    def picker_callback(self, picker):
        global LIST_AMF_OBJECTS, CURRENT_SELECTED_OBJECT, DICT_MATERIAL

        # Catch the errors here
        output = vtk.vtkFileOutputWindow()
        output.SetFileName("log.txt")
        vtk.vtkOutputWindow().SetInstance(output)

        picker_outside = True
        # Check if the object picked belongs to our LIST_AMF_OBJECTS
        for i in range(len(LIST_AMF_OBJECTS)):
            if picker.actor in LIST_AMF_OBJECTS[i].geometry.actor.actors:
                # The user picked an object in our LIST_AMF_OBJECTS
                picker_outside = False

                # Update the visualization
                LIST_AMF_OBJECTS[
                    i].geometry.actor.mapper.scalar_visibility = False  # Disable the scalar colors assigned to the object
                LIST_AMF_OBJECTS[i].geometry.actor.property.color = (
                    1, 0, 0)  # Color the picked object in red
                LIST_AMF_OBJECTS[
                    i].geometry.actor.property.line_width = 8  # Increase slighly the size of the wireframe edges

                # Update the GUI
                self.GUI_OBJECT_NAME = LIST_AMF_OBJECTS[i].name
                self.GUI_ID = LIST_AMF_OBJECTS[i].xmlObjectID
                self.GUI_MATERIAL_ID = LIST_AMF_OBJECTS[i].materialId
                self.GUI_MATERIAL_NAME = DICT_MATERIAL[
                    LIST_AMF_OBJECTS[i].materialId]

                CURRENT_SELECTED_OBJECT = i
                # LIST_AMF_OBJECTS[i].geometry.actor.actor.scale = (1,1,2) # Just a placeholder in case we want to slightly increase the height of the selected object
            else:
                # The object was not picked - Reapply the original Scalar Color and line width
                LIST_AMF_OBJECTS[
                    i].geometry.actor.mapper.scalar_visibility = True
                LIST_AMF_OBJECTS[i].geometry.actor.property.line_width = 2
                # LIST_AMF_OBJECTS[i].geometry.actor.actor.scale = (1,1,1) # Just a placeholder to assign the orignal height to the object

        if picker_outside:
            # The picker did not select an object belonging to our LIST_AMF_OBJECTS
            self.GUI_MATERIAL_ID = ""
            self.GUI_OBJECT_NAME = ""
            self.GUI_ID = "No Object Selected"
            self.GUI_MATERIAL_NAME = ""
            CURRENT_SELECTED_OBJECT = -1

    # When clicked, change the objects in the visualizer from wireframe to surface representation and vice-versa
    # TODO: No real purpose now but could be useful if we plan to apply material textures
    @on_trait_change('GUI_CHANGE_REPRESENTATION')
    def switchSurfaceWireframe(self):
        global LIST_AMF_OBJECTS
        # Update the rendering
        if self.GUI_CHANGE_REPRESENTATION:
            # Apply Surface
            for i in range(len(LIST_AMF_OBJECTS)):
                # Placeholder code to apply texture
                # LIST_AMF_OBJECTS[i].surface.actor.actor.property.representation = 'surface'
                # textureFile = tvtk.JPEGReader()
                # textureFile.file_name= TextureFolder +  str(LIST_AMF_OBJECTS[i].materialId) + ".jpg" #any jpeg file
                # wallTexture1 = tvtk.Texture(input_connection=textureFile.output_port, interpolate=0)
                # LIST_AMF_OBJECTS[i].surface.actor.enable_texture = True
                # LIST_AMF_OBJECTS[i].surface.actor.tcoord_generator_mode = 'plane'
                # LIST_AMF_OBJECTS[i].surface.actor.actor.texture = wallTexture1
                LIST_AMF_OBJECTS[
                    i].geometry.actor.actor.property.representation = 'surface'
        else:
            # Apply Wireframe
            for i in range(len(LIST_AMF_OBJECTS)):
                LIST_AMF_OBJECTS[
                    i].geometry.actor.actor.property.representation = 'wireframe'
                LIST_AMF_OBJECTS[i].geometry.actor.enable_texture = False

        # Update the rendering
        force_render()
        self.sceneView1.render()
        self.sceneView1.mayavi_scene.render()

    # Handle new material assigmment
    @on_trait_change('GUI_CHANGE_MATERIAL')
    def update_material_test(self):
        global CURRENT_SELECTED_OBJECT, LIST_AMF_OBJECTS, AMF_ROOT, AMF_TREE
        if CURRENT_SELECTED_OBJECT != -1:
            # Apply the new color corresponding to the newly material assigned to the selected object
            dataset = mlab.pipeline.get_vtk_src(
                LIST_AMF_OBJECTS[CURRENT_SELECTED_OBJECT].geometry
            )  # Get the dataset associated with the object
            currentScalar = dataset[0].point_data.scalars.to_array(
            )  # Get the scalars, i.e, the material ID color
            newScalar = np.full_like(
                currentScalar,
                self.GUI_CHANGE_MATERIAL)  # Create the new scalar color
            LIST_AMF_OBJECTS[
                CURRENT_SELECTED_OBJECT].geometry.mlab_source.trait_set(
                    scalars=newScalar)  # Apply the color to the object
            LIST_AMF_OBJECTS[
                CURRENT_SELECTED_OBJECT].geometry.actor.mapper.scalar_visibility = True
            LIST_AMF_OBJECTS[
                CURRENT_SELECTED_OBJECT].materialId = self.GUI_CHANGE_MATERIAL  # Update the object material ID

            # Update the GUI with the material Name and Material ID
            self.GUI_MATERIAL_ID = LIST_AMF_OBJECTS[
                CURRENT_SELECTED_OBJECT].materialId
            self.GUI_MATERIAL_NAME = DICT_MATERIAL[
                LIST_AMF_OBJECTS[CURRENT_SELECTED_OBJECT].materialId]

            # Update the AMF File of the selected object with the new material selected
            idObject = LIST_AMF_OBJECTS[CURRENT_SELECTED_OBJECT].xmlObjectID
            pathToUpdate = "./object/[@id=\"" + idObject + "\"]/mesh/volume"
            volumesToUpdate = AMF_ROOT.findall(
                pathToUpdate
            )  # Get all the volumes corresponding to the selected object
            for i in range(len(volumesToUpdate)):
                volumesToUpdate[i].attrib[
                    "materialid"] = self.GUI_CHANGE_MATERIAL

            # Save a new AMF file incuding the changes of Material
            amfFileToSave = AMF_SAVED_PREFIX + AMF_FILE
            amfFileToSave = str(Path(AMF_FOLDER) / amfFileToSave)
            AMF_TREE.write(amfFileToSave)

        force_render()
        self.sceneView1.render()
        self.sceneView1.mayavi_scene.render()

    ################################################################
    ##########     INITIALIZE THE VISUALIZATION     ################
    ################################################################

    # Parse the AMF file and create the visualization
    def __init__(self):
        global LIST_AMF_OBJECTS, AMF_TREE, AMF_ROOT, DICT_MATERIAL
        self.engine1.start()

        amfFileToParse = str(Path(AMF_FOLDER) / AMF_FILE)
        try:
            AMF_TREE = ET.parse(amfFileToParse)
        except OSError as e:
            print("Error:", e)
            exit()

        AMF_ROOT = AMF_TREE.getroot()
        objectsDict = {}
        # By default, we add a material with ID 0 that corresponds to the case where no material is assigned to a volume
        # Obviously, this choice imposes to use Material ID in the library with an ID greater than 0 TODO: Check if it's the case once we know how to manage the material library
        noMaterialID = "0"
        DICT_MATERIAL[noMaterialID] = "No Material"

        # Start by handling the material in the AMF file to build the material library
        for tMaterial in AMF_ROOT.iter('material'):
            # Iterate through all the material in the scenario
            materialID = tMaterial.attrib['id']
            for tName in tMaterial.iter('metadata'):
                materialName = tName.text  # Get the material Name
                DICT_MATERIAL[
                    materialID] = materialName  # Add the material to the material dictionary

        # Handle the case where no Material exists in the AMF file - For example NISTGaithersburg.xml
        # Here is just a placeholder for the default material library
        # In this implementation, we will create a fake material made of 100 materials (completely arbitrary choice)
        if len(DICT_MATERIAL) == 1:
            # No Material defined
            nbMaterial = 100
            for i in range(1, nbMaterial + 1):
                DICT_MATERIAL[str(i)] = "FakematerialName" + str(i)

        for tObject in AMF_ROOT.iter('object'):
            # Iterate through all the objects in the AMF File
            coordinateX = []
            coordinateY = []
            coordinateZ = []
            DONOTADD = False
            xmlObjectID = tObject.attrib['id']  # Get the Object ID
            for tName in tObject.iter('metadata'):
                xmlObjectName = tName.text  # Get the object Name
                # There is a bug in the way geodata scenario are generated
                # It includes twice every object so we handle that here
                # TODO: Fix the geodata scenarios generation and update the code accordingly
                if xmlObjectName in objectsDict:
                    # If an object with the same name has already been parsed, flag it
                    DONOTADD = True
                else:
                    # The object does not exist in the object dictionnary, just add it to the objects dictionary
                    objectsDict[xmlObjectName] = True

            # Get the X, Y, Z coordinates corresponding to an object
            for tcoordinatesX in tObject.iter('x'):
                # Get x coordinates
                coordinateX.append(float(tcoordinatesX.text))
            for tcoordinatesY in tObject.iter('y'):
                # Get y coordinates
                coordinateY.append(float(tcoordinatesY.text))
            for tcoordinatesZ in tObject.iter('z'):
                # Get z coordinates
                coordinateZ.append(float(tcoordinatesZ.text))

            for tVolume in tObject.iter('volume'):
                # Iterate over the volume, i.e., the triangles connections and material
                # Please note that an object can be defined with more than one volume
                try:
                    materialId = tVolume.attrib[
                        'materialid']  # Get the material ID associated to the triangles connections
                except KeyError:
                    # It's possible that a volume is not having any material assigned - Handle it
                    # print("Warning: Object :", xmlObjectName, " is not having any material associated to it") TODO Commented for now
                    materialId = None

                v1 = []  # First vertex
                v2 = []  # Second vertex
                v3 = []  # Third vertex
                for tTriangles in tVolume.iter('triangle'):
                    # Iterate over the triangles of a volume
                    for tFirstPoint in tTriangles.iter('v1'):
                        # Get First vertex
                        v1.append(int(tFirstPoint.text))
                    for tSecondPoint in tTriangles.iter('v2'):
                        # Get Second vertex
                        v2.append(int(tSecondPoint.text))
                    for tThirdPoint in tTriangles.iter('v3'):
                        # Get Third vertex
                        v3.append(int(tThirdPoint.text))

                # Get the final triangles coordinates by connecting the vertices to their associated coordinates
                finalX = []
                finalY = []
                finalZ = []
                for index in range(len(v1)):
                    finalX.append([
                        coordinateX[v1[index]], coordinateX[v2[index]],
                        coordinateX[v3[index]]
                    ])
                    finalY.append([
                        coordinateY[v1[index]], coordinateY[v2[index]],
                        coordinateY[v3[index]]
                    ])
                    finalZ.append([
                        coordinateZ[v1[index]], coordinateZ[v2[index]],
                        coordinateZ[v3[index]]
                    ])

                # Create the triangles connections
                triangles = [(i * 3, (i * 3) + 1, (i * 3) + 2)
                             for i in range(0, len(finalX))]

                # Manage automatically the color of each volume depending on the material ID
                # The colormap is having 0:nbMaterial+1 possible values
                # We define a scalar that we associate with the volume
                if materialId == None:
                    # Assign the No Material ID in case no material was assigned to a volume
                    materialId = noMaterialID
                color = np.ones(np.asarray(finalX).shape) * int(materialId)

                if DONOTADD == False:
                    # Add the volume to the visualization only it it was not added previously

                    # Create the volume to visualize
                    volume = mlab.triangular_mesh(
                        finalX,
                        finalY,
                        finalZ,
                        triangles,
                        scalars=color,
                        vmin=0,
                        vmax=len(DICT_MATERIAL) - 1,
                        colormap='Spectral',
                        representation='wireframe',
                        name="volume:" + xmlObjectName,
                        figure=self.sceneView1.mayavi_scene,
                        reset_zoom=False)
                    volume.module_manager.scalar_lut_manager.lut.number_of_colors = 256

                    # Create a label for each volume
                    labels = Labels()
                    vtk_data_source = volume
                    self.engine1.add_filter(labels, vtk_data_source)
                    labels.mapper.label_format = (xmlObjectName)
                    labels.number_of_labels = 1
                    labels.mask.filter.random_mode = False

                    # Store the objects
                    currentObject = ObjectGeometry(xmlObjectID, xmlObjectName,
                                                   volume, materialId)
                    LIST_AMF_OBJECTS.append(currentObject)

        # Present the Material ID library ordered in the GUI
        materialIDSorted = sorted(list(DICT_MATERIAL.keys()), key=int)
        self.GUI_MATERIAL_LIBRARY = materialIDSorted
        HasTraits.__init__(self)

    # GUI Definition
    view = View(
        HSplit(
            Group(
                Item('sceneView1',
                     editor=SceneEditor(scene_class=MayaviScene),
                     height=800,
                     width=700,
                     show_label=False,
                     resizable=True),
                # Group used to inspect the different objects of the scenario
                HGroup(
                    Group(Item(name='GUI_CHANGE_REPRESENTATION',
                               label='Wireframe/Surface'),
                          Item(name='GUI_ID', label='ID', style='readonly'),
                          Item(name='GUI_OBJECT_NAME',
                               label='Name',
                               style='readonly'),
                          Item(name='GUI_MATERIAL_ID',
                               label='Material ID',
                               style='readonly'),
                          Item(name='GUI_MATERIAL_NAME',
                               label='Material Name',
                               style='readonly'),
                          label='Object Inspector',
                          show_border=True),
                    #  visible_when='GUI_ID != "1"',          #TODO Can allow to hide or display the group
                ),
                # Group used to edit the objects material (TODO: On-Hold as no convergence for the material ID library management)
                HGroup(
                    Group(Item(
                        name='GUI_CHANGE_MATERIAL',
                        editor=CheckListEditor(name='GUI_MATERIAL_LIBRARY'),
                        label='Change Material'),
                          label='Object Editor',
                          show_border=True), )), ),
        resizable=True,
    )
Beispiel #21
0
from traits.api import Str, Bool, Float, Range, List, Instance, HasTraits, DelegatesTo, Button
from traitsui.api import View, Group, Item, HGroup,spring
from labtools.agilent.funcgen import AgilentFuncGen, INITCMD, LOGLEVEL, find_address

from labtools.utils.instrui import BaseInstrumentUI, instrument_group, status_group



from labtools.log import create_logger



logger = create_logger(__name__, LOGLEVEL)

output_group = HGroup(Item('voltage'),
    spring,Item('output_button',show_label = False, enabled_when = '_initialized==True'),show_border = True, label = 'Output')

class IOSettings(HasTraits):
    """IO Settings for Keithley. defines port (instrument) name, communication timeout
    and initialization commands.
    """
    timeout = Range(0.,100.,10., desc = 'communication timeout')
    instr = Str(desc = 'instrument name')
    initcmd = Str(INITCMD, desc = 'initialization command')

    view = View('timeout', 'instr', Item('initcmd', style = 'custom'), buttons = ['OK', 'Cancel'])
 
class OutputSettings(HasTraits):
    voltage = Float(10.)
    frequency = Float(40.)
    offset = Float(0.)
Beispiel #22
0
class PlotApp2(HasTraits):
    numPcaScores = PCA.nums
    plotdata = Instance(ArrayPlotData)

    Y_PCA = Str
    YPCA = List(Str)

    X_PCA = Str
    XPCA = List(Str)

    Color = Str
    Colordropdownlist = List(Str)
    colors = List(str)

    Shape = Str
    Shapedropdownlist = List(Str)

    Size = Str
    Sizedropdownlist = List(Str)

    shapes_name = List(Str)
    colors_name = List(Str)
    sizes_name = List(Str)

    active_scores_combobox = Enum(['Post Scores', 'Pre Scores'])
    start_selection = Button(label='Start Selection')
    stop_selection = Button(label='Stop Selection')

    RightPlot = Instance(OverlayPlotContainer)
    LeftPlot = Instance(OverlayPlotContainer)

    button_editor = ButtonEditor()

    table = List(Instance(MyData))
    columns = [ObjectColumn(name='name')]
    columns.append(ObjectColumn(name="Value"))
    table_editor = TableEditor(columns=columns,
                               deletable=True,
                               sortable=False,
                               sort_model=False,
                               show_lines=True,
                               line_color="black",
                               editable=False,
                               show_column_labels=False)

    shape_table = List(Instance(ShapeTable))
    shape_columns = List(Instance(ObjectColumn))

    color_table = List(Instance(ColorTable))
    color_columns = List(Instance(ObjectColumn))

    size_table = List(Instance(SizeTable))
    size_columns = List(Instance(ObjectColumn))

    traits_view = View(VSplit(
        HSplit(
            VGroup(
                VGroup(
                    Item(
                        'Y_PCA',
                        editor=EnumEditor(
                            name='YPCA',
                            evaluate=validate_choice,
                        ),
                    ),
                    Item(
                        'X_PCA',
                        editor=EnumEditor(
                            name='XPCA',
                            evaluate=validate_choice,
                        ),
                    ),
                    Item('active_scores_combobox', width=225, label="Score"),
                    HGroup(
                        Item('start_selection',
                             editor=button_editor,
                             show_label=False,
                             width=0.5),
                        Item('stop_selection',
                             editor=button_editor,
                             show_label=False,
                             width=0.5)),
                ),
                Item('LeftPlot',
                     editor=ComponentEditor(),
                     show_label=False,
                     width=590,
                     height=800),
            ),
            VSplit(
                HGroup(
                    VGroup(
                        Item(
                            'Shape',
                            editor=EnumEditor(
                                name='Shapedropdownlist',
                                evaluate=validate_choice,
                            ),
                        ),
                        Item('shape_table',
                             editor=TableEditor(columns_name='shape_columns',
                                                deletable=True,
                                                sortable=False,
                                                sort_model=False,
                                                show_lines=True,
                                                line_color="black",
                                                editable=False,
                                                show_column_labels=False),
                             show_label=False,
                             width=0.3,
                             padding=5)),
                    VGroup(
                        Item(
                            'Color',
                            editor=EnumEditor(
                                name='Colordropdownlist',
                                evaluate=validate_choice,
                            ),
                        ),
                        Item('color_table',
                             editor=TableEditor(columns_name='color_columns',
                                                deletable=True,
                                                sortable=False,
                                                sort_model=False,
                                                show_lines=True,
                                                line_color="black",
                                                editable=False,
                                                show_column_labels=False),
                             show_label=False,
                             width=0.3,
                             padding=5)),
                    VGroup(
                        Item(
                            'Size',
                            editor=EnumEditor(
                                name='Sizedropdownlist',
                                evaluate=validate_choice,
                            ),
                        ),
                        Item('size_table',
                             editor=TableEditor(columns_name='size_columns',
                                                deletable=True,
                                                sortable=False,
                                                sort_model=False,
                                                show_lines=True,
                                                line_color="black",
                                                editable=False,
                                                show_column_labels=False),
                             show_label=False,
                             width=0.3,
                             padding=5)),
                ),
                Item('RightPlot',
                     editor=ComponentEditor(),
                     show_label=False,
                     height=640),
            )), Item('table',
                     editor=table_editor,
                     show_label=False,
                     padding=15)),
                       width=1100,
                       height=700,
                       resizable=True,
                       title="Principal Components Visualizer")

    def __init__(self, PCAData):
        super(PlotApp2, self).__init__()
        #self.phenotypes, self.pheno_dict = readPhenotypesFromCSVFile('..\..\IOdata\pca_phenotypes.csv')
        self.phenotypes, self.pheno_dict = readPhenotypesFromCSVFile_pd(
            '..\IOdata\phenotypes_table_2.csv')
        print(self.phenotypes, self.pheno_dict)
        self.shapes_name = self.pheno_dict[self.phenotypes[1]]
        self.colors_name = self.pheno_dict[self.phenotypes[2]]
        self.sizes_name = self.pheno_dict[self.phenotypes[3]]
        self.colors = get_colors(len(self.colors_name))
        #print('self.color=',self.colors)

        self.table_editor.columns = [ObjectColumn(name='name')]
        for i in range(len(PCAData) - 1):
            self.table_editor.columns.append(ObjectColumn(name="PCA" + str(i)))

        self.PCAData = PCAData
        self.YPCA = [str(i) for i in range(len(PCAData) - 1)]
        self.XPCA = [str(i) for i in range(len(PCAData) - 1)]

        self.Shapedropdownlist = self.phenotypes
        self.Colordropdownlist = self.phenotypes
        self.Sizedropdownlist = self.phenotypes

        self.X_PCA = '0'
        self.Y_PCA = '0'

        self.Shape = self.phenotypes[1]
        self.Color = self.phenotypes[2]
        self.Size = self.phenotypes[3]

        self.activeScore = 'Pre Scores'
        self._updateTable()
        self._updateShapeTable()
        self._updateColorTable()
        self._updateSizeTable()
        self._update_Both_graph()

        return

    def _getPCAArray(self, pcaIndex):
        x0 = []
        for batch in self.PCAData.batchs:
            if (self.active_scores_combobox == "Post Scores"):
                x0.append(batch.postscores[pcaIndex])
            else:
                x0.append(batch.prescores[pcaIndex])
        return x0

    def _create_1D1_plot(self):
        index = 0
        plot0 = Plot(self.plotdata, padding=0)
        plot0.padding_left = 5
        plot0.padding_bottom = 5
        Container = OverlayPlotContainer(padding=50,
                                         fill_padding=True,
                                         bgcolor="lightgray",
                                         use_backbuffer=True)

        y1 = range(len(self.PCAData.batchs[0].prescores))
        points = []
        for batch in self.PCAData.batchs:
            if (self.active_scores_combobox == "Post Scores"):
                x1 = self.PCAData.batchs[index].postscores
            else:
                x1 = self.PCAData.batchs[index].prescores

            if (self.Shape == self.phenotypes[0]):
                a = 1
            elif (self.Shape == self.phenotypes[1]):
                a = batch.number
            elif (self.Shape == self.phenotypes[2]):
                a = batch.type
            else:
                a = 0

            if (self.Color == self.phenotypes[0]):
                b = 0
            elif (self.Color == self.phenotypes[1]):
                b = batch.number
            elif (self.Color == self.phenotypes[2]):
                b = batch.type
            else:
                b = 0

            tmarker = shapes[a]
            bcolor = self.colors[b]

            for i in range(len(x1)):
                points.append((x1[i], y1[i]))
            plot0 = create_scatter_plot((x1, y1),
                                        marker=tmarker,
                                        color=getColor(bcolor))

            if batch.isSelected:
                plot0.alpha = 1
            else:
                plot0.alpha = 0.2

            plot0.bgcolor = "white"
            plot0.border_visible = True

            if index == 0:
                value_mapper = plot0.value_mapper
                index_mapper = plot0.index_mapper
                add_default_grids(plot0)
                add_default_axes(plot0,
                                 vtitle='PCA Indices',
                                 htitle='PCA Scores')
                plot0.index_range.tight_bounds = False
                plot0.index_range.refresh()
                plot0.value_range.tight_bounds = False
                plot0.value_range.refresh()
                plot0.tools.append(PanTool(plot0))
                zoom = ZoomTool(plot0,
                                tool_mode="box",
                                always_on=False,
                                maintain_aspect_ratio=False)
                plot0.overlays.append(zoom)
                dragzoom = DragZoom(plot0,
                                    drag_button="right",
                                    maintain_aspect_ratio=False)
                plot0.tools.append(dragzoom)

            else:
                plot0.value_mapper = value_mapper
                value_mapper.range.add(plot0.value)
                plot0.index_mapper = index_mapper
                index_mapper.range.add(plot0.index)

            Container.add(plot0)
            index = index + 1

        self.RightPlot = Container

    def _create_2D_plot(self):

        index = 0
        secContainer = OverlayPlotContainer(padding=50,
                                            fill_padding=True,
                                            bgcolor="lightgray",
                                            use_backbuffer=True)
        try:
            pcaPoints = []
            for batch in self.PCAData.batchs:
                if (self.active_scores_combobox == "Post Scores"):
                    y = [batch.postscores[int(self.Y_PCA)]]
                    x = [batch.postscores[int(self.X_PCA)]]
                else:
                    x = [batch.prescores[int(self.X_PCA)]]
                    y = [batch.prescores[int(self.Y_PCA)]]
                for i in range(len(x)):
                    pcaPoints.append((x[i], y[i]))

                if (self.Shape == self.phenotypes[0]):
                    a = 1
                elif (self.Shape == self.phenotypes[1]):
                    a = batch.number
                elif (self.Shape == self.phenotypes[2]):
                    a = batch.type
                else:
                    a = 0

                if (self.Color == self.phenotypes[0]):
                    b = 0
                elif (self.Color == self.phenotypes[1]):
                    b = batch.number
                elif (self.Color == self.phenotypes[2]):
                    b = batch.type
                else:
                    b = 0

                tmarker = shapes[a]
                bcolor = self.colors[b]

                plot = create_scatter_plot((x, y),
                                           marker=tmarker,
                                           color=getColor(bcolor))
                if batch.isSelected:
                    plot.alpha = 1
                else:
                    plot.fill_alpha = 0.2
                plot.bgcolor = "white"
                plot.border_visible = True

                if index == 0:
                    value_mapper = plot.value_mapper
                    index_mapper = plot.index_mapper
                    add_default_grids(plot)
                    add_default_axes(plot,
                                     vtitle='PCA ' + self.Y_PCA,
                                     htitle='PCA ' + self.X_PCA)
                    plot.index_range.tight_bounds = False
                    plot.index_range.refresh()
                    plot.value_range.tight_bounds = False
                    plot.value_range.refresh()

                    plot.tools.append(PanTool(plot))
                    zoom = ZoomTool(plot, tool_mode="box", always_on=False)
                    plot.overlays.append(zoom)
                    dragzoom = DragZoom(plot, drag_button="right")
                    plot.tools.append(dragzoom)

                else:
                    plot.value_mapper = value_mapper
                    value_mapper.range.add(plot.value)
                    plot.index_mapper = index_mapper
                    index_mapper.range.add(plot.index)

                secContainer.add(plot)
                index = index + 1
            lineDraw = LineDrawer2D(plot)
            lineDraw.setPCAData(self, self.PCAData)
            plot.overlays.append(lineDraw)
            self.LeftPlot = secContainer
        except ValueError:

            pass

    def _Y_PCA_changed(self, selectedValue):
        self.Y_PCA = selectedValue
        self._create_2D_plot()

    def _X_PCA_changed(self, selectedValue):
        self.X_PCA = selectedValue
        self._create_2D_plot()

    def _Color_changed(self, selectedValue):
        self.pcolor = selectedValue
        self.colors_name = self.pheno_dict[self.pcolor]
        self.colors = get_colors(len(self.colors_name))
        #print(self.Color, self.colors_name, self.colors)
        self._updateColorTable()
        self._update_Both_graph()

    def _Size_changed(self, selectedValue):
        self.psize = selectedValue
        self.sizes_name = self.pheno_dict[self.psize]
        self._updateSizeTable()
        self._update_Both_graph()

    def _Shape_changed(self, selectedValue):
        self.pshape = selectedValue
        self.shapes_name = self.pheno_dict[self.pshape]
        self._updateShapeTable()
        self._update_Both_graph()

    def _active_scores_combobox_changed(self):
        self._update_Both_graph()

    def _start_selection_fired(self):
        for batch in self.PCAData.batchs:
            batch.isSelected = False
        self._create_1D1_plot()
        self._create_2D_plot()

    def _stop_selection_fired(self):
        for batch in self.PCAData.batchs:
            batch.isSelected = True
        self._create_1D1_plot()
        self._create_2D_plot()

    def _updateShapeTable(self):
        del (self.shape_table)

        columns = [ObjectColumn(name='name')]
        for i in range(len(self.shapes_name)):
            columns.append(ObjectColumn(name='s' + self.shapes_name[i]))
        data = ShapeTable()
        self.shape_table.append(data)
        self.shape_columns = columns
        self.shape_table.remove(data)

        data = ShapeTable()
        data.name = self.pshape
        for i in range(len(self.shapes_name)):
            exec('data.s' + self.shapes_name[i] + '="' + self.shapes_name[i] +
                 '"')
        self.shape_table.append(data)

        data = ShapeTable()
        data.name = "Shape"
        for i in range(len(self.shapes_name)):
            exec('data.s' + self.shapes_name[i] + '="' + shapes[i] + '"')
        self.shape_table.append(data)

    def _updateColorTable(self):
        del (self.color_table)
        columns = [ObjectColumn(name='name')]
        for i in range(len(self.colors_name)):
            columns.append(
                ObjectColumn(name='s' + self.colors_name[i],
                             cell_color=getColor(self.colors[i])))
        data = ColorTable()
        self.color_table.append(data)
        self.color_columns = columns
        self.color_table.remove(data)

        data = ColorTable()
        data.name = self.pcolor
        for i in range(len(self.colors_name)):
            exec('data.s' + self.colors_name[i] + '="' + self.colors_name[i] +
                 '"')
        self.color_table.append(data)

        data = ColorTable()
        data.name = "Color"
        for i in range(len(self.colors_name)):
            exec('data.s' + self.colors_name[i] + '=""')
        self.color_table.append(data)

    def _updateSizeTable(self):
        del (self.size_table)

        columns = [ObjectColumn(name='name')]
        for i in range(len(self.sizes_name)):
            columns.append(ObjectColumn(name='s' + self.sizes_name[i]))
        data = SizeTable()
        self.size_table.append(data)
        self.size_columns = columns
        self.size_table.remove(data)

        data = SizeTable()
        data.name = self.psize
        for i in range(len(self.sizes_name)):
            exec('data.s' + self.sizes_name[i] + '="' + self.sizes_name[i] +
                 '"')
        self.size_table.append(data)

        data = SizeTable()
        data.name = "Size"
        for i in range(len(self.sizes_name)):
            exec('data.s' + self.sizes_name[i] + '="' + sizes[i] + '"')
        self.size_table.append(data)

    def _updateTable(self):
        numPcaScores = len(self.PCAData) - 1
        pca_vars = []
        sumVar = 0.0
        sumPercent = 0.0
        del (self.table)

        data = MyData()
        data.name = 'PCA Index'
        for i in range(numPcaScores):
            exec('data.PCA' + str(i) + '=' + str(i))
        self.table.append(data)

        data = MyData()
        data.name = 'Percentage Power'
        for i in range(numPcaScores):
            pca = self._getPCAArray(i)
            temp = var(pca)
            pca_vars.append(temp)
            sumVar = sumVar + temp
        for i in range(numPcaScores):
            percent = 100 * pca_vars[i] / sumVar
            exec('data.PCA' + str(i) + ('=%0.2f' % percent))
        self.table.append(data)

        data = MyData()
        data.name = 'Cumulative Percentage Power'
        for i in range(numPcaScores):
            percent = 100 * pca_vars[i] / sumVar
            sumPercent = sumPercent + percent
            exec('data.PCA' + str(i) + ('=%0.2f' % sumPercent))
        self.table.append(data)

    def _update_Both_graph(self):
        self.activeScore = self.active_scores_combobox
        self._create_2D_plot()
        self._create_1D1_plot()
        self._updateTable()
Beispiel #23
0
class DoubleSview(HasTraits):
    ''' Container for two instances of scatter view.  Takes in full Sview objects, so that composite
        plots can be built up using these '''

    scatt1 = Instance(ScatterView)
    scatt2 = Instance(ScatterView)

    implements(ICompositeView)

    datanames = ['Scattering', 'Absorbance', 'Extinction']
    hideplots = List(
        editor=CheckListEditor(
            values=['Scattering', 'Absorbance', 'Extinction'], cols=3)
    )  #THESE ARE KEYS USED TO SETDATA IN SVIEW OBJECT (DON'T ALTER IN EITHER CODE)

    #Following is used to keep keys in plot objects separate (e.g. Absorbance is a plot key for scatt1 and scatt2#
    #These will turn it into Absorbance%s1 and Absorbance%s2#
    delimiter = Str('%')
    s1_id = Str('s1')
    s2_id = Str('s2')
    s1_color = Str('blue')
    s2_color = Str('red')

    alldata = Instance(ArrayPlotData)
    doubleplot = Instance(Plot)

    def _alldata_default(self):
        """ Default ArrayPlotData with reserved names which will be updated when individual plot data
        objects are changed.
        names for the ArrayPlotData objects based on datanames (sig, absorb) plus the id and delimiter.  I reserve
        only one instance of 'x' """
        alldata = ArrayPlotData()

        for name in self.datanames:
            alldata.set_data(name + self.delimiter + self.s1_id, [])
            alldata.set_data(name + self.delimiter + self.s2_id, [])
        alldata.set_data('x', [])
        return alldata

    def _doubleplot_default(self):
        ''' I add all the plots in one go, then use hide/show functions to change them'''
        plot = Plot(self.alldata)
        for name in self.alldata.list_data():
            if name != 'x':
                if name.split(self.delimiter)[1] == self.s1_id:
                    color = self.s1_color
                elif name.split(self.delimiter)[1] == self.s2_id:
                    color = self.s2_color
                plot.plot(('x', name), name=name, linewidth=5, color=color)
        return plot

    @on_trait_change('scatt1.data.arrays, scatt2.data.arrays')
    def update_alldata(self):
        ''' This is how the plots update in real time, by listening to data.arrays.  I extract 'x' from
            the first plot, assuming it is the same between plots '''
        if self.scatt1 is not None:
            for name in self.scatt1.data.arrays:
                if name == 'x':
                    self.alldata.set_data((str(name)),
                                          self.scatt1.data.arrays[name])
                else:
                    self.alldata.set_data(
                        (str(name) + self.delimiter + self.s1_id),
                        self.scatt1.data.arrays[name])
        if self.scatt2 is not None:
            for name in self.scatt2.data.arrays:
                if name != 'x':
                    self.alldata.set_data(
                        (str(name) + self.delimiter + self.s2_id),
                        self.scatt2.data.arrays[name])

    @on_trait_change('hideplots')
    def update_lines(self):
        ''' Allows users to hide or show plots by first plotting all the lines.  Note that since there 
            are two plots, there are actually two matches to name.  EG if name is "abs" then its going
            to hide or show abs%1 and abs%2, that is why I only need to put one call below '''
        for name in self.doubleplot.plots:
            if name.split(self.delimiter)[0] in self.hideplots:
                self.doubleplot.hideplot(name)
            else:
                self.doubleplot.showplot(name)
        self.doubleplot.request_redraw()  #Necessary

    traits_view = View(VGroup(HGroup(Item('scatt1',
                                          style='custom',
                                          show_label=False),
                                     Item('scatt2',
                                          style='custom',
                                          show_label=False),
                                     label="Separate"),
                              VGroup(Item('hideplots',
                                          style='custom',
                                          label='Hide Plot'),
                                     Item('doubleplot',
                                          editor=ComponentEditor(size=(200,
                                                                       100)),
                                          show_label=False),
                                     label="Combined"),
                              layout='tabbed'),
                       resizable=True)
Beispiel #24
0
 def traits_view(self):
     v = View(
         HGroup(UItem('use'),
                UItem('det', editor=EnumEditor(name='detectors')),
                Item('value'), Label(PLUSMINUS), UItem('error')))
     return v
Beispiel #25
0
 def _info_grp(self):
     return HGroup(
         Readonly('local_commit', label='Your Version'),
         Readonly('latest_remote_commit', label='Latest Version'),
         Readonly('n', label='Commits Behind', visible_when='show_behind'))
class DataSourceWizardView(DataSourceWizard):

    #----------------------------------------------------------------------
    # Private traits
    #----------------------------------------------------------------------

    _top_label = Str('Describe your data')

    _info_text = Str('Array size do not match')

    _array_label = Str('Available arrays')

    _data_type_text = Str("What does your data represents?")

    _lines_text = Str("Connect the points with lines")

    _scalar_data_text = Str("Array giving the value of the scalars")

    _optional_scalar_data_text = Str("Associate scalars with the data points")

    _connectivity_text = Str("Array giving the triangles")

    _vector_data_text = Str("Associate vector components")

    _position_text = Property(depends_on="position_type_")

    _position_text_dict = {'explicit':
                'Coordinnates of the data points:',
                           'orthogonal grid':
                'Position of the layers along each axis:',
            }

    def _get__position_text(self):
        return self._position_text_dict.get(self.position_type_, "")

    _shown_help_text = Str

    _data_sources_wrappers = Property(depends_on='data_sources')

    def _get__data_sources_wrappers(self):
        return [
            ArrayColumnWrapper(name=name,
                shape=repr(self.data_sources[name].shape))
                    for name in self._data_sources_names
                ]

    # A traits pointing to the object, to play well with traitsUI
    _self = Instance(DataSourceWizard)

    _suitable_traits_view = Property(depends_on="data_type_")

    def _get__suitable_traits_view(self):
        return "_%s_data_view" % self.data_type_

    ui = Any(False)

    _preview_button = Button(label='Preview structure')

    def __preview_button_fired(self):
        if self.ui:
            self.build_data_source()
            self.preview()

    _ok_button = Button(label='OK')

    def __ok_button_fired(self):
        if self.ui:
            self.ui.dispose()
            self.build_data_source()

    _cancel_button = Button(label='Cancel')

    def __cancel_button_fired(self):
        if self.ui:
            self.ui.dispose()

    _is_ok = Bool

    _is_not_ok = Bool

    def _anytrait_changed(self):
        """ Validates if the OK button is enabled.
        """
        if self.ui:
            self._is_ok = self.check_arrays()
            self._is_not_ok = not self._is_ok

    _preview_window = Instance(PreviewWindow, ())

    _info_image = Instance(ImageResource,
                    ImageLibrary.image_resource('@std:alert16',))

    #----------------------------------------------------------------------
    # TraitsUI views
    #----------------------------------------------------------------------
    _coordinates_group = \
                        HGroup(
                           Item('position_x', label='x',
                               editor=EnumEditor(name='_data_sources_names',
                                        invalid='_is_not_ok')),
                           Item('position_y', label='y',
                               editor=EnumEditor(name='_data_sources_names',
                                        invalid='_is_not_ok')),
                           Item('position_z', label='z',
                               editor=EnumEditor(name='_data_sources_names',
                                        invalid='_is_not_ok')),
                       )

    _position_group = \
                    Group(
                       Item('position_type'),
                       Group(
                           Item('_position_text', style='readonly',
                                    resizable=False,
                                    show_label=False),
                           _coordinates_group,
                           visible_when='not position_type_=="image data"',
                       ),
                       Group(
                           Item('grid_shape_source_',
                            label='Grid shape',
                            editor=EnumEditor(
                                name='_grid_shape_source_labels',
                                        invalid='_is_not_ok')),
                           HGroup(
                            spring,
                            Item('grid_shape', style='custom',
                                    editor=ArrayEditor(width=-60),
                                    show_label=False),
                           enabled_when='grid_shape_source==""',
                            ),
                           visible_when='position_type_=="image data"',
                       ),
                       label='Position of the data points',
                       show_border=True,
                       show_labels=False,
                   ),

    _connectivity_group = \
                   Group(
                       HGroup(
                         Item('_connectivity_text', style='readonly',
                                resizable=False),
                         spring,
                         Item('connectivity_triangles',
                                editor=EnumEditor(name='_data_sources_names'),
                                show_label=False,
                                ),
                         show_labels=False,
                       ),
                       label='Connectivity information',
                       show_border=True,
                       show_labels=False,
                       enabled_when='position_type_=="explicit"',
                   ),

    _scalar_data_group = \
                   Group(
                       Item('_scalar_data_text', style='readonly',
                           resizable=False,
                           show_label=False),
                       HGroup(
                           spring,
                           Item('scalar_data',
                               editor=EnumEditor(name='_data_sources_names',
                                        invalid='_is_not_ok')),
                           show_labels=False,
                           ),
                       label='Scalar value',
                       show_border=True,
                       show_labels=False,
                   )

    _optional_scalar_data_group = \
                   Group(
                       HGroup(
                       'has_scalar_data',
                       Item('_optional_scalar_data_text',
                            resizable=False,
                            style='readonly'),
                       show_labels=False,
                       ),
                       Item('_scalar_data_text', style='readonly',
                            resizable=False,
                            enabled_when='has_scalar_data',
                           show_label=False),
                       HGroup(
                           spring,
                           Item('scalar_data',
                               editor=EnumEditor(name='_data_sources_names',
                                        invalid='_is_not_ok'),
                               enabled_when='has_scalar_data'),
                           show_labels=False,
                           ),
                       label='Scalar data',
                       show_border=True,
                       show_labels=False,
                   ),

    _vector_data_group = \
                   VGroup(
                       HGroup(
                           Item('vector_u', label='u',
                               editor=EnumEditor(name='_data_sources_names',
                                        invalid='_is_not_ok')),
                           Item('vector_v', label='v',
                               editor=EnumEditor(name='_data_sources_names',
                                        invalid='_is_not_ok')),
                           Item('vector_w', label='w',
                               editor=EnumEditor(name='_data_sources_names',
                                        invalid='_is_not_ok')),
                       ),
                       label='Vector data',
                       show_border=True,
                   ),

    _optional_vector_data_group = \
                   VGroup(
                        HGroup(
                            Item('has_vector_data', show_label=False),
                            Item('_vector_data_text', style='readonly',
                                resizable=False,
                                show_label=False),
                        ),
                       HGroup(
                           Item('vector_u', label='u',
                               editor=EnumEditor(name='_data_sources_names',
                                        invalid='_is_not_ok')),
                           Item('vector_v', label='v',
                               editor=EnumEditor(name='_data_sources_names',
                                        invalid='_is_not_ok')),
                           Item('vector_w', label='w',
                               editor=EnumEditor(name='_data_sources_names',
                                        invalid='_is_not_ok')),
                           enabled_when='has_vector_data',
                       ),
                       label='Vector data',
                       show_border=True,
                   ),

    _array_view = \
                View(
                    Item('_array_label', editor=TitleEditor(),
                        show_label=False),
                    Group(
                    Item('_data_sources_wrappers',
                      editor=TabularEditor(
                          adapter=ArrayColumnAdapter(),
                      ),
                    ),
                    show_border=True,
                    show_labels=False
                ))

    _questions_view = View(
                Item('_top_label', editor=TitleEditor(),
                        show_label=False),
                HGroup(
                    Item('_data_type_text', style='readonly',
                                resizable=False),
                    spring,
                    'data_type',
                    spring,
                    show_border=True,
                    show_labels=False,
                  ),
                HGroup(
                    Item('_self', style='custom',
                        editor=InstanceEditor(
                                    view_name='_suitable_traits_view'),
                        ),
                    Group(
                        # FIXME: Giving up on context sensitive help
                        # because of lack of time.
                        #Group(
                        #    Item('_shown_help_text', editor=HTMLEditor(),
                        #        width=300,
                        #        label='Help',
                        #        ),
                        #    show_labels=False,
                        #    label='Help',
                        #),
                        #Group(
                            Item('_preview_button',
                                    enabled_when='_is_ok'),
                            Item('_preview_window', style='custom',
                                    label='Preview structure'),
                            show_labels=False,
                            #label='Preview structure',
                        #),
                        #layout='tabbed',
                        #dock='tab',
                    ),
                    show_labels=False,
                    show_border=True,
                ),
            )

    _point_data_view = \
                View(Group(
                   Group(_coordinates_group,
                        label='Position of the data points',
                        show_border=True,
                   ),
                   HGroup(
                       'lines',
                       Item('_lines_text', style='readonly',
                                        resizable=False),
                       label='Lines',
                       show_labels=False,
                       show_border=True,
                   ),
                   _optional_scalar_data_group,
                   _optional_vector_data_group,
                   # XXX: hack to have more vertical space
                   Label('\n'),
                   Label('\n'),
                   Label('\n'),
                ))

    _surface_data_view = \
                View(Group(
                   _position_group,
                   _connectivity_group,
                   _optional_scalar_data_group,
                   _optional_vector_data_group,
                ))

    _vector_data_view = \
                View(Group(
                   _vector_data_group,
                   _position_group,
                   _optional_scalar_data_group,
                ))

    _volumetric_data_view = \
                View(Group(
                   _scalar_data_group,
                   _position_group,
                   _optional_vector_data_group,
                ))

    _wizard_view = View(
          Group(
            HGroup(
                Item('_self', style='custom', show_label=False,
                     editor=InstanceEditor(view='_array_view'),
                     width=0.17,
                     ),
                '_',
                Item('_self', style='custom', show_label=False,
                     editor=InstanceEditor(view='_questions_view'),
                     ),
                ),
            HGroup(
                Item('_info_image', editor=ImageEditor(),
                    visible_when="_is_not_ok"),
                Item('_info_text', style='readonly', resizable=False,
                    visible_when="_is_not_ok"),
                spring,
                '_cancel_button',
                Item('_ok_button', enabled_when='_is_ok'),
                show_labels=False,
            ),
          ),
        title='Import arrays',
        resizable=True,
        )

    #----------------------------------------------------------------------
    # Public interface
    #----------------------------------------------------------------------

    def __init__(self, **traits):
        DataSourceFactory.__init__(self, **traits)
        self._self = self

    def view_wizard(self):
        """ Pops up the view of the wizard, and keeps the reference it to
            be able to close it.
        """
        # FIXME: Workaround for traits bug in enabled_when
        self.position_type_
        self.data_type_
        self._suitable_traits_view
        self.grid_shape_source
        self._is_ok
        self.ui = self.edit_traits(view='_wizard_view')

    def preview(self):
        """ Display a preview of the data structure in the preview
            window.
        """
        self._preview_window.clear()
        self._preview_window.add_source(self.data_source)
        data = lambda name: self.data_sources[name]
        g = Glyph()
        g.glyph.glyph_source.glyph_source = \
                    g.glyph.glyph_source.glyph_list[0]
        g.glyph.scale_mode = 'data_scaling_off'
        if not (self.has_vector_data or self.data_type_ == 'vector'):
            g.glyph.glyph_source.glyph_source.glyph_type = 'cross'
            g.actor.property.representation = 'points'
            g.actor.property.point_size = 3.
        self._preview_window.add_module(g)
        if not self.data_type_ in ('point', 'vector') or self.lines:
            s = Surface()
            s.actor.property.opacity = 0.3
            self._preview_window.add_module(s)
        if not self.data_type_ == 'point':
            self._preview_window.add_filter(ExtractEdges())
            s = Surface()
            s.actor.property.opacity = 0.2
            self._preview_window.add_module(s)
class MayaviGrid(HasTraits):
    ''' This class is used to plot the data in a vlsv file as a mayavi grid The following will bring up a new window and plot the grid in the vlsv file:

   .. code-block:: python

      grid = pt.grid.MayaviGrid(vlsvReader=f, variable="rho", operator='pass', threaded=False)

   Once you have the window open you can use the picker tool in the right-upper corner and use various point-click tools for analyzing data.

   Picker options:
   
   **None** Does nothing upon clicking somewhere in the grid
   
   **Velocity_space** Plots the velocity space at a specific position upon clicking somewhere in the grid Note: If the vlsv file does not have the velocity space at the position where you are clicking, this will not work
   
   **Velocity_space_iso_surface** Plots the velocity space at a specific position upon clicking somewhere in the grid in iso-surface plotting style Note: If the vlsv file does not have the velocity space at the position where you are clicking, this will not work
   
   **Velocity_space_nearest_cellid** Plots the velocity space of the closest cell id to the picking point Note: If the vlsv file does not have velocity space saved at all, this will not work
   
   **Velocity_space_nearest_cellid_iso_surface** Plots the velocity space of the closest cell id to the picking point in iso-surface plotting style Note: If the vlsv file does not have velocity space saved at all, this will not work
   
   **Pitch_angle** Plots the pitch angle distribution at the clicking position Note: If the vlsv file does not have the velocity space at the position where you are clicking, this will not work
   
   **Gyrophase_angle** Plots the gyrophase angle distribution at the clicking position Note: If the vlsv file does not have the velocity space at the position where you are clicking, this will not work
   
   **Cut_through** Is used to plot or save the cut-through between two clicking points. This option requires you to use the args section at top-left. To use the args section to plot variables you must write for example: **plot rho B,x E,y** Upon clicking at two points a new window would open with a cut-through plot of rho, x-component of B and y-component of E Alternatively, you can save the cut-through to a variable in the MayaviGrid class by typing instead: **rho B,x E,y** and then going to the terminal and typing
   
   .. code-block:: python

      cut_through_data = grid.cut_through
      print cut_through_data

   '''
    picker = Enum('None', 'Velocity_space', "Velocity_space_nearest_cellid",
                  'Velocity_space_iso_surface',
                  'Velocity_space_nearest_cellid_iso_surface', "Pitch_angle",
                  "Gyrophase_angle", "Cut_through")

    args = ""

    variable_plotted = ""

    labels = []

    cut_through = []

    plot = []

    scene = Instance(MlabSceneModel, ())

    engine_view = Instance(EngineView)

    current_selection = Property

    dataset = []

    # Define the view:
    view = View(
        HGroup(
            Item('scene',
                 editor=SceneEditor(scene_class=MayaviScene),
                 height=250,
                 width=300,
                 show_label=False,
                 resizable=True),
            Group(
                #'cell_pick',
                'picker',
                'args',
                show_labels=True),
        ),
        resizable=True,
    )

    def __init__(self,
                 vlsvReader,
                 variable,
                 operator="pass",
                 threaded=True,
                 **traits):
        ''' Initializes the class and loads the mayavi grid

          :param vlsvReader:        Some vlsv reader with a file open
          :type vlsvReader:         :class:`vlsvfile.VlsvReader`
          :param variable:          Name of the variable
          :param operator:          Operator for the variable
          :param threaded:          Boolean value for using threads or not using threads to draw the grid (threads enable interactive mode)
      '''
        HasTraits.__init__(self, **traits)
        self.__vlsvReader = vlsvReader
        self.engine_view = EngineView(engine=self.scene.engine)
        self.__engine = self.scene.engine
        self.__picker = []
        self.__mins = []
        self.__maxs = []
        self.__cells = []
        self.__last_pick = []
        self.__structured_figures = []
        self.__unstructured_figures = []
        self.__thread = []
        self.__load_grid(variable=variable,
                         operator=operator,
                         threaded=threaded)
        self.variable_plotted = variable

    def __module_manager(self):
        import mayavi.core.module_manager as MM
        module_manager = self.scene.mayavi_scene
        # Find the module manager:
        while (True):
            module_manager = module_manager.children[0]
            if type(module_manager) == type(MM.ModuleManager()):
                break
        return module_manager

    def __add_label(self, cellid):
        # Add dataset:
        from mayavi.modules.labels import Labels
        indices = self.__vlsvReader.get_cell_indices(cellid)
        self.labels = Labels()
        self.labels.number_of_labels = 1
        self.labels.mask.filter.random_mode = False
        self.labels.mask.filter.offset = int(
            indices[0] + (self.__cells[0] + 1) * indices[1] +
            (self.__cells[0] + 1) * (self.__cells[1] + 1) * (indices[2] + 1))
        module_manager = self.__module_manager()
        # Add the label / marker:
        self.__engine.add_filter(self.labels, module_manager)
        #module_manager = engine.scenes[0].children[0].children[0]
        #engine.add_filter(labels1, module_manager)
        #self.labels = self.scene.mlab.pipeline.labels( self.dataset )

    def __add_normal_labels(self, point1, point2):
        # Get spatial grid sizes:
        xcells = (int)(self.__vlsvReader.read_parameter("xcells_ini"))
        ycells = (int)(self.__vlsvReader.read_parameter("ycells_ini"))
        zcells = (int)(self.__vlsvReader.read_parameter("zcells_ini"))

        xmin = self.__vlsvReader.read_parameter("xmin")
        ymin = self.__vlsvReader.read_parameter("ymin")
        zmin = self.__vlsvReader.read_parameter("zmin")
        xmax = self.__vlsvReader.read_parameter("xmax")
        ymax = self.__vlsvReader.read_parameter("ymax")
        zmax = self.__vlsvReader.read_parameter("zmax")

        dx = (xmax - xmin) / (float)(xcells)
        dy = (ymax - ymin) / (float)(ycells)
        dz = (zmax - zmin) / (float)(zcells)

        # Get normal vector from point2 and point1
        point1 = np.array(point1)
        point2 = np.array(point2)
        normal_vector = (point2 - point1) / np.linalg.norm(point2 - point1)
        normal_vector = np.dot(rotation_matrix_2d(
            -0.5 * np.pi), (point2 - point1)) / np.linalg.norm(point2 - point1)
        normal_vector = normal_vector * np.array([1, 1, 0])
        point1_shifted = point1 + 0.5 * (point2 -
                                         point1) - normal_vector * (8 * dx)
        point2_shifted = point1 + 0.5 * (point2 -
                                         point1) + normal_vector * (8 * dx)
        point1 = np.array(point1_shifted)
        point2 = np.array(point2_shifted)

        cellid1 = self.__vlsvReader.get_cellid(point1)
        cellid2 = self.__vlsvReader.get_cellid(point2)

        # Input label:
        self.__add_label(cellid1)
        self.__add_label(cellid2)

    def __load_grid(self, variable, operator="pass", threaded=True):
        ''' Creates a grid and inputs scalar variables from a vlsv file
          :param variable:        Name of the variable to plot
          :param operator:        Operator for the variable
          :param threaded:        Boolean value for using threads or not using threads to draw the grid (threads enable interactive mode)
      '''
        # Get the cell params:
        mins = np.array([
            self.__vlsvReader.read_parameter("xmin"),
            self.__vlsvReader.read_parameter("ymin"),
            self.__vlsvReader.read_parameter("zmin")
        ])
        cells = np.array([
            self.__vlsvReader.read_parameter("xcells_ini"),
            self.__vlsvReader.read_parameter("ycells_ini"),
            self.__vlsvReader.read_parameter("zcells_ini")
        ])
        maxs = np.array([
            self.__vlsvReader.read_parameter("xmax"),
            self.__vlsvReader.read_parameter("ymax"),
            self.__vlsvReader.read_parameter("zmax")
        ])
        # Get the variables:
        index_for_cellid_dict = self.__vlsvReader.get_cellid_locations()
        variable_array = self.__vlsvReader.read_variable(name=variable,
                                                         operator=operator)
        # Sort the dictionary by cell id
        import operator as oper
        sorted_index_for_cellid_dict = sorted(
            index_for_cellid_dict.iteritems(), key=oper.itemgetter(0))
        # Add the variable values:
        variable_array_sorted = []
        for i in sorted_index_for_cellid_dict:
            variable_array_sorted.append(variable_array[i[1]])
        # Store the mins and maxs:
        self.__mins = mins
        self.__maxs = maxs
        self.__cells = cells
        # Draw the grid:
        if threaded == True:
            thread = threading.Thread(target=self.__generate_grid,
                                      args=(mins, maxs, cells,
                                            variable_array_sorted, variable))
            thread.start()
        else:
            self.__generate_grid(mins=mins,
                                 maxs=maxs,
                                 cells=cells,
                                 datas=variable_array_sorted,
                                 names=variable)

    def __picker_callback(self, picker):
        """ This gets called when clicking on a cell
      """
        if (self.picker != "Cut_through"):
            # Make sure the last pick is null (used in cut_through)
            self.__last_pick = []

        coordinates = picker.pick_position
        coordinates = np.array(
            [coordinates[0], coordinates[1], coordinates[2]])
        # For numerical inaccuracy
        epsilon = 80
        # Check for numerical inaccuracy
        for i in xrange(3):
            if (coordinates[i] < self.__mins[i]) and (coordinates[i] + epsilon
                                                      > self.__mins[i]):
                # Correct the numberical inaccuracy
                coordinates[i] = self.__mins[i] + 1
            if (coordinates[i] > self.__maxs[i]) and (coordinates[i] - epsilon
                                                      < self.__maxs[i]):
                # Correct the values
                coordinates[i] = self.__maxs[i] - 1
        print "COORDINATES:" + str(coordinates)
        cellid = self.__vlsvReader.get_cellid(coordinates)
        print "CELL ID: " + str(cellid)
        # Check for an invalid cell id
        if cellid == 0:
            print "Invalid cell id"
            return

        if (self.picker == "Velocity_space"):
            # Set label to give out the location of the cell:
            self.__add_label(cellid)
            # Generate velocity space
            self.__generate_velocity_grid(cellid)
        elif (self.picker == "Velocity_space_nearest_cellid"):
            # Find the nearest cell id with distribution:
            # Read cell ids with velocity distribution in:
            cell_candidates = self.__vlsvReader.read("SpatialGrid",
                                                     "CELLSWITHBLOCKS")
            # Read in the coordinates of the cells:
            cell_candidate_coordinates = [
                self.__vlsvReader.get_cell_coordinates(cell_candidate)
                for cell_candidate in cell_candidates
            ]
            # Read in the cell's coordinates:
            pick_cell_coordinates = self.__vlsvReader.get_cell_coordinates(
                cellid)
            # Find the nearest:
            from operator import itemgetter
            norms = np.sum(
                (cell_candidate_coordinates - pick_cell_coordinates)**2,
                axis=-1)**(1. / 2)
            norm, i = min((norm, idx) for (idx, norm) in enumerate(norms))
            # Get the cell id:
            cellid = cell_candidates[i]
            # Set label to give out the location of the cell:
            self.__add_label(cellid)
            # Generate velocity grid
            self.__generate_velocity_grid(cellid)
        elif (self.picker == "Velocity_space_iso_surface"):
            # Set label to give out the location of the cell:
            self.__add_label(cellid)
            self.__generate_velocity_grid(cellid, True)
        elif (self.picker == "Velocity_space_nearest_cellid_iso_surface"):
            # Find the nearest cell id with distribution:
            # Read cell ids with velocity distribution in:
            cell_candidates = self.__vlsvReader.read("SpatialGrid",
                                                     "CELLSWITHBLOCKS")
            # Read in the coordinates of the cells:
            cell_candidate_coordinates = [
                self.__vlsvReader.get_cell_coordinates(cell_candidate)
                for cell_candidate in cell_candidates
            ]
            # Read in the cell's coordinates:
            pick_cell_coordinates = self.__vlsvReader.get_cell_coordinates(
                cellid)
            # Find the nearest:
            from operator import itemgetter
            norms = np.sum(
                (cell_candidate_coordinates - pick_cell_coordinates)**2,
                axis=-1)**(1. / 2)
            norm, i = min((norm, idx) for (idx, norm) in enumerate(norms))
            # Get the cell id:
            cellid = cell_candidates[i]
            # Set label to give out the location of the cell:
            self.__add_label(cellid)
            # Generate velocity grid
            self.__generate_velocity_grid(cellid, True)
        elif (self.picker == "Pitch_angle"):
            # Set label to give out the location of the cell:
            self.__add_label(cellid)
            # Plot pitch angle distribution:
            from pitchangle import pitch_angles
            result = pitch_angles(vlsvReader=self.__vlsvReader,
                                  cellid=cellid,
                                  cosine=True,
                                  plasmaframe=True)
            # plot:
            pl.hist(result[0].data, weights=result[1].data, bins=50, log=False)
            pl.show()
        elif (self.picker == "Gyrophase_angle"):
            # Plot gyrophase angle distribution:
            from gyrophaseangle import gyrophase_angles_from_file
            result = gyrophase_angles_from_file(vlsvReader=self.__vlsvReader,
                                                cellid=cellid)
            # plot:
            pl.hist(result[0].data,
                    weights=result[1].data,
                    bins=36,
                    range=[-180.0, 180.0],
                    log=True,
                    normed=1)
            pl.show()
        elif (self.picker == "Cut_through"):
            if len(self.__last_pick) == 3:
                from cutthrough import cut_through
                # Get a cut-through
                self.cut_through = cut_through(self.__vlsvReader,
                                               point1=self.__last_pick,
                                               point2=coordinates)
                # Get cell ids and distances separately
                cellids = self.cut_through[0].data
                distances = self.cut_through[1]
                # Get any arguments from the user:
                args = self.args.split()
                if len(args) == 0:
                    #Do nothing
                    print "Bad args"
                    self.__last_pick = []
                    return
                plotCut = False
                plotRankine = False
                # Optimize file read:
                self.__vlsvReader.optimize_open_file()
                variables = []
                # Save variables
                for i in xrange(len(args)):
                    # Check if the user has given the plot argument
                    if args[i] == "plot":
                        plotCut = True
                    elif args[i] == "rankine":
                        # set labels:
                        self.__add_normal_labels(point1=self.__last_pick,
                                                 point2=coordinates)
                        fig = plot_rankine(self.__vlsvReader,
                                           point1=self.__last_pick,
                                           point2=coordinates)
                        #pl.show()
                        self.__last_pick = []
                        self.plot = fig
                        return
                    else:
                        if args[i].find(",") != -1:
                            _variable = args[i].split(',')[0]
                            _operator = args[i].split(',')[1]
                            variable_info = self.__vlsvReader.read_variable_info(
                                name=_variable,
                                cellids=cellids,
                                operator=_operator)
                            variables.append(variable_info)
                            self.cut_through.append(variable_info)
                        else:
                            variable_info = self.__vlsvReader.read_variable_info(
                                name=args[i], cellids=cellids)
                            variables.append(variable_info)
                            self.cut_through.append(variable_info)
                if plotCut == True:
                    # Set label to give out the location of the cell:
                    self.__add_label(cellids[0])
                    self.__add_label(cellids[len(cellids) - 1])
                    if plotRankine == True:
                        # Plot Rankine-Hugoniot jump conditions:
                        normal_vector = (coordinates - self.__last_pick
                                         ) / np.linalg.norm(coordinates -
                                                            self.__last_pick)
                        # Read V, B, T and rho
                        V = self.__vlsvReader.read_variable("v",
                                                            cellids=cellids[0])
                        B = self.__vlsvReader.read_variable("B",
                                                            cellids=cellids[0])
                        T = self.__vlsvReader.read_variable("Temperature",
                                                            cellids=cellids[0])
                        rho = self.__vlsvReader.read_variable(
                            "rho", cellids=cellids[0])
                        # Get parallel and perpendicular components:
                        Vx = np.dot(V, normal_vector)
                        Vy = np.linalg.norm(V - Vx * normal_vector)
                        Bx = np.dot(B, normal_vector)
                        By = np.linalg.norm(B - Bx * normal_vector)
                        # Calculate jump conditions
                        conditions = oblique_shock(Vx, Vy, Bx, By, T, rho)
                        rankine_variables = []
                        for i in xrange(len(get_data(distances))):
                            if i < len(get_data(distances)) * 0.5:
                                rankine_variables.append(rho)
                            else:
                                rankine_variables.append(conditions[5])
                        variables.append(rankine_variables)
                    from plot import plot_multiple_variables
                    fig = plot_multiple_variables(
                        [distances for i in xrange(len(args) - 1)],
                        variables,
                        figure=[])
                    pl.show()
                # Close the optimized file read:
                self.__vlsvReader.optimize_close_file()
                # Read in the necessary variables:
                self.__last_pick = []
            else:
                self.__last_pick = coordinates

    def __generate_grid(self, mins, maxs, cells, datas, names):
        ''' Generates a grid from given data
          :param mins:           An array of minimum coordinates for the grid for ex. [-100, 0, 0]
          :param maxs:           An array of maximum coordinates for the grid for ex. [-100, 0, 0]
          :param cells:          An array of number of cells in x, y, z direction
          :param datas:          Scalar data for the grid e.g. array([ cell1Rho, cell2Rho, cell3Rho, cell4Rho, .., cellNRho ])
          :param names:          Name for the scalar data
      '''
        # Create nodes
        x, y, z = mgrid[mins[0]:maxs[0]:(cells[0] + 1) * complex(0, 1),
                        mins[1]:maxs[1]:(cells[1] + 1) * complex(0, 1),
                        mins[2]:maxs[2]:(cells[2] + 1) * complex(0, 1)]

        # Create points for the nodes:
        pts = empty(z.shape + (3, ), dtype=float)
        pts[..., 0] = x
        pts[..., 1] = y
        pts[..., 2] = z

        # Input scalars
        scalars = np.array(datas)

        # We reorder the points, scalars and vectors so this is as per VTK's
        # requirement of x first, y next and z last.
        pts = pts.transpose(2, 1, 0, 3).copy()
        pts.shape = pts.size / 3, 3
        scalars = scalars.T.copy()

        # Create the dataset.
        sg = tvtk.StructuredGrid(dimensions=x.shape, points=pts)
        sg.cell_data.scalars = ravel(scalars.copy())
        sg.cell_data.scalars.name = names

        # Visualize the data
        d = self.scene.mlab.pipeline.add_dataset(sg)
        iso = self.scene.mlab.pipeline.surface(d)

        # Add labels:
        #      from mayavi.modules.labels import Labels
        #      testlabels = self.scene.mlab.pipeline.labels(d)

        self.dataset = d

        # Configure traits
        self.configure_traits()

        # Note: This is not working properly -- it seemingly works out at first but it eventually causes segmentation faults in some places
        #self.__thread = threading.Thread(target=self.configure_traits, args=())
        #self.__thread.start()

    def __generate_velocity_grid(self, cellid, iso_surface=False):
        '''Generates a velocity grid from a given spatial cell id
         :param cellid:           The spatial cell's ID
         :param iso_surface:      If true, plots the iso surface
      '''
        # Create nodes
        # Get velocity blocks and avgs:
        blocksAndAvgs = self.__vlsvReader.read_blocks(cellid)
        if len(blocksAndAvgs) == 0:
            print "CELL " + str(cellid) + " HAS NO VELOCITY BLOCK"
            return False
        # Create a new scene
        self.__engine.new_scene()
        mayavi.mlab.set_engine(self.__engine)  #CONTINUE
        # Create a new figure
        figure = mayavi.mlab.gcf(engine=self.__engine)
        figure.scene.disable_render = True
        blocks = blocksAndAvgs[0]
        avgs = blocksAndAvgs[1]
        # Get nodes:
        nodesAndKeys = self.__vlsvReader.construct_velocity_cell_nodes(blocks)
        # Create an unstructured grid:
        points = nodesAndKeys[0]
        tets = nodesAndKeys[1]
        tet_type = tvtk.Voxel().cell_type  #VTK_VOXEL

        ug = tvtk.UnstructuredGrid(points=points)
        # Set up the cells
        ug.set_cells(tet_type, tets)
        # Input data
        values = np.ravel(avgs)
        ug.cell_data.scalars = values
        ug.cell_data.scalars.name = 'avgs'

        # Plot B if possible:
        # Read B vector and plot it:
        if self.__vlsvReader.check_variable("B") == True:
            B = self.__vlsvReader.read_variable(name="B", cellids=cellid)
        elif self.__vlsvReader.check_variable("B_vol") == True:
            B = self.__vlsvReader.read_variable(name="B_vol", cellids=cellid)
        else:
            B = self.__vlsvReader.read_variable(
                name="background_B",
                cellids=cellid) + self.__vlsvReader.read_variable(
                    name="perturbed_B", cellids=cellid)

        points2 = np.array([[0, 0, 0]])
        ug2 = tvtk.UnstructuredGrid(points=points2)
        ug2.point_data.vectors = [B / np.linalg.norm(B)]
        ug2.point_data.vectors.name = 'B_vector'
        #src2 = VTKDataSource(data = ug2)
        d2 = mayavi.mlab.pipeline.add_dataset(ug2)
        #mayavi.mlab.add_module(Vectors())
        vec = mayavi.mlab.pipeline.vectors(d2)
        vec.glyph.mask_input_points = True
        vec.glyph.glyph.scale_factor = 1e6
        vec.glyph.glyph_source.glyph_source.center = [0, 0, 0]

        # Visualize
        d = mayavi.mlab.pipeline.add_dataset(ug)
        if iso_surface == False:
            iso = mayavi.mlab.pipeline.surface(d)
        else:
            ptdata = mayavi.mlab.pipeline.cell_to_point_data(d)
            iso = mayavi.mlab.pipeline.iso_surface(
                ptdata, contours=[1e-15, 1e-14, 1e-12], opacity=0.3)
        figure.scene.disable_render = False
        self.__unstructured_figures.append(figure)
        # Name the figure
        figure.name = str(cellid) + ", " + self.variable_plotted + " = " + str(
            self.__vlsvReader.read_variable(self.variable_plotted,
                                            cellids=cellid))

        from mayavi.modules.axes import Axes
        axes = Axes()
        axes.name = 'Axes'
        axes.axes.fly_mode = 'none'
        axes.axes.number_of_labels = 8
        axes.axes.font_factor = 0.5
        #module_manager = self.__module_manager()
        # Add the label / marker:
        self.__engine.add_filter(axes)
        from mayavi.modules.outline import Outline
        outline = Outline()
        outline.name = 'Outline'
        self.__engine.add_filter(outline)
        return True

    def generate_diff_grid(self, cellid1, cellid2):
        ''' Generates a diff grid of given cell ids (shows avgs diff)

          :param cellid1:          The first cell id
          :param cellid2:          The second cell id

          .. code-block:: python

             # Example:
             grid.generate_diff_grid( 29219, 2910 )

          .. note:: If the cell id does not have a certain velocity cell, it is assumed that the avgs value of that cell is 0

      '''
        # Create nodes
        # Get velocity blocks and avgs (of cellid 1)
        blocksAndAvgs1 = self.__vlsvReader.read_blocks(cellid1)
        if len(blocksAndAvgs1) == 0:
            print "CELL " + str(cellid1) + " HAS NO VELOCITY BLOCK"
            return False
        blocks1 = blocksAndAvgs1[0]
        avgs1 = blocksAndAvgs1[1]

        # Get velocity blocks and avgs (of cellid 2)
        blocksAndAvgs2 = self.__vlsvReader.read_blocks(cellid2)
        if len(blocksAndAvgs2) == 0:
            print "CELL " + str(cellid2) + " HAS NO VELOCITY BLOCK"
            return False
        blocks2 = blocksAndAvgs2[0]
        avgs2 = blocksAndAvgs2[1]
        print len(avgs2)
        print len(blocks2)

        # Compare blocks and create a new avgs array values:
        avgs_same = []
        avgs_cellid1 = []
        avgs_cellid2 = []
        blocks_same = []
        blocks_cellid1 = []
        blocks_cellid2 = []
        print np.shape(avgs1[0])
        for i in xrange(len(blocks1)):
            b = blocks1[i]
            # Get index of block
            i2 = np.where(blocks2 == b)[0]
            if len(i2) != 0:
                # Fetch the block:
                #print avgs1[64*i:64*(i+1)]
                #print avgs2[64*i2[0]:64*(i2[0]+1)]
                avgs_same.append(avgs1[i:(i + 1)] - avgs2[i2[0]:(i2[0] + 1)])
                blocks_same.append(b)
            else:
                avgs_cellid1.append(avgs1[i:(i + 1)])
                blocks_cellid1.append(b)
        for i in xrange(len(blocks2)):
            b = blocks2[i]
            if (b in blocks1) == False:
                avgs_cellid2.append(avgs2[i:(i + 1)])
                blocks_cellid2.append(b)
        # Make a list for the avgs etc
        avgs = np.zeros(
            64 * (len(avgs_same) + len(avgs_cellid1) + len(avgs_cellid2)))
        #avgs = np.reshape(avgs, (len(avgs_same)+len(avgs_cellid1)+len(avgs_cellid2), 64))
        print np.shape(avgs_same)
        blocks = np.zeros(
            len(blocks_same) + len(blocks_cellid1) + len(blocks_cellid2))

        index = 0
        avgs[64 * index:64 * (index + len(blocks_same))] = np.ravel(
            np.array(avgs_same))
        blocks[index:index + len(blocks_same)] = np.array(blocks_same)

        index = index + len(blocks_same)
        avgs[64 * index:64 * (index + len(blocks_cellid1))] = np.ravel(
            np.array(avgs_cellid1))
        blocks[index:index + len(blocks_cellid1)] = np.array(blocks_cellid1)

        index = index + len(blocks_cellid1)
        avgs[64 * index:64 * (index + len(blocks_cellid2))] = np.ravel(
            np.array(avgs_cellid2))
        blocks[index:index + len(blocks_cellid2)] = np.array(blocks_cellid2)

        blocks = blocks.astype(int)

        # Get nodes:
        nodesAndKeys = self.__vlsvReader.construct_velocity_cell_nodes(blocks)

        # Create an unstructured grid:
        points = nodesAndKeys[0]
        tets = nodesAndKeys[1]

        # Create a new scene
        self.__engine.new_scene()
        mayavi.mlab.set_engine(self.__engine)  #CONTINUE
        # Create a new figure
        figure = mayavi.mlab.gcf(engine=self.__engine)
        figure.scene.disable_render = True
        tet_type = tvtk.Voxel().cell_type  #VTK_VOXEL

        ug = tvtk.UnstructuredGrid(points=points)
        #Thissetsupthecells.
        ug.set_cells(tet_type, tets)
        #Attributedata.
        values = np.ravel(avgs)
        ug.cell_data.scalars = values
        ug.cell_data.scalars.name = 'avgs'
        d = mayavi.mlab.pipeline.add_dataset(ug)
        iso = mayavi.mlab.pipeline.surface(d)
        figure.scene.disable_render = False
        self.__unstructured_figures.append(figure)
        # Name the figure
        figure.name = str(cellid1) + " " + str(cellid2)
        mayavi.mlab.show()
        return True

    def __do_nothing(self, picker):
        return

    # Trait events:
    @on_trait_change('scene.activated')
    def set_mouse_click(self):
        # Temporary bug fix (MayaVi needs a dummy pick to be able to remove cells callbacks from picker.. )
        #self.figure.on_mouse_pick( self.__do_nothing, type='world'
        self.figure = self.scene.mlab.gcf()
        # Cell picker
        func = self.__picker_callback
        typeid = 'world'
        click = 'Left'
        picker = self.figure.on_mouse_pick(func, type='world')
        self.__picker = [func, typeid, click]
        #picker.tolerance = 0
        # Show legend bar
        manager = self.figure.children[0].children[0]
        manager.scalar_lut_manager.show_scalar_bar = True
        manager.scalar_lut_manager.show_legend = True
Beispiel #28
0
    Menu(
        ActionGroup(new_item_action, name='list_group'),
        name=_('Edit'),
    ), )

# ----------------------------------------------------------------------------
# TraitsUI Views
# ----------------------------------------------------------------------------

#: Stripped down view for use in list editor
to_do_item_view = View(
    HGroup(
        Item('completed', show_label=False),
        Item('creation_time',
             show_label=False,
             style='readonly',
             editor=TextEditor(format_func=format_date, )),
        Item('description', show_label=False, springy=True),
        Item('controller.delete',
             show_label=False,
             editor=ButtonEditor(label=_('Delete')))), )

#: View for main model view
todo_list_view = View(
    VGroup(
        HGroup(
            Item('remaining', style='readonly', show_label=False),
            Spring(),
            Item('display_selection',
                 label=_('Show'),
                 editor=EnumEditor(values={
                     'all': _('All'),
Beispiel #29
0
class MayaviViewer(HasTraits):
    """
    This class represents a Mayavi based viewer for the particles.  They
    are queried from a running solver.
    """

    particle_arrays = List(Instance(ParticleArrayHelper), [])
    pa_names = List(Str, [])

    interpolator = Instance(InterpolatorView)

    # The default scalar to load up when running the viewer.
    scalar = Str("rho")

    scene = Instance(MlabSceneModel, ())

    ########################################
    # Traits to pull data from a live solver.
    live_mode = Bool(False, desc='if data is obtained from a running solver '
                                 'or from saved files')

    shell = Button('Launch Python Shell')
    host = Str('localhost', desc='machine to connect to')
    port = Int(8800, desc='port to use to connect to solver')
    authkey = Password('pysph', desc='authorization key')
    host_changed = Bool(True)
    client = Instance(MultiprocessingClient)
    controller = Property(depends_on='live_mode, host_changed')

    ########################################
    # Traits to view saved solver output.
    files = List(Str, [])
    directory = Directory()
    current_file = Str('', desc='the file being viewed currently')
    update_files = Button('Refresh')
    file_count = Range(low='_low', high='_n_files', value=0,
                       desc='the file counter')
    play = Bool(False, desc='if all files are played automatically')
    play_delay = Float(0.2, desc='the delay between loading files')
    loop = Bool(False, desc='if the animation is looped')
    # This is len(files) - 1.
    _n_files = Int(0)
    _low = Int(0)

    ########################################
    # Timer traits.
    timer = Instance(Timer)
    interval = Range(0.5, 20.0, 2.0,
                     desc='frequency in seconds with which plot is updated')

    ########################################
    # Solver info/control.
    current_time = Float(0.0, desc='the current time in the simulation')
    time_step = Float(0.0, desc='the time-step of the solver')
    iteration = Int(0, desc='the current iteration number')
    pause_solver = Bool(False, desc='if the solver should be paused')

    ########################################
    # Movie.
    record = Bool(False, desc='if PNG files are to be saved for animation')
    frame_interval = Range(1, 100, 5, desc='the interval between screenshots')
    movie_directory = Str
    # internal counters.
    _count = Int(0)
    _frame_count = Int(0)
    _last_time = Float
    _solver_data = Any
    _file_name = Str
    _particle_array_updated = Bool

    ########################################
    # The layout of the dialog created
    view = View(HSplit(
                  Group(
                    Group(
                        Group(
                            Item(name='directory'),
                            Item(name='current_file'),
                            Item(name='file_count'),
                            HGroup(Item(name='play'),
                                   Item(name='play_delay',
                                        label='Delay',
                                        resizable=True),
                                   Item(name='loop'),
                                   Item(name='update_files',
                                        show_label=False),
                                   padding=0),
                            padding=0,
                            label='Saved Data',
                            selected=True,
                            enabled_when='not live_mode',
                            ),
                        Group(
                            Item(name='live_mode'),
                            Group(
                                Item(name='host'),
                                Item(name='port'),
                                Item(name='authkey'),
                                enabled_when='live_mode',
                            ),
                            label='Connection',
                        ),
                        layout='tabbed'
                    ),
                    Group(
                        Group(
                              Item(name='current_time'),
                              Item(name='time_step'),
                              Item(name='iteration'),
                              Item(name='pause_solver',
                                   enabled_when='live_mode'
                                   ),
                              Item(name='interval',
                                   enabled_when='not live_mode'
                                   ),
                              label='Solver',
                             ),
                        Group(
                              Item(name='record'),
                              Item(name='frame_interval'),
                              Item(name='movie_directory'),
                              label='Movie',
                            ),
                        layout='tabbed',

                        ),
                    Group(
                          Item(name='particle_arrays',
                               style='custom',
                               show_label=False,
                               editor=ListEditor(use_notebook=True,
                                                 deletable=False,
                                                 page_name='.name'
                                                 )
                               ),
                          Item(name='interpolator',
                               style='custom',
                               show_label=False),
                          layout='tabbed'
                         ),
                    Item(name='shell', show_label=False),
                  ),
                  Group(
                    Item('scene', editor=SceneEditor(scene_class=MayaviScene),
                         height=400, width=600, show_label=False),
                  )
                ),
                resizable=True,
                title='PySPH Particle Viewer',
                height=640,
                width=1024,
                handler=ViewerHandler
                )

    ######################################################################
    # `MayaviViewer` interface.
    ######################################################################
    def on_close(self):
        self._handle_particle_array_updates()

    @on_trait_change('scene:activated')
    def start_timer(self):
        if not self.live_mode:
            # No need for the timer if we are rendering files.
            return

        # Just accessing the timer will start it.
        t = self.timer
        if not t.IsRunning():
            t.Start(int(self.interval*1000))

    @on_trait_change('scene:activated')
    def update_plot(self):

        # No need to do this if files are being used.
        if not self.live_mode:
            return

        # do not update if solver is paused
        if self.pause_solver:
            return

        if self.client is None:
            self.host_changed = True

        controller = self.controller
        if controller is None:
            return

        self.current_time = t = controller.get_t()
        self.time_step = controller.get_dt()
        self.iteration = controller.get_count()

        arrays = []
        for idx, name in enumerate(self.pa_names):
            pa = controller.get_named_particle_array(name)
            arrays.append(pa)
            pah = self.particle_arrays[idx]
            pah.set(particle_array=pa, time=t)

        self.interpolator.particle_arrays = arrays

        if self.record:
            self._do_snap()

    def run_script(self, path):
        """Execute a script in the namespace of the viewer.
        """
        with open(path) as fp:
            data = fp.read()
            ns = self._get_shell_namespace()
            exec(compile(data, path, 'exec'), ns)

    ######################################################################
    # Private interface.
    ######################################################################
    def _do_snap(self):
        """Generate the animation."""
        p_arrays = self.particle_arrays
        if len(p_arrays) == 0:
            return
        if self.current_time == self._last_time:
            return

        if len(self.movie_directory) == 0:
            controller = self.controller
            output_dir = controller.get_output_directory()
            movie_dir = os.path.join(output_dir, 'movie')
            self.movie_directory = movie_dir
        else:
            movie_dir = self.movie_directory
        if not os.path.exists(movie_dir):
            os.mkdir(movie_dir)

        interval = self.frame_interval
        count = self._count
        if count % interval == 0:
            fname = 'frame%06d.png' % (self._frame_count)
            p_arrays[0].scene.save_png(os.path.join(movie_dir, fname))
            self._frame_count += 1
            self._last_time = self.current_time
        self._count += 1

    @on_trait_change('host,port,authkey')
    def _mark_reconnect(self):
        if self.live_mode:
            self.host_changed = True

    @cached_property
    def _get_controller(self):
        ''' get the controller, also sets the iteration count '''
        if not self.live_mode:
            return None

        reconnect = self.host_changed
        if not reconnect:
            try:
                c = self.client.controller
            except Exception as e:
                logger.info('Error: no connection or connection closed: '
                            'reconnecting: %s' % e)
                reconnect = True
                self.client = None
            else:
                try:
                    self.client.controller.get_count()
                except IOError:
                    self.client = None
                    reconnect = True

        if reconnect:
            self.host_changed = False
            try:
                if MultiprocessingClient.is_available((self.host, self.port)):
                    self.client = MultiprocessingClient(
                        address=(self.host, self.port),
                        authkey=self.authkey
                    )
                else:
                    logger.info(
                        'Could not connect: Multiprocessing Interface'
                        ' not available on %s:%s' % (self.host, self.port)
                    )
                    return None
            except Exception as e:
                logger.info('Could not connect: check if solver is '
                            'running:%s' % e)
                return None
            c = self.client.controller
            self.iteration = c.get_count()

        if self.client is None:
            return None
        else:
            return self.client.controller

    def _client_changed(self, old, new):
        if not self.live_mode:
            return

        self._clear()
        if new is None:
            return
        else:
            self.pa_names = self.client.controller.get_particle_array_names()

        self.particle_arrays = [
            self._make_particle_array_helper(self.scene, x)
            for x in self.pa_names
        ]
        self.interpolator = InterpolatorView(scene=self.scene)
        # Turn on the legend for the first particle array.
        if len(self.particle_arrays) > 0:
            self.particle_arrays[0].set(show_legend=True, show_time=True)

    def _timer_event(self):
        # catch all Exceptions else timer will stop
        try:
            self.update_plot()
        except Exception as e:
            logger.info('Exception: %s caught in timer_event' % e)

    def _interval_changed(self, value):
        t = self.timer
        if t is None:
            return
        if t.IsRunning():
            t.Stop()
            t.Start(int(value*1000))

    def _timer_default(self):
        return Timer(int(self.interval*1000), self._timer_event)

    def _pause_solver_changed(self, value):
        if self.live_mode:
            c = self.controller
            if c is None:
                return
            if value:
                c.pause_on_next()
            else:
                c.cont()

    def _record_changed(self, value):
        if value:
            self._do_snap()

    def _files_changed(self, value):
        if len(value) == 0:
            return
        else:
            d = os.path.dirname(os.path.abspath(value[0]))
            self.movie_directory = os.path.join(d, 'movie')
            self.set(directory=d, trait_change_notify=False)
        self._n_files = len(value) - 1
        self._frame_count = 0
        self._count = 0
        self.frame_interval = 1
        fc = self.file_count
        self.file_count = 0
        if fc == 0:
            # Force an update when our original file count is 0.
            self._file_count_changed(fc)
        t = self.timer
        if not self.live_mode:
            if t.IsRunning():
                t.Stop()
        else:
            if not t.IsRunning():
                t.Stop()
                t.Start(self.interval*1000)

    def _file_count_changed(self, value):
        # Save out any updates for the previous file if needed.
        self._handle_particle_array_updates()
        # Load the new file.
        fname = self.files[value]
        self._file_name = fname
        self.current_file = os.path.basename(fname)
        # Code to read the file, create particle array and setup the helper.
        data = load(fname)
        solver_data = data["solver_data"]
        arrays = data["arrays"]
        self._solver_data = solver_data
        self.current_time = t = float(solver_data['t'])
        self.time_step = float(solver_data['dt'])
        self.iteration = int(solver_data['count'])
        names = list(arrays.keys())
        pa_names = self.pa_names

        if len(pa_names) == 0:
            self.interpolator = InterpolatorView(scene=self.scene)
            self.pa_names = names
            pas = []
            for name in names:
                pa = arrays[name]
                pah = self._make_particle_array_helper(self.scene, name)
                # Must set this after setting the scene.
                pah.set(particle_array=pa, time=t)
                pas.append(pah)
            self.particle_arrays = pas
        else:
            for idx, name in enumerate(pa_names):
                pa = arrays[name]
                pah = self.particle_arrays[idx]
                pah.set(particle_array=pa, time=t)

        self.interpolator.particle_arrays = list(arrays.values())

        if self.record:
            self._do_snap()

    def _loop_changed(self, value):
        if value and self.play:
            self._play_changed(self.play)

    def _play_changed(self, value):
        t = self.timer
        if value:
            t.Stop()
            t.callable = self._play_event
            t.Start(1000*self.play_delay)
        else:
            t.Stop()
            t.callable = self._timer_event

    def _clear(self):
        self.pa_names = []
        self.scene.mayavi_scene.children[:] = []

    def _play_event(self):
        nf = self._n_files
        pc = self.file_count
        pc += 1
        if pc > nf:
            if self.loop:
                pc = 0
            else:
                self.timer.Stop()
                pc = nf
        self.file_count = pc
        self._handle_particle_array_updates()

    def _play_delay_changed(self):
        if self.play:
            self._play_changed(self.play)

    def _scalar_changed(self, value):
        for pa in self.particle_arrays:
            pa.scalar = value

    def _update_files_fired(self):
        fc = self.file_count
        files = glob_files(self.files[fc])
        sort_file_list(files)
        self.files = files
        self.file_count = fc
        if self.play:
            self._play_changed(self.play)

    def _shell_fired(self):
        ns = self._get_shell_namespace()
        obj = PythonShellView(ns=ns)
        obj.edit_traits()

    def _get_shell_namespace(self):
        pas = {}
        for i, x in enumerate(self.particle_arrays):
            pas[i] = x
            pas[x.name] = x
        return dict(viewer=self, particle_arrays=pas,
                    interpolator=self.interpolator, scene=self.scene,
                    mlab=self.scene.mlab)

    def _directory_changed(self, d):
        ext = os.path.splitext(self.files[-1])[1]
        files = glob.glob(os.path.join(d, '*' + ext))
        if len(files) > 0:
            self._clear()
            sort_file_list(files)
            self.files = files
            self.file_count = min(self.file_count, len(files))
        else:
            pass
        config_file = os.path.join(d, 'mayavi_config.py')
        if os.path.exists(config_file):
            self.run_script(config_file)

    def _live_mode_changed(self, value):
        if value:
            self._file_name = ''
            self.client = None
            self._clear()
            self._mark_reconnect()
            self.start_timer()
        else:
            self.client = None
            self._clear()
            self.timer.Stop()

    def _particle_array_helper_updated(self, value):
        self._particle_array_updated = True

    def _handle_particle_array_updates(self):
        # Called when the particle array helper fires an updated event.
        if self._particle_array_updated and self._file_name:
            sd = self._solver_data
            arrays = [x.particle_array for x in self.particle_arrays]
            detailed = self._requires_detailed_output(arrays)
            dump(self._file_name, arrays, sd, detailed_output=detailed,
                 only_real=False)
            self._particle_array_updated = False

    def _requires_detailed_output(self, arrays):
        detailed = False
        for pa in arrays:
            props = set(pa.properties.keys())
            output = set(pa.output_property_arrays)
            diff = props - output
            for prop in diff:
                array = pa.get(prop)
                if (array.max() - array.min()) > 0:
                    detailed = True
                    break
            if detailed:
                break
        return detailed

    def _make_particle_array_helper(self, scene, name):
        pah = ParticleArrayHelper(scene=scene, name=name, scalar=self.scalar)
        pah.on_trait_change(self._particle_array_helper_updated, 'updated')
        return pah
class Hotel(HasPrivateTraits):

    # The season of the year:
    season = Enum('Winter', 'Spring', 'Summer', 'Fall')

    # The current cost of heating fuel (in dollars/gallon):
    fuel_cost = Range(2.00, 10.00, 4.00)

    # The current minimum temparature allowed by the hotel:
    min_temperature = Property(observe='season, fuel_cost')

    # The guests currently staying at the hotel:
    guests = List  # ( Instance( 'Guest' ) )

    # Add a new guest to the hotel:
    add_guest = Button('Add Guest')

    # The view of the hotel:
    view = View(
        VGroup(
            HGroup(
                Item('season'),
                '20',
                Item('fuel_cost', width=300),
                spring,
                Item('add_guest', show_label=False),
                show_border=True,
                label='Hotel Information',
            ),
            VGroup(
                Item(
                    'guests',
                    style='custom',
                    editor=ListEditor(
                        use_notebook=True,
                        deletable=True,
                        dock_style='tab',
                        page_name='.name',
                    ),
                ),
                show_labels=False,
                show_border=True,
                label='Guests',
            ),
        ),
        title='The Belmont Hotel Dashboard',
        width=0.6,
        height=0.2,
        resizable=True,
    )

    # Property implementations:
    @cached_property
    def _get_min_temperature(self):
        return {
            'Winter': 32,
            'Spring': 40,
            'Summer': 45,
            'Fall': 40
        }[self.season] + min(int(60.00 / self.fuel_cost), 15)

    # Event handlers:
    @observe('guests.items')
    def _guests_modified(self, event):
        # The entire guests list changed
        if isinstance(event.object, Hotel):
            for guest in event.new:
                guest.hotel = self
        # the contents of the guests list changed
        else:
            for guest in event.added:
                guest.hotel = self

    def _add_guest_changed(self):
        self.guests.append(Guest(hotel=self))