Esempio n. 1
0
 def _field_folder(self, fields, **kwargs):
     folder = super(UniverseWidget, self)._field_folder(**kwargs)
     folder.deactivate('nx', 'ny', 'nz')
     fopts = Dropdown(options=fields)
     def _fopts(c):
         for scn in self.active(): scn.field_idx = c.new
     fopts.observe(_fopts, names='value')
     folder['fopts'] = fopts
     return folder
Esempio n. 2
0
 def _field_folder(self, **kwargs):
     """Folder that houses field GUI controls."""
     folder = super(DemoContainer, self)._field_folder(**kwargs)
     fopts = Dropdown(options=['null', 'Sphere', 'Torus', 'Ellipsoid'])
     fopts.active = True
     fopts.disabled = False
     def _field(c):
         for scn in self.active():
             scn.field = c.new
     fopts.observe(_field, names='value')
     folder.insert(1, 'options', fopts)
     return folder
Esempio n. 3
0
    def _make_repr_name_choices(self, component_slider, repr_slider):
        repr_choices = Dropdown(options=[" ",])

        def on_chose(change):
            repr_name = change['new']
            repr_index = repr_choices.options.index(repr_name)
            repr_slider.value = repr_index

        repr_choices.observe(on_chose, names='value')
        repr_choices.layout.width = default.DEFAULT_TEXT_WIDTH

        self.widget_repr_choices = repr_choices
        return self.widget_repr_choices
Esempio n. 4
0
class NGLDisplay:
    """Structure display class

    Provides basic structure/trajectory display
    in the notebook and optional gui which can be used to enhance its
    usability.  It is also possible to extend the functionality of the
    particular instance of the viewer by adding further widgets
    manipulating the structure.
    """
    def __init__(self, atoms, xsize=500, ysize=500):
        import nglview
        from ipywidgets import Dropdown, FloatSlider, IntSlider, HBox, VBox
        self.atoms = atoms
        if isinstance(atoms[0], Atoms):
            # Assume this is a trajectory or struct list
            self.view = nglview.show_asetraj(atoms)
            self.frm = IntSlider(value=0, min=0, max=len(atoms) - 1)
            self.frm.observe(self._update_frame)
            self.struct = atoms[0]
        else:
            # Assume this is just a single structure
            self.view = nglview.show_ase(atoms)
            self.struct = atoms
            self.frm = None

        self.colors = {}
        self.view._remote_call('setSize', target='Widget',
                               args=['%dpx' % (xsize,), '%dpx' % (ysize,)])
        self.view.add_unitcell()
        self.view.add_spacefill()
        self.view.camera = 'orthographic'
        self.view.update_spacefill(radiusType='covalent', scale=0.7)
        self.view.center()

        self.asel = Dropdown(options=['All'] +
                             list(set(self.struct.get_chemical_symbols())),
                             value='All', description='Show')

        self.rad = FloatSlider(value=0.8, min=0.0, max=1.5, step=0.01,
                               description='Ball size')

        self.asel.observe(self._select_atom)
        self.rad.observe(self._update_repr)

        wdg = [self.asel, self.rad]
        if self.frm:
            wdg.append(self.frm)

        self.gui = HBox([self.view, VBox(wdg)])
        # Make useful shortcuts for the user of the class
        self.gui.view = self.view
        self.gui.control_box = self.gui.children[1]
        self.gui.custom_colors = self.custom_colors

    def _update_repr(self, chg=None):
        self.view.update_spacefill(radiusType='covalent', scale=self.rad.value)

    def _update_frame(self, chg=None):
        self.view.frame = self.frm.value
        return

    def _select_atom(self, chg=None):
        sel = self.asel.value
        self.view.remove_spacefill()
        for e in set(self.struct.get_chemical_symbols()):
            if (sel == 'All' or e == sel):
                if e in self.colors:
                    self.view.add_spacefill(selection='#' + e,
                                            color=self.colors[e])
                else:
                    self.view.add_spacefill(selection='#' + e)
        self._update_repr()

    def custom_colors(self, clr=None):
        """
        Define custom colors for some atoms. Pass a dictionary of the form
        {'Fe':'red', 'Au':'yellow'} to the function.
        To reset the map to default call the method without parameters.
        """
        if clr:
            self.colors = clr
        else:
            self.colors = {}
        self._select_atom()
Esempio n. 5
0
    def build_options(self):
        grid = GridspecLayout(4, 2)
        options_map = {}
        style = {'description_width': '60%'}

        # plot_type
        plot_type = Dropdown(
            description='Plot:',
            options=['force', 'decision', 'both'],
            description_tooltip='Which plot to draw decision, force or both',
            style=style)
        options_map['plot_type'] = plot_type

        # background_data
        background_data = Dropdown(
            description='Background data:',
            options={
                'KMeans': 'kmeans',
                'Custom variable': 'custom'
            },
            value='kmeans',
            description_tooltip=
            'What background data will be used to sample from, when simulating "missing" feature\n'
            ' - KMeans: use KMeans to sample from provided dataset\n'
            ' - Custom variable: provide variable with instances to use',
            style=style)
        options_map['background_data'] = background_data

        # kmeans_count (only show when KMeans is chosen)
        kmeans_count = BoundedIntText(
            value=100,
            min=1,
            max=len(self.X_train),
            description='Count of KMeans centers:',
            description_tooltip=
            'Number of means to use when creating background data',
            style=style)
        options_map['kmeans_count'] = kmeans_count

        # data (only show when Custom variable is chosen)
        data = UpdatingCombobox(
            options_keys=self.globals_options,
            description='Background data variable:',
            options=list(self.globals_options),
            description_tooltip=
            'Variable with background data from which the "missing" features will be sampled',
            style=style)
        options_map['data'] = data

        # set up swap of options
        def swap_kmeans(change):
            if change['new'] == 'kmeans':
                data.lookup_in_kernel = False
                grid[1, 1] = kmeans_count
            else:
                data.lookup_in_kernel = True
                grid[1, 1] = data

        background_data.observe(swap_kmeans, names=['value'])

        # link
        link = Dropdown(
            description='Link:',
            options=['identity', 'logit'],
            value='identity',
            description_tooltip=
            'A generalized linear model link to connect the feature importance values '
            'to the model output.\n'
            'Since the feature importance values, phi, sum up to the model output, '
            'it often makes sense to connect them to the ouput with a link function '
            'where link(outout) = sum(phi).\n '
            'If the model output is a probability then the LogitLink link function makes '
            'the feature importance values have log-odds units.',
            style=style)
        options_map['link'] = link

        # nsamples
        nsamples = BoundedIntText(
            min=1,
            max=999999,
            value=2048,
            disabled=True,
            description='Model sample size:',
            description_tooltip=
            'Number of times to re-evaluate the model when explaining each prediction.\n'
            'More samples lead to lower variance estimates of the SHAP values.\n'
            'The "auto" setting uses nsamples = 2 * X.shape[1] + 2048.',
            style=style)
        options_map['nsamples'] = nsamples

        # auto_nsamples
        auto_nsamples = Checkbox(description='Auto choose model sample size',
                                 value=True,
                                 style={'description_width': 'auto'})
        options_map['auto_nsamples'] = auto_nsamples

        def disable_nsamples(change):
            nsamples.disabled = change['new']

        auto_nsamples.observe(disable_nsamples, names=['value'])

        # l1_reg
        l1_reg = Combobox(
            description='L1 regularization:',
            options=['auto', 'aic', 'bic'],
            value='auto',
            description_tooltip=
            'The l1 regularization to use for feature selection '
            '(the estimation procedure is based on a debiased lasso).\n'
            ' - The auto option currently uses "aic" when less that 20% '
            'of the possible sample space is enumerated, otherwise it uses no regularization.\n'
            ' - The "aic" and "bic" options use the AIC and BIC rules for regularization.\n'
            ' - Integer selects a fix number of top features.\n'
            ' - float directly sets the "alpha" parameter of the sklearn.linear_model.Lasso model '
            'used for feature selection',
            style=style)
        options_map['l1_reg'] = l1_reg

        # class_to_explain (only if classification)
        if self.is_classification:
            class_to_explain = Dropdown(
                description='Class to plot:',
                options={val: e
                         for e, val in enumerate(self.class_names)},
                description_tooltip=
                'For classification select a class for which the prediction will be explained',
                style=style)
            options_map['class_to_explain'] = class_to_explain
            grid[3, 1] = class_to_explain

        grid[0, 0] = plot_type
        grid[1, 0] = background_data
        grid[1, 1] = kmeans_count
        grid[0, 1] = link
        grid[2, 0] = nsamples
        grid[2, 1] = auto_nsamples
        grid[3, 0] = l1_reg

        return options_map, grid
Esempio n. 6
0
class SubstrateTab(object):

    def __init__(self):
        
        self.output_dir = '.'
#        self.output_dir = 'tmpdir'

        # self.fig = plt.figure(figsize=(7.2,6))  # this strange figsize results in a ~square contour plot

        # initial value
        self.field_index = 4
        # self.field_index = self.mcds_field.value + 4

        # define dummy size of mesh (set in the tool's primary module)
        self.numx = 0
        self.numy = 0

        tab_height = '500px'
        tab_height = '700px'
        constWidth = '180px'
        constWidth2 = '150px'
        tab_layout = Layout(width='900px',   # border='2px solid black',
                            height=tab_height, ) #overflow_y='scroll')

        max_frames = 1   
        self.mcds_plot = interactive(self.plot_substrate, frame=(0, max_frames), continuous_update=False)  
        svg_plot_size = '900px'
        svg_plot_size = '600px'
        svg_plot_size = '500px'
        self.mcds_plot.layout.width = svg_plot_size
        self.mcds_plot.layout.height = svg_plot_size

        self.max_frames = BoundedIntText(
            min=0, max=99999, value=max_frames,
            description='Max',
           layout=Layout(width='160px'),
        )
        self.max_frames.observe(self.update_max_frames)

        self.field_min_max = {'dummy': [0., 1.]}
        # hacky I know, but make a dict that's got (key,value) reversed from the dict in the Dropdown below
        self.field_dict = {0:'dummy'}

        self.mcds_field = Dropdown(
            options={'dummy': 0},
            value=0,
            #     description='Field',
           layout=Layout(width=constWidth)
        )
        # print("substrate __init__: self.mcds_field.value=",self.mcds_field.value)
#        self.mcds_field.observe(self.mcds_field_cb)
        self.mcds_field.observe(self.mcds_field_changed_cb)

        # self.field_cmap = Text(
        #     value='viridis',
        #     description='Colormap',
        #     disabled=True,
        #     layout=Layout(width=constWidth),
        # )
        self.field_cmap = Dropdown(
            options=['viridis', 'jet', 'YlOrRd'],
            value='viridis',
            #     description='Field',
           layout=Layout(width=constWidth)
        )
        #self.field_cmap.observe(self.plot_substrate)
#        self.field_cmap.observe(self.plot_substrate)
        self.field_cmap.observe(self.mcds_field_cb)

        self.cmap_fixed = Checkbox(
            description='Fix',
            disabled=False,
#           layout=Layout(width=constWidth2),
        )

        self.save_min_max= Button(
            description='Save', #style={'description_width': 'initial'},
            button_style='success',  # 'success', 'info', 'warning', 'danger' or ''
            tooltip='Save min/max for this substrate',
            disabled=True,
           layout=Layout(width='90px')
        )

        def save_min_max_cb(b):
#            field_name = self.mcds_field.options[]
#            field_name = next(key for key, value in self.mcds_field.options.items() if value == self.mcds_field.value)
            field_name = self.field_dict[self.mcds_field.value]
#            print(field_name)
#            self.field_min_max = {'oxygen': [0., 30.], 'glucose': [0., 1.], 'H+ ions': [0., 1.], 'ECM': [0., 1.], 'NP1': [0., 1.], 'NP2': [0., 1.]}
            self.field_min_max[field_name][0] = self.cmap_min.value
            self.field_min_max[field_name][1] = self.cmap_max.value
#            print(self.field_min_max)

        self.save_min_max.on_click(save_min_max_cb)

        self.cmap_min = FloatText(
            description='Min',
            value=0,
            step = 0.1,
            disabled=True,
            layout=Layout(width=constWidth2),
        )
        self.cmap_min.observe(self.mcds_field_cb)

        self.cmap_max = FloatText(
            description='Max',
            value=38,
            step = 0.1,
            disabled=True,
            layout=Layout(width=constWidth2),
        )
        self.cmap_max.observe(self.mcds_field_cb)

        def cmap_fixed_cb(b):
            if (self.cmap_fixed.value):
                self.cmap_min.disabled = False
                self.cmap_max.disabled = False
                self.save_min_max.disabled = False
            else:
                self.cmap_min.disabled = True
                self.cmap_max.disabled = True
                self.save_min_max.disabled = True
#            self.mcds_field_cb()

        self.cmap_fixed.observe(cmap_fixed_cb)

        field_cmap_row2 = HBox([self.field_cmap, self.cmap_fixed])

#        field_cmap_row3 = HBox([self.save_min_max, self.cmap_min, self.cmap_max])
        items_auto = [
            self.save_min_max, #layout=Layout(flex='3 1 auto', width='auto'),
            self.cmap_min, 
            self.cmap_max,  
         ]
        box_layout = Layout(display='flex',
                    flex_flow='row',
                    align_items='stretch',
                    width='90%')
        field_cmap_row3 = Box(children=items_auto, layout=box_layout)

#        field_cmap_row3 = Box([self.save_min_max, self.cmap_min, self.cmap_max])

        # mcds_tab = widgets.VBox([mcds_dir, mcds_plot, mcds_play], layout=tab_layout)
        mcds_params = VBox([self.mcds_field, field_cmap_row2, field_cmap_row3, self.max_frames])  # mcds_dir
#        mcds_params = VBox([self.mcds_field, field_cmap_row2, field_cmap_row3, self.max_frames], layout=tab_layout)  # mcds_dir

#        mcds_params = VBox([self.mcds_field, field_cmap_row2, field_cmap_row3,])  # mcds_dir

#        self.tab = HBox([mcds_params, self.mcds_plot], layout=tab_layout)
#        self.tab = HBox([mcds_params, self.mcds_plot])

        help_label = Label('select slider: drag or left/right arrows')
        row1 = Box([help_label, Box( [self.max_frames, self.mcds_field, self.field_cmap], layout=Layout(border='0px solid black',
                            width='50%',
                            height='',
                            align_items='stretch',
                            flex_direction='row',
                            display='flex'))] )
        row2 = Box([self.cmap_fixed, self.cmap_min, self.cmap_max], layout=Layout(border='0px solid black',
                            width='50%',
                            height='',
                            align_items='stretch',
                            flex_direction='row',
                            display='flex'))
        if (hublib_flag):
            self.download_button = Download('mcds.zip', style='warning', icon='cloud-download', 
                                                tooltip='Download data', cb=self.download_cb)
            download_row = HBox([self.download_button.w, Label("Download all substrate data (browser must allow pop-ups).")])

    #        self.tab = VBox([row1, row2, self.mcds_plot])
            self.tab = VBox([row1, row2, self.mcds_plot, download_row])
        else:
            # self.tab = VBox([row1, row2])
            self.tab = VBox([row1, row2, self.mcds_plot])

    #---------------------------------------------------
    def update_dropdown_fields(self, data_dir):
        # print('update_dropdown_fields called --------')
        self.output_dir = data_dir
        tree = None
        try:
            fname = os.path.join(self.output_dir, "initial.xml")
            tree = ET.parse(fname)
            xml_root = tree.getroot()
        except:
            print("Cannot open ",fname," to read info, e.g., names of substrate fields.")
            return

        xml_root = tree.getroot()
        self.field_min_max = {}
        self.field_dict = {}
        dropdown_options = {}
        uep = xml_root.find('.//variables')
        comment_str = ""
        field_idx = 0
        if (uep):
            for elm in uep.findall('variable'):
                # print("-----> ",elm.attrib['name'])
                self.field_min_max[elm.attrib['name']] = [0., 1.]
                self.field_dict[field_idx] = elm.attrib['name']
                dropdown_options[elm.attrib['name']] = field_idx
                field_idx += 1

#        constWidth = '180px'
        # print('options=',dropdown_options)
        self.mcds_field.value=0
        self.mcds_field.options=dropdown_options
#         self.mcds_field = Dropdown(
# #            options={'oxygen': 0, 'glucose': 1},
#             options=dropdown_options,
#             value=0,
#             #     description='Field',
#            layout=Layout(width=constWidth)
#         )

    def update_max_frames_expected(self, value):  # called when beginning an interactive Run
        self.max_frames.value = value  # assumes naming scheme: "snapshot%08d.svg"
        self.mcds_plot.children[0].max = self.max_frames.value

#    def update(self, rdir):
    def update(self, rdir=''):
        # with debug_view:
        #     print("substrates: update rdir=", rdir)        

        if rdir:
            self.output_dir = rdir

        all_files = sorted(glob.glob(os.path.join(self.output_dir, 'output*.xml')))
        if len(all_files) > 0:
            last_file = all_files[-1]
            self.max_frames.value = int(last_file[-12:-4])  # assumes naming scheme: "snapshot%08d.svg"

        # with debug_view:
        #     print("substrates: added %s files" % len(all_files))


        # self.output_dir = rdir
        # if rdir == '':
        #     # self.max_frames.value = 0
        #     tmpdir = os.path.abspath('tmpdir')
        #     self.output_dir = tmpdir
        #     all_files = sorted(glob.glob(os.path.join(tmpdir, 'output*.xml')))
        #     if len(all_files) > 0:
        #         last_file = all_files[-1]
        #         self.max_frames.value = int(last_file[-12:-4])  # assumes naming scheme: "output%08d.xml"
        #         self.mcds_plot.update()
        #     return

        # all_files = sorted(glob.glob(os.path.join(rdir, 'output*.xml')))
        # if len(all_files) > 0:
        #     last_file = all_files[-1]
        #     self.max_frames.value = int(last_file[-12:-4])  # assumes naming scheme: "output%08d.xml"
        #     self.mcds_plot.update()

    def download_cb(self):
        file_xml = os.path.join(self.output_dir, '*.xml')
        file_mat = os.path.join(self.output_dir, '*.mat')
        # print('zip up all ',file_str)
        with zipfile.ZipFile('mcds.zip', 'w') as myzip:
            for f in glob.glob(file_xml):
                myzip.write(f, os.path.basename(f)) # 2nd arg avoids full filename path in the archive
            for f in glob.glob(file_mat):
                myzip.write(f, os.path.basename(f))

    def update_max_frames(self,_b):
        self.mcds_plot.children[0].max = self.max_frames.value

    def mcds_field_changed_cb(self, b):
        # print("mcds_field_changed_cb: self.mcds_field.value=",self.mcds_field.value)
        if (self.mcds_field.value == None):
            return
        self.field_index = self.mcds_field.value + 4

        field_name = self.field_dict[self.mcds_field.value]
#        print('mcds_field_cb: '+field_name)
        self.cmap_min.value = self.field_min_max[field_name][0]
        self.cmap_max.value = self.field_min_max[field_name][1]
        self.mcds_plot.update()

    def mcds_field_cb(self, b):
        #self.field_index = self.mcds_field.value
#        self.field_index = self.mcds_field.options.index(self.mcds_field.value) + 4
#        self.field_index = self.mcds_field.options[self.mcds_field.value]
        self.field_index = self.mcds_field.value + 4

        # field_name = self.mcds_field.options[self.mcds_field.value]
        # self.cmap_min.value = self.field_min_max[field_name][0]  # oxygen, etc
        # self.cmap_max.value = self.field_min_max[field_name][1]  # oxygen, etc

#        self.field_index = self.mcds_field.value + 4

#        print('field_index=',self.field_index)
        self.mcds_plot.update()

    def plot_substrate(self, frame):
        # global current_idx, axes_max, gFileId, field_index
        fname = "output%08d_microenvironment0.mat" % frame
        xml_fname = "output%08d.xml" % frame
        # fullname = output_dir_str + fname

#        fullname = fname
        full_fname = os.path.join(self.output_dir, fname)
        full_xml_fname = os.path.join(self.output_dir, xml_fname)
#        self.output_dir = '.'

#        if not os.path.isfile(fullname):
        if not os.path.isfile(full_fname):
            print("Once output files are generated, click the slider.")  # No:  output00000000_microenvironment0.mat
            return

#        tree = ET.parse(xml_fname)
        tree = ET.parse(full_xml_fname)
        xml_root = tree.getroot()
        mins= round(int(float(xml_root.find(".//current_time").text)))  # TODO: check units = mins
        hrs = int(mins/60)
        days = int(hrs/24)
        title_str = '%dd, %dh, %dm' % (int(days),(hrs%24), mins - (hrs*60))


        info_dict = {}
#        scipy.io.loadmat(fullname, info_dict)
        scipy.io.loadmat(full_fname, info_dict)
        M = info_dict['multiscale_microenvironment']
        #     global_field_index = int(mcds_field.value)
        #     print('plot_substrate: field_index =',field_index)
        f = M[self.field_index, :]   # 4=tumor cells field, 5=blood vessel density, 6=growth substrate
        # plt.clf()
        # my_plot = plt.imshow(f.reshape(400,400), cmap='jet', extent=[0,20, 0,20])
    
        self.fig = plt.figure(figsize=(7.2,6))  # this strange figsize results in a ~square contour plot
        #     fig.set_tight_layout(True)
        #     ax = plt.axes([0, 0.05, 0.9, 0.9 ]) #left, bottom, width, height
        #     ax = plt.axes([0, 0.0, 1, 1 ])
        #     cmap = plt.cm.viridis # Blues, YlOrBr, ...
        #     im = ax.imshow(f.reshape(100,100), interpolation='nearest', cmap=cmap, extent=[0,20, 0,20])
        #     ax.grid(False)

        # print("substrates.py: ------- numx, numy = ", self.numx, self.numy )
        if (self.numx == 0):   # need to parse vals from the config.xml
            fname = os.path.join(self.output_dir, "config.xml")
            tree = ET.parse(fname)
            xml_root = tree.getroot()
            xmin = float(xml_root.find(".//x_min").text)
            xmax = float(xml_root.find(".//x_max").text)
            dx = float(xml_root.find(".//dx").text)
            ymin = float(xml_root.find(".//y_min").text)
            ymax = float(xml_root.find(".//y_max").text)
            dy = float(xml_root.find(".//dy").text)
            self.numx =  math.ceil( (xmax - xmin) / dx)
            self.numy =  math.ceil( (ymax - ymin) / dy)

        xgrid = M[0, :].reshape(self.numy, self.numx)
        ygrid = M[1, :].reshape(self.numy, self.numx)

        num_contours = 15
        levels = MaxNLocator(nbins=num_contours).tick_values(self.cmap_min.value, self.cmap_max.value)
        contour_ok = True
        if (self.cmap_fixed.value):
            try:
                my_plot = plt.contourf(xgrid, ygrid, M[self.field_index, :].reshape(self.numy, self.numx), levels=levels, extend='both', cmap=self.field_cmap.value)
            except:
                contour_ok = False
                # print('got error on contourf 1.')
        else:    
            try:
                my_plot = plt.contourf(xgrid, ygrid, M[self.field_index, :].reshape(self.numy,self.numx), num_contours, cmap=self.field_cmap.value)
            except:
                contour_ok = False
                # print('got error on contourf 2.')

        if (contour_ok):
            plt.title(title_str)
            plt.colorbar(my_plot)
        axes_min = 0
        axes_max = 2000
Esempio n. 7
0
class MLSection:
    def __init__(self):
        self.data = pickle.load(open('all_data.pkl', 'rb'))
        self.setup_widgets()
        self.refresh_plot()

    def setup_widgets(self):
        amine_list = sorted(list(self.data.keys()))
        self.select_amine = Dropdown(
            options=amine_list,
            description='Amine: ',
            disabled=False,
        )

        self.select_metric = Dropdown(
            options=['Accuracy', 'Precision', 'Recall', 'F1'],
            description='Metric: ',
            disabled=False,
        )

        self.figure = go.FigureWidget()

        self.select_amine.observe(self.select_amine_callback, 'value')
        self.select_metric.observe(self.select_amine_callback, 'value')

        self.full_widget = VBox(
            [self.figure,
             HBox([self.select_amine, self.select_metric])])

    def select_amine_callback(self, state):
        self.refresh_plot()

    def refresh_plot(self):
        color_list = [
            'rgba(31, 118, 180, 1)', 'rgba(255, 127, 14, 1)',
            'rgba(44, 160, 44, 1)', 'rgba(214, 39, 39, 1)',
            'rgba(147, 103, 189, 1)', 'rgba(140, 86, 75, 1)',
            'rgba(227, 119, 195, 1)', 'rgba(127, 127, 127, 1)',
            'rgba(189, 189, 34, 1)', 'rgba(23, 189, 207, 1)'
        ]
        amine = self.select_amine.value
        metric = self.select_metric.value
        x_values = self.data[amine]['learn_rate']
        # y_values = self.data[amine]
        layout = go.Layout(
            hovermode='closest',
            showlegend=True,
            xaxis=go.layout.XAxis(title=go.layout.xaxis.Title(
                text="Number of training experiments", ), ),
            yaxis=go.layout.YAxis(title=go.layout.yaxis.Title(text=metric, )),
        )

        trace_list = []
        for i, model in enumerate(sorted(self.data[amine]['model'].keys())):
            y_mean = [
                np.mean(y_data.flatten())
                for y_data in self.data[amine]['model'][model][metric.lower()]
            ]
            x = x_values

            trace = go.Scatter(
                name=model,
                x=x,
                y=y_mean,
                marker=dict(
                    size=5,
                    color=color_list[i % len(color_list)],
                ),
                opacity=1.0,
            )
            trace_list.append(trace)

            y_std_dev = [
                np.std(y_data.flatten())
                for y_data in self.data[amine]['model'][model][metric.lower()]
            ]

            y_upper = np.array(y_mean) + np.array(y_std_dev)
            y_lower = np.array(y_mean) - np.array(y_std_dev)

            trace2 = go.Scatter(
                x=x + x[::-1],
                y=list(y_upper) + list(reversed(y_lower)),
                fill='tozerox',
                fillcolor=self.change_alpha(color_list[i % len(color_list)],
                                            0.3),
                line=dict(color='rgba(255,255,255,0)'),
                name=model,
                showlegend=False,
            )
            trace_list.append(trace2)
            """
            if std_dev[model]:

                x_rev = x[::-1]
                y_upper = np.array(data[model]) + np.array(std_dev[model])
                y_lower = np.array(data[model]) - np.array(std_dev[model])
                trace2 = go.Scatter(
                    x=x+x_rev,
                    y=list(y_upper)+list(y_lower)[::-1],
                    fill='tozerox',
                    fillcolor=self.change_alpha(
                        color_list[i % len(color_list)], 0.3),
                    line=dict(color='rgba(255,255,255,0)'),
                    name=model,
                    showlegend=False,
                )
                trace_list.append(trace2)
            """
        # self.figure = go.FigureWidget(data=trace_list, layout=layout)
        with self.figure.batch_update():
            self.figure.data = []
            # for trace in trace_list:
            self.figure.add_traces(trace_list)
            self.figure.layout = layout

    def change_alpha(self, color, alpha):
        color = color.split(',')
        color[-1] = '{})'.format(alpha)
        return ','.join(color)

    @property
    def plot(self):
        return self.full_widget
class WikipediaPageRow(Document):
    def __init__(self, name=None):
        self.editable = name is None
        self.checkbox = Checkbox(value=True,
                                 layout=_checkbox_layout,
                                 indent=False)
        self.true_name = self.summary = self.last_textfield = None

        if self.editable:
            self.text_field = Text(layout=_label_layout)
        else:
            self.text_field = Label(value=name, layout=_label_layout)

        self.remove_button = Button(
            description='Remove',
            disabled=False,
            button_style=
            'danger',  # 'success', 'info', 'warning', 'danger' or ''
            layout=_remove_layout,
        )
        self.additional_info = Label("", layout=_additional_info_layout)
        self.ambiguity_dropdown = None

    def __iter__(self):
        yield self.checkbox
        yield self.text_field
        yield self.remove_button

        if self.ambiguity_dropdown is None:
            yield self.additional_info
        else:
            yield self.ambiguity_dropdown

    def _search(self):
        if self.last_textfield != self.text_field_value:
            try:
                self.last_textfield = self.text_field_value
                self.true_name = _get_wikipedia_search(
                    name=self.text_field_value)[0]
                self.summary = _get_wikipedia_summary(self.true_name)
                self.ambiguity_dropdown = None

            except (wikipedia.DisambiguationError, IndexError) as e:
                if isinstance(e, wikipedia.DisambiguationError):
                    options = [
                        val for val in e.options if not "All pages" in val
                    ]

                    self.ambiguity_dropdown = Dropdown(
                        options=options,
                        value=options[0],
                        description='-> Ambiguity:',
                        disabled=False,
                        layout=_additional_info_layout)
                    self.ambiguity_dropdown.observe(
                        self._true_name_from_dropdown)
                    self._true_name_from_dropdown()
                else:
                    self.last_textfield = ""
                    self.true_name = ""
                    self.summary = None
                    self.ambiguity_dropdown = None

    def _true_name_from_dropdown(self, _=None):
        self.true_name = self.ambiguity_dropdown.value
        self.summary = _get_wikipedia_summary(self.true_name)

    @property
    def text_field_value(self):
        return self.text_field.value

    @property
    def name(self):
        self._search()
        return self.true_name

    @property
    def text(self):
        self._search()
        return self.summary

    @property
    def on(self):
        return self.checkbox.value and self.text_field_value

    @staticmethod
    def make_header():
        return HBox(
            (Label("Use", layout=_checkbox_layout),
             Label("Page Search Name",
                   layout=_label_layout), Label("Remove",
                                                layout=_remove_layout),
             Label("Search Result", layout=_additional_info_layout)))
Esempio n. 9
0
    def _create_controls(
        self,
        time: Union[pd.DatetimeIndex, pd.TimedeltaIndex, List[pd.Timestamp]],
        reference_system: str,
        show_data_labels: bool,
        show_labels: bool,
        show_origins: bool,
        show_traces: bool,
        show_vectors: bool,
        show_wireframe: bool,
    ):
        """Create the control panel.

        Parameters
        ----------
        time : pandas.DatetimeIndex, pandas.TimedeltaIndex, List[pandas.Timestamp], or \
               LocalCoordinateSystem
            The time steps that should be plotted initially
        reference_system : str
            Name of the initial reference system. If `None` is provided, the root system
            of the `CoordinateSystemManager` instance will be used
        show_data_labels : bool
            If `True`, the data labels will be shown initially
        show_labels  : bool
            If `True`, the coordinate system labels will be shown initially
        show_origins : bool
            If `True`, the coordinate systems' origins will be shown initially
        show_traces : bool
            If `True`, the coordinate systems' traces will be shown initially
        show_vectors : bool
            If `True`, the coordinate systems' axis vectors will be shown initially
        show_wireframe : bool
            If `True`, spatial data containing mesh data will be drawn as wireframe

        """
        num_times = 1
        disable_time_widgets = True
        lo = Layout(width="200px")

        # create widgets
        if time is not None:
            num_times = len(time)
            disable_time_widgets = False

        play = Play(
            min=0,
            max=num_times - 1,
            value=self._current_time_index,
            step=1,
        )
        time_slider = IntSlider(
            min=0,
            max=num_times - 1,
            value=self._current_time_index,
            description="Time:",
        )
        reference_dropdown = Dropdown(
            options=self._csm.coordinate_system_names,
            value=reference_system,
            description="Reference:",
            disabled=False,
        )
        data_dropdown = Dropdown(
            options=SpatialDataVisualizer.visualization_methods,
            value="auto",
            description="data repr.:",
            disabled=False,
            layout=lo,
        )

        lo = Layout(width="200px")
        vectors_cb = Checkbox(value=show_vectors,
                              description="show vectors",
                              layout=lo)
        origin_cb = Checkbox(value=show_origins,
                             description="show origins",
                             layout=lo)
        traces_cb = Checkbox(value=show_traces,
                             description="show traces",
                             layout=lo)
        labels_cb = Checkbox(value=show_labels,
                             description="show labels",
                             layout=lo)
        wf_cb = Checkbox(value=show_wireframe,
                         description="show wireframe",
                         layout=lo)
        data_labels_cb = Checkbox(value=show_data_labels,
                                  description="show data labels",
                                  layout=lo)

        jslink((play, "value"), (time_slider, "value"))
        play.disabled = disable_time_widgets
        time_slider.disabled = disable_time_widgets

        # callback functions
        def _reference_callback(change):
            self.update_reference_system(change["new"])

        def _time_callback(change):
            self.update_time_index(change["new"])

        def _vectors_callback(change):
            self.show_vectors(change["new"])

        def _origins_callback(change):
            self.show_origins(change["new"])

        def _traces_callback(change):
            self.show_traces(change["new"])

        def _labels_callback(change):
            self.show_labels(change["new"])

        def _data_callback(change):
            self.set_data_visualization_method(change["new"])

        def _data_labels_callback(change):
            self.show_data_labels(change["new"])

        def _wireframe_callback(change):
            self.show_wireframes(change["new"])

        # register callbacks
        time_slider.observe(_time_callback, names="value")
        reference_dropdown.observe(_reference_callback, names="value")
        vectors_cb.observe(_vectors_callback, names="value")
        origin_cb.observe(_origins_callback, names="value")
        traces_cb.observe(_traces_callback, names="value")
        labels_cb.observe(_labels_callback, names="value")
        data_dropdown.observe(_data_callback, names="value")
        data_labels_cb.observe(_data_labels_callback, names="value")
        wf_cb.observe(_wireframe_callback, names="value")

        # create control panel
        row_1 = HBox([time_slider, play, reference_dropdown])
        row_2 = HBox([vectors_cb, origin_cb, traces_cb, labels_cb])
        if len(self._data_vis) > 0:
            row_3 = HBox([data_dropdown, wf_cb, data_labels_cb])
            return VBox([row_1, row_2, row_3])
        return VBox([row_1, row_2])
Esempio n. 10
0
class TimeSeriesSmoothing():
    """
    Class to plot a single time step and per-pixel time series
    """
    debug_view = widgets.Output(layout={'border': '1px solid black'})

    def __init__(self, fname, band=1, isNotebook=True):
        """
        :param ts: TATSSI qa_analytics object
        """
        # Clear cell
        clear_output()

        # Time series object
        self.ts = Analysis(fname=fname)

        self.isNotebook = isNotebook
        if self.isNotebook is True:
            # Smoothing methods
            # set in __fill_smoothing_method
            self.smoothing_methods = None

            # Display controls
            self.__display_controls()

        # Create plot objects
        self.__create_plot_objects()
        # Create plot
        self.__plot(band)

        # Disable RasterIO logging, just show ERRORS
        log = rio_logging.getLogger()
        log.setLevel(rio_logging.ERROR)

    def __create_plot_objects(self):
        """
        Create plot objects
        """
        self.fig = plt.figure(figsize=(10.0, 3.0))

        # Image plot
        self.img_p = plt.subplot2grid((1, 4), (0, 0), colspan=1)
        # Time series plot
        self.ts_p = plt.subplot2grid((1, 4), (0, 1), colspan=3)

    def __display_controls(self):
        """
        Display widgets in an horizontal box
        """
        self.__fill_data_variables()
        self.__fill_smoothing_method()
        self.__fill_smooth_factor()

        left_box = VBox([self.data_vars])
        center_box = VBox([self.smoothing_methods])
        right_box = VBox([self.smooth_factor])
        #_HBox = HBox([left_box, center_box, right_box],
        _HBox = HBox([left_box, center_box, right_box],
                      layout={'height': '80px',
                              'width' : '99%'}
        )
        display(_HBox)

    def __fill_smooth_factor(self):
        """
        Fill smooth factor bounded float text
        """
        self.smooth_factor = widgets.BoundedFloatText(
                value=0.75,
                min=0.1,
                max=10.0,
                step=0.05,
                description='Smooth factor:',
                disabled=False,
                style = {'description_width': 'initial'},
                layout={'width': '150px'}
        )

    def __fill_data_variables(self):
        """
        Fill the data variables dropdown list
        """
        data_vars = []
        for data_var in self.ts.data.data_vars:
            data_vars.append(data_var)

        self.data_vars = Dropdown(
            options=data_vars,
            value=data_vars[0],
            description='Data variables:',
            disabled=False,
            style = {'description_width': 'initial'},
            layout={'width': '400px'},
        )

        self.data_vars.observe(self.on_data_vars_change)

    def on_data_vars_change(self, change):
        """
        Handles a change in the data variable to display
        """
        if change['type'] == 'change' and change['name'] == 'value':
            self.left_ds = getattr(self.ts.data, change['new'])
            if self.mask is None:
                self.right_ds = self.left_ds.copy(deep=True)
            else:
                self.right_ds = self.left_ds * self.mask

            self.left_imshow.set_data(self.left_ds.data[0])
            self.right_imshow.set_data(self.right_ds.data[0])

    def __fill_smoothing_method(self):
        """
        Fill smooth methods
        """
        smoothing_methods = ['smoothn',
                             'ExponentialSmoothing',
                             'SimpleExpSmoothing',
                             'Holt']

        self.smoothing_methods = SelectMultiple(
                options=tuple(smoothing_methods),
                value=tuple([smoothing_methods[0]]),
                rows=len(smoothing_methods),
                description='Smoothing methods',
                disabled=False,
                style = {'description_width': 'initial'},
                layout={'width': '330px'},
        )

    def __plot(self, band, is_qa=False):
        """
        Plot a variable and time series
        """

        self.img_ds = getattr(self.ts.data, self.data_vars.value)
        # Create plot
        self.img_imshow = self.img_ds[band].plot.imshow(cmap='Greys_r',
                ax=self.img_p, add_colorbar=False)

        # Turn off axis
        self.img_p.axis('off')
        self.img_p.set_aspect('equal')
        self.fig.canvas.draw_idle()

        # Connect the canvas with the event
        cid = self.fig.canvas.mpl_connect('button_press_event',
                                          self.on_click)

        # Plot the centroid
        _layers, _rows, _cols = self.img_ds.shape
        # Get y-axis max and min
        #y_min, y_max = self.ds.data.min(), self.ds.data.max()

        plot_sd = self.img_ds[:, int(_cols / 2), int(_rows / 2)]
        plot_sd.plot(ax = self.ts_p, color='black',
                linestyle = '-', linewidth=1, label='Original data')


        plt.margins(tight=True)
        plt.tight_layout()

        # Legend
        self.ts_p.legend(loc='best', fontsize='small',
                         fancybox=True, framealpha=0.5)

        # Grid
        self.ts_p.grid(axis='both', alpha=.3)

        plt.show()

    @debug_view.capture(clear_output=True)
    def on_click(self, event):
        """
        Event handler
        """
        # Event does not apply for time series plot
        # Check if the click was in a
        if event.inaxes in [self.ts_p]:
            return

        # Clear subplot
        self.ts_p.clear()

        # Delete last reference point
        if len(self.img_p.lines) > 0:
            del self.img_p.lines[0]

        # Draw a point as a reference
        self.img_p.plot(event.xdata, event.ydata,
                marker='o', color='red', markersize=7, alpha=0.7)

        # Interpolated data to smooth
        img_plot_sd = self.img_ds.sel(longitude=event.xdata,
                                        latitude=event.ydata,
                                        method='nearest')
        if img_plot_sd.chunks is not None:
            img_plot_sd = img_plot_sd.compute()

        # Plots
        img_plot_sd.plot(ax=self.ts_p, color='black',
                linestyle = '-', linewidth=1, label='Original data')

        # For every smoothing method selected by the user
        for method in self.smoothing_methods.value:
            y = img_plot_sd.data
            s = float(self.smooth_factor.value)

            if method is 'smoothn':
                # Smoothing
                fittedvalues = smoothn(y, isrobust=True,
                        s=s, TolZ=1e-6, axis=0)[0]

            else:
                _method = getattr(tsa, method)
                # Smoothing
                #fit = _method(y).fit(smoothing_level=s, optimized=False)
                fit = _method(y.astype(float)).fit(smoothing_level=s)
                # Re-cast to original data type
                fittedvalues = np.zeros_like(fit.fittedvalues)
                fittedvalues[0:-1] = fit.fittedvalues[1::]
                fittedvalues[-1] = y[-1]

            # Plot
            tmp_ds = img_plot_sd.copy(deep=True,
                        data=fittedvalues)
            tmp_ds.plot(ax = self.ts_p, label=method, linewidth=2)

        # Change ylimits
        max_val = img_plot_sd.data.max()
        min_val = img_plot_sd.data.min()

        data_range = max_val - min_val
        max_val = max_val + (data_range * 0.2)
        min_val = min_val - (data_range * 0.2)
        self.ts_p.set_ylim([min_val, max_val])

        # Legend
        self.ts_p.legend(loc='best', fontsize='small',
                         fancybox=True, framealpha=0.5)

        # Grid
        self.ts_p.grid(axis='both', alpha=.3)

        # Redraw plot
        plt.draw()

    @staticmethod
    def __enhance(data):

        # Histogram
        _histogram = np.histogram(data)[1]

        # Change ylimits
        max_val = _histogram[-3]
        min_val = _histogram[2]

        return min_val, max_val
Esempio n. 11
0
class TrajectoryPlayer(DOMWidget):
    # should set default values here different from desired defaults
    # so `observe` can be triggered
    step = Int(0).tag(sync=True)
    sync_frame = Bool(True).tag(sync=True)
    interpolate = Bool(False).tag(sync=False)
    delay = Float(0.0).tag(sync=True)
    parameters = Dict().tag(sync=True)
    iparams = Dict().tag(sync=False)
    _interpolation_t = Float().tag(sync=False)
    _iterpolation_type = CaselessStrEnum(['linear', 'spline']).tag(sync=False)
    spin = Bool(False).tag(sync=False)
    _spin_x = Int(1).tag(sync=False)
    _spin_y = Int(0).tag(sync=False)
    _spin_z = Int(0).tag(sync=False)
    _spin_speed = Float(0.005).tag(sync=False)
    camera = CaselessStrEnum(['perspective', 'orthographic'],
        default_value='perspective').tag(sync=False)
    _render_params = Dict().tag(sync=False)
    _real_time_update = Bool(False).tag(sync=False)

    widget_tab = Any(None).tag(sync=False)
    widget_repr = Any(None).tag(sync=False)
    widget_repr_parameters = Any(None).tag(sync=False)
    widget_quick_repr = Any(None).tag(sync=False)
    widget_general = Any(None).tag(sync=False)
    widget_picked = Any(None).tag(sync=False)
    widget_preference = Any(None).tag(sync=False)
    widget_extra = Any(None).tag(sync=False)
    widget_theme = Any(None).tag(sync=False)
    widget_help = Any(None).tag(sync=False)
    widget_export_image = Any(None).tag(sync=False)
    widget_component_slider = Any(None).tag(sync=False)
    widget_repr_slider = Any(None).tag(sync=False)
    widget_repr_choices = Any(None).tag(sync=False)
    widget_repr_control_buttons = Any(None).tag(sync=False)
    widget_repr_add = Any(None).tag(sync=False)
    widget_accordion_repr_parameters = Any(None).tag(sync=False)
    widget_repr_parameters_dialog = Any(None).tag(sync=False)
    widget_repr_name = Any(None).tag(sync=False)
    widget_component_dropdown = Any(None).tag(sync=False)
    widget_drag = Any(None).tag(sync=False)

    def __init__(self, view, step=1, delay=100,
                 sync_frame=False, min_delay=40):
        self._view = view
        self.step = step
        self.sync_frame = sync_frame
        self.delay = delay
        self.min_delay = min_delay
        self._interpolation_t = 0.5
        self._iterpolation_type = 'linear'
        self.iparams = dict(
            t=self._interpolation_t,
            step=1,
            type=self._iterpolation_type)
        self._render_params = dict(factor=4,
                                   antialias=True,
                                   trim=False,
                                   transparent=False)

        self._widget_names = [w for w in dir(self) if w.startswith('wiget_')]
        self.observe(self._on_widget_built, names=['widget_repr_parameters',
            'widget_repr',
            'widget_preference'])
        self._movie_maker = None

    def _on_widget_built(self, change):
        widget = change['new']
        if widget is not None:
            widget.layout.padding = '5%'

    def _update_padding(self, padding=default.DEFAULT_PADDING):
        widget_collection = [
                self.widget_general,
                self.widget_repr,
                self.widget_preference,
                self.widget_repr_parameters,
                self.widget_help,
                self.widget_extra,
                self.widget_picked
        ]
        for widget in widget_collection:
            if widget is not None:
                widget.layout.padding = padding

    def _create_all_widgets(self):
        if self.widget_tab is None:
            self.widget_tab = self._display()

        old_index = self.widget_tab.selected_index
        for index, _ in enumerate(self.widget_tab.children):
            self.widget_tab.selected_index = index

        self.widget_tab.selected_index = old_index

    def smooth(self):
        self.interpolate = True

    @observe('camera')
    def on_camera_changed(self, change):
        camera_type = change['new']
        self._view._remote_call("setParameters",
                                target='Stage',
                                kwargs=dict(cameraType=camera_type))

    @property
    def frame(self):
        return self._view.frame

    @frame.setter
    def frame(self, value):
        self._view.frame = value

    @property
    def count(self):
        return self._view.count

    @observe('sync_frame')
    def update_sync_frame(self, change):
        value = change['new']
        if value:
            self._view._set_sync_frame()
        else:
            self._view._set_unsync_frame()

    @observe("delay")
    def update_delay(self, change):
        delay = change['new']
        self._view._set_delay(delay)

    @observe('parameters')
    def update_parameters(self, change):
        params = change['new']
        self.sync_frame = params.get("sync_frame", self.sync_frame)
        self.delay = params.get("delay", self.delay)
        self.step = params.get("step", self.step)

    @observe('_interpolation_t')
    def _interpolation_t_changed(self, change):
        self.iparams['t'] = change['new']

    @observe('spin')
    def on_spin_changed(self, change):
        self.spin = change['new']
        if self.spin:
            self._view._set_spin([self._spin_x, self._spin_y, self._spin_z],
                                 self._spin_speed)
        else:
            # stop
            self._view._set_spin(None, None)

    @observe('_spin_x')
    def on_spin_x_changed(self, change):
        self._spin_x = change['new']
        if self.spin:
            self._view._set_spin([self._spin_x, self._spin_y, self._spin_z],
                                 self._spin_speed)

    @observe('_spin_y')
    def on_spin_y_changed(self, change):
        self._spin_y = change['new']
        if self.spin:
            self._view._set_spin([self._spin_x, self._spin_y, self._spin_z],
                                 self._spin_speed)

    @observe('_spin_z')
    def on_spin_z_changed(self, change):
        self._spin_z = change['new']
        if self.spin:
            self._view._set_spin([self._spin_x, self._spin_y, self._spin_z],
                                 self._spin_speed)

    @observe('_spin_speed')
    def on_spin_speed_changed(self, change):
        self._spin_speed = change['new']
        if self.spin:
            self._view._set_spin([self._spin_x, self._spin_y, self._spin_z],
                                 self._spin_speed)

    def _display(self):
        box_factory = [(self._make_general_box, 'General'),
                       (self._make_widget_repr, 'Representation'),
                       (self._make_widget_preference, 'Preference'),
                       (self._make_theme_box, 'Theme'),
                       (self._make_extra_box, 'Extra'),
                       (self._show_website, 'Help')]

        tab = _make_delay_tab(box_factory, selected_index=-1)
        # tab = _make_autofit(tab)
        tab.layout.align_self = 'center'
        tab.layout.align_items = 'stretch'

        self.widget_tab = tab

        return self.widget_tab

    def _make_widget_tab(self):
        return self._display()

    def _make_button_center(self):
        button = Button(description=' Center', icon='fa-bullseye')
        @button.on_click
        def on_click(button):
            self._view.center()
        return button

    def _make_button_theme(self):
        button = Button(description='Oceans16')
        @button.on_click
        def on_click(button):
            from nglview import theme
            display(theme.oceans16())
            self._view._remote_call('cleanOutput',
                                    target='Widget')
        return button

    def _make_button_reset_theme(self, hide_toolbar=False):
        from nglview import theme

        if hide_toolbar:
            button = Button(description='Simplified Default')
            @button.on_click
            def on_click(button):
                theme.reset(hide_toolbar=True)
        else:
            button = Button(description='Default')
            @button.on_click
            def on_click(button):
                theme.reset()
        return button

    def _make_button_clean_error_output(self):
        button = Button(description='Clear Error')
        @button.on_click
        def on_click(_):
            js_utils.clean_error_output()
        return button

    def _make_widget_preference(self, width='100%'):
        def make_func():
            parameters = self._view._full_stage_parameters
            def func(pan_speed=parameters.get('panSpeed', 0.8),
                     rotate_speed=parameters.get('rotateSpeed', 2),
                     zoom_speed=parameters.get('zoomSpeed', 1.2),
                     clip_dist=parameters.get('clipDist', 10),
                     camera_fov=parameters.get('cameraFov', 40),
                     clip_far=parameters.get('clipFar', 100),
                     clip_near=parameters.get('clipNear', 0),
                     fog_far=parameters.get('fogFar', 100),
                     fog_near=parameters.get('fogNear', 50),
                     impostor=parameters.get('impostor', True),
                     light_intensity=parameters.get('lightIntensity', 1),
                     quality=parameters.get('quality', 'medium'),
                     sample_level=parameters.get('sampleLevel', 1)):

                self._view.parameters = dict(
                    panSpeed=pan_speed,
                    rotateSpeed=rotate_speed,
                    zoomSpeed=zoom_speed,
                    clipDist=clip_dist,
                    clipFar=clip_far,
                    clipNear=clip_near,
                    cameraFov=camera_fov,
                    fogFar=fog_far,
                    fogNear=fog_near,
                    impostor=impostor,
                    lightIntensity=light_intensity,
                    quality=quality,
                    sampleLevel=sample_level)

            return func

        def make_widget_box():
            widget_sliders = interactive(make_func(),
                      pan_speed=(0, 10, 0.1),
                      rotate_speed=(0, 10, 1),
                      zoom_speed=(0, 10, 1),
                      clip_dist=(0, 200, 5),
                      clip_far=(0, 100, 1),
                      clip_near=(0, 100, 1),
                      camera_fov=(15, 120, 1),
                      fog_far=(0, 100, 1),
                      fog_near=(0, 100, 1),
                      light_intensity=(0, 10, 0.02),
                      quality=['low', 'medium', 'high'],
                      sample_level=(-1, 5, 1))

            for child in widget_sliders.children:
                if isinstance(child, (IntSlider, FloatSlider)):
                    child.layout.width = default.DEFAULT_SLIDER_WIDTH
            return widget_sliders

        if self.widget_preference is None:
            widget_sliders = make_widget_box()
            reset_button = Button(description='Reset')
            widget_sliders.children = [reset_button,] + list(widget_sliders.children)

            @reset_button.on_click
            def on_click(reset_button):
                self._view.parameters = self._view._original_stage_parameters
                self._view._full_stage_parameters = self._view._original_stage_parameters
                widget_sliders.children = [reset_button,] + list(make_widget_box().children)

            self.widget_preference = _relayout_master(widget_sliders, width=width)
        return self.widget_preference

    def _show_download_image(self):
        # "interactive" does not work for True/False in ipywidgets 4 yet.
        button = Button(description=' Screenshot', icon='fa-camera')
        @button.on_click
        def on_click(button):
            self._view.download_image()
        return button

    def _make_button_url(self, url, description):
        button = Button(description=description)

        @button.on_click
        def on_click(button):
            display(Javascript(js_utils.open_url_template.format(url=url)))
        return button

    def _show_website(self, ngl_base_url=default.NGL_BASE_URL):
        buttons = [self._make_button_url(url.format(ngl_base_url), description) for url, description in
            [("'http://arose.github.io/nglview/latest/'", "nglview"),
             ("'{}/index.html'", "NGL"),
             ("'{}/tutorial-selection-language.html'", "Selection"),
             ("'{}/tutorial-molecular-representations.html'", "Representation")]
        ]
        self.widget_help = _make_autofit(HBox(buttons))
        return self.widget_help

    def _make_button_qtconsole(self):
        from nglview import js_utils
        button = Button(description='qtconsole',
                tooltip='pop up qtconsole')

        @button.on_click
        def on_click(button):
            js_utils.launch_qtconsole()
        return button

    def _make_text_picked(self):
        ta = Textarea(value=json.dumps(self._view.picked), description='Picked atom')
        ta.layout.width = '300px'
        return ta

    def _refresh(self, component_slider, repr_slider):
        """update representation and component information
        """
        self._view._request_repr_parameters(component=component_slider.value,
                                            repr_index=repr_slider.value)
        self._view._remote_call('requestReprInfo', target='Widget')
        self._view._handle_repr_dict_changed(change=dict(new=self._view._repr_dict))

    def _make_button_repr_control(self, component_slider, repr_slider, repr_selection):
        button_refresh = Button(description=' Refresh', tooltip='Get representation info', icon='fa-refresh')
        button_center_selection = Button(description=' Center', tooltip='center selected atoms',
                icon='fa-bullseye')
        button_center_selection._ngl_name = 'button_center_selection'
        button_hide = Button(description=' Hide',
                icon='fa-eye-slash',
                tooltip='Hide/Show current representation')
        button_remove = Button(description=' Remove',
                icon='fa-trash',
                tooltip='Remove current representation')
        button_repr_parameter_dialog = Button(description=' Dialog',
                tooltip='Pop up representation parameters control dialog')

        @button_refresh.on_click
        def on_click_refresh(button):
            self._refresh(component_slider, repr_slider)

        @button_center_selection.on_click
        def on_click_center(center_selection):
            self._view.center_view(selection=repr_selection.value,
                                   component=component_slider.value)

        @button_hide.on_click
        def on_click_hide(button_hide):
            component=component_slider.value
            repr_index=repr_slider.value

            if button_hide.description == 'Hide':
                hide = True
                button_hide.description = 'Show'
            else:
                hide = False
                button_hide.description = 'Hide'

            self._view._remote_call('setVisibilityForRepr',
                                    target='Widget',
                                    args=[component, repr_index, not hide])

        @button_remove.on_click
        def on_click_remove(button_remove):
            self._view._remove_representation(component=component_slider.value,
                                              repr_index=repr_slider.value)
            self._view._request_repr_parameters(component=component_slider.value,
                                                repr_index=repr_slider.value)

        @button_repr_parameter_dialog.on_click
        def on_click_repr_dialog(_):
            from nglview.widget_box import DraggableBox
            if self.widget_repr_parameters is not None and self.widget_repr_choices:
                self.widget_repr_parameters_dialog = DraggableBox([self.widget_repr_choices,
                                     self.widget_repr_parameters])
                self.widget_repr_parameters_dialog._ipython_display_()
                self.widget_repr_parameters_dialog._dialog = 'on'

        bbox = _make_autofit(HBox([button_refresh, button_center_selection,
                                   button_hide, button_remove,
                                   button_repr_parameter_dialog]))
        return bbox

    def _make_widget_repr(self):
        self.widget_repr_name = Text(value='', description='representation')
        self.widget_repr_name._ngl_name = 'repr_name_text'
        repr_selection = Text(value=' ', description='selection')
        repr_selection._ngl_name = 'repr_selection'
        repr_selection.width = self.widget_repr_name.width = default.DEFAULT_TEXT_WIDTH 

        max_n_components = max(self._view.n_components-1, 0)
        self.widget_component_slider = IntSlider(value=0, max=max_n_components, min=0, description='component')
        self.widget_component_slider._ngl_name = 'component_slider'

        cvalue = ' '
        self.widget_component_dropdown = Dropdown(value=cvalue, options=[cvalue,],
                description='component')
        self.widget_component_dropdown._ngl_name = 'component_dropdown'

        self.widget_repr_slider = IntSlider(value=0, description='representation', width=default.DEFAULT_SLIDER_WIDTH)
        self.widget_repr_slider._ngl_name = 'repr_slider'
        self.widget_repr_slider.visible = True

        self.widget_component_slider.layout.width = default.DEFAULT_SLIDER_WIDTH
        self.widget_repr_slider.layout.width = default.DEFAULT_SLIDER_WIDTH
        self.widget_component_dropdown.layout.width = self.widget_component_dropdown.max_width = default.DEFAULT_TEXT_WIDTH

        # turn off for now
        self.widget_component_dropdown.layout.display = 'none'
        self.widget_component_dropdown.description = ''

        # self.widget_accordion_repr_parameters = Accordion()
        self.widget_accordion_repr_parameters = Tab()
        self.widget_repr_parameters =  self._make_widget_repr_parameters(self.widget_component_slider,
                self.widget_repr_slider,
                self.widget_repr_name)
        self.widget_accordion_repr_parameters.children = [self.widget_repr_parameters, Box()]
        self.widget_accordion_repr_parameters.set_title(0, 'Parameters')
        self.widget_accordion_repr_parameters.set_title(1, 'Hide')
        self.widget_accordion_repr_parameters.selected_index = 1
        
        checkbox_reprlist = Checkbox(value=False, description='reprlist')
        checkbox_reprlist._ngl_name = 'checkbox_reprlist'
        self.widget_repr_choices = self._make_repr_name_choices(self.widget_component_slider,
                self.widget_repr_slider)
        self.widget_repr_choices._ngl_name = 'reprlist_choices'

        self.widget_repr_add = self._make_add_widget_repr(self.widget_component_slider)

        def on_update_checkbox_reprlist(change):
            self.widget_repr_choices.visible= change['new']
        checkbox_reprlist.observe(on_update_checkbox_reprlist, names='value')

        def on_repr_name_text_value_changed(change):
            name = change['new'].strip()
            old = change['old'].strip()

            should_update = (self._real_time_update
                             and old and name
                             and name in REPRESENTATION_NAMES
                             and name != change['old'].strip())

            if should_update:
                component=self.widget_component_slider.value
                repr_index=self.widget_repr_slider.value
                self._view._remote_call('setRepresentation',
                                 target='Widget',
                                 args=[change['new'], {}, component, repr_index])
                self._view._request_repr_parameters(component, repr_index)

        def on_component_or_repr_slider_value_changed(change):
            self._view._request_repr_parameters(component=self.widget_component_slider.value,
                                                repr_index=self.widget_repr_slider.value)
            self.widget_component_dropdown.options = tuple(self._view._ngl_component_names)

            if self.widget_accordion_repr_parameters.selected_index >= 0:
                self.widget_repr_parameters.name = self.widget_repr_name.value
                self.widget_repr_parameters.repr_index = self.widget_repr_slider.value
                self.widget_repr_parameters.component_index = self.widget_component_slider.value

        def on_repr_selection_value_changed(change):
            if self._real_time_update:
                component = self.widget_component_slider.value
                repr_index = self.widget_repr_slider.value
                self._view._set_selection(change['new'],
                                          component=component,
                                          repr_index=repr_index)

        def on_change_component_dropdown(change):
            choice = change['new']
            if choice:
                 self.widget_component_slider.value = self._view._ngl_component_names.index(choice)

        self.widget_component_dropdown.observe(on_change_component_dropdown, names='value')

        self.widget_repr_slider.observe(on_component_or_repr_slider_value_changed, names='value')
        self.widget_component_slider.observe(on_component_or_repr_slider_value_changed, names='value')
        self.widget_repr_name.observe(on_repr_name_text_value_changed, names='value')
        repr_selection.observe(on_repr_selection_value_changed, names='value')

        self.widget_repr_control_buttons = self._make_button_repr_control(self.widget_component_slider,
        self.widget_repr_slider, repr_selection)

        blank_box = Box([Label("")])

        all_kids = [self.widget_repr_control_buttons,
                    blank_box,
                    self.widget_repr_add,
                    self.widget_component_dropdown,
                    self.widget_repr_name,
                    repr_selection,
                    self.widget_component_slider,
                    self.widget_repr_slider,
                    self.widget_repr_choices,
                    self.widget_accordion_repr_parameters
        ]

        vbox = VBox(all_kids)

        self._view._request_repr_parameters(component=self.widget_component_slider.value,
            repr_index=self.widget_repr_slider.value)

        self.widget_repr = _relayout_master(vbox, width='100%')

        self._refresh(self.widget_component_slider, self.widget_repr_slider)

        setattr(self.widget_repr, "_saved_widgets", [])
        for _box in self.widget_repr.children:
            if hasattr(_box, 'children'):
                for kid in _box.children:
                    self.widget_repr._saved_widgets.append(kid)

        return self.widget_repr

    def _make_widget_repr_parameters(self, component_slider, repr_slider, repr_name_text=None):
        name = repr_name_text.value if repr_name_text is not None else ' '
        widget = self._view._display_repr(component=component_slider.value,
                                          repr_index=repr_slider.value,
                                          name=name)
        widget._ngl_name = 'repr_parameters_box'
        return widget

    def _make_button_export_image(self):
        slider_factor = IntSlider(value=4, min=1, max=10, description='scale')
        checkbox_antialias = Checkbox(value=True, description='antialias')
        checkbox_trim = Checkbox(value=False, description='trim')
        checkbox_transparent = Checkbox(value=False, description='transparent')
        filename_text = Text(value='Screenshot', description='Filename')
        delay_text = FloatText(value=1, description='delay (s)', tooltip='hello')

        start_text, stop_text, step_text = (IntText(value=0, description='start'),
                                            IntText(value=self._view.count, description='stop'),
                                            IntText(value=1, description='step'))

        start_text.layout.max_width = stop_text.layout.max_width = step_text.layout.max_width \
                = filename_text.layout.max_width = delay_text.layout.max_width = default.DEFAULT_TEXT_WIDTH

        button_movie_images = Button(description='Export Images')
        def download_image(filename):
            self._view.download_image(factor=slider_factor.value,
                    antialias=checkbox_antialias.value,
                    trim=checkbox_trim.value,
                    transparent=checkbox_transparent.value,
                    filename=filename)

        @button_movie_images.on_click
        def on_click_images(button_movie_images):
            for i in range(start_text.value, stop_text.value, step_text.value):
                self._view.frame = i
                time.sleep(delay_text.value)
                download_image(filename=filename_text.value + str(i))
                time.sleep(delay_text.value)

        vbox = VBox([
            button_movie_images,
            start_text,
            stop_text,
            step_text,
            delay_text,
            filename_text,
            slider_factor,
            checkbox_antialias,
            checkbox_trim,
            checkbox_transparent,
            ])

        form_items = _relayout(vbox, make_form_item_layout())
        form = Box(form_items, layout=_make_box_layout())
        # form = _relayout_master(vbox)
        return form

    def _make_resize_notebook_slider(self):
        resize_notebook_slider = IntSlider(min=300, max=2000, description='resize notebook')
        def on_resize_notebook(change):
            width = change['new']
            self._view._remote_call('resizeNotebook',
                    target='Widget',
                    args=[width,])
        resize_notebook_slider.observe(on_resize_notebook, names='value')
        return resize_notebook_slider

    def _make_add_widget_repr(self, component_slider):
        dropdown_repr_name = Dropdown(options=REPRESENTATION_NAMES, value='cartoon')
        repr_selection = Text(value='*', description='')
        repr_button = Button(description='Add', tooltip="""Add representation.
        You can also hit Enter in selection box""")
        repr_button.layout = Layout(width='auto', flex='1 1 auto')

        dropdown_repr_name.layout.width = repr_selection.layout.width = default.DEFAULT_TEXT_WIDTH

        def on_click_or_submit(button_or_text_area):
            self._view.add_representation(selection=repr_selection.value.strip(),
                    repr_type=dropdown_repr_name.value,
                    component=component_slider.value)

        repr_button.on_click(on_click_or_submit)
        repr_selection.on_submit(on_click_or_submit)
        add_repr_box = HBox([repr_button, dropdown_repr_name, repr_selection])
        add_repr_box._ngl_name = 'add_repr_box'

        return add_repr_box

    def _make_repr_playground(self):
        vbox = VBox()
        children = []

        rep_names = REPRESENTATION_NAMES[:]
        excluded_names = ['ball+stick', 'distance']
        for name in excluded_names:
            rep_names.remove(name)

        repr_selection = Text(value='*')
        repr_selection.layout.width = default.DEFAULT_TEXT_WIDTH
        repr_selection_box  = HBox([Label('selection'), repr_selection])
        setattr(repr_selection_box, 'value', repr_selection.value)

        for index, name in enumerate(rep_names):
            button = ToggleButton(description=name)

            def make_func():
                def on_toggle_button_value_change(change, button=button):
                    selection = repr_selection.value
                    new = change['new'] # True/False
                    if new:
                        self._view.add_representation(button.description, selection=selection)
                    else:
                        self._view._remove_representations_by_name(button.description)
                return on_toggle_button_value_change

            button.observe(make_func(), names='value')
            children.append(button)

        button_clear = Button(description='clear', button_style='info',
                icon='fa-eraser')

        @button_clear.on_click
        def on_clear(button_clear):
            self._view.clear()
            for kid in children:
                # unselect
                kid.value = False

        vbox.children = children + [repr_selection, button_clear]
        _make_autofit(vbox)
        self.widget_quick_repr = vbox
        return self.widget_quick_repr

    def _make_repr_name_choices(self, component_slider, repr_slider):
        repr_choices = Dropdown(options=[" ",])

        def on_chose(change):
            repr_name = change['new']
            repr_index = repr_choices.options.index(repr_name)
            repr_slider.value = repr_index

        repr_choices.observe(on_chose, names='value')
        repr_choices.layout.width = default.DEFAULT_TEXT_WIDTH

        self.widget_repr_choices = repr_choices
        return self.widget_repr_choices

    def _make_drag_widget(self):
        button_drag = Button(description='widget drag: off', tooltip='dangerous')
        drag_nb = Button(description='notebook drag: off', tooltip='dangerous')
        button_reset_notebook = Button(description='notebook: reset', tooltip='reset?')
        button_dialog = Button(description='dialog', tooltip='make a dialog')
        button_split_half = Button(description='split screen', tooltip='try best to make a good layout')

        @button_drag.on_click
        def on_drag(button_drag):
            if button_drag.description == 'widget drag: off':
                self._view._set_draggable(True)
                button_drag.description = 'widget drag: on'
            else:
                self._view._set_draggable(False)
                button_drag.description = 'widget drag: off'

        @drag_nb.on_click
        def on_drag_nb(button_drag):
            if drag_nb.description == 'notebook drag: off':
                js_utils._set_notebook_draggable(True)
                drag_nb.description = 'notebook drag: on'
            else:
                js_utils._set_notebook_draggable(False)
                drag_nb.description = 'notebook drag: off'

        @button_reset_notebook.on_click
        def on_reset(button_reset_notebook):
            js_utils._reset_notebook()

        @button_dialog.on_click
        def on_dialog(button_dialog):
            self._view._remote_call('setDialog', target='Widget')

        @button_split_half.on_click
        def on_split_half(button_dialog):
            from nglview import js_utils
            import time
            js_utils._move_notebook_to_the_left()
            js_utils._set_notebook_width('5%')
            time.sleep(0.1)
            self._view._remote_call('setDialog', target='Widget')

        drag_box = HBox([button_drag, drag_nb, button_reset_notebook,
                        button_dialog, button_split_half])
        drag_box = _make_autofit(drag_box)
        self.widget_drag = drag_box
        return drag_box

    def _make_spin_box(self):
        checkbox_spin = Checkbox(self.spin, description='spin')
        spin_x_slide = IntSlider(
            self._spin_x,
            min=-1,
            max=1,
            description='spin_x')
        spin_y_slide = IntSlider(
            self._spin_y,
            min=-1,
            max=1,
            description='spin_y')
        spin_z_slide = IntSlider(
            self._spin_z,
            min=-1,
            max=1,
            description='spin_z')
        spin_speed_slide = FloatSlider(
            self._spin_speed,
            min=0,
            max=0.2,
            step=0.001,
            description='spin speed')
        # spin
        link((checkbox_spin, 'value'), (self, 'spin'))
        link((spin_x_slide, 'value'), (self, '_spin_x'))
        link((spin_y_slide, 'value'), (self, '_spin_y'))
        link((spin_z_slide, 'value'), (self, '_spin_z'))
        link((spin_speed_slide, 'value'), (self, '_spin_speed'))

        spin_box= VBox([checkbox_spin,
                   spin_x_slide,
                   spin_y_slide,
                   spin_z_slide,
                   spin_speed_slide])
        spin_box = _relayout_master(spin_box, width='75%')
        return spin_box

    def _make_widget_picked(self):
        self.widget_picked = self._make_text_picked()
        picked_box = HBox([self.widget_picked,])
        return _relayout_master(picked_box, width='75%')

    def _make_export_image_widget(self):
        if self.widget_export_image is None:
            self.widget_export_image = HBox([self._make_button_export_image()])
        return self.widget_export_image

    def _make_extra_box(self):
        if self.widget_extra is None:
            extra_list = [(self._make_drag_widget, 'Drag'),
                          (self._make_spin_box, 'Spin'),
                          (self._make_widget_picked, 'Picked'),
                          (self._make_repr_playground, 'Quick'),
                          (self._make_export_image_widget, 'Image'),
                          (self._make_command_box, 'Command')]

            extra_box = _make_delay_tab(extra_list, selected_index=0)
            self.widget_extra = extra_box
        return self.widget_extra

    def _make_theme_box(self):
        if self.widget_theme is None:
            self.widget_theme = Box([self._make_button_theme(),
                                     self._make_button_reset_theme(hide_toolbar=False),
                                     self._make_button_reset_theme(hide_toolbar=True),
                                     self._make_button_clean_error_output()])
        return self.widget_theme

    def _make_general_box(self):
        if self.widget_general is None:
            step_slide = IntSlider(
                value=self.step,
                min=-100,
                max=100,
                description='step')
            delay_text = IntSlider(
                value=self.delay,
                min=10,
                max=1000,
                description='delay')
            toggle_button_interpolate = ToggleButton(self.interpolate, description='Smoothing',
                                                     tooltip='smoothing trajectory')
            link((toggle_button_interpolate, 'value'), (self, 'interpolate'))

            background_color_picker = ColorPicker(value='white', description='background')
            camera_type = Dropdown(value=self.camera,
                                   options=['perspective', 'orthographic'], description='camera')

            link((step_slide, 'value'), (self, 'step'))
            link((delay_text, 'value'), (self, 'delay'))
            link((toggle_button_interpolate, 'value'), (self, 'interpolate'))
            link((camera_type, 'value'), (self, 'camera'))
            link((background_color_picker, 'value'), (self._view, 'background'))

            center_button = self._make_button_center()
            render_button = self._show_download_image()
            qtconsole_button = self._make_button_qtconsole()
            center_render_hbox = _make_autofit(HBox([toggle_button_interpolate, center_button,
                                                     render_button, qtconsole_button]))

            v0_left = VBox([step_slide,
                       delay_text,
                       background_color_picker,
                       camera_type,
                       center_render_hbox,
                       ])

            v0_left = _relayout_master(v0_left, width='100%')
            self.widget_general = v0_left
        return self.widget_general

    def _make_command_box(self):
        widget_text_command = Text()

        @widget_text_command.on_submit
        def _on_submit_command(_):
            command = widget_text_command.value
            js_utils.execute(command)
            widget_text_command.value = ''
        return widget_text_command

    def _create_all_tabs(self):
        tab = self._display()
        for index, _ in enumerate(tab.children):
            # trigger ceating widgets
            tab.selected_index = index

        self.widget_extra = self._make_extra_box()
        for index, _ in enumerate(self.widget_extra.children):
            self.widget_extra.selected_index = index

    def _simplify_repr_control(self):
        for widget in self.widget_repr._saved_widgets:
            if not isinstance(widget, Tab):
                widget.layout.display = 'none'
        self.widget_repr_choices.layout.display = 'flex'
        self.widget_accordion_repr_parameters.selected_index = 0
Esempio n. 12
0
class ExplorerReports(ExplorerPane):
    def __init__(self, es: ExplorerThresholds, parent_widget=None):
        super().__init__(parent_widget=parent_widget)
        self.selector = es
        self.report_picker = Dropdown(
            options=[
                ' ', _report_picker_current_selection,
                _report_picker_build_nobuild, 'Other Report'
            ],
            value=' ',
            description='Choose:',
            disabled=False,
        )
        self.report_picker.observe(self.report_picker_action)

        self.second_picker = Dropdown(
            options=(" ", ),
            value=' ',
            description=" ",
            disabled=False,
        )
        self.second_picker.layout.visibility = 'hidden'

        self.report_pane = Output(layout=Layout(width='7.5in', ), )
        self.make_stack(
            self.report_picker,
            self.second_picker,
            self.report_pane,
        )

        self.next_button.disabled = True

    def redraw_with_no_second_picker(self):
        self.second_picker.layout.visibility = 'hidden'

    def redraw_with_bnb_picker(self, second_options=(' ', ), label="Choose:"):

        # self.second_picker = Dropdown(
        # 	options=second_options,
        # 	description=label,
        # 	disabled=True,
        # )
        #
        self.second_picker.layout.visibility = 'visible'

        self.second_picker.options = (' ', ) + tuple(second_options)

        self.second_picker.description = "Strategy:"

        #
        # self.stack = VBox([
        # 	self.report_picker,
        # 	self.second_picker,
        # 	self.report_pane,
        # ])

        self.second_picker.observe(self.bnb_picker_action)

    def report_picker_action(self, action_content):
        if 'name' in action_content and action_content['name'] == 'value':
            if 'new' in action_content:
                if action_content['new'] == _report_picker_current_selection:
                    self.redraw_with_no_second_picker()
                    self.report_pane.clear_output(wait=True)
                    single_report(self.selector, output_to=self.report_pane)
                elif action_content['new'] == _report_picker_build_nobuild:
                    # self.report_pane.clear_output(wait=True)
                    # build_no_build_report(self.selector, output_to=self.report_pane)
                    self.redraw_with_bnb_picker(
                        second_options=self.selector.data.strategy_names)
                else:
                    self.report_pane.clear_output(wait=True)
                    with self.report_pane:
                        print(
                            f"{action_content['new']} is not implemented in this version of Explorer"
                        )

    def bnb_picker_action(self, action_content):
        if 'name' in action_content and action_content['name'] == 'value':
            if 'new' in action_content:
                if action_content['new'] == " ":
                    self.report_pane.clear_output()
                else:
                    self.report_pane.clear_output(wait=True)
                    build_no_build_report(self.selector,
                                          bnb=action_content['new'],
                                          output_to=self.report_pane)
Esempio n. 13
0
            datetime.now(), kwargs['coordinates'], random.randint(
                -20, 20), random.randint(0, 100))
        out.value = add_log(msg)


m.on_interaction(handle_interaction)


def on_map_selected(change):
    m.layers = [
        basemap_to_tiles(maps[basemap_selector.value]),
        weather_maps[heatmap_selector.value]
    ]


basemap_selector.observe(on_map_selected, names='value')
heatmap_selector.observe(on_map_selected, names='value')

# In[18]:

temp = TileLayer(
    min_zoom=1,
    max_zoom=18,
    url='https://tile.openweathermap.org/map/temp_new/{z}/{x}/{y}.png?appid=' +
    OWM_API_KEY,
    name='owm',
    attribute='me')
precipitation = TileLayer(
    min_zoom=1,
    max_zoom=18,
    url=
Esempio n. 14
0
def time_series_widget(aoi, year, pid):

    path = normpath(
        join(config.get_value(['paths', 'temp']), aoi, str(year), str(pid)))
    # confvalues = config.read()
    # inst = confvalues['set']['institution']
    file_info = normpath(join(path, 'info.json'))

    with open(file_info, 'r') as f:
        info_data = json.loads(f.read())
    pid = info_data['pid'][0]

    ts_cloud = Checkbox(value=True,
                        description='Cloud free',
                        disabled=False,
                        indent=False)

    ts_files = glob.glob(normpath(join(path, '*time_series*.csv')))
    ts_file_types = [b.split('_')[-1].split('.')[0] for b in ts_files]
    if 's2' in ts_file_types:
        ts_file_types.append('ndvi')
    ts_types = [t for t in data_options.pts_tstype() if t[1] in ts_file_types]

    ts_type = Dropdown(
        options=ts_types,
        description='Select type:',
        disabled=False,
    )

    btn_ts = Button(value=False,
                    description='Plot TS',
                    disabled=False,
                    button_style='info',
                    tooltip='Refresh output',
                    icon='')

    ts_out = Output()

    @btn_ts.on_click
    def btn_ts_on_click(b):
        btn_ts.description = 'Refresh'
        btn_ts.icon = 'refresh'
        with ts_out:
            ts_out.clear_output()
            if ts_type.value == 's2':
                time_series.s2(aoi, str(year), str(pid), bands=['B4', 'B8'])
            elif ts_type.value == 'ndvi':
                time_series.ndvi(aoi, str(year), str(pid))
            elif ts_type.value == 'bs':
                time_series.s1(aoi, str(year), str(pid), 'bs')
            elif ts_type.value == 'c6':
                time_series.s1(aoi, str(year), str(pid), 'c6')

    def on_ts_type_change(change):
        if ts_type.value == 's2':
            wbox_ts.children = [btn_ts, ts_type]
        else:
            wbox_ts.children = [btn_ts, ts_type]

    ts_type.observe(on_ts_type_change, 'value')

    wbox_ts = HBox([btn_ts, ts_type, ts_cloud])

    wbox = VBox([wbox_ts, ts_out])

    return wbox
Esempio n. 15
0
class TrafficWidget(object):

    # -- Constructor --
    def __init__(self, traffic: Traffic, projection=EuroPP()) -> None:

        ipython = get_ipython()
        ipython.magic("matplotlib ipympl")
        from ipympl.backend_nbagg import FigureCanvasNbAgg, FigureManagerNbAgg

        self.fig_map = Figure(figsize=(6, 6))
        self.fig_time = Figure(figsize=(6, 4))

        self.canvas_map = FigureCanvasNbAgg(self.fig_map)
        self.canvas_time = FigureCanvasNbAgg(self.fig_time)

        self.manager_map = FigureManagerNbAgg(self.canvas_map, 0)
        self.manager_time = FigureManagerNbAgg(self.canvas_time, 0)

        layout = {"width": "590px", "height": "800px", "border": "none"}
        self.output = Output(layout=layout)

        self._traffic = traffic
        self.t_view = traffic.sort_values("timestamp")
        self.trajectories: Dict[str, List[Artist]] = defaultdict(list)

        self.create_map(projection)

        self.projection = Dropdown(options=["EuroPP", "Lambert93", "Mercator"])
        self.projection.observe(self.on_projection_change)

        self.identifier_input = Text(description="Callsign/ID")
        self.identifier_input.observe(self.on_id_input)

        self.identifier_select = SelectMultiple(
            options=sorted(self._traffic.callsigns),  # type: ignore
            value=[],
            rows=20,
        )
        self.identifier_select.observe(self.on_id_change)

        self.area_input = Text(description="Area")
        self.area_input.observe(self.on_area_input)

        self.extent_button = Button(description="Extent")
        self.extent_button.on_click(self.on_extent_button)

        self.plot_button = Button(description="Plot")
        self.plot_button.on_click(self.on_plot_button)

        self.clear_button = Button(description="Reset")
        self.clear_button.on_click(self.on_clear_button)

        self.plot_airport = Button(description="Airport")
        self.plot_airport.on_click(self.on_plot_airport)

        self.area_select = SelectMultiple(options=[],
                                          value=[],
                                          rows=3,
                                          disabled=False)
        self.area_select.observe(self.on_area_click)

        self.altitude_select = SelectionRangeSlider(
            options=[0, 5000, 10000, 15000, 20000, 25000, 30000, 35000, 40000],
            index=(0, 8),
            description="Altitude",
            disabled=False,
            continuous_update=False,
        )
        self.altitude_select.observe(self.on_altitude_select)

        self.time_slider = SelectionRangeSlider(
            options=list(range(100)),
            index=(0, 99),
            description="Date",
            continuous_update=False,
        )
        self.lock_time_change = False
        self.set_time_range()

        self.time_slider.observe(self.on_time_select)
        self.canvas_map.observe(self.on_axmap_change,
                                ["_button", "_png_is_old"])
        self.canvas_time.observe(self.on_axtime_change, ["_png_is_old"])

        col_options = []
        for column, dtype in self._traffic.data.dtypes.items():
            if column not in ("latitude", "longitude"):
                if dtype in ["float64", "int64"]:
                    col_options.append(column)

        self.y_selector = SelectMultiple(options=col_options,
                                         value=[],
                                         rows=5,
                                         disabled=False)
        self.y_selector.observe(self.on_id_change)

        self.sec_y_selector = SelectMultiple(options=col_options,
                                             value=[],
                                             rows=5,
                                             disabled=False)
        self.sec_y_selector.observe(self.on_id_change)

        self.time_tab = VBox(
            [HBox([self.y_selector, self.sec_y_selector]), self.canvas_time])

        self.tabs = Tab()
        self.tabs.children = [self.canvas_map, self.time_tab]
        self.tabs.set_title(0, "Map")
        self.tabs.set_title(1, "Plots")

        self._main_elt = HBox([
            self.tabs,
            VBox([
                self.projection,
                HBox([self.extent_button, self.plot_button]),
                HBox([self.plot_airport, self.clear_button]),
                self.area_input,
                self.area_select,
                self.time_slider,
                self.altitude_select,
                self.identifier_input,
                self.identifier_select,
            ]),
        ])

    @property
    def traffic(self) -> Traffic:
        return self._traffic

    def _ipython_display_(self) -> None:
        clear_output()
        self.canvas_map.draw_idle()
        self._main_elt._ipython_display_()

    def debug(self) -> None:
        if self.tabs.children[-1] != self.output:
            self.tabs.children = list(self.tabs.children) + [self.output]

    def set_time_range(self) -> None:
        with self.output:
            tz_now = datetime.now().astimezone().tzinfo
            start_time = cast(pd.Timestamp, self._traffic.start_time)
            end_time = cast(pd.Timestamp, self._traffic.end_time)
            self.dates = [
                start_time + i * (end_time - start_time) / 99
                for i in range(100)
            ]
            if cast(pd.Timestamp, self._traffic.start_time).tzinfo is not None:
                options = [
                    t.tz_convert("utc").strftime("%H:%M") for t in self.dates
                ]
            else:
                options = [
                    t.tz_localize(tz_now).tz_convert("utc").strftime("%H:%M")
                    for t in self.dates
                ]

            self.lock_time_change = True
            self.time_slider.options = options
            self.time_slider.index = (0, 99)
            self.lock_time_change = False

    def create_map(self,
                   projection: Union[str, Projection] = "EuroPP()") -> None:
        with self.output:
            if isinstance(projection, str):
                if not projection.endswith("()"):
                    projection = projection + "()"
                projection = eval(projection)

            self.projection = projection

            with plt.style.context("traffic"):

                self.fig_map.clear()
                self.trajectories.clear()
                self.ax_map = self.fig_map.add_subplot(
                    111, projection=self.projection)
                self.ax_map.add_feature(countries())
                if projection.__class__.__name__.split(".")[-1] in [
                        "Lambert93"
                ]:
                    self.ax_map.add_feature(rivers())

                self.fig_map.set_tight_layout(True)
                self.ax_map.background_patch.set_visible(False)
                self.ax_map.outline_patch.set_visible(False)
                self.ax_map.format_coord = lambda x, y: ""
                self.ax_map.set_global()

            self.default_plot()
            self.canvas_map.draw_idle()

    def default_plot(self) -> None:
        with self.output:
            # clear all trajectory pieces
            for key, value in self.trajectories.items():
                for elt in value:
                    elt.remove()
            self.trajectories.clear()
            self.ax_map.set_prop_cycle(None)

            lon_min, lon_max, lat_min, lat_max = self.ax_map.get_extent(
                PlateCarree())
            cur_flights = list(
                f.at() for f in self.t_view
                if lat_min <= getattr(f.at(), "latitude", -90) <= lat_max
                and lon_min <= getattr(f.at(), "longitude", -180) <= lon_max)

            def params(at):
                if len(cur_flights) < 10:
                    return dict(s=8, text_kw=dict(s=at.callsign))
                else:
                    return dict(s=8, text_kw=dict(s=""))

            for at in cur_flights:
                if at is not None:
                    self.trajectories[at.callsign] += at.plot(
                        self.ax_map, **params(at))

            self.canvas_map.draw_idle()

    def create_timeplot(self) -> None:
        with plt.style.context("traffic"):
            self.fig_time.clear()
            self.ax_time = self.fig_time.add_subplot(111)
            self.fig_time.set_tight_layout(True)

    # -- Callbacks --

    def on_projection_change(self, change: Dict[str, Any]) -> None:
        with self.output:
            if change["name"] == "value":
                self.create_map(change["new"])

    def on_clear_button(self, elt: Dict[str, Any]) -> None:
        with self.output:
            self.t_view = self.traffic.sort_values("timestamp")
            self.create_map(self.projection)
            self.create_timeplot()

    def on_area_input(self, elt: Dict[str, Any]) -> None:
        with self.output:
            if elt["name"] != "value":
                return
            search_text = elt["new"]
            if len(search_text) == 0:
                self.area_select.options = list()
            else:
                from ..data import nm_airspaces

                self.area_select.options = list(
                    x.name for x in nm_airspaces.parse(search_text))

    def on_area_click(self, elt: Dict[str, Any]) -> None:
        with self.output:
            if elt["name"] != "value":
                return
            from ..data import nm_airspaces

            self.ax_map.set_extent(nm_airspaces[elt["new"][0]])
            self.canvas_map.draw_idle()

    def on_extent_button(self, elt: Dict[str, Any]) -> None:
        with self.output:
            if len(self.area_select.value) == 0:
                if len(self.area_input.value) == 0:
                    self.ax_map.set_global()
                else:
                    self.ax_map.set_extent(location(self.area_input.value))
            else:
                from ..data import nm_airspaces

                self.ax_map.set_extent(nm_airspaces[self.area_select.value[0]])

            t1, t2 = self.time_slider.index
            low, up = self.altitude_select.value
            self.on_filter(low, up, t1, t2)
            self.canvas_map.draw_idle()

    def on_axtime_change(self, change: Dict[str, Any]) -> None:
        with self.output:
            if change["name"] == "_png_is_old":
                # go away!!
                return self.canvas_map.set_window_title("")

    def on_axmap_change(self, change: Dict[str, Any]) -> None:
        with self.output:
            if change["name"] == "_png_is_old":
                # go away!!
                return self.canvas_map.set_window_title("")
            if change["new"] is None:
                t1, t2 = self.time_slider.index
                low, up = self.altitude_select.value
                self.on_filter(low, up, t1, t2)

    def on_id_input(self, elt: Dict[str, Any]) -> None:
        with self.output:
            # typing issue because of the lru_cache_wrappen
            callsigns = cast(Set[str], self.t_view.callsigns)
            # low, up = alt.value
            self.identifier_select.options = sorted(
                callsign for callsign in callsigns if re.match(
                    elt["new"]["value"], callsign, flags=re.IGNORECASE))

    def on_plot_button(self, elt: Dict[str, Any]) -> None:
        with self.output:
            if len(self.area_select.value) == 0:
                if len(self.area_input.value) == 0:
                    return self.default_plot()
                location(self.area_input.value).plot(self.ax_map,
                                                     color="grey",
                                                     linestyle="dashed")
            else:
                from ..data import nm_airspaces

                airspace = nm_airspaces[self.area_select.value[0]]
                if airspace is not None:
                    airspace.plot(self.ax_map)
            self.canvas_map.draw_idle()

    def on_plot_airport(self, elt: Dict[str, Any]) -> None:
        with self.output:
            if len(self.area_input.value) == 0:
                from cartotools.osm import request, tags

                west, east, south, north = self.ax_map.get_extent(
                    crs=PlateCarree())
                if abs(east - west) > 1 or abs(north - south) > 1:
                    # that would be a too big request
                    return
                request((west, south, east, north),
                        **tags.airport).plot(self.ax_map)
            else:
                from ..data import airports

                airport_handle = airports[self.area_input.value]
                assert airport_handle is not None
                airport_handle.plot(self.ax_map)
            self.canvas_map.draw_idle()

    def on_id_change(self, change: Dict[str, Any]) -> None:
        with self.output:
            if change["name"] != "value":
                return

            y = self.y_selector.value + self.sec_y_selector.value
            secondary_y = self.sec_y_selector.value
            callsigns = self.identifier_select.value

            if len(y) == 0:
                y = ["altitude"]
            extra_dict = dict()
            if len(y) > 1:
                # just to avoid confusion...
                callsigns = callsigns[:1]

            # clear all trajectory pieces
            self.create_timeplot()
            for key, value in self.trajectories.items():
                for elt in value:
                    elt.remove()
            self.trajectories.clear()

            for callsign in callsigns:
                flight = self.t_view[callsign]
                if len(y) == 1:
                    extra_dict["label"] = callsign
                if flight is not None:
                    try:
                        self.trajectories[callsign] += flight.plot(self.ax_map)
                        at = flight.at()
                        if at is not None:
                            self.trajectories[callsign] += at.plot(
                                self.ax_map, s=8, text_kw=dict(s=callsign))
                    except Exception:  # NoneType object is not iterable
                        pass

                    try:
                        flight.plot_time(
                            self.ax_time,
                            y=y,
                            secondary_y=secondary_y,
                            **extra_dict,
                        )
                    except Exception:  # no numeric data to plot
                        pass

            if len(callsigns) == 0:
                self.default_plot()
            else:
                self.ax_time.legend()

            # non conformal with traffic style
            for elt in self.ax_time.get_xticklabels():
                elt.set_size(12)
            for elt in self.ax_time.get_yticklabels():
                elt.set_size(12)
            self.ax_time.set_xlabel("")

            self.canvas_map.draw_idle()
            self.canvas_time.draw_idle()

            if len(callsigns) != 0:
                low, up = self.ax_time.get_ylim()
                if (up - low) / up < 0.05:
                    self.ax_time.set_ylim(up - 0.05 * up, up + 0.05 * up)
                    self.canvas_time.draw_idle()

    def on_filter(self, low, up, t1, t2) -> None:
        with self.output:
            west, east, south, north = self.ax_map.get_extent(
                crs=PlateCarree())

            self.t_view = (self.traffic.between(
                self.dates[t1], self.dates[t2]).query(
                    f"{low} <= altitude <= {up} or altitude != altitude"
                ).query(
                    f"{west} <= longitude <= {east} and "
                    f"{south} <= latitude <= {north}").sort_values("timestamp")
                           )
            self.identifier_select.options = sorted(
                flight.callsign for flight in self.t_view
                if flight is not None and re.match(
                    self.identifier_input.value,
                    flight.callsign,
                    flags=re.IGNORECASE,
                ))
            return self.default_plot()

    def on_altitude_select(self, change: Dict[str, Any]) -> None:
        with self.output:
            if change["name"] != "value":
                return

            low, up = change["new"]
            t1, t2 = self.time_slider.index
            self.on_filter(low, up, t1, t2)

    def on_time_select(self, change: Dict[str, Any]) -> None:
        with self.output:
            if self.lock_time_change:
                return
            if change["name"] != "index":
                return
            t1, t2 = change["new"]
            low, up = self.altitude_select.value
            self.on_filter(low, up, t1, t2)
Esempio n. 16
0
def time_series(path):
    import matplotlib.pyplot as plt
    import matplotlib.dates as mdates
    from datetime import timedelta
    import pandas as pd
    import json
    import glob

    confvalues = config.read()
    inst = confvalues['set']['institution']
    file_info = glob.glob(f"{path}*_information.json")[0]

    with open(file_info, 'r') as f:
        info_data = json.loads(f.read())
    pid = info_data['ogc_fid'][0]
    crop_name = info_data['cropname'][0]
    area = info_data['area'][0]
    figure_dpi = 50

    def plot_ts_s2(cloud):
        file_ts = glob.glob(f"{path}*_time_series_s2.csv")[0]
        df = pd.read_csv(file_ts, index_col=0)

        df['date'] = pd.to_datetime(df['date_part'], unit='s')
        start_date = df.iloc[0]['date'].date()
        end_date = df.iloc[-1]['date'].date()
        print(f"From '{start_date}' to '{end_date}'.")

        pd.set_option('max_colwidth', 200)
        pd.set_option('display.max_columns', 20)

        # Plot settings are confirm IJRS graphics instructions
        plt.rcParams['axes.titlesize'] = 16
        plt.rcParams['axes.labelsize'] = 14
        plt.rcParams['xtick.labelsize'] = 12
        plt.rcParams['ytick.labelsize'] = 12
        plt.rcParams['legend.fontsize'] = 14

        df.set_index(['date'], inplace=True)

        dfB4 = df[df.band == 'B4'].copy()
        dfB8 = df[df.band == 'B8'].copy()
        datesFmt = mdates.DateFormatter('%-d %b %Y')
        if cloud is False:
            # Plot NDVI
            fig = plt.figure(figsize=(16.0, 10.0))
            axb = fig.add_subplot(1, 1, 1)

            axb.set_title(
                f"Parcel {pid} (crop: {crop_name}, area: {area:.2f} ha)")
            axb.set_xlabel("Date")
            axb.xaxis.set_major_formatter(datesFmt)

            axb.set_ylabel(r'DN')
            axb.plot(dfB4.index,
                     dfB4['mean'],
                     linestyle=' ',
                     marker='s',
                     markersize=10,
                     color='DarkBlue',
                     fillstyle='none',
                     label='B4')
            axb.plot(dfB8.index,
                     dfB8['mean'],
                     linestyle=' ',
                     marker='o',
                     markersize=10,
                     color='Red',
                     fillstyle='none',
                     label='B8')

            axb.set_xlim(start_date, end_date + timedelta(1))
            axb.set_ylim(0, 10000)

            axb.legend(frameon=False)  # loc=2)

            return plt.show()

        else:
            # Plot Cloud free NDVI.
            dfSC = df[df.band == 'SC'].copy()
            dfNDVI = (dfB8['mean'] - dfB4['mean']) / \
                (dfB8['mean'] + dfB4['mean'])

            cloudfree = ((dfSC['mean'] >= 4) & (dfSC['mean'] < 6))

            fig = plt.figure(figsize=(16.0, 10.0))
            axb = fig.add_subplot(1, 1, 1)

            axb.set_title(
                f"{inst}\nParcel {pid} (crop: {crop_name}, area: {area:.2f} sqm)"
            )

            axb.set_xlabel("Date")
            axb.xaxis.set_major_formatter(datesFmt)

            axb.set_ylabel(r'NDVI')
            axb.plot(dfNDVI.index,
                     dfNDVI,
                     linestyle=' ',
                     marker='s',
                     markersize=10,
                     color='DarkBlue',
                     fillstyle='none',
                     label='NDVI')
            axb.plot(dfNDVI[cloudfree].index,
                     dfNDVI[cloudfree],
                     linestyle=' ',
                     marker='P',
                     markersize=10,
                     color='Red',
                     fillstyle='none',
                     label='Cloud free NDVI')

            axb.set_xlim(start_date, end_date + timedelta(1))
            axb.set_ylim(0, 1.0)

            axb.legend(frameon=False)  # loc=2)

            return plt.show()

    def plot_ts_bs():
        import numpy as np
        file_ts = glob.glob(f"{path}*_time_series_bs.csv")[0]
        df = pd.read_csv(file_ts, index_col=0)

        df['date'] = pd.to_datetime(df['date_part'], unit='s')
        start_date = df.iloc[0]['date'].date()
        end_date = df.iloc[-1]['date'].date()
        print(f"From '{start_date}' to '{end_date}'.")

        pd.set_option('max_colwidth', 200)
        pd.set_option('display.max_columns', 20)

        # Plot settings are confirm IJRS graphics instructions
        plt.rcParams['axes.titlesize'] = 16
        plt.rcParams['axes.labelsize'] = 14
        plt.rcParams['xtick.labelsize'] = 12
        plt.rcParams['ytick.labelsize'] = 12
        plt.rcParams['legend.fontsize'] = 14

        df.set_index(['date'], inplace=True)
        datesFmt = mdates.DateFormatter('%-d %b %Y')
        # Plot Backscattering coefficient

        datesFmt = mdates.DateFormatter('%-d %b %Y')
        df = df[df['mean'] >= 0]  # to remove negative values

        dfVV = df[df.band == 'VV'].copy()
        dfVH = df[df.band == 'VH'].copy()
        fig = plt.figure(figsize=(16.0, 10.0))
        axb = fig.add_subplot(1, 1, 1)

        dfVV['mean'] = dfVV['mean'].map(lambda s: 10.0 * np.log10(s))
        dfVH['mean'] = dfVH['mean'].map(lambda s: 10.0 * np.log10(s))

        axb.set_title(
            f"{inst}\nParcel {pid} (crop: {crop_name}, area: {area:.2f} sqm)")
        axb.set_xlabel("Date")
        axb.xaxis.set_major_formatter(datesFmt)

        axb.set_ylabel(r'Backscattering coefficient, $\gamma\degree$ (dB)')
        axb.plot(dfVH.index,
                 dfVH['mean'],
                 linestyle=' ',
                 marker='s',
                 markersize=10,
                 color='DarkBlue',
                 fillstyle='none',
                 label='VH')
        axb.plot(dfVV.index,
                 dfVV['mean'],
                 linestyle=' ',
                 marker='o',
                 markersize=10,
                 color='Red',
                 fillstyle='none',
                 label='VV')

        axb.set_xlim(start_date, end_date + timedelta(1))
        axb.set_ylim(-25, 0)

        axb.legend(frameon=False)  # loc=2)

        return plt.show()

    def plot_ts_c6():
        file_ts = glob.glob(f"{path}*_time_series_c6.csv")[0]
        df = pd.read_csv(file_ts, index_col=0)

        df['date'] = pd.to_datetime(df['date_part'], unit='s')
        start_date = df.iloc[0]['date'].date()
        end_date = df.iloc[-1]['date'].date()
        print(f"From '{start_date}' to '{end_date}'.")

        pd.set_option('max_colwidth', 200)
        pd.set_option('display.max_columns', 20)
        datesFmt = mdates.DateFormatter('%-d %b %Y')

        # Plot settings are confirm IJRS graphics instructions
        plt.rcParams['axes.titlesize'] = 16
        plt.rcParams['axes.labelsize'] = 14
        plt.rcParams['xtick.labelsize'] = 12
        plt.rcParams['ytick.labelsize'] = 12
        plt.rcParams['legend.fontsize'] = 14

        df.set_index(['date'], inplace=True)

        # Plot Coherence

        dfVV = df[df.band == 'VV'].copy()
        dfVH = df[df.band == 'VH'].copy()
        fig = plt.figure(figsize=(16.0, 10.0))
        axb = fig.add_subplot(1, 1, 1)

        axb.set_title(
            f"{inst}\nParcel {pid} (crop: {crop_name}, area: {area:.2f} sqm)")
        axb.set_xlabel("Date")
        axb.xaxis.set_major_formatter(datesFmt)

        axb.set_ylabel(r'Coherence')
        axb.plot(dfVH.index,
                 dfVH['mean'],
                 linestyle=' ',
                 marker='s',
                 markersize=10,
                 color='DarkBlue',
                 fillstyle='none',
                 label='VH')
        axb.plot(dfVV.index,
                 dfVV['mean'],
                 linestyle=' ',
                 marker='o',
                 markersize=10,
                 color='Red',
                 fillstyle='none',
                 label='VV')

        axb.set_xlim(start_date, end_date + timedelta(1))
        axb.set_ylim(0, 1)

        axb.legend(frameon=False)  # loc=2)

        return plt.show()

    ts_cloud = Checkbox(value=True,
                        description='Cloud free',
                        disabled=False,
                        indent=False)

    ts_files = glob.glob(f"{path}*time_series*.csv")
    ts_file_types = [b.split('_')[-1].split('.')[0] for b in ts_files]
    ts_types = [t for t in data_options.pts_tstype() if t[1] in ts_file_types]

    ts_type = Dropdown(
        options=ts_types,
        description='Select type:',
        disabled=False,
    )

    btn_ts = Button(value=False,
                    description='Plot TS',
                    disabled=False,
                    button_style='info',
                    tooltip='Refresh output',
                    icon='')

    ts_out = Output()

    @btn_ts.on_click
    def btn_ts_on_click(b):
        btn_ts.description = 'Refresh'
        btn_ts.icon = 'refresh'
        with ts_out:
            ts_out.clear_output()
            if ts_type.value == 's2':
                plot_ts_s2(ts_cloud.value)
            elif ts_type.value == 'bs':
                plot_ts_bs()
            elif ts_type.value == 'c6':
                plot_ts_c6()

    def on_ts_type_change(change):
        if ts_type.value == 's2':
            wbox_ts.children = [btn_ts, ts_type, ts_cloud]
        else:
            wbox_ts.children = [btn_ts, ts_type]

    ts_type.observe(on_ts_type_change, 'value')

    wbox_ts = HBox([btn_ts, ts_type, ts_cloud])

    wbox = VBox([wbox_ts, ts_out])

    return wbox
Esempio n. 17
0
    def _tensor_folder(self):
        alo = Layout(width='70px')
        rlo = Layout(width='220px')
        scale =  FloatSlider(max=10.0, step=0.001, readout=True, value=1.0)
        xs = [Text(layout=alo,disabled=True),
              Text(layout=alo,disabled=True),
              Text(layout=alo,disabled=True)]
        ys = [Text(layout=alo,disabled=True),
              Text(layout=alo,disabled=True),
              Text(layout=alo,disabled=True)]
        zs = [Text(layout=alo,disabled=True),
              Text(layout=alo,disabled=True),
              Text(layout=alo,disabled=True)]
        cs = [Text(layout=alo,disabled=True),
              Text(layout=alo,disabled=True),
              Text(layout=alo,disabled=True)]
        cidx = HBox([Text(disabled=True,description='Atom Index',layout=rlo)])
        xbox = HBox(xs, layout=rlo)
        ybox = HBox(ys, layout=rlo)
        zbox = HBox(zs, layout=rlo)
        cbox = HBox(cs, layout=rlo)
        tens = Button(description=' Tensor', icon='bank')
        tensor_cont = VBox([xbox,ybox,zbox])
        tensorIndex = Dropdown(options=[0],value=0,description='Tensor')
#        sceneIndex = Dropdown(options=[0],value=0,description='Scene')
        ten_label = Label(value="Change selected tensor:")
        sel_label = Label(value="Selected tensor in gray frame")
        cod_label = Label(value="Center of selected tensor: (x,y,z)")
        tensor = []
        self.coords = []

        def _changeTensor(tensor, tdx):
            carts = ['x','y','z']
            for i,bra in enumerate(carts):
                for j,ket in enumerate(carts):
                    tensor_cont.children[i].children[j].disabled=False
                    tensor_cont.children[i].children[j].value = \
                                            str(tensor[0][tdx][bra+ket])
                    tensor_cont.children[i].children[j].disabled=True
            adx = tensor[0][tdx]['atom']
            cidx.children[0].value = str(adx)
            cbox.children[0].value = str(self.coords[0][int(adx)])
            cbox.children[1].value = str(self.coords[1][int(adx)])
            cbox.children[2].value = str(self.coords[2][int(adx)])
#            scale.value = tensor[0][tdx]['scale']

        def _tens(c):
            for scn in self.active(): scn.tens = not scn.tens
            self.coords = self._filter_coords()
#            sceneIndex.options = [x for x in range(len(self.active()))]
#            sceneIndex.value = sceneIndex.options[0]
            tensor = self.active()[0].tensor_d
            tensorIndex.options = [x for x in range(len(tensor[0]))]
            tensorIndex.value = tensorIndex.options[0]
            tdx = tensorIndex.value
            _changeTensor(tensor, tdx)

        def _scale(c):
            for scn in self.active(): scn.scale = c.new
#            tdx = tensorIndex.value
#            tensor = self.active()[0].tensor_d
#            tensor[0][tdx]['scale'] = c.new

        def _idx(c):
            for scn in self.active(): scn.tidx = c.new
            tensor = self.active()[0].tensor_d
            tdx = c.new
            _changeTensor(tensor, tdx)

#        def _sdx(c):
#            tensor = self.active()[sceneIndex.value].tensor_d
#            tensorIndex.options = [x for x in range(len(tensor[0]))]
#            tensorIndex.value = tensorIndex.options[0]
#            tdx = tensorIndex.value
#            _changeTensor(tensor, tdx)

        tens.on_click(_tens)
        scale.observe(_scale, names='value')
        tensorIndex.observe(_idx, names='value')
#        sceneIndex.observe(_sdx, names='value')
        content = _ListDict([
                ('scale', scale),
                ('ten', ten_label),
#               ('sdx', sceneIndex),
                ('tdx', tensorIndex),
                ('tensor', tensor_cont),
                ('sel', sel_label),
                ('cidx', cidx),
                ('center', cod_label),
                ('coord', cbox)])
        return Folder(tens, content)
class Figure1:
    def __init__(self, csv_file_path, base_path='', inchi_key='XFYICZOIWSBQSK-UHFFFAOYSA-N', cluster=None):
        self.selected_plate = None
        self.old_plate = None
        self.base_path = base_path
        self.clustering = cluster
        self.full_perovskite_data = pd.read_csv(
            csv_file_path, low_memory=False, skiprows=4)
        self.full_perovskite_data = self.full_perovskite_data[
            self.full_perovskite_data['_raw_ExpVer'] >= 1.1]
        self.organic_inchis = pd.read_csv(
            './perovskitedata/organic_inchikey.csv', sep='\t')
        self.solvent_inchis = json.load(open('./perovskitedata/solvents.json'))

        # Filtering inchis that exist in full_perovskite_data

        self.state_spaces = pd.read_csv('./perovskitedata/state_spaces.csv')
        self.ss_dict = {}
        for row in self.state_spaces.iterrows():
            row = list(row[1])
            # app.logger.info(row)
            points = [ast.literal_eval(pt) for pt in row[1:-1]]
            chemical_abbrev = ast.literal_eval(row[-1])[1]
            inchi_row = self.organic_inchis[self.organic_inchis['Chemical Abbreviation']
                                            == chemical_abbrev]
            if not inchi_row.empty:
                row = inchi_row.iloc[0]
                self.ss_dict[row['InChI Key (ID)']] = points
        self.generate_plot(inchi_key, '')
        self.setup_widgets()

    def generate_plot(self, inchi_key, solvent_inchi):
        if inchi_key in self.ss_dict:
            self.setup_hull(hull_points=self.ss_dict[inchi_key])
        else:
            self.setup_hull(hull_points=[[0, 0, 0]])
        self.gen_amine_traces(inchi_key, solvent=solvent_inchi)
        self.setup_plot()

    def setup_hull(self, hull_points=[[0., 0., 0.], [0., 2.3, 0.], [1.86, 1.86, 0.],
                                      [0., 0., 9.5], [1.19339, 1.19339, 9.5], [0., 1.4757, 9.5]]):
        xp, yp, zp = zip(*hull_points)
        self.hull_mesh = go.Mesh3d(x=xp,
                                   y=yp,
                                   z=zp,
                                   color='green',
                                   opacity=0.50,
                                   alphahull=0)

    def gen_amine_traces(self, inchi_key, amine_short_name='Me2NH2I', solvent=None):
        amine_data = self.full_perovskite_data.loc[self.full_perovskite_data['_rxn_organic-inchikey'] == inchi_key]
        if solvent:
            amine_data = amine_data[amine_data['_raw_reagent_0_chemicals_0_InChIKey'] == solvent]
        print(f'Total points: {len(amine_data)}')
        self.max_inorg = amine_data['_rxn_M_inorganic'].max()
        self.max_org = amine_data['_rxn_M_organic'].max()
        self.max_acid = amine_data['_rxn_M_acid'].max()

        # Splitting by crystal scores. Assuming crystal scores from 1-4
        self.amine_crystal_dfs = []
        for i in range(1, 5):
            self.amine_crystal_dfs.append(
                amine_data.loc[amine_data['_out_crystalscore'] == i])

        self.amine_crystal_traces = []
        self.trace_colors = ['rgba(65, 118, 244, 1.0)', 'rgba(92, 244, 65, 1.0)',
                             'rgba(244, 238, 66, 1.0)', 'rgba(244, 66, 66, 1.0)']
        for i, df in enumerate(self.amine_crystal_dfs):
            trace = go.Scatter3d(
                x=df['_rxn_M_inorganic'],
                y=df['_rxn_M_organic'],
                z=df['_rxn_M_acid'],
                mode='markers',
                name='Score {}'.format(i+1),
                text=['<b>PbI3</b>: {:.3f} <br><b>Amine</b>: {:.3f} <br><b>FAH</b>: {:.3f}'.format(
                    row['_rxn_M_inorganic'], row['_rxn_M_organic'], row['_rxn_M_acid']) for idx, row in df.iterrows()],
                hoverinfo='text',
                marker=dict(
                    size=4,
                    color=self.trace_colors[i],
                    line=dict(
                        width=0.2
                    ),
                    opacity=1.0
                )
            )
            self.amine_crystal_traces.append(trace)
            if i == 3:
                # normed = preprocessing.minmax_scale(
                #    [df['_rxn_M_inorganic'], df['_rxn_M_organic'], df['_rxn_M_acid']], axis=1)

                # normed_success_points = np.dstack(
                #    (normed[0], normed[1], normed[2]))[0]
                success_points = np.dstack(
                    (df['_rxn_M_inorganic'], df['_rxn_M_organic'], df['_rxn_M_acid']))[0]

                ones_hull = None
                if self.clustering is not None:
                    self.clustering.fit(success_points)
                    # print(self.clustering.labels_)
                    one_labels = success_points[[
                        True if i == 0 else False for i in self.clustering.labels_]]
                    ones_hull = ConvexHull(one_labels)

                success_hull = None
                if len(success_points):
                    success_hull = ConvexHull(success_points)

        self.data = self.amine_crystal_traces

        if ones_hull is not None:
            xp, yp, zp = zip(*one_labels[ones_hull.vertices])
            self.ones_hull_plot = go.Mesh3d(x=xp,
                                            y=yp,
                                            z=zp,
                                            color='yellow',
                                            opacity=0.50,
                                            alphahull=0)

            x_mean = np.mean(xp)
            y_mean = np.mean(yp)
            z_mean = np.mean(zp)

            # print('Cluster Hull centroid wrt points: ({}, {}, {})'.format(
            #    x_mean, y_mean, z_mean))
            # print('Cluster Hull centroid wrt sides: ({}, {}, {})'.format(
            #    *self.com_edges(xp, yp, zp)))
            self.data += [self.ones_hull_plot]

        if success_hull:
            xp, yp, zp = zip(*success_points[success_hull.vertices])
            self.success_hull_plot = go.Mesh3d(x=xp,
                                               y=yp,
                                               z=zp,
                                               color='red',
                                               opacity=0.50,
                                               alphahull=0)

            x_mean = np.mean(xp)
            y_mean = np.mean(yp)
            z_mean = np.mean(zp)

            # print('Success Hull centroid wrt points: ({}, {}, {})'.format(
            #    x_mean, y_mean, z_mean))
            # print('Success Hull centroid wrt sides: ({}, {}, {})'.format(
            #    *self.com_edges(xp, yp, zp)))
            self.data += [self.success_hull_plot]

        if self.hull_mesh:
            self.data += [self.hull_mesh]

    def com_edges(self, px, py, pz):
        sx = sy = sz = slen = 0
        x1 = px[-1]
        y1 = py[-1]
        z1 = pz[-1]
        for i in range(len(px)):
            x2 = px[i]
            y2 = py[i]
            z2 = pz[i]
            dx = x2 - x1
            dy = y2 - y1
            dz = z2 - z1
            length = math.sqrt(dx*dx + dy*dy + dz*dz)
            sx = sx + (x1 + x2)/2*length
            sy = sy + (y1 + y2)/2*length
            sz = sz + (z1 + z2)/2*length
            slen = slen + length
            x1 = x2
            y1 = y2
            z1 = z2
        cx = sx/slen
        cy = sy/slen
        cz = sz/slen
        return cx, cy, cz

    def setup_plot(self, xaxis_label='Lead Iodide [PbI3] (M)',
                   yaxis_label='Dimethylammonium Iodide<br>[Me2NH2I] (M)',
                   zaxis_label='Formic Acid [FAH] (M)'):
        self.layout = go.Layout(
            scene=dict(
                xaxis=dict(
                    title=xaxis_label,
                    tickmode='linear',
                    dtick=0.5,
                    range=[0, self.max_inorg],
                ),
                yaxis=dict(
                    title=yaxis_label,
                    tickmode='linear',
                    dtick=0.5,
                    range=[0, self.max_org],
                ),
                zaxis=dict(
                    title=zaxis_label,
                    tickmode='linear',
                    dtick=1.0,
                    range=[0, self.max_acid],
                ),
            ),
            legend=go.layout.Legend(
                x=0,
                y=1,
                traceorder="normal",
                font=dict(
                    family="sans-serif",
                    size=12,
                    color="black"
                ),
                bgcolor="LightSteelBlue",
                bordercolor="Black",
                borderwidth=2
            ),
            width=975,
            height=700,
            margin=go.layout.Margin(
                l=20,
                r=20,
                b=20,
                t=20,
                pad=2
            ),
        )
        try:
            with self.fig.batch_update():
                for i, trace in enumerate(self.data):
                    self.fig.data[i].x = trace.x
                    self.fig.data[i].y = trace.y
                    self.fig.data[i].z = trace.z
                self.fig.layout.update(self.layout)
        except:
            self.fig = go.FigureWidget(data=self.data, layout=self.layout)
            for trace in self.fig.data[:-1]:
                trace.on_click(self.show_data_3d_callback)

    def setup_widgets(self, image_folder='images'):
        image_folder = self.base_path + '/' + image_folder
        self.image_list = os.listdir(image_folder)

        # Data Filter Setup
        download_robot_file = Button(
            description='Download Robot File',
            disabled=False,
            button_style='',
            tooltip='Click to download robot file of the current plate',
        )

        download_prep_file = Button(
            description='Download Reagent Prep',
            disabled=False,
            button_style='',
            tooltip='Click to download reagent preperation file for the current plate',
        )

        reset_plot = Button(
            description='Reset',
            disabled=False,
            tooltip='Reset the colors of the plot'
        )

        xy_check = Button(
            description='Show X-Y axes',
            disabled=False,
            button_style='',
            tooltip='Click to show X-Y axes'
        )

        show_hull_check = ToggleButton(
            value=True,
            description='Show State Space',
            disabled=False,
            button_style='',
            tooltip='Toggle to show/hide state space',
            icon='check'
        )

        show_success_hull = ToggleButton(
            value=True,
            description='Show sucess hull',
            disabled=False,
            button_style='',
            tooltip='Toggle to show/hide success hull',
            icon='check'
        )

        self.select_amine = Dropdown(
            options=[row[1]['Chemical Name'] for row in self.organic_inchis.iterrows(
            ) if len(self.full_perovskite_data.loc[self.full_perovskite_data['_rxn_organic-inchikey'] == row[1]['InChI Key (ID)']]) > 0],
            description='Amine:',
            disabled=False,
        )

        self.select_solvent = Dropdown(
            options=[None],
            description='Solvent:',
            disabled=False,
        )

        download_robot_file.on_click(self.download_robot_callback)
        download_prep_file.on_click(self.download_prep_callback)
        reset_plot.on_click(self.reset_plot_callback)
        xy_check.on_click(self.set_xy_camera)
        show_hull_check.observe(self.toggle_mesh, 'value')
        show_success_hull.observe(self.toggle_success_mesh, 'value')
        self.select_amine.observe(self.select_amine_callback, 'value')
        self.select_solvent.observe(self.select_solvent_callback, 'value')

        # Experiment data tab setup
        self.experiment_table = HTML()
        self.experiment_table.value = "Please click on a point to explore experiment details"

        self.image_data = {}
        for img_filename in os.listdir(image_folder):
            with open("{}/{}".format(image_folder, img_filename), "rb") as f:
                b = f.read()
                self.image_data[img_filename] = b

        self.image_widget = Image(
            value=self.image_data['not_found.png'],
            layout=Layout(height='400px', width='650px')
        )

        experiment_view_vbox = VBox(
            [HBox([self.experiment_table, self.image_widget])])

        plot_tabs = Tab([VBox([self.fig,
                               HBox([self.select_amine, self.select_solvent]),
                               HBox([xy_check, show_hull_check, show_success_hull, reset_plot])]),
                         ])
        plot_tabs.set_title(0, 'Chemical Space')

        self.full_widget = VBox([plot_tabs, experiment_view_vbox])
        self.full_widget.layout.align_items = 'center'

    def select_amine_callback(self, state):
        new_amine_name = state['new']
        new_amine_inchi = self.organic_inchis[self.organic_inchis['Chemical Name']
                                              == new_amine_name].iloc[0]['InChI Key (ID)']
        amine_data = self.full_perovskite_data[self.full_perovskite_data['_rxn_organic-inchikey'] == new_amine_inchi]
        solvents = [
            inchi for inchi in amine_data['_raw_reagent_0_chemicals_0_InChIKey'].unique()]

        self.select_solvent.options = ['All'] + [
            key for key, value in self.solvent_inchis.items() if value in solvents]

        solvent_inchi = ""
        self.generate_plot(new_amine_inchi, solvent_inchi)

    def select_solvent_callback(self, state):
        new_solvent_inchi = self.solvent_inchis[state['new']]

        amine = self.select_amine.value
        amine_inchi = self.organic_inchis[self.organic_inchis['Chemical Name']
                                          == amine].iloc[0]['InChI Key (ID)']
        self.generate_plot(amine_inchi, new_solvent_inchi)

    def get_plate_options(self):
        plates = set()
        for df in self.amine_crystal_dfs:
            for i, row in df.iterrows():
                name = str(row['name'])
                plate_name = '_'.join(name.split('_')[:-1])
                plates.add(plate_name)
        plate_options = []
        for i, plate in enumerate(plates):
            plate_options.append(plate)
        return plate_options

    def generate_table(self, row, columns, column_names):
        table_html = """ <table border="1" style="width:100%;">
                        <tbody>"""
        for i, column in enumerate(columns):
            if isinstance(row[column], str):
                value = row[column].split('_')[-1]
            else:
                value = np.round(row[column], decimals=3)
            table_html += """
                            <tr>
                                <td style="padding: 8px;">{}</td>
                                <td style="padding: 8px;">{}</td>
                            </tr>
                          """.format(column_names[i], value)
        table_html += """
                        </tbody>
                        </table>
                        """
        return table_html

    def toggle_mesh(self, state):
        with self.fig.batch_update():
            self.fig.data[-1].visible = state.new

    def toggle_success_mesh(self, state):
        with self.fig.batch_update():
            self.fig.data[-2].visible = state.new

    def set_xy_camera(self, state):
        camera = dict(
            up=dict(x=0, y=0, z=1),
            center=dict(x=0, y=0, z=0),
            eye=dict(x=0.0, y=0.0, z=2.5)
        )

        self.fig['layout'].update(
            scene=dict(camera=camera),
        )

    def download_robot_callback(self, b):
        if self.selected_plate:
            js_string = """
                        var base_uri = utils.get_body_data("baseUrl");
                        var file_location = utils.encode_uri_components('{}_RobotInput.xls');
                        // var final_url = utils.url_path_join(base_uri, 'files', file_location)
                        var final_url = 'files/' + file_location
                        console.log(final_url)
                        window.open(final_url, IPython._target);
                        """.format(self.selected_plate)

            display(Javascript(js_string))

    def download_prep_callback(self, b):
        if self.selected_plate:
            js_string = """
                        var base_uri = utils.get_body_data("baseUrl");
                        var file_location = utils.encode_uri_components('{}_ExpDataEntry.xlsx');
                        // var final_url = utils.url_path_join(base_uri, 'files', file_location)
                        var final_url = 'files/' + file_location
                        console.log(final_url)
                        window.open(final_url, IPython._target);
                        """.format(self.selected_plate)

            display(Javascript(js_string))

    def reset_plot_callback(self, b):
        with self.fig.batch_update():
            for i in range(len(self.fig.data[:4])):
                self.fig.data[i].marker.color = self.trace_colors[i]
                self.fig.data[i].marker.size = 4

    def show_data_3d_callback(self, trace, point, selector):
        if point.point_inds and point.trace_index < 4:

            selected_experiment = self.amine_crystal_dfs[point.trace_index].iloc[point.point_inds[0]]
            with self.fig.batch_update():
                for i in range(len(self.fig.data[:4])):
                    color = self.trace_colors[i].split(',')
                    color[-1] = '0.5)'
                    color = ','.join(color)
                    if i == point.trace_index:
                        marker_colors = [color for x in range(len(trace['x']))]
                        marker_colors[point.point_inds[0]
                                      ] = self.trace_colors[i]
                        self.fig.data[i].marker.color = marker_colors
                        self.fig.data[i].marker.size = 6
                    else:
                        self.fig.data[i].marker.color = color
                        self.fig.data[i].marker.size = 4
            self.populate_data(selected_experiment)

    def populate_data(self, selected_experiment):
        name = selected_experiment['name']
        if name+'.jpg' in self.image_list:
            self.image_widget.value = self.image_data[name+'.jpg']
        else:
            self.image_widget.value = self.image_data['not_found.png']
        columns = ['name', '_rxn_M_acid', '_rxn_M_inorganic', '_rxn_M_organic',
                   '_rxn_mixingtime1S', '_rxn_mixingtime2S', '_rxn_reactiontimeS',
                   '_rxn_stirrateRPM', '_rxn_temperatureC_actual_bulk']
        column_names = ['Well ID', 'Formic Acid [FAH]', 'Lead Iodide [PbI2]', 'Dimethylammonium Iodide [Me2NH2I]',
                        'Mixing Time Stage 1 (s)', 'Mixing Time Stage 2 (s)', 'Reaction Time (s)',
                        'Stir Rate (RPM)', 'Temperature (C)']

        prefix = '_'.join(name.split('_')[:-1])
        self.selected_plate = prefix
        self.experiment_table.value = '<p>Plate ID:<br> {}</p>'.format(prefix) + self.generate_table(
            selected_experiment.loc[columns], columns, column_names)

    @property
    def plot(self):
        return self.full_widget
Esempio n. 19
0
def hyperExplore(df,initial_axis,initial_surface_axis,legend_group,hover_items):

    data = df.assign(x=df[initial_axis[0]],y=df[initial_axis[1]])\
       .sort_values(legend_group)\
       .reset_index(drop=True)

    group_ops = data[legend_group].sort_values().unique()
    num_groups = len(group_ops)
    axis_ops = data.columns.values
    lenSlide = '500px'

    fig = px.scatter(data, x="x", y="y", color=legend_group,hover_data=hover_items,
                 log_x=True, title='Hyperparameter Exploration',height=600)

    fig.update_layout(
        legend=dict(
        orientation="v",
        yanchor="top",
        y=1.02,
        xanchor="left",
        x=1),
        xaxis=dict(title=initial_axis[0],
                   titlefont=dict(size=14)),
        yaxis=dict(title=initial_axis[1],
                    titlefont=dict(size=14))
        )

    fig.update_traces(marker=dict(size=20,line=dict(width=1.5,
                                            color='DarkSlateGrey')),
                      selector=dict(mode='markers'))

    fig.update_layout(plot_bgcolor='rgba(0,0,0,0)')
    fig.update_xaxes(showgrid=True, gridwidth=.1, gridcolor='lightgrey')
    fig.update_yaxes(showgrid=True, gridwidth=.1, gridcolor='lightgrey')

    param_drop1 = Dropdown(
        value='None',
        options=np.insert(axis_ops,0,'None'),
        description='Parameter 1:'
    )

    slider1 = widgets.SelectionSlider(
        options=['Select Parameter'],
        value='Select Parameter',
        layout=Layout(width=lenSlide),
        continuous_update=True
    )

    size_drop = Dropdown(
        value='None',
        options=np.insert(axis_ops,0,'None'),
        description='Size:'
    )

    size_slider = widgets.IntSlider(
        value=20,
        min=10,
        max=50,
        step=1,
        disabled=False,
        continuous_update=True,
        orientation='horizontal',
        layout=Layout(width=lenSlide),
        readout=True,
        readout_format='d'
    )

    slider_group1 = widgets.HBox([param_drop1, slider1])
    slider_group2 = widgets.HBox([size_drop, size_slider])

    xaxis = Dropdown(
        value=initial_axis[0],
        options=axis_ops,
        description='X-axis:'
    )

    yaxis = Dropdown(
        value=initial_axis[1],
        options=axis_ops,
        description='Y-axis:'
    )

    container = widgets.VBox(children=[slider_group1,slider_group2,xaxis,yaxis])

    g = go.FigureWidget(data=fig,
                        layout=go.Layout(
                            title=dict(
                                text='Hyperparameter Exploration'
                            )
                        ))

    x_surface = Dropdown(
        value=initial_surface_axis[0],
        options=axis_ops,
        description='X-axis'
    )
    y_surface = Dropdown(
        value=initial_surface_axis[1],
        options=axis_ops,
        description='Y-axis'
    )
    z_surface = Dropdown(
        value=initial_surface_axis[2],
        options=axis_ops,
        description='Z-axis'
    )

    surface_buttons = widgets.RadioButtons(
        options=group_ops,
        value=group_ops[0], # Defaults to 'pineapple'
        description=legend_group+":",
        disabled=False
    )


    z_vals = data.query('{} == "{}"'\
            .format(legend_group,surface_buttons.value))[[x_surface.value,y_surface.value,z_surface.value]]\
            .groupby([x_surface.value,y_surface.value])\
            .median().reset_index()\
            .pivot(index=x_surface.value,columns=y_surface.value,values=z_surface.value)

    fig2 = go.Figure(data=[go.Surface(z=z_vals)])
    fig2.update_layout(title='Hyperparameter Surface: '+surface_buttons.value, autosize=False,
                      margin=dict(l=65, r=50, b=65, t=90),
                      height=600)

    layout = go.Layout(
                    scene = dict(
                        xaxis = dict(
                            title = initial_surface_axis[0]),
                        yaxis = dict(
                            title = initial_surface_axis[1]),
                        zaxis = dict(
                            title = initial_surface_axis[2]),
                                ))
    fig2.update_layout(layout)

    container2 = widgets.HBox(children=[surface_buttons,x_surface,y_surface,z_surface])


    g2 = go.FigureWidget(data=fig2,
                        layout=go.Layout(
                            title=dict(
                                text='Hyperparameter Surface: '+surface_buttons.value
                            )
                        ))


    def axis_response(change):
        with g.batch_update():
            #Gets the widget that was altered
            modified = change.owner.description

            if modified == xaxis.description:
                for i in range(num_groups):
                    #Get data for legend group
                    filtered_data = data.query("{} == '{}'".format(legend_group,g.data[i].name))

                    #Query filtered data for slider specs
                    query_filt(filtered_data,i)

                    g.layout.xaxis.title = xaxis.value

            elif modified == yaxis.description:
                for i in range(num_groups):
                    #Get data for legend group
                    filtered_data = data.query("{} == '{}'".format(legend_group,g.data[i].name))

                    #Query filtered data for slider specs
                    query_filt(filtered_data,i)

                    g.layout.yaxis.title = yaxis.value

    def slider1_response(change):
        with g.batch_update():
            for i in range(num_groups):
                #Get data for legend group
                filtered_data = data.query("{} == '{}'".format(legend_group,g.data[i].name))#make key var that iters

                #Query filtered data for slider specs
                query_filt(filtered_data,i)

    def query_filt(filtered_data,i):
        #Query filtered data for slider specs
    #     filt_bool = (filtered_data.learning_rate == lr_slider.value)#make learning_rate var
        if param_drop1.value == 'None':
            #Assign data to graph
            g.data[i].x = filtered_data[xaxis.value]
            g.data[i].y = filtered_data[yaxis.value]
        else:
            filt_bool = (filtered_data[param_drop1.value] == slider1.value)#make learning_rate var
            #Filter out data
            xfilt = [v if b else None for v,b in zip(filtered_data[xaxis.value],filt_bool)]
            yfilt = [v if b else None for v,b in zip(filtered_data[yaxis.value],filt_bool)]
            #Assign data to graph
            g.data[i].x = xfilt
            g.data[i].y = yfilt

    def create_slider_options(drop_value):
        if drop_value == 'None':
            slide_ops = ['Select Parameter']
        else:
            slide_ops = data[drop_value].sort_values().unique()
        return slide_ops

    def param_update(change):
        #everytime we change param, update the slider options and current value
        slider1.options = create_slider_options(param_drop1.value)
        slider1.value = slider1.options[0]

    def size_response(change):
         with g.batch_update():
                if size_drop.value == 'None':
                    g.update_traces(marker=dict(size=size_slider.value))
                else:
                    sizeFig = px.scatter(data, x="x", y="y", color="model",
                                         size=size_drop.value, size_max=size_slider.value)
                    traceSizes = [x.marker.size for x in sizeFig.data]

                    for i in range(num_groups):
                        g.data[i].marker.size = traceSizes[i]
                        g.data[i].marker.sizeref = sizeFig.data[0].marker.sizeref
                        g.data[i].marker.sizemode = sizeFig.data[0].marker.sizemode
                        g.data[i].marker.sizemin = 4

    def surface_response(change):
        with g.batch_update():
            z_vals = data.query('{} == "{}"'\
            .format(legend_group,surface_buttons.value))[[x_surface.value,y_surface.value,z_surface.value]]\
            .groupby([x_surface.value,y_surface.value])\
            .median().reset_index()\
            .pivot(index=x_surface.value,columns=y_surface.value,values=z_surface.value)

            g2.data[0].z = z_vals.values

            layout = go.Layout(
                        scene = dict(
                            xaxis = dict(
                                title = x_surface.value),
                            yaxis = dict(
                                title = y_surface.value),
                            zaxis = dict(
                                title = z_surface.value),
                                    ),
                         title=dict(
                                text='Hyperparameter Surface: '+surface_buttons.value
                            ))

            g2.update_layout(layout)

    surface_buttons.observe(surface_response,"value")
    x_surface.observe(surface_response,"value")
    y_surface.observe(surface_response,"value")
    z_surface.observe(surface_response,"value")

    size_drop.observe(size_response,"value")
    size_slider.observe(size_response, "value")
    slider1.observe(slider1_response, names="value")
    xaxis.observe(axis_response, names="value")
    yaxis.observe(axis_response, names="value")
    param_drop1.observe(param_update, names="value")

    scatterTab = widgets.VBox([container,g])
    surfaceTab = widgets.VBox([container2,g2])
    tab = widgets.Tab([scatterTab,surfaceTab])
    tab.set_title(0,'Scatter')
    tab.set_title(1,'Surface')

    return tab
Esempio n. 20
0
class NasaGibsViewer(PanelObject):
  def __init__(self,ptype='time',*args,**kwargs):
    self.title = 'NASA GIBS Image Viewer'
    PanelObject.__init__(self,*args, **kwargs)
    self.url = 'https://gibs.earthdata.nasa.gov/wmts/epsg4326/best/wmts.cgi'  
    
    self.plat = 24.42
    self.plon = 54.43
    self.height = 1.0
    self.width = 1.0



  def getCP(self):
    self.setLabel()
    
    self.imgDate = datetime.now()
    
    self.selectVar ='MODIS_Terra_SurfaceReflectance_Bands143'
   
    self.dateSW = DatePicker(description='Date',
                              layout=Layout(width='220px'),
                              value = self.imgDate,
                              disabled=False)
    
    self.vardict = {'TerraRGB':'MODIS_Terra_SurfaceReflectance_Bands143',
                    'AquaRGB' :'MODIS_Aqua_SurfaceReflectance_Bands143',
                    'AquaLST Day':'MODIS_Aqua_Land_Surface_Temp_Day'}
 
    self.varSW   = Dropdown(options=['TerraRGB','AquaRGB','AquaLST Day'],
                            value='TerraRGB',
                            layout=Layout(width='220px'),
                            description='Var:',
                            disabled=False
                            )
  
    self.latSW = Text(description='Lat:',disabled=False,value='24.42',layout=Layout(width='220px'))

    self.lonSW = Text(description='Lon:',disabled=False,value='54.43',layout=Layout(width='220px')) 
                                  
    self.plotPB =Button(description='Plot',disabled=False,layout={'width':'auto','border':'3px outset'})

    self.latRS =     FloatSlider( value=5,
                                      min=2.0,
                                      max=15,
                                      step=0.2,
                                      description='Width',
                                      disabled=False,
                                      continuous_update=False,
                                      orientation='horizontal',
                                      readout=True,
                                      readout_format='.1f',
                                      )
    
    self.lonRS    =  FloatSlider( value=5.0,
                                      min=2.0,
                                      max=15.0,
                                      step=0.2,
                                      description='Height:',
                                      disabled=False,
                                      continuous_update=False,
                                      orientation='horizontal',
                                      readout=True,
                                      readout_format='.1f'
                                      )    
    self.inpUSR.children+= (HBox([
                                  VBox([self.plotPB]),
                                  VBox([self.dateSW,self.latSW,self.lonSW]),
                                  VBox([self.latRS,self.lonRS,self.varSW ])
                                  
                                 ],
                                 layout={'overflow':'visible'}
                                ),)
    
    
    self.dateSW.observe(self.dateSWCB)
    self.varSW.observe(self.varSWCB,names='value')
    self.latSW.observe(self.latSWCB,names='value')
    self.lonSW.observe(self.lonSWCB,names='value')
    self.latRS.observe(self.latRSCB,names='value')
    self.lonRS.observe(self.lonRSCB,names='value')
    self.plotPB.on_click(self.plotGIBS)
    return self.cp

  def dateSWCB(self,change):
    if change['type'] == 'change':
      self.imgDate = self.dateSW.value

  def varSWCB(self,b):
    self.selectVar = self.vardict[self.varSW.value]
  
  def latSWCB(self,change):
      self.plat = float(self.latSW.value)
      
  def lonSWCB(self,change):
      self.plon = float(self.lonSW.value)

  def latRSCB(self,change):
      self.height = self.latRS.value*0.5
      
  def lonRSCB(self,change):
      self.width = self.lonRS.value*0.5

       
 
  def plotGIBS(self,b):
    self.lat1 = self.plat - self.height
    self.lat2 = self.plat + self.height
    self.lon1 = self.plon - self.width
    self.lon2 = self.plon + self.width
    with self.out_cp:
      plt.ioff()
      layer = self.selectVar 
      
      date_str = '{}-{}-{}'.format(self.imgDate.strftime('%Y'),
                                   self.imgDate.strftime('%m'),
                                   self.imgDate.strftime('%d') 
                                   )
      print(layer,date_str)
      fig = plt.figure(figsize=(8, 8))
      ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())
      ax.add_wmts(self.url, layer,wmts_kwargs={'time': date_str})
      self.out_cp.clear_output()
      ax.set_extent([self.lon1, self.lon2, self.lat1, self.lat2], crs=ccrs.PlateCarree())
      ax.coastlines(resolution='50m', color='yellow')
      plt.plot(self.plon, self.plat, marker='o', color='red', markersize=15,
         alpha=1.0)
      plt.show()
        value_1 = A_1.value * np.sin(w_1.value * t)
        value_2 = A_2.value * np.cos(w_2.value * t)
    else:
        value_1 = A_1.value * np.sin(2 * math.pi * f_1.value*t - Phi_1.value * np.pi/180)
        value_2 = A_2.value * np.cos(2 * math.pi * f_2.value*t - Phi_2.value * np.pi/180)
    return value_1, value_2

# parameters
t = np.arange(0.0, 10.0, 0.001)
y_1, y_2 = calculate()

# figure
data = [go.Scatter(y = y_1, x = t, opacity = 0.75, name = 'Trace 1'), go.Scatter(y = y_2, x = t, opacity = 0.75, name = 'Trace 2')]
layout = {'yaxis': {'range': [-2, 2], 'title': "CALCULATED VALUE"}, 'xaxis': {'range': [0, 10], 'title': "TIME"}}
fig = go.FigureWidget(data, layout)

def recalculate(value):
    global fig
    fig.data[0].y, fig.data[1].y = calculate()
        
A_1.observe(recalculate, 'value')
A_2.observe(recalculate, 'value')
f_1.observe(recalculate, 'value')
f_2.observe(recalculate, 'value')
w_1.observe(recalculate, 'value')
w_2.observe(recalculate, 'value')
Phi_1.observe(recalculate, 'value')
Phi_2.observe(recalculate, 'value')
use.observe(recalculate, 'value')

fig
Esempio n. 22
0
class ImBox(VBox):
    """Widget for inspecting images that contain bounding boxes."""
    def __init__(self,
                 df: pd.DataFrame,
                 box_col: str = 'box',
                 img_col: str = 'image',
                 text_cols: Union[str, List[str]] = None,
                 text_fmts: Union[Callable, List[Callable]] = None,
                 style_col: str = None):
        """
        :param pd.DataFrame df: `DataFrame` with images and boxes
        :param str box_col: column in the dataframe that contains boxes
        :param str img_col: column in the dataframe that contains image paths
        :param Union[str, List[str]] text_cols: (optional) the column(s) in the
        dataframe to use for creating the text that is shown on top of a box.
        When multiple columns are give, the text will be created by a
        comma-separated list of the contents of the given columns.
        :param Unions[Callable, List[Callable]] text_fmts: (optional) a
        callable, or list of callables, that takes the corresponding value from
        the `text_cols` column(s) as an input and returns the string to print
        for that value.
        :param str style_col: the column containing a dict of style attributes.
        Available attributes are:
            - `stroke_width`: the stroke width of a box (default 2)
            - `stroke_color`: the stroke color of a box (default 'red')
            - `fill_color`: the fill color of a box (default  '#00000000')
            - `hover_fill`: the fill color of a box when it is hovered on
              (default '#00000088')
            - `hover_stroke`: the stroke color of a box when it is hovered on
              (default 'blue')
            - `active_fill`: the fill color of a box when it is clicked on
              (default '#ffffff22')
            - `active_stroke`: the stroke color of a box when it is clicked on
              (default 'green')
            - `font_family`: the font family to use for box text (default
            'arial'). NOTE: exported text will always be Arial.
            - `font_size`: the font size in points (default 10)
        """
        if text_cols is None:
            text_cols = []
        if isinstance(text_cols, str):
            text_cols = [text_cols]
        if text_fmts is None:
            text_fmts = [None] * len(text_cols)
        if isinstance(text_fmts, Callable):
            text_fmts = [text_fmts]
        self.text_cols = text_cols
        self.text_fmts = text_fmts

        df2 = df.copy()

        def row2text(row):
            txts = row[text_cols]
            return ', '.join([
                fmt(txt) if fmt is not None else str(txt)
                for txt, fmt in zip(txts, self.text_fmts)
            ])

        if style_col is None:
            style_col = '_dfim_style'
            df2[style_col] = [DEFAULT_STYLE] * len(df2)
        else:
            df2[style_col] = df2[style_col].apply(lambda s: {
                k: s[k] if k in s else DEFAULT_STYLE[k]
                for k in DEFAULT_STYLE
            })

        df2['box_text'] = df2.apply(lambda row: row2text(row), axis=1)
        df2['box_dict'] = df2.apply(
            lambda row: dict(index=row.name,
                             box=row[box_col],
                             text=row['box_text'],
                             style=row[style_col])
            if (box_col in row.index and row[box_col] is not None) else None,
            axis=1)

        self.df_img = df2.groupby(img_col).agg(list).reset_index()
        self.df = df
        self.img_col = img_col
        self.box_col = box_col

        # SELECTION widget
        self.idx_wgt = BoundedIntText(value=0,
                                      min=0,
                                      max=len(self.df_img) - 1,
                                      step=1,
                                      description='Choose index',
                                      disabled=False)
        self.drop_wgt = Dropdown(options=self.df_img[img_col],
                                 description='or image',
                                 value=None,
                                 disabled=False)
        self.drop_wgt.observe(self.drop_changed, names='value')
        self.idx_wgt.observe(self.idx_changed, names='value')
        self.imsel_wgt = VBox([self.idx_wgt, self.drop_wgt])
        self.imsel_wgt.layout = Layout(margin='auto')

        # IMAGE PANE
        self.img_title = HTML(placeholder='(Image path)')
        self.img_title.layout = Layout(margin='auto')
        self.imbox_wgt = ImBoxWidget()
        self.imbox_wgt.layout = Layout(margin='1em auto')
        self.imbox_wgt.observe(self.box_changed, names='active_box')
        self.imbox_wgt.observe(self.img_changed, names='img')

        # DETAILS PANE
        self.crop_wgt = CropBoxWidget()
        self.crop_wgt.layout = Layout(margin='0 1em')
        self.detail_wgt = DetailsWidget()
        self.detail_wgt.layout = Layout(margin='auto')
        self.detail_pane = HBox([self.crop_wgt, self.detail_wgt])
        self.detail_pane.layout = Layout(margin='1em auto')

        # PLAY widget
        self.play_btns = Play(interval=100,
                              value=0,
                              min=0,
                              max=len(self.df_img) - 1,
                              step=1,
                              description="Play",
                              disabled=False)
        self.play_slider = widgets.IntSlider(value=0,
                                             min=0,
                                             max=len(self.df_img) - 1,
                                             step=1)
        widgets.jslink((self.play_btns, 'value'), (self.idx_wgt, 'value'))
        widgets.jslink((self.play_btns, 'value'), (self.play_slider, 'value'))

        self.play_wgt = widgets.HBox([self.play_btns, self.play_slider])
        self.play_wgt.layout = Layout(margin='auto')

        # IMAGE EXPORT widget
        self.imexp_dest = Text(description='Output file',
                               value='output/output.png')
        self.imexp_btn = Button(description='Export')
        self.imexp_btn.on_click(self.export_img)
        self.imexp_wgt = HBox([self.imexp_dest, self.imexp_btn])

        # VIDEO EXPORT widget
        self.videxp_dest = Text(description='Output file',
                                value='output/output.mp4')
        self.videxp_start = BoundedIntText(value=0,
                                           min=0,
                                           max=len(self.df_img) - 1,
                                           step=1,
                                           description='From index',
                                           disabled=False)
        self.videxp_start.observe(self.vididx_changed, names='value')
        self.videxp_end = BoundedIntText(value=0,
                                         min=0,
                                         max=len(self.df_img) - 1,
                                         step=1,
                                         description='Until index',
                                         disabled=False)
        self.videxp_end.observe(self.vididx_changed, names='value')
        self.videxp_fps = FloatText(value=30, description='FPS')
        self.videxp_btn = Button(description='Export')
        self.videxp_btn.on_click(self.export_vid)

        self.videxp_wgt = VBox([
            HBox([self.videxp_start, self.videxp_end]),
            HBox([self.videxp_dest, self.videxp_fps]), self.videxp_btn
        ])
        self.exp_wgt = Tab(children=[self.imexp_wgt, self.videxp_wgt])
        self.exp_wgt.set_title(0, 'Export image')
        self.exp_wgt.set_title(1, 'Export video')
        self.exp_wgt.layout = Layout(margin='0 1em')

        super().__init__([
            self.imsel_wgt,
            VBox([
                self.img_title, self.imbox_wgt, self.play_wgt, self.detail_pane
            ]), self.exp_wgt
        ])
        self.idx_changed({'new': 0})

    def box_changed(self, change):
        if change['new'] is None:
            self.detail_wgt.data = {}
            self.crop_wgt.box = None
        else:
            new_idx = change['new']['index']
            self.detail_wgt.data = dict(self.df.loc[new_idx])
            self.crop_wgt.box = change['new']['box']

    def img_changed(self, change):
        new_img = change['new']
        self.detail_wgt.data = {}
        self.crop_wgt.img = new_img
        self.img_title.value = f'Image path: <a href="{new_img}">{new_img}</a>'
        self.imexp_dest.value = f'output/{Path(new_img).stem}.png'
        self.imexp_btn.button_style = ''
        self.imexp_btn.description = 'Export'
        self.imexp_btn.disabled = False

    def drop_changed(self, change):
        idx = self.df_img[self.df_img[self.img_col] == change['new']].index[0]
        self.idx = idx
        self.imbox_wgt.img = self.df_img.loc[idx, self.img_col]
        self.imbox_wgt.boxes = self.df_img.loc[idx, 'box_dict']
        self.idx_wgt.value = idx

    def idx_changed(self, change):
        self.idx = change['new']
        self.imbox_wgt.img = self.df_img.loc[self.idx, self.img_col]
        self.imbox_wgt.boxes = self.df_img.loc[self.idx, 'box_dict']
        self.drop_wgt.value = self.imbox_wgt.img

    def vididx_changed(self, change):
        start = self.videxp_start.value
        end = self.videxp_end.value
        self.videxp_dest.value = f'output/{start}_{end}.mp4'
        self.videxp_btn.button_style = ''
        self.videxp_btn.description = 'Export'
        self.videxp_btn.disabled = False

    def get_pilim_from_idx(self, idx):
        """Return the processed PIL image that belongs to an image index.
        """
        im = Image.open(self.df_img.loc[idx, self.img_col])
        draw = ImageDraw.Draw(im, mode='RGBA')

        box_dicts = self.df_img.loc[idx, 'box_dict']
        for bd in box_dicts:
            box = bd['box']
            draw.rectangle([(box.x_min, box.y_min), (box.x_max, box.y_max)],
                           fill=bd['style']['fill_color'],
                           outline=bd['style']['stroke_color'],
                           width=bd['style']['stroke_width'])

            fontfile = str(Path(__file__).parent / 'etc/Arial.ttf')

            # size*4 to make it look more similar to example in widget
            fontsize = bd['style']['font_size'] * 4
            font = ImageFont.truetype(fontfile, size=fontsize)
            w, h = draw.textsize(bd['text'], font=font)
            draw.text((box.x_min, box.y_min - h),
                      text=bd['text'],
                      fill=bd['style']['stroke_color'],
                      font=font)
        return im

    def export_img(self, button):
        self.imexp_btn.disabled = True
        self.imexp_btn.description = 'Exporting...'
        im = self.get_pilim_from_idx(self.idx)
        try:
            im.save(self.imexp_dest.value)
            self.imexp_btn.button_style = 'success'
            self.imexp_btn.description = 'Export Successful'
        except (IOError, KeyError) as e:
            self.imexp_btn.button_style = 'danger'
            self.imexp_btn.description = 'Export Failed'
            logging.exception('Export Failed')

    def export_vid(self, button):
        self.videxp_btn.disabled = True
        self.videxp_btn.description = 'Exporting...'
        fps = str(self.videxp_fps.value)
        writer = FFmpegWriter(self.videxp_dest.value,
                              inputdict={'-framerate': fps})

        for idx in tqdm(range(self.videxp_start.value, self.videxp_end.value)):
            im = self.get_pilim_from_idx(idx)
            writer.writeFrame(np.array(im))

        try:
            writer.close()
            self.videxp_btn.button_style = 'success'
            self.videxp_btn.description = 'Export successful'
        except OSError as e:
            self.videxp_btn.button_style = 'danger'
            self.videxp_btn.description = 'Export failed'
            logging.exception('Export Failed')
Esempio n. 23
0
class Figure1:
    def __init__(self, csv_file_path, base_path='', inchi_key='JMXLWMIFDJCGBV-UHFFFAOYSA-N'):
        self.selected_plate = None
        self.old_plate = None
        self.base_path = base_path
        self.full_perovskite_data = pd.read_csv(
            csv_file_path, low_memory=False, skiprows=4)
        self.setup_hull()
        self.gen_amine_traces(inchi_key)
        self.setup_plot()
        self.generate_xrd()
        self.setup_widgets()

    def setup_hull(self, hull_points=[[0., 0., 0.], [0., 2.3, 0.], [1.86, 1.86, 0.],
                                      [0., 0., 9.5], [1.19339, 1.19339, 9.5], [0., 1.4757, 9.5]]):
        xp, yp, zp = zip(*hull_points)
        self.hull_mesh = go.Mesh3d(x=xp,
                                   y=yp,
                                   z=zp,
                                   color='#FFB6C1',
                                   opacity=0.50,
                                   alphahull=0)

    def gen_amine_traces(self, inchi_key, amine_short_name='Me2NH2I'):
        amine_data = self.full_perovskite_data.loc[self.full_perovskite_data['_rxn_organic-inchikey'] == inchi_key]
        # Splitting by crystal scores. Assuming crystal scores from 1-4
        self.amine_crystal_dfs = []
        for i in range(1, 5):
            self.amine_crystal_dfs.append(
                amine_data.loc[amine_data['_out_crystalscore'] == i])

        self.amine_crystal_traces = []
        self.trace_colors = ['rgba(65, 118, 244, 1.0)', 'rgba(92, 244, 65, 1.0)',
                             'rgba(244, 238, 66, 1.0)', 'rgba(244, 66, 66, 1.0)']
        for i, df in enumerate(self.amine_crystal_dfs):
            trace = go.Scatter3d(
                x=df['_rxn_M_inorganic'],
                y=df['_rxn_M_organic'],
                z=df['_rxn_M_acid'],
                mode='markers',
                name='Score {}'.format(i+1),
                text=['<b>PbI3</b>: {:.3f} <br><b>Amine</b>: {:.3f} <br><b>FAH</b>: {:.3f}'.format(
                    row['_rxn_M_inorganic'], row['_rxn_M_organic'], row['_rxn_M_acid']) for idx, row in df.iterrows()],
                hoverinfo='text',
                marker=dict(
                    size=4,
                    color=self.trace_colors[i],
                    line=dict(
                        width=0.2
                    ),
                    opacity=1.0
                )
            )
            self.amine_crystal_traces.append(trace)
        self.data = self.amine_crystal_traces

        if self.hull_mesh:
            self.data += [self.hull_mesh]

    def setup_plot(self, xaxis_label='Lead Iodide [PbI3] (M)',
                   yaxis_label='Dimethylammonium Iodide<br>[Me2NH2I] (M)',
                   zaxis_label='Formic Acid [FAH] (M)'):
        self.layout = go.Layout(
            scene=dict(
                xaxis=dict(
                    title=xaxis_label,
                    tickmode='linear',
                    dtick=0.5,
                    range=[0, 2.0],
                ),
                yaxis=dict(
                    title=yaxis_label,
                    tickmode='linear',
                    dtick=0.5,
                    range=[0, 2.5],
                ),
                zaxis=dict(
                    title=zaxis_label,
                    tickmode='linear',
                    dtick=1.0,
                    range=[0, 9.5],
                ),
            ),
            legend=go.layout.Legend(
                x=0,
                y=1,
                traceorder="normal",
                font=dict(
                    family="sans-serif",
                    size=12,
                    color="black"
                ),
                bgcolor="LightSteelBlue",
                bordercolor="Black",
                borderwidth=2
            ),
            width=975,
            height=700,
            margin=go.layout.Margin(
                l=20,
                r=20,
                b=20,
                t=20,
                pad=2
            ),
        )
        self.fig = go.FigureWidget(data=self.data, layout=self.layout)
        for trace in self.fig.data[:-1]:
            trace.on_click(self.show_data_3d_callback)

    def setup_widgets(self, image_folder='images'):
        image_folder = self.base_path + '/' + image_folder
        self.image_list = os.listdir(image_folder)

        # Data Filter Setup
        download_robot_file = Button(
            description='Download Robot File',
            disabled=False,
            button_style='',
            tooltip='Click to download robot file of the current plate',
        )

        download_prep_file = Button(
            description='Download Reagent Prep',
            disabled=False,
            button_style='',
            tooltip='Click to download reagent preperation file for the current plate',
        )

        reset_plot = Button(
            description='Reset',
            disabled=False,
            tooltip='Reset the colors of the plot'
        )

        xy_check = Button(
            description='Show X-Y axes',
            disabled=False,
            button_style='',
            tooltip='Click to show X-Y axes'
        )

        show_hull_check = ToggleButton(
            value=True,
            description='Show Convex Hull',
            disabled=False,
            button_style='',
            tooltip='Toggle to show/hide convex hull',
            icon='check'
        )

        download_robot_file.on_click(self.download_robot_callback)
        download_prep_file.on_click(self.download_prep_callback)
        reset_plot.on_click(self.reset_plot_callback)
        xy_check.on_click(self.set_xy_camera)
        show_hull_check.observe(self.toggle_mesh, 'value')

        # Experiment data tab setup
        self.experiment_table = HTML()
        self.experiment_table.value = "Please click on a point to explore experiment details"

        self.image_data = {}
        for img_filename in os.listdir(image_folder):
            with open("{}/{}".format(image_folder, img_filename), "rb") as f:
                b = f.read()
                self.image_data[img_filename] = b

        self.image_widget = Image(
            value=self.image_data['not_found.png'],
            layout=Layout(height='400px', width='650px')
        )

        experiment_view_vbox = VBox(
            [HBox([self.experiment_table, self.image_widget])])

        self.thermal_plot = self.init_thermal_plot()
        plate_options = self.get_plate_options()
        self.selected_plate = plate_options[0]
        self.generate_thermal(self.selected_plate)
        self.plate_dropdown = Dropdown(options=plate_options,
                                       description='Plate:',
                                       )
        self.plate_dropdown.observe(self.change_plates, 'value')

        #tab = Tab()
        #tab.children = [experiment_view_vbox]
        #tab.set_title(0, 'Experiment Details')
        #tab.set_title(1, 'XRD data')

        plot_tabs = Tab([VBox([self.fig,
                               HBox([xy_check, show_hull_check, reset_plot])]),
                         VBox([self.thermal_plot,
                               HBox([self.plate_dropdown, download_robot_file, download_prep_file])]),
                         ])
        plot_tabs.set_title(0, 'Chemical Space')
        plot_tabs.set_title(1, 'Plate')

        self.full_widget = VBox([plot_tabs, experiment_view_vbox])
        self.full_widget.layout.align_items = 'center'

    def get_plate_options(self):
        plates = set()
        for df in self.amine_crystal_dfs:
            for i, row in df.iterrows():
                name = str(row['name'])
                plate_name = '_'.join(name.split('_')[:-1])
                plates.add(plate_name)
        plate_options = []
        for i, plate in enumerate(plates):
            plate_options.append(plate)
        return plate_options

    def change_plates(self, state):
        self.selected_plate = state.new
        self.generate_thermal(self.selected_plate)

    def init_thermal_plot(self):
        import plotly.graph_objs as go

        #base_url = list(notebookapp.list_running_servers())[0]['base_url']
        #data_url = base_url + 'files/sd2e-community/perovskite-data/data_connected_pub'
        full_url = 'images/not_found.png'
        layout = go.Layout(
            hovermode='closest',
            xaxis=dict(
                title='Column',
                showgrid=False,
                ticktext=[i+1 for i in range(12)],
                tickvals=[i*1.0+0.5 for i in range(12)],

            ),
            yaxis=dict(
                title='Row',
                showgrid=False,
                ticktext=list('ABCDEFGH'),
                tickvals=[i*1.0+0.5 for i in range(8)],

            ),
            images=[
                go.layout.Image(
                    source=full_url,
                    xref="x",
                    yref="y",
                    x=0,
                    y=8,
                    sizex=12,
                    sizey=8,
                    sizing="stretch",
                    opacity=0.8,
                    layer="below")
            ],

            width=950,
            height=700,

        )
        from itertools import product
        xy = list(product([i*1.0+0.5 for i in range(12)],
                          [i*1.0+0.5 for i in range(8)]))
        x, y = list(zip(*xy))
        self.vial_labels = list(product([i+1 for i in range(12)],
                                        list('ABCDEFGH')))
        trace1 = go.Scatter(
            x=x,
            y=y,
            mode='markers',
            marker=dict(size=45,
                        color='rgba(66, 245, 87, 0.1)',
                        line=dict(width=3,
                                  color='rgb(0, 0, 0)')),
            opacity=1.0,
        )
        fig = go.FigureWidget(data=[trace1], layout=layout)
        fig.data[0].on_click(self.show_data_thermal_callback)
        return fig

    def generate_xrd(self):
        import pandas as pd
        dat = pd.read_csv(self.base_path +
                          '/2019-02-21T16_54_38.714239+00_00_LBL_1.xy', skiprows=1, delimiter=' ')
        dat.columns = ['x', 'y']
        trace = go.Scatter(
            x=dat['x'],
            y=dat['y'],
        )
        data = [trace]
        layout = go.Layout(
            autosize=False,
            width=1000,
            height=600,
            margin=go.layout.Margin(
                l=50,
                r=50,
                b=100,
                t=100,
                pad=4
            ),
        )
        self.xrd_plot = go.FigureWidget(data=data, layout=layout)

    def generate_table(self, row, columns, column_names):
        table_html = """ <table border="1" style="width:100%;">
                        <tbody>"""
        for i, column in enumerate(columns):
            if isinstance(row[column], str):
                value = row[column].split('_')[-1]
            else:
                value = np.round(row[column], decimals=3)
            table_html += """
                            <tr>
                                <td style="padding: 8px;">{}</td>
                                <td style="padding: 8px;">{}</td>
                            </tr>
                          """.format(column_names[i], value)
        table_html += """
                        </tbody>
                        </table>
                        """
        return table_html

    def toggle_mesh(self, state):
        with self.fig.batch_update():
            self.fig.data[-1].visible = state.new

    def set_xy_camera(self, state):
        camera = dict(
            up=dict(x=0, y=0, z=1),
            center=dict(x=0, y=0, z=0),
            eye=dict(x=0.0, y=0.0, z=2.5)
        )

        self.fig['layout'].update(
            scene=dict(camera=camera),
        )

    def download_robot_callback(self, b):
        if self.selected_plate:
            js_string = """
                        var base_uri = utils.get_body_data("baseUrl");
                        var file_location = utils.encode_uri_components('{}_RobotInput.xls');
                        // var final_url = utils.url_path_join(base_uri, 'files', file_location)
                        var final_url = 'files/' + file_location
                        console.log(final_url)
                        window.open(final_url, IPython._target);
                        """.format(self.selected_plate)

            display(Javascript(js_string))

    def download_prep_callback(self, b):
        if self.selected_plate:
            js_string = """
                        var base_uri = utils.get_body_data("baseUrl");
                        var file_location = utils.encode_uri_components('{}_ExpDataEntry.xlsx');
                        // var final_url = utils.url_path_join(base_uri, 'files', file_location)
                        var final_url = 'files/' + file_location
                        console.log(final_url)
                        window.open(final_url, IPython._target);
                        """.format(self.selected_plate)

            display(Javascript(js_string))

    def reset_plot_callback(self, b):
        with self.fig.batch_update():
            for i in range(len(self.fig.data[:-1])):
                self.fig.data[i].marker.color = self.trace_colors[i]
                self.fig.data[i].marker.size = 4

    def generate_thermal(self, new_plate):
        if new_plate != self.old_plate:
            self.old_plate = new_plate
            with self.thermal_plot.batch_update():
                # base_url = list(notebookapp.list_running_servers())[
                #    0]['base_url']
                #data_url = base_url + 'files/sd2e-community/perovskite-data/data_connected_pub'
                full_url = 'images/{}_thermal.PNG'.format(new_plate)
                self.thermal_plot.layout.images = [go.layout.Image(
                    source=full_url,
                    xref="x",
                    yref="y",
                    x=0,
                    y=8,
                    sizex=12,
                    sizey=8,
                    sizing="stretch",
                    opacity=0.8,
                    layer="below")]

    def show_data_3d_callback(self, trace, point, selector):
        if point.point_inds:
            selected_experiment = self.amine_crystal_dfs[point.trace_index].iloc[point.point_inds[0]]
            with self.fig.batch_update():
                for i in range(len(self.fig.data[:-1])):
                    color = self.trace_colors[i].split(',')
                    color[-1] = '0.5)'
                    color = ','.join(color)
                    if i == point.trace_index:
                        marker_colors = [color for x in range(len(trace['x']))]
                        marker_colors[point.point_inds[0]
                                      ] = self.trace_colors[i]
                        self.fig.data[i].marker.color = marker_colors
                        self.fig.data[i].marker.size = 6
                    else:
                        self.fig.data[i].marker.color = color
                        self.fig.data[i].marker.size = 4
            self.populate_data(selected_experiment)
            # Code to update thermal image
            self.generate_thermal(self.selected_plate)

    def show_data_thermal_callback(self, trace, point, selector):
        pt_idx = point.point_inds[0]
        vial_name = self.vial_labels[pt_idx][1] + \
            str(self.vial_labels[pt_idx][0])
        experiment_name = self.selected_plate+'_'+vial_name
        #self.amine_crystal_dfs['preTestScore'].where(df['postTestScore'] > 50)
        selected_experiment = None
        for df in self.amine_crystal_dfs:
            if not df.loc[df['name'] == experiment_name].empty:
                selected_experiment = df.loc[df['name']
                                             == experiment_name].iloc[0]
                # print(selected_experiment['name'])
                self.populate_data(selected_experiment)
                break
        marker_colors = [
            'rgba(66, 245, 87, 0.1)' for i in range(len(trace['x']))]
        score = int(selected_experiment['_out_crystalscore'] - 1)
        marker_colors[pt_idx] = self.trace_colors[score]
        with self.thermal_plot.batch_update():
            self.thermal_plot.data[0].marker.color = marker_colors

    def populate_data(self, selected_experiment):
        name = selected_experiment['name']
        if name+'.jpg' in self.image_list:
            self.image_widget.value = self.image_data[name+'.jpg']
        else:
            self.image_widget.value = self.image_data['not_found.png']
        columns = ['name', '_rxn_M_acid', '_rxn_M_inorganic', '_rxn_M_organic',
                   '_rxn_mixingtime1S', '_rxn_mixingtime2S', '_rxn_reactiontimeS',
                   '_rxn_stirrateRPM', '_rxn_temperatureC_actual_bulk']
        column_names = ['Well ID', 'Formic Acid [FAH]', 'Lead Iodide [PbI2]', 'Dimethylammonium Iodide [Me2NH2I]',
                        'Mixing Time Stage 1 (s)', 'Mixing Time Stage 2 (s)', 'Reaction Time (s)',
                        'Stir Rate (RPM)', 'Temperature (C)']

        prefix = '_'.join(name.split('_')[:-1])
        self.selected_plate = prefix
        self.experiment_table.value = '<p>Plate ID:<br> {}</p>'.format(prefix) + self.generate_table(
            selected_experiment.loc[columns], columns, column_names)

    @property
    def plot(self):
        return self.full_widget
Esempio n. 24
0
class FileChooser(VBox):

    _LBL_TEMPLATE = '<span style="margin-left:10px; color:{1};">{0}</span>'
    _LBL_NOFILE = 'No file selected'

    def __init__(self,
                 path=os.getcwd(),
                 filename='',
                 show_hidden=False,
                 **kwargs):

        self._default_path = path.rstrip(os.path.sep)
        self._default_filename = filename
        self._selected_path = ''
        self._selected_filename = ''
        self._show_hidden = show_hidden

        # Widgets
        self._pathlist = Dropdown(description="",
                                  layout=Layout(width='auto',
                                                grid_area='pathlist'))
        self._filename = Text(placeholder='output filename',
                              layout=Layout(width='auto',
                                            grid_area='filename'))
        self._dircontent = Select(rows=8,
                                  layout=Layout(width='auto',
                                                grid_area='dircontent'))
        self._cancel = Button(
            description='Cancel',
            button_style=
            'warning',  # 'success', 'info', 'warning', 'danger' or ''
            layout=Layout(width='auto', display='none'))
        self._select = Button(
            description='Select',
            button_style=
            'success',  # 'success', 'info', 'warning', 'danger' or ''
            layout=Layout(width='auto'))

        # Widget observe handlers
        self._pathlist.observe(self._on_pathlist_select, names='value')
        self._dircontent.observe(self._on_dircontent_select, names='value')
        self._filename.observe(self._on_filename_change, names='value')
        self._select.on_click(self._on_select_click)
        self._cancel.on_click(self._on_cancel_click)

        # Selected file label
        self._label = HTML(value=self._LBL_TEMPLATE.format(
            self._LBL_NOFILE, 'black'),
                           placeholder='',
                           description='')

        # Layout
        self._gb = GridBox(
            children=[self._pathlist, self._filename, self._dircontent],
            layout=Layout(display='none',
                          width='500px',
                          grid_gap='0px 0px',
                          grid_template_rows='auto auto',
                          grid_template_columns='60% 40%',
                          grid_template_areas='''
                    'pathlist filename'
                    'dircontent dircontent'
                    '''))
        buttonbar = HBox(children=[self._select, self._cancel, self._label],
                         layout=Layout(width='auto'))

        # Call setter to set initial form values
        self._set_form_values(self._default_path, self._default_filename)

        # Call VBox super class __init__
        super().__init__(children=[
            self._gb,
            buttonbar,
        ],
                         layout=Layout(width='auto'),
                         **kwargs)

    def _set_form_values(self, path, filename):
        '''Set the form values'''

        # Disable triggers to prevent selecting an entry in the Select
        # box from automatically triggering a new event.
        self._pathlist.unobserve(self._on_pathlist_select, names='value')
        self._dircontent.unobserve(self._on_dircontent_select, names='value')
        self._filename.unobserve(self._on_filename_change, names='value')

        # Set form values
        self._pathlist.options = get_subpaths(path)
        self._pathlist.value = path
        self._filename.value = filename
        self._dircontent.options = get_dir_contents(path,
                                                    hidden=self._show_hidden)

        # If the value in the filename Text box equals a value in the
        # Select box and the entry is a file then select the entry.
        if ((filename in self._dircontent.options)
                and os.path.isfile(os.path.join(path, filename))):
            self._dircontent.value = filename
        else:
            self._dircontent.value = None

        # Reenable triggers again
        self._pathlist.observe(self._on_pathlist_select, names='value')
        self._dircontent.observe(self._on_dircontent_select, names='value')
        self._filename.observe(self._on_filename_change, names='value')

        # Set the state of the select Button
        if self._gb.layout.display is None:
            selected = os.path.join(self._selected_path,
                                    self._selected_filename)

            # filename value is empty or equals the selected value
            if (filename == '') or (os.path.join(path, filename) == selected):
                self._select.disabled = True
            else:
                self._select.disabled = False

    def _on_pathlist_select(self, change):
        '''Handler for when a new path is selected'''
        self._set_form_values(change['new'], self._filename.value)

    def _on_dircontent_select(self, change):
        '''Handler for when a folder entry is selected'''
        new_path = update_path(self._pathlist.value, change['new'])

        # Check if folder or file
        if os.path.isdir(new_path):
            path = new_path
            filename = self._filename.value
        elif os.path.isfile(new_path):
            path = self._pathlist.value
            filename = change['new']

        self._set_form_values(path, filename)

    def _on_filename_change(self, change):
        '''Handler for when the filename field changes'''
        self._set_form_values(self._pathlist.value, change['new'])

    def _on_select_click(self, b):
        '''Handler for when the select button is clicked'''
        if self._gb.layout.display is 'none':
            self._gb.layout.display = None
            self._cancel.layout.display = None

            # Show the form with the correct path and filename
            if self._selected_path and self._selected_filename:
                path = self._selected_path
                filename = self._selected_filename
            else:
                path = self._default_path
                filename = self._default_filename

            self._set_form_values(path, filename)

        else:
            self._gb.layout.display = 'none'
            self._cancel.layout.display = 'none'
            self._select.description = 'Change'
            self._selected_path = self._pathlist.value
            self._selected_filename = self._filename.value
            # self._default_path = self._selected_path
            # self._default_filename = self._selected_filename

            selected = os.path.join(self._selected_path,
                                    self._selected_filename)

            if os.path.isfile(selected):
                self._label.value = self._LBL_TEMPLATE.format(
                    selected, 'orange')
            else:
                self._label.value = self._LBL_TEMPLATE.format(
                    selected, 'green')

    def _on_cancel_click(self, b):
        '''Handler for when the cancel button is clicked'''
        self._gb.layout.display = 'none'
        self._cancel.layout.display = 'none'
        self._select.disabled = False

    def reset(self, path=None, filename=None):
        '''Reset the form to the default path and filename'''
        self._selected_path = ''
        self._selected_filename = ''

        self._label.value = self._LBL_TEMPLATE.format(self._LBL_NOFILE,
                                                      'black')

        if path is not None:
            self._default_path = path.rstrip(os.path.sep)

        if filename is not None:
            self._default_filename = filename

        self._set_form_values(self._default_path, self._default_filename)

    def refresh(self):
        '''Re-render the form'''
        self._set_form_values(self._pathlist.value, self._filename.value)

    @property
    def show_hidden(self):
        '''Get current number of rows'''
        return self._show_hidden

    @show_hidden.setter
    def show_hidden(self, hidden):
        '''Set number of rows'''
        self._show_hidden = hidden
        self.refresh()

    @property
    def rows(self):
        '''Get current number of rows'''
        return self._dircontent.rows

    @rows.setter
    def rows(self, rows):
        '''Set number of rows'''
        self._dircontent.rows = rows

    @property
    def default(self):
        '''Get the default value'''
        return os.path.join(self._default_path, self._default_filename)

    @property
    def default_path(self):
        '''Get the default_path value'''
        return self._default_path

    @default_path.setter
    def default_path(self, path):
        '''Set the default_path'''
        self._default_path = path.rstrip(os.path.sep)
        self._default = os.path.join(self._default_path, self._filename.value)
        self._set_form_values(self._default_path, self._filename.value)

    @property
    def default_filename(self):
        '''Get the default_filename value'''
        return self._default_filename

    @default_filename.setter
    def default_filename(self, filename):
        '''Set the default_filename'''
        self._default_filename = filename
        self._default = os.path.join(self._pathlist.value,
                                     self._default_filename)
        self._set_form_values(self._pathlist.value, self._default_filename)

    @property
    def selected(self):
        '''Get selected value'''
        return os.path.join(self._selected_path, self._selected_filename)

    @property
    def selected_path(self):
        '''Get selected_path value'''
        return self._selected_path

    @property
    def selected_filename(self):
        '''Get the selected_filename'''
        return self._selected_filename

    @property
    def nmrname(self):  # added by MAD
        return os.path.join(
            os.path.basename(os.path.dirname(self._selected_path)),
            os.path.basename(self._selected_path))

    def __repr__(self):
        str_ = ("FileChooser("
                "path='{0}', "
                "filename='{1}', "
                "show_hidden='{2}')").format(self._default_path,
                                             self._default_filename,
                                             self._show_hidden)
        return str_
Esempio n. 25
0
class NGLDisplay:
    """Structure display class

    Provides basic structure/trajectory display
    in the notebook and optional gui which can be used to enhance its
    usability.  It is also possible to extend the functionality of the
    particular instance of the viewer by adding further widgets
    manipulating the structure.
    """
    def __init__(self, atoms, xsize=500, ysize=500):
        import nglview
        import nglview.color

        from ipywidgets import Dropdown, FloatSlider, IntSlider, HBox, VBox
        self.atoms = atoms
        if isinstance(atoms[0], Atoms):
            # Assume this is a trajectory or struct list
            self.view = nglview.show_asetraj(atoms, default=False)
            self.frm = IntSlider(value=0, min=0, max=len(atoms) - 1)
            self.frm.observe(self._update_frame)
            self.struct = atoms[0]
        else:
            # Assume this is just a single structure
            self.view = nglview.show_ase(atoms, default=False)
            self.struct = atoms
            self.frm = None

        self.colors = {}
        self.view._remote_call('setSize', target='Widget',
                               args=['%dpx' % (xsize,), '%dpx' % (ysize,)])
        self.view.add_unitcell()
        self.view.add_spacefill()
        self.view.camera = 'orthographic'
        self.view.parameters = { "clipDist": 0 }

        self.view.center()

        self.asel = Dropdown(options=['All'] +
                             list(set(self.struct.get_chemical_symbols())),
                             value='All', description='Show')

        self.csel = Dropdown(options=nglview.color.COLOR_SCHEMES,
                             value='element', description='Color scheme')

        self.rad = FloatSlider(value=0.5, min=0.0, max=1.5, step=0.01,
                               description='Ball size')

        self.asel.observe(self._select_atom)
        self.csel.observe(self._update_repr)
        self.rad.observe(self._update_repr)

        self.view.update_spacefill(radiusType='covalent',
                                   radiusScale=0.5,
                                   color_scheme=self.csel.value,
                                   color_scale='rainbow')

        wdg = [self.asel, self.csel, self.rad]
        if self.frm:
            wdg.append(self.frm)

        self.gui = HBox([self.view, VBox(wdg)])
        # Make useful shortcuts for the user of the class
        self.gui.view = self.view
        self.gui.control_box = self.gui.children[1]
        self.gui.custom_colors = self.custom_colors

    def _update_repr(self, chg=None):
        self.view.update_spacefill(radiusType='covalent',
                                   radiusScale=self.rad.value,
                                   color_scheme=self.csel.value,
                                   color_scale='rainbow')

    def _update_frame(self, chg=None):
        self.view.frame = self.frm.value
        return

    def _select_atom(self, chg=None):
        sel = self.asel.value
        self.view.remove_spacefill()
        for e in set(self.struct.get_chemical_symbols()):
            if (sel == 'All' or e == sel):
                if e in self.colors:
                    self.view.add_spacefill(selection='#' + e,
                                            color=self.colors[e])
                else:
                    self.view.add_spacefill(selection='#' + e)
        self._update_repr()

    def custom_colors(self, clr=None):
        """
        Define custom colors for some atoms. Pass a dictionary of the form
        {'Fe':'red', 'Au':'yellow'} to the function.
        To reset the map to default call the method without parameters.
        """
        if clr:
            self.colors = clr
        else:
            self.colors = {}
        self._select_atom()
Esempio n. 26
0
class CellDefTab(object):

    def __init__(self):
        
        micron_units = Label('micron')   # use "option m" (Mac, for micro symbol)

        constWidth = '180px'
        tab_height = '500px'
        stepsize = 10

        #style = {'description_width': '250px'}
        style = {'description_width': '25%'}
        layout = {'width': '400px'}

        name_button_layout={'width':'25%'}
        widget_layout = {'width': '15%'}
        units_button_layout ={'width':'15%'}
        desc_button_layout={'width':'45%'}
        # divider_button_layout={'width':'40%', 'align_items':'left'}
        divider_button_layout={'width':'40%'}

        self.cell_parent_dict = {'lung epithelium':'default', 'immune':'default', 'CD8 Tcell':'immune'}
        self.cell_type = Dropdown(description='Cell:',
          options={'default':'default', 'lung epithelium':'lung epithelium', 'immune':'immune', 'CD8 Tcell':'CD8 Tcell'})
        self.cell_type.style = {'description_width': '%sch' % str(len(self.cell_type.description) + 1)}
        self.cell_type.observe(self.cell_type_cb)

        self.parent_name = Text(value='None',placeholder='Type something',description='Parent:',disabled=True)

        menv_var1 = Button(description='director_signal', disabled=True, layout=name_button_layout)
        menv_var1.style.button_color = 'tan'

        param_name1 = Button(description='cycle trans rate', disabled=True, layout=name_button_layout)

        self.cycle_trans_rate = FloatText(value=1000,
          step=100,style=style, layout=widget_layout)

        param_name2 = Button(description='decay_rate', disabled=True, layout=name_button_layout)

        self.director_signal_decay_rate = FloatText(value=.1,
          step=0.01,style=style, layout=widget_layout)
        param_name3 = Button(description='initial_condition', disabled=True, layout=name_button_layout)

        self.director_signal_initial_condition = FloatText(value=0,style=style, layout=widget_layout)
        param_name4 = Button(description='Dirichlet_boundary_condition', disabled=True, layout=name_button_layout)

        self.director_signal_Dirichlet_boundary_condition = FloatText(value=1,style=style, layout=widget_layout)
        self.director_signal_Dirichlet_boundary_condition_toggle = Checkbox(description='on/off', disabled=False,style=style, layout=widget_layout)

        menv_var2 = Button(description='cargo_signal', disabled=True, layout=name_button_layout)
        menv_var2.style.button_color = 'lightgreen'

        param_name5 = Button(description='diffusion_coefficient', disabled=True, layout=name_button_layout)

        self.cargo_signal_diffusion_coefficient = FloatText(value=1000,
          step=100,style=style, layout=widget_layout)

        param_name6 = Button(description='decay_rate', disabled=True, layout=name_button_layout)

        self.cargo_signal_decay_rate = FloatText(value=.4,
          step=0.1,style=style, layout=widget_layout)
        param_name7 = Button(description='initial_condition', disabled=True, layout=name_button_layout)

        self.cargo_signal_initial_condition = FloatText(value=0,style=style, layout=widget_layout)
        param_name8 = Button(description='Dirichlet_boundary_condition', disabled=True, layout=name_button_layout)

        self.cargo_signal_Dirichlet_boundary_condition = FloatText(value=1,style=style, layout=widget_layout)
        self.cargo_signal_Dirichlet_boundary_condition_toggle = Checkbox(description='on/off', disabled=False,style=style, layout=widget_layout)
        self.calculate_gradient = Checkbox(description='calculate_gradients', disabled=False, layout=desc_button_layout)
        self.track_internal = Checkbox(description='track_in_agents', disabled=False, layout=desc_button_layout)




        row_director_signal = [menv_var1,  ] 

        box_layout = Layout(display='flex', flex_flow='row', align_items='stretch', width='100%')
        """
        box_director_signal = Box(children=row_director_signal, layout=box_layout)
        box1 = Box(children=row1, layout=box_layout)

        box_cargo_signal = Box(children=row_cargo_signal, layout=box_layout)
        box5 = Box(children=row5, layout=box_layout)
        """

        #--------------------------
        div_cycle = Button(description='Phenotype:cycle', disabled=True, layout=divider_button_layout)

        param_name1 = Button(description='transition rate: 0->1', disabled=True, layout=name_button_layout)
        param_name1.style.button_color = 'tan'

        param_name1_units = Button(description='1/min', disabled=True, layout=units_button_layout) 
        param_name1_units.style.button_color = 'tan'

        self.cycle_trans_rate1 = FloatText(
          value=0.0001,
          step=0.00001,
          style=style, layout=widget_layout)

        row1 = [param_name1, self.cycle_trans_rate1, param_name1_units]
        box1 = Box(children=row1, layout=box_layout)


        param_name2 = Button(description='transition rate: 1->2', disabled=True, layout=name_button_layout)
        param_name2.style.button_color = 'lightgreen'

        param_name2_units = Button(description='1/min', disabled=True, layout=units_button_layout) 
        param_name2_units.style.button_color = 'lightgreen'

        self.cycle_trans_rate2 = FloatText(
          value=0.0002,
          step=0.00001,
          style=style, layout=widget_layout)

        row2 = [param_name2, self.cycle_trans_rate2, param_name2_units]
        box2 = Box(children=row2, layout=box_layout)

        #--------------------------
        div_death = Button(description='Phenotype:death', disabled=True, layout=divider_button_layout)

        #--------------------------
        div_volume = Button(description='Phenotype:volume', disabled=True, layout=divider_button_layout)

        param_name9 = Button(description='volume', disabled=True, layout=name_button_layout)
        param_name9.style.button_color = 'tan'

        param_name9_units = Button(description='micron^3', disabled=True, layout=units_button_layout) 
        param_name9_units.style.button_color = 'tan'

        self.volume = FloatText(
          value=2.15e3,
          step=100,
          style=style, layout=widget_layout)

        row9 = [param_name9, self.volume, param_name9_units]
        box9 = Box(children=row9, layout=box_layout)

        #--------------------------
        #--------------------------
        div_mechanics = Button(description='Phenotype:mechanics', disabled=True, layout=divider_button_layout)

        #--------------------------
        div_motility = Button(description='Phenotype:motility', disabled=True, layout=divider_button_layout)

        #--------------------------
        div_secretion = Button(description='Phenotype:secretion', disabled=True, layout=divider_button_layout)

        #--------------------------
        div_intracellular = Button(description='Phenotype:intracellular', disabled=True, layout=divider_button_layout)

        #--------------------------
        div_custom_data = Button(description='Custom data', disabled=True, layout=divider_button_layout)
# <elastic_coefficient length=”1” units=”1/min”>1.0</elastic_coefficient>
# <attachment_point length=”3” units=”micron”>-12.8,13.9,0.0</attachment_point>
        param_name31 = Button(description='elastic_coefficient', disabled=True, layout=name_button_layout)
        param_name31.style.button_color = 'tan'
        param_name31_units = Button(description='1/min', disabled=True, layout=units_button_layout) 
        param_name31_units.style.button_color = 'tan'
        self.custom_elastic_coef = FloatText(
          value=1.0,
          step=0.1,
          style=style, layout=widget_layout)
        row31 = [param_name31, self.custom_elastic_coef, param_name31_units]
        box31 = Box(children=row31, layout=box_layout)

        param_name32 = Button(description='attachment_point', disabled=True, layout=name_button_layout)
        param_name32.style.button_color = 'lightgreen'
        param_name32_units = Button(description='micron', disabled=True, layout=units_button_layout) 
        param_name32_units.style.button_color = 'lightgreen'
        self.custom_attachment_point = Text(
          value="-12.8,13.9,0.0",
          style=style, layout=widget_layout)
        row32 = [param_name32, self.custom_attachment_point, param_name32_units]
        box32 = Box(children=row32, layout=box_layout)
        #--------------------------

        self.vbox1 = VBox([
          div_cycle,
          box1,
          box2,
          div_death,
          div_volume,
          box9,
          div_mechanics,
          div_motility,
          div_secretion,
          div_intracellular,
          div_custom_data,
          box31,
          box32,
        ])
        self.vbox2 = VBox([
          box1,
        ])
        self.cell_stuff = self.vbox1
        self.tab = VBox([
          HBox([self.cell_type, self.parent_name]),
          self.vbox1,
         self.vbox2
        ])

    #------------------------------
    def cell_type_cb(self, change):
      if change['type'] == 'change' and change['name'] == 'value':
        print("changed to %s" % change['new'])
        # self.vbox1.layout.visibility = 'hidden'  # vs. visible
        # self.vbox1.layout.visibility = None 
        self.vbox1.layout.display = 'none' 
        # self.tab[1] = self.vbox2
        # self.cell_stuff = self.vbox2
        # self.tab.children[1] = self.vbox2
        # print("self.tab.children[1] = ",self.tab.children[1])

#      print('update_parent_cb')

    #--------------------------
    # Populate the GUI widgets with values from the XML
    def fill_gui(self, xml_root):
      return

    # Read values from the GUI widgets to enable editing XML
    def fill_xml(self, xml_root):
        uep = xml_root.find('.//microenvironment_setup')  # find unique entry point
        vp = []   # pointers to <variable> nodes
        if uep:
            for var in uep.findall('variable'):
                vp.append(var)

        uep = xml_root.find('.//microenvironment_setup')  # find unique entry point
        vp[0].find('.//diffusion_coefficient').text = str(self.director_signal_diffusion_coefficient.value)
        vp[0].find('.//decay_rate').text = str(self.director_signal_decay_rate.value)
        vp[0].find('.//initial_condition').text = str(self.director_signal_initial_condition.value)
        vp[0].find('.//Dirichlet_boundary_condition').text = str(self.director_signal_Dirichlet_boundary_condition.value)
        vp[0].find('.//Dirichlet_boundary_condition').attrib['enabled'] = str(self.director_signal_Dirichlet_boundary_condition_toggle.value).lower()

        vp[1].find('.//diffusion_coefficient').text = str(self.cargo_signal_diffusion_coefficient.value)
        vp[1].find('.//decay_rate').text = str(self.cargo_signal_decay_rate.value)
        vp[1].find('.//initial_condition').text = str(self.cargo_signal_initial_condition.value)
        vp[1].find('.//Dirichlet_boundary_condition').text = str(self.cargo_signal_Dirichlet_boundary_condition.value)
        vp[1].find('.//Dirichlet_boundary_condition').attrib['enabled'] = str(self.cargo_signal_Dirichlet_boundary_condition_toggle.value).lower()


        uep.find('.//options//calculate_gradients').text = str(self.calculate_gradient.value)
        uep.find('.//options//track_internalized_substrates_in_each_agent').text = str(self.track_internal.value)
Esempio n. 27
0
class JupyterRenderer:
    def __init__(
            self,
            size=(640, 480),
            compute_normals_mode=NORMAL.SERVER_SIDE,
            default_shape_color=format_color(166, 166, 166),  # light grey
            default_edge_color=format_color(32, 32, 32),  # dark grey
            default_vertex_color=format_color(8, 8, 8),  # darker grey
            pick_color=format_color(232, 176, 36),  # orange
            background_color='white'):
        """ Creates a jupyter renderer.
        size: a tuple (width, height). Must be a square, or shapes will look like deformed
        compute_normals_mode: optional, set to SERVER_SIDE by default. This flag lets you choose the
        way normals are computed. If SERVER_SIDE is selected (default value), then normals
        will be computed by the Tesselator, packed as a python tuple, and send as a json structure
        to the client. If, on the other hand, CLIENT_SIDE is chose, then the computer only compute vertex
        indices, and let the normals be computed by the client (the web js machine embedded in the webrowser).

        * SERVER_SIDE: higher server load, loading time increased, lower client load. Poor performance client will
          choose this option (mobile terminals for instance)
        * CLIENT_SIDE: lower server load, loading time decreased, higher client load. Higher performance clients will
                            choose this option (laptops, desktop machines).
        * default_shape_color
        * default_e1dge_color:
        * default_pick_color:
        * background_color:
        """
        self._default_shape_color = default_shape_color
        self._default_edge_color = default_edge_color
        self._default_vertex_color = default_vertex_color
        self._pick_color = pick_color

        self._background = background_color
        self._background_opacity = 1
        self._size = size
        self._compute_normals_mode = compute_normals_mode

        self._bb = None  # the bounding box, necessary to compute camera position

        # the default camera object
        self._camera_target = [0., 0., 0.]  # the point to look at
        self._camera_position = [0, 0., 100.]  # the camera initial position
        self._camera = None
        self._camera_distance_factor = 6
        self._camera_initial_zoom = 2.5

        # a dictionnary of all the shapes belonging to the renderer
        # each element is a key 'mesh_id:shape'
        self._shapes = {}

        # we save the renderer so that is can be accessed
        self._renderer = None

        # the group of 3d and 2d objects to render
        self._displayed_pickable_objects = Group()

        # the group of other objects (grid, trihedron etc.) that can't be selected
        self._displayed_non_pickable_objects = Group()

        # event manager/selection manager
        self._picker = None

        self._current_shape_selection = None
        self._current_mesh_selection = None
        self._savestate = None

        self._selection_color = format_color(232, 176, 36)

        self._select_callbacks = [
        ]  # a list of all functions called after an object is selected

        # UI
        self.layout = Layout(width='auto', height='auto')
        self._toggle_shp_visibility_button = self.create_button(
            "Hide/Show", "Toggle Shape Visibility", True,
            self.toggle_shape_visibility)
        self._shp_properties_button = Dropdown(options=[
            'Compute', 'Inertia', 'Recognize Face', 'Aligned BBox',
            'Oriented BBox'
        ],
                                               value='Compute',
                                               description='',
                                               layout=self.layout,
                                               disabled=True)
        self._shp_properties_button.observe(self.on_compute_change)
        self._remove_shp_button = self.create_button(
            "Remove", "Permanently remove the shape from the Scene", True,
            self.remove_shape)
        self._controls = [
            self.create_checkbox("axes", "Axes", True,
                                 self.toggle_axes_visibility),
            self.create_checkbox("grid", "Grid", True,
                                 self.toggle_grid_visibility),
            self.create_button("Reset View", "Restore default view", False,
                               self._reset), self._shp_properties_button,
            self._toggle_shp_visibility_button, self._remove_shp_button
        ]
        self.html = HTML("")

    def create_button(self, description, tooltip, disabled, handler):
        button = Button(disabled=disabled,
                        tooltip=tooltip,
                        description=description,
                        layout=self.layout)
        button.on_click(handler)
        return button

    def create_checkbox(self, kind, description, value, handler):
        checkbox = Checkbox(value=value,
                            description=description,
                            layout=self.layout)
        checkbox.observe(handler, "value")
        checkbox.add_class("view_%s" % kind)
        return checkbox

    def remove_shape(self, *kargs):
        self.clicked_obj.visible = not self.clicked_obj.visible
        # remove shape fro mthe mapping dict
        cur_id = self.clicked_obj.name
        del self._shapes[cur_id]
        self._remove_shp_button.disabled = True

    def on_compute_change(self, change):
        if change['type'] == 'change' and change['name'] == 'value':
            selection = change['new']
            output = ""
            if 'Inertia' in selection:
                cog, mass, mass_property = measure_shape_mass_center_of_gravity(
                    self._current_shape_selection)
                # display this point (type gp_Pnt)
                self.DisplayShape([cog])
                output += "<u><b>Center of Gravity</b></u>:<br><b>Xcog=</b>%.3f<br><b>Ycog=</b>%.3f<br><b>Zcog=</b>%.3f<br>" % (
                    cog.X(), cog.Y(), cog.Z())
                output += "<u><b>%s=</b></u>:<b>%.3f</b><br>" % (mass_property,
                                                                 mass)
            elif 'Oriented' in selection:
                center, dim, oobb_shp = get_oriented_boundingbox(
                    self._current_shape_selection)
                self.DisplayShape(oobb_shp,
                                  render_edges=True,
                                  transparency=True,
                                  opacity=0.2,
                                  selectable=False)
                output += "<u><b>OOBB center</b></u>:<br><b>X=</b>%.3f<br><b>Y=</b>%.3f<br><b>Z=</b>%.3f<br>" % (
                    center.X(), center.Y(), center.Z())
                output += "<u><b>OOBB dimensions</b></u>:<br><b>dX=</b>%.3f<br><b>dY=</b>%.3f<br><b>dZ=</b>%.3f<br>" % (
                    dim[0], dim[1], dim[2])
                output += "<u><b>OOBB volume</b></u>:<br><b>V=</b>%.3f<br>" % (
                    dim[0] * dim[1] * dim[2])
            elif 'Aligned' in selection:
                center, dim, albb_shp = get_aligned_boundingbox(
                    self._current_shape_selection)
                self.DisplayShape(albb_shp,
                                  render_edges=True,
                                  transparency=True,
                                  opacity=0.2,
                                  selectable=False)
                output += "<u><b>ABB center</b></u>:<br><b>X=</b>%.3f<br><b>Y=</b>%.3f<br><b>Z=</b>%.3f<br>" % (
                    center.X(), center.Y(), center.Z())
                output += "<u><b>ABB dimensions</b></u>:<br><b>dX=</b>%.3f<br><b>dY=</b>%.3f<br><b>dZ=</b>%.3f<br>" % (
                    dim[0], dim[1], dim[2])
                output += "<u><b>ABB volume</b></u>:<br><b>V=</b>%.3f<br>" % (
                    dim[0] * dim[1] * dim[2])
            elif 'Recognize' in selection:
                # try featrue recognition
                kind, pnt, vec = recognize_face(self._current_shape_selection)
                output += "<u><b>Type</b></u>: %s<br>" % kind
                if kind == "Plane":
                    self.DisplayShape([pnt])
                    output += "<u><b>Properties</b></u>:<br>"
                    output += "<u><b>Point</b></u>:<br><b>X=</b>%.3f<br><b>Y=</b>%.3f<br><b>Z=</b>%.3f<br>" % (
                        pnt.X(), pnt.Y(), pnt.Z())
                    output += "<u><b>Normal</b></u>:<br><b>u=</b>%.3f<br><b>v=</b>%.3f<br><b>w=</b>%.3f<br>" % (
                        vec.X(), vec.Y(), vec.Z())
                elif kind == "Cylinder":
                    self.DisplayShape([pnt])
                    output += "<u><b>Properties</b></u>:<br>"
                    output += "<u><b>Axis point</b></u>:<br><b>X=</b>%.3f<br><b>Y=</b>%.3f<br><b>Z=</b>%.3f<br>" % (
                        pnt.X(), pnt.Y(), pnt.Z())
                    output += "<u><b>Axis direction</b></u>:<br><b>u=</b>%.3f<br><b>v=</b>%.3f<br><b>w=</b>%.3f<br>" % (
                        vec.X(), vec.Y(), vec.Z())
            self.html.value = output

    def toggle_shape_visibility(self, *kargs):
        self.clicked_obj.visible = not self.clicked_obj.visible

    def toggle_axes_visibility(self, change):
        self.axes.set_visibility(_bool_or_new(change))

    def toggle_grid_visibility(self, change):
        self.horizontal_grid.set_visibility(_bool_or_new(change))
        self.vertical_grid.set_visibility(_bool_or_new(change))

    def click(self, value):
        """ called whenever a shape  or edge is clicked
        """
        obj = value.owner.object
        self.clicked_obj = obj
        if self._current_mesh_selection != obj:
            if self._current_mesh_selection is not None:
                self._current_mesh_selection.material.color = self._current_selection_material_color
                self._current_mesh_selection.material.transparent = False
                self._current_mesh_selection = None
                self._current_selection_material_color = None
                self._shp_properties_button.value = "Compute"
                self._shp_properties_button.disabled = True
                self._toggle_shp_visibility_button.disabled = True
                self._remove_shp_button.disabled = True
                self._current_shape_selection = None
            if obj is not None:
                self._shp_properties_button.disabled = False
                self._toggle_shp_visibility_button.disabled = False
                self._remove_shp_button.disabled = False
                id_clicked = obj.name  # the mesh id clicked
                self._current_mesh_selection = obj
                self._current_selection_material_color = obj.material.color
                obj.material.color = self._selection_color
                # selected part becomes transparent
                obj.material.transparent = True
                obj.material.opacity = 0.5
                # get the shape from this mesh id
                selected_shape = self._shapes[id_clicked]
                html_value = "<b>Shape type:</b> %s<br>" % get_type_as_string(
                    selected_shape)
                html_value += "<b>Shape id:</b> %s<br>" % id_clicked
                self.html.value = html_value
                self._current_shape_selection = selected_shape
            else:
                self.html.value = "<b>Shape type:</b> None<br><b>Shape id:</b> None"
            # then execute calbacks
            for callback in self._select_callbacks:
                callback(self._current_shape_selection)

    def register_select_callback(self, callback):
        """ Adds a callback that will be called each time a shape is selected
        """
        if not callable(callback):
            raise AssertionError(
                "You must provide a callable to register the callback")
        else:
            self._select_callbacks.append(callback)

    def unregister_callback(self, callback):
        """ Remove a callback from the callback list
        """
        if callback not in self._select_callbacks:
            raise AssertionError("This callback is not registered")
        else:
            self._select_callbacks.remove(callback)

    def GetSelectedShape(self):
        """ Returns the selected shape
        """
        return self._current_shape_selection

    def DisplayShapeAsSVG(self,
                          shp,
                          export_hidden_edges=True,
                          location=gp_Pnt(0, 0, 0),
                          direction=gp_Dir(1, 1, 1),
                          color="black",
                          line_width=0.5):
        svg_string = export_shape_to_svg(
            shp,
            export_hidden_edges=export_hidden_edges,
            location=location,
            direction=direction,
            color=color,
            line_width=line_width,
            margin_left=0,
            margin_top=0)
        svg = SVG(data=svg_string)
        display(svg)

    def DisplayShape(self,
                     shp,
                     shape_color=None,
                     render_edges=False,
                     edge_color=None,
                     edge_deflection=0.05,
                     vertex_color=None,
                     quality=1.0,
                     transparency=False,
                     opacity=1.,
                     topo_level='default',
                     update=False,
                     selectable=True):
        """ Displays a topods_shape in the renderer instance.
        shp: the TopoDS_Shape to render
        shape_color: the shape color, in html corm, eg '#abe000'
        render_edges: optional, False by default. If True, compute and dislay all
                      edges as a linear interpolation of segments.
        edge_color: optional, black by default. The color used for edge rendering,
                    in html form eg '#ff00ee'
        edge_deflection: optional, 0.05 by default
        vertex_color: optional
        quality: optional, 1.0 by default. If set to something lower than 1.0,
                      mesh will be more precise. If set to something higher than 1.0,
                      mesh will be less precise, i.e. lower numer of triangles.
        transparency: optional, False by default (opaque).
        opacity: optional, float, by default to 1 (opaque). if transparency is set to True,
                 0. is fully opaque, 1. is fully transparent.
        topo_level: "default" by default. The value should be either "compound", "shape", "vertex".
        update: optional, False by default. If True, render all the shapes.
        selectable: if True, can be doubleclicked from the 3d window
        """
        if edge_color is None:
            edge_color = self._default_edge_color
        if shape_color is None:
            shape_color = self._default_shape_color
        if vertex_color is None:
            vertex_color = self._default_vertex_color

        output = []  # a list of all geometries created from the shape
        # is it list of gp_Pnt ?
        if isinstance(shp, list) and isinstance(shp[0], gp_Pnt):
            result = self.AddVerticesToScene(shp, vertex_color)
            output.append(result)
        # or a 1d element such as edge or wire ?
        elif is_wire(shp) or is_edge(shp):
            result = self.AddCurveToScene(shp, edge_color, edge_deflection)
            output.append(result)
        elif topo_level != "default":
            t = TopologyExplorer(shp)
            map_type_and_methods = {
                "Solid": t.solids,
                "Face": t.faces,
                "Shell": t.shells,
                "Compound": t.compounds,
                "Compsolid": t.comp_solids
            }
            for subshape in map_type_and_methods[topo_level]():
                result = self.AddShapeToScene(subshape, shape_color,
                                              render_edges, edge_color,
                                              vertex_color, quality,
                                              transparency, opacity)
                output.append(result)
        else:
            result = self.AddShapeToScene(shp, shape_color, render_edges,
                                          edge_color, vertex_color, quality,
                                          transparency, opacity)
            output.append(result)

        if selectable:  # Add geometries to pickable or non pickable objects
            for elem in output:
                self._displayed_pickable_objects.add(elem)

        if update:
            self.Display()

    def AddVerticesToScene(self, pnt_list, vertex_color, vertex_width=5):
        """ shp is a list of gp_Pnt
        """
        vertices_list = []  # will be passed to pythreejs
        BB = BRep_Builder()
        compound = TopoDS_Compound()
        BB.MakeCompound(compound)

        for vertex in pnt_list:
            vertex_to_add = BRepBuilderAPI_MakeVertex(vertex).Shape()
            BB.Add(compound, vertex_to_add)
            vertices_list.append([vertex.X(), vertex.Y(), vertex.Z()])

        # map the Points and the AIS_PointCloud
        # and to the dict of shapes, to have a mapping between meshes and shapes
        point_cloud_id = "%s" % uuid.uuid4().hex
        self._shapes[point_cloud_id] = compound

        vertices_list = np.array(vertices_list, dtype=np.float32)
        attributes = {
            "position": BufferAttribute(vertices_list, normalized=False)
        }
        mat = PointsMaterial(color=vertex_color,
                             sizeAttenuation=True,
                             size=vertex_width)
        geom = BufferGeometry(attributes=attributes)
        points = Points(geometry=geom, material=mat, name=point_cloud_id)
        return points

    def AddCurveToScene(self, shp, edge_color, deflection):
        """ shp is either a TopoDS_Wire or a TopodS_Edge.
        """
        if is_edge(shp):
            pnts = discretize_edge(shp, deflection)
        elif is_wire(shp):
            pnts = discretize_wire(shp, deflection)
        np_edge_vertices = np.array(pnts, dtype=np.float32)
        np_edge_indices = np.arange(np_edge_vertices.shape[0], dtype=np.uint32)
        edge_geometry = BufferGeometry(
            attributes={
                'position': BufferAttribute(np_edge_vertices),
                'index': BufferAttribute(np_edge_indices)
            })
        edge_material = LineBasicMaterial(color=edge_color, linewidth=1)

        # and to the dict of shapes, to have a mapping between meshes and shapes
        edge_id = "%s" % uuid.uuid4().hex
        self._shapes[edge_id] = shp

        edge_line = Line(geometry=edge_geometry,
                         material=edge_material,
                         name=edge_id)

        # and to the dict of shapes, to have a mapping between meshes and shapes
        edge_id = "%s" % uuid.uuid4().hex
        self._shapes[edge_id] = shp

        return edge_line

    def AddShapeToScene(
            self,
            shp,
            shape_color=None,  # the default
            render_edges=False,
            edge_color=None,
            vertex_color=None,
            quality=1.0,
            transparency=False,
            opacity=1.):
        # first, compute the tesselation
        tess = ShapeTesselator(shp)
        tess.Compute(compute_edges=render_edges,
                     mesh_quality=quality,
                     parallel=True)
        # get vertices and normals
        vertices_position = tess.GetVerticesPositionAsTuple()

        number_of_triangles = tess.ObjGetTriangleCount()
        number_of_vertices = len(vertices_position)

        # number of vertices should be a multiple of 3
        if number_of_vertices % 3 != 0:
            raise AssertionError("Wrong number of vertices")
        if number_of_triangles * 9 != number_of_vertices:
            raise AssertionError("Wrong number of triangles")

        # then we build the vertex and faces collections as numpy ndarrays
        np_vertices = np.array(vertices_position, dtype='float32').reshape(
            int(number_of_vertices / 3), 3)
        # Note: np_faces is just [0, 1, 2, 3, 4, 5, ...], thus arange is used
        np_faces = np.arange(np_vertices.shape[0], dtype='uint32')

        # set geometry properties
        buffer_geometry_properties = {
            'position': BufferAttribute(np_vertices),
            'index': BufferAttribute(np_faces)
        }
        if self._compute_normals_mode == NORMAL.SERVER_SIDE:
            # get the normal list, converts to a numpy ndarray. This should not raise
            # any issue, since normals have been computed by the server, and are available
            # as a list of floats
            np_normals = np.array(tess.GetNormalsAsTuple(),
                                  dtype='float32').reshape(-1, 3)
            # quick check
            if np_normals.shape != np_vertices.shape:
                raise AssertionError("Wrong number of normals/shapes")
            buffer_geometry_properties['normal'] = BufferAttribute(np_normals)

        # build a BufferGeometry instance
        shape_geometry = BufferGeometry(attributes=buffer_geometry_properties)

        # if the client has to render normals, add the related js instructions
        if self._compute_normals_mode == NORMAL.CLIENT_SIDE:
            shape_geometry.exec_three_obj_method('computeVertexNormals')

        # then a default material
        shp_material = self._material(shape_color,
                                      transparent=transparency,
                                      opacity=opacity)

        # and to the dict of shapes, to have a mapping between meshes and shapes
        mesh_id = "%s" % uuid.uuid4().hex
        self._shapes[mesh_id] = shp

        # finally create the mesh
        shape_mesh = Mesh(geometry=shape_geometry,
                          material=shp_material,
                          name=mesh_id)

        # edge rendering, if set to True
        if render_edges:
            edges = list(
                map(
                    lambda i_edge: [
                        tess.GetEdgeVertex(i_edge, i_vert)
                        for i_vert in range(tess.ObjEdgeGetVertexCount(i_edge))
                    ], range(tess.ObjGetEdgeCount())))
            edge_list = _flatten(list(map(_explode, edges)))
            lines = LineSegmentsGeometry(positions=edge_list)
            mat = LineMaterial(linewidth=1, color=edge_color)
            edge_lines = LineSegments2(lines, mat)
            self._displayed_non_pickable_objects.add(edge_lines)

        return shape_mesh

    def _scale(self, vec):
        r = self._bb._max_dist_from_center() * self._camera_distance_factor
        n = np.linalg.norm(vec)
        new_vec = [v / n * r for v in vec]
        return new_vec

    def _material(self, color, transparent=False, opacity=1.0):
        #material = MeshPhongMaterial()
        material = CustomMaterial("standard")
        material.color = color
        material.clipping = True
        material.side = "DoubleSide"
        material.polygonOffset = True
        material.polygonOffsetFactor = 1
        material.polygonOffsetUnits = 1
        material.transparent = transparent
        material.opacity = opacity
        material.update("metalness", 0.3)
        material.update("roughness", 0.8)
        return material

    def EraseAll(self):
        self._shapes = {}
        self._displayed_pickable_objects = Group()
        self._current_shape_selection = None
        self._current_mesh_selection = None
        self._current_selection_material = None
        self._renderer.scene = Scene(children=[])

    def Display(self, position=None, rotation=None):
        # Get the overall bounding box
        if self._shapes:
            self._bb = BoundingBox([self._shapes.values()])
        else:  # if nothing registered yet, create a fake bb
            self._bb = BoundingBox([[BRepPrimAPI_MakeSphere(5.).Shape()]])
        bb_max = self._bb.max
        orbit_radius = 1.5 * self._bb._max_dist_from_center()

        # Set up camera
        camera_target = self._bb.center
        camera_position = _add(
            self._bb.center,
            self._scale(
                [1, 1, 1] if position is None else self._scale(position)))
        camera_zoom = self._camera_initial_zoom

        self._camera = CombinedCamera(position=camera_position,
                                      width=self._size[0],
                                      height=self._size[1])
        self._camera.up = (0.0, 0.0, 1.0)
        self._camera.mode = 'orthographic'
        self._camera_target = camera_target
        self._camera.position = camera_position
        if rotation is not None:
            self._camera.rotation = rotation
        # Set up lights in every of the 8 corners of the global bounding box
        positions = list(
            itertools.product(*[(-orbit_radius, orbit_radius)] * 3))
        key_lights = [
            DirectionalLight(color='white', position=pos, intensity=0.5)
            for pos in positions
        ]
        ambient_light = AmbientLight(intensity=0.1)

        # Set up Helpers
        self.axes = Axes(bb_center=self._bb.center, length=bb_max * 1.1)
        self.horizontal_grid = Grid(bb_center=self._bb.center,
                                    maximum=bb_max,
                                    colorCenterLine='#aaa',
                                    colorGrid='#ddd')
        self.vertical_grid = Grid(bb_center=self._bb.center,
                                  maximum=bb_max,
                                  colorCenterLine='#aaa',
                                  colorGrid='#ddd')
        # Set up scene
        environment = self.axes.axes + key_lights + [
            ambient_light, self.horizontal_grid.grid, self.vertical_grid.grid,
            self._camera
        ]

        scene_shp = Scene(children=[
            self._displayed_pickable_objects,
            self._displayed_non_pickable_objects
        ] + environment)

        # Set up Controllers
        self._controller = OrbitControls(controlling=self._camera,
                                         target=camera_target,
                                         target0=camera_target)
        # Update controller to instantiate camera position
        self._camera.zoom = camera_zoom
        self._update()

        # setup Picker
        self._picker = Picker(controlling=self._displayed_pickable_objects,
                              event='dblclick')
        self._picker.observe(self.click)

        self._renderer = Renderer(camera=self._camera,
                                  background=self._background,
                                  background_opacity=self._background_opacity,
                                  scene=scene_shp,
                                  controls=[self._controller, self._picker],
                                  width=self._size[0],
                                  height=self._size[1],
                                  antialias=True)

        # set rotation and position for each grid
        self.horizontal_grid.set_position((0, 0, 0))
        self.horizontal_grid.set_rotation((math.pi / 2.0, 0, 0, "XYZ"))

        self.vertical_grid.set_position((0, -bb_max, 0))

        self._savestate = (self._camera.rotation, self._controller.target)

        # then display both 3d widgets and webui
        display(HBox([VBox([HBox(self._controls), self._renderer]),
                      self.html]))

    def ExportToHTML(self, filename):
        embed.embed_minimal_html(filename,
                                 views=self._renderer,
                                 title='pythonocc')

    def _reset(self, *kargs):
        self._camera.rotation, self._controller.target = self._savestate
        self._camera.position = _add(self._bb.center, self._scale((1, 1, 1)))
        self._camera.zoom = self._camera_initial_zoom
        self._update()

    def _update(self):
        self._controller.exec_three_obj_method('update')

    def __repr__(self):
        self.Display()
        return ""
Esempio n. 28
0
class SubstrateTab(object):
    def __init__(self):

        self.output_dir = '.'
        # self.output_dir = 'tmpdir'

        # self.fig = plt.figure(figsize=(7.2,6))  # this strange figsize results in a ~square contour plot

        self.first_time = True
        self.modulo = 1

        self.use_defaults = True

        self.svg_delta_t = 0
        self.substrate_delta_t = 0
        self.svg_frame = 1
        self.substrate_frame = 1

        self.svg_xmin = 0

        # Probably don't want to hardwire these if we allow changing the domain size
        self.svg_xrange = 2000
        self.xmin = -1000.
        self.xmax = 1000.
        self.ymin = -1000.
        self.ymax = 1000.
        self.x_range = 2000.
        self.y_range = 2000.

        self.show_nucleus = 0
        self.show_edge = False

        # initial value
        self.field_index = 4
        # self.field_index = self.mcds_field.value + 4

        # define dummy size of mesh (set in the tool's primary module)
        self.numx = 0
        self.numy = 0

        self.title_str = ''

        tab_height = '600px'
        tab_height = '500px'
        constWidth = '180px'
        constWidth2 = '150px'
        tab_layout = Layout(
            width='900px',  # border='2px solid black',
            height=tab_height,
        )  #overflow_y='scroll')

        max_frames = 1
        # self.mcds_plot = interactive(self.plot_substrate, frame=(0, max_frames), continuous_update=False)
        # self.i_plot = interactive(self.plot_plots, frame=(0, max_frames), continuous_update=False)
        self.i_plot = interactive(self.plot_substrate,
                                  frame=(0, max_frames),
                                  continuous_update=False)

        # "plot_size" controls the size of the tab height, not the plot (rf. figsize for that)
        # NOTE: the Substrates Plot tab has an extra row of widgets at the top of it (cf. Cell Plots tab)
        svg_plot_size = '700px'
        svg_plot_size = '600px'
        svg_plot_size = '700px'
        svg_plot_size = '900px'
        self.i_plot.layout.width = svg_plot_size
        self.i_plot.layout.height = svg_plot_size

        self.fontsize = 20

        self.max_frames = BoundedIntText(
            min=0,
            max=99999,
            value=max_frames,
            description='# cell frames',
            layout=Layout(width='160px'),
        )
        self.max_frames.observe(self.update_max_frames)

        # self.field_min_max = {'dummy': [0., 1.]}
        # NOTE: manually setting these for now (vs. parsing them out of data/initial.xml)
        self.field_min_max = {
            'director signal': [0., 1.],
            'cargo signal': [0., 1.]
        }
        # hacky I know, but make a dict that's got (key,value) reversed from the dict in the Dropdown below
        # self.field_dict = {0:'dummy'}
        self.field_dict = {0: 'director signal', 1: 'cargo signal'}

        self.mcds_field = Dropdown(
            options={
                'director signal': 0,
                'cargo signal': 1
            },
            value=0,
            #     description='Field',
            layout=Layout(width=constWidth))
        # print("substrate __init__: self.mcds_field.value=",self.mcds_field.value)
        #        self.mcds_field.observe(self.mcds_field_cb)
        self.mcds_field.observe(self.mcds_field_changed_cb)

        # self.field_cmap = Text(
        #     value='viridis',
        #     description='Colormap',
        #     disabled=True,
        #     layout=Layout(width=constWidth),
        # )
        self.field_cmap = Dropdown(
            options=['viridis', 'jet', 'YlOrRd'],
            value='YlOrRd',
            #     description='Field',
            layout=Layout(width=constWidth))
        #        self.field_cmap.observe(self.plot_substrate)
        self.field_cmap.observe(self.mcds_field_cb)

        self.cmap_fixed = Checkbox(
            description='Fix',
            disabled=False,
            #           layout=Layout(width=constWidth2),
        )

        self.save_min_max = Button(
            description='Save',  #style={'description_width': 'initial'},
            button_style=
            'success',  # 'success', 'info', 'warning', 'danger' or ''
            tooltip='Save min/max for this substrate',
            disabled=True,
            layout=Layout(width='90px'))

        def save_min_max_cb(b):
            #            field_name = self.mcds_field.options[]
            #            field_name = next(key for key, value in self.mcds_field.options.items() if value == self.mcds_field.value)
            field_name = self.field_dict[self.mcds_field.value]
            #            print(field_name)
            #            self.field_min_max = {'oxygen': [0., 30.], 'glucose': [0., 1.], 'H+ ions': [0., 1.], 'ECM': [0., 1.], 'NP1': [0., 1.], 'NP2': [0., 1.]}
            self.field_min_max[field_name][0] = self.cmap_min.value
            self.field_min_max[field_name][1] = self.cmap_max.value
#            print(self.field_min_max)

        self.save_min_max.on_click(save_min_max_cb)

        self.cmap_min = FloatText(
            description='Min',
            value=0,
            step=0.1,
            disabled=True,
            layout=Layout(width=constWidth2),
        )
        self.cmap_min.observe(self.mcds_field_cb)

        self.cmap_max = FloatText(
            description='Max',
            value=38,
            step=0.1,
            disabled=True,
            layout=Layout(width=constWidth2),
        )
        self.cmap_max.observe(self.mcds_field_cb)

        def cmap_fixed_cb(b):
            if (self.cmap_fixed.value):
                self.cmap_min.disabled = False
                self.cmap_max.disabled = False
                self.save_min_max.disabled = False
            else:
                self.cmap_min.disabled = True
                self.cmap_max.disabled = True
                self.save_min_max.disabled = True
#            self.mcds_field_cb()

        self.cmap_fixed.observe(cmap_fixed_cb)

        field_cmap_row2 = HBox([self.field_cmap, self.cmap_fixed])

        #        field_cmap_row3 = HBox([self.save_min_max, self.cmap_min, self.cmap_max])
        items_auto = [
            self.save_min_max,  #layout=Layout(flex='3 1 auto', width='auto'),
            self.cmap_min,
            self.cmap_max,
        ]
        box_layout = Layout(display='flex',
                            flex_flow='row',
                            align_items='stretch',
                            width='80%')
        field_cmap_row3 = Box(children=items_auto, layout=box_layout)

        #---------------------
        self.cell_edges_toggle = Checkbox(
            description='edges',
            disabled=False,
            value=False,
            #           layout=Layout(width=constWidth2),
        )

        def cell_edges_toggle_cb(b):
            # self.update()
            if (self.cell_edges_toggle.value):
                self.show_edge = True
            else:
                self.show_edge = False
            self.i_plot.update()

        self.cell_edges_toggle.observe(cell_edges_toggle_cb)

        self.cells_toggle = Checkbox(
            description='Cells',
            disabled=False,
            value=True,
            #           layout=Layout(width=constWidth2),
        )

        def cells_toggle_cb(b):
            # self.update()
            self.i_plot.update()
            if (self.cells_toggle.value):
                self.cell_edges_toggle.disabled = False
            else:
                self.cell_edges_toggle.disabled = True

        self.cells_toggle.observe(cells_toggle_cb)

        #---------------------
        self.substrates_toggle = Checkbox(
            description='Substrates',
            disabled=False,
            value=True,
            #           layout=Layout(width=constWidth2),
        )

        def substrates_toggle_cb(b):
            if (self.substrates_toggle.value):  # seems bass-ackwards
                self.cmap_fixed.disabled = False
                self.cmap_min.disabled = False
                self.cmap_max.disabled = False
                self.mcds_field.disabled = False
                self.field_cmap.disabled = False
            else:
                self.cmap_fixed.disabled = True
                self.cmap_min.disabled = True
                self.cmap_max.disabled = True
                self.mcds_field.disabled = True
                self.field_cmap.disabled = True

        self.substrates_toggle.observe(substrates_toggle_cb)

        self.grid_toggle = Checkbox(
            description='grid',
            disabled=False,
            value=True,
            #           layout=Layout(width=constWidth2),
        )

        def grid_toggle_cb(b):
            # self.update()
            self.i_plot.update()

        self.grid_toggle.observe(grid_toggle_cb)

        #        field_cmap_row3 = Box([self.save_min_max, self.cmap_min, self.cmap_max])

        # mcds_tab = widgets.VBox([mcds_dir, mcds_plot, mcds_play], layout=tab_layout)
        # mcds_params = VBox([self.mcds_field, field_cmap_row2, field_cmap_row3, self.max_frames])  # mcds_dir
        #        mcds_params = VBox([self.mcds_field, field_cmap_row2, field_cmap_row3,])  # mcds_dir

        #        self.tab = HBox([mcds_params, self.mcds_plot], layout=tab_layout)

        help_label = Label('select slider: drag or left/right arrows')
        # row1 = Box([help_label, Box( [self.max_frames, self.mcds_field, self.field_cmap], layout=Layout(border='0px solid black',
        row1a = Box([self.max_frames, self.mcds_field, self.field_cmap],
                    layout=Layout(border='1px solid black',
                                  width='50%',
                                  height='',
                                  align_items='stretch',
                                  flex_direction='row',
                                  display='flex'))
        row1b = Box([self.cells_toggle, self.cell_edges_toggle],
                    layout=Layout(border='1px solid black',
                                  width='50%',
                                  height='',
                                  align_items='stretch',
                                  flex_direction='row',
                                  display='flex'))
        row1 = HBox([row1a, Label('.....'), row1b])

        row2a = Box([self.cmap_fixed, self.cmap_min, self.cmap_max],
                    layout=Layout(border='1px solid black',
                                  width='50%',
                                  height='',
                                  align_items='stretch',
                                  flex_direction='row',
                                  display='flex'))
        # row2b = Box( [self.substrates_toggle, self.grid_toggle], layout=Layout(border='1px solid black',
        row2b = Box([
            self.substrates_toggle,
        ],
                    layout=Layout(border='1px solid black',
                                  width='50%',
                                  height='',
                                  align_items='stretch',
                                  flex_direction='row',
                                  display='flex'))
        # row2 = HBox( [row2a, self.substrates_toggle, self.grid_toggle])
        row2 = HBox([row2a, Label('.....'), row2b])

        if (hublib_flag):
            self.download_button = Download('mcds.zip',
                                            style='warning',
                                            icon='cloud-download',
                                            tooltip='Download data',
                                            cb=self.download_cb)

            self.download_svg_button = Download(
                'svg.zip',
                style='warning',
                icon='cloud-download',
                tooltip='You need to allow pop-ups in your browser',
                cb=self.download_svg_cb)
            download_row = HBox([
                self.download_button.w, self.download_svg_button.w,
                Label("Download all cell plots (browser must allow pop-ups).")
            ])

            # box_layout = Layout(border='0px solid')
            controls_box = VBox([row1,
                                 row2])  # ,width='50%', layout=box_layout)
            self.tab = VBox([controls_box, self.i_plot, download_row])
        else:
            # self.tab = VBox([row1, row2])
            self.tab = VBox([row1, row2, self.i_plot])

    #---------------------------------------------------
    def update_dropdown_fields(self, data_dir):
        # print('update_dropdown_fields called --------')
        self.output_dir = data_dir
        tree = None
        try:
            fname = os.path.join(self.output_dir, "initial.xml")
            tree = ET.parse(fname)
            xml_root = tree.getroot()
        except:
            print("Cannot open ", fname,
                  " to read info, e.g., names of substrate fields.")
            return

        xml_root = tree.getroot()
        self.field_min_max = {}
        self.field_dict = {}
        dropdown_options = {}
        uep = xml_root.find('.//variables')
        comment_str = ""
        field_idx = 0
        if (uep):
            for elm in uep.findall('variable'):
                # print("-----> ",elm.attrib['name'])
                self.field_min_max[elm.attrib['name']] = [0., 1.]
                self.field_dict[field_idx] = elm.attrib['name']
                dropdown_options[elm.attrib['name']] = field_idx
                field_idx += 1

#        constWidth = '180px'
# print('options=',dropdown_options)
        self.mcds_field.value = 0
        self.mcds_field.options = dropdown_options
#         self.mcds_field = Dropdown(
# #            options={'oxygen': 0, 'glucose': 1},
#             options=dropdown_options,
#             value=0,
#             #     description='Field',
#            layout=Layout(width=constWidth)
#         )

# def update_max_frames_expected(self, value):  # called when beginning an interactive Run
#     self.max_frames.value = value  # assumes naming scheme: "snapshot%08d.svg"
#     self.mcds_plot.children[0].max = self.max_frames.value

#------------------------------------------------------------------------------
#    def update(self, rdir):
#   Called from pc4biorobots.py (among other places?)

    def update(self, rdir=''):
        # with debug_view:
        #     print("substrates: update rdir=", rdir)
        # print("substrates: update rdir=", rdir)

        if rdir:
            self.output_dir = rdir

        # print('update(): self.output_dir = ', self.output_dir)

        # if self.first_time:
        if True:
            self.first_time = False
            full_xml_filename = Path(
                os.path.join(self.output_dir, 'config.xml'))
            # print("substrates: update(), config.xml = ",full_xml_filename)
            # self.num_svgs = len(glob.glob(os.path.join(self.output_dir, 'snap*.svg')))
            # self.num_substrates = len(glob.glob(os.path.join(self.output_dir, 'output*.xml')))
            # print("substrates: num_svgs,num_substrates =",self.num_svgs,self.num_substrates)
            # argh - no! If no files created, then denom = -1
            # self.modulo = int((self.num_svgs - 1) / (self.num_substrates - 1))
            # print("substrates: update(): modulo=",self.modulo)
            if full_xml_filename.is_file():
                tree = ET.parse(
                    full_xml_filename
                )  # this file cannot be overwritten; part of tool distro
                xml_root = tree.getroot()
                self.svg_delta_t = int(xml_root.find(".//SVG//interval").text)
                self.substrate_delta_t = int(
                    xml_root.find(".//full_data//interval").text)
                # print("substrates: svg,substrate delta_t values=",self.svg_delta_t,self.substrate_delta_t)
                self.modulo = int(self.substrate_delta_t / self.svg_delta_t)
                # print("substrates: update(): modulo=",self.modulo)

        # all_files = sorted(glob.glob(os.path.join(self.output_dir, 'output*.xml')))  # if the substrates/MCDS

        all_files = sorted(
            glob.glob(os.path.join(self.output_dir, 'snap*.svg')))  # if .svg
        if len(all_files) > 0:
            last_file = all_files[-1]
            self.max_frames.value = int(
                last_file[-12:-4])  # assumes naming scheme: "snapshot%08d.svg"

    def download_svg_cb(self):
        file_str = os.path.join(self.output_dir, '*.svg')
        # print('zip up all ',file_str)
        with zipfile.ZipFile('svg.zip', 'w') as myzip:
            for f in glob.glob(file_str):
                myzip.write(f, os.path.basename(
                    f))  # 2nd arg avoids full filename path in the archive

    def download_cb(self):
        file_xml = os.path.join(self.output_dir, '*.xml')
        file_mat = os.path.join(self.output_dir, '*.mat')
        # print('zip up all ',file_str)
        with zipfile.ZipFile('mcds.zip', 'w') as myzip:
            for f in glob.glob(file_xml):
                myzip.write(f, os.path.basename(
                    f))  # 2nd arg avoids full filename path in the archive
            for f in glob.glob(file_mat):
                myzip.write(f, os.path.basename(f))

    def update_max_frames(self, _b):
        self.i_plot.children[0].max = self.max_frames.value

    def mcds_field_changed_cb(self, b):
        # print("mcds_field_changed_cb: self.mcds_field.value=",self.mcds_field.value)
        if (self.mcds_field.value == None):
            return
        self.field_index = self.mcds_field.value + 4

        field_name = self.field_dict[self.mcds_field.value]
        # print('mcds_field_cb: '+field_name)
        self.cmap_min.value = self.field_min_max[field_name][0]
        self.cmap_max.value = self.field_min_max[field_name][1]
        self.i_plot.update()

    def mcds_field_cb(self, b):
        #self.field_index = self.mcds_field.value
        #        self.field_index = self.mcds_field.options.index(self.mcds_field.value) + 4
        #        self.field_index = self.mcds_field.options[self.mcds_field.value]
        self.field_index = self.mcds_field.value + 4

        # field_name = self.mcds_field.options[self.mcds_field.value]
        # self.cmap_min.value = self.field_min_max[field_name][0]  # oxygen, etc
        # self.cmap_max.value = self.field_min_max[field_name][1]  # oxygen, etc

        #        self.field_index = self.mcds_field.value + 4

        #        print('field_index=',self.field_index)
        self.i_plot.update()

    #---------------------------------------------------------------------------
    def circles(self, x, y, s, c='b', vmin=None, vmax=None, **kwargs):
        """
        See https://gist.github.com/syrte/592a062c562cd2a98a83 

        Make a scatter plot of circles. 
        Similar to plt.scatter, but the size of circles are in data scale.
        Parameters
        ----------
        x, y : scalar or array_like, shape (n, )
            Input data
        s : scalar or array_like, shape (n, ) 
            Radius of circles.
        c : color or sequence of color, optional, default : 'b'
            `c` can be a single color format string, or a sequence of color
            specifications of length `N`, or a sequence of `N` numbers to be
            mapped to colors using the `cmap` and `norm` specified via kwargs.
            Note that `c` should not be a single numeric RGB or RGBA sequence 
            because that is indistinguishable from an array of values
            to be colormapped. (If you insist, use `color` instead.)  
            `c` can be a 2-D array in which the rows are RGB or RGBA, however. 
        vmin, vmax : scalar, optional, default: None
            `vmin` and `vmax` are used in conjunction with `norm` to normalize
            luminance data.  If either are `None`, the min and max of the
            color array is used.
        kwargs : `~matplotlib.collections.Collection` properties
            Eg. alpha, edgecolor(ec), facecolor(fc), linewidth(lw), linestyle(ls), 
            norm, cmap, transform, etc.
        Returns
        -------
        paths : `~matplotlib.collections.PathCollection`
        Examples
        --------
        a = np.arange(11)
        circles(a, a, s=a*0.2, c=a, alpha=0.5, ec='none')
        plt.colorbar()
        License
        --------
        This code is under [The BSD 3-Clause License]
        (http://opensource.org/licenses/BSD-3-Clause)
        """

        if np.isscalar(c):
            kwargs.setdefault('color', c)
            c = None

        if 'fc' in kwargs:
            kwargs.setdefault('facecolor', kwargs.pop('fc'))
        if 'ec' in kwargs:
            kwargs.setdefault('edgecolor', kwargs.pop('ec'))
        if 'ls' in kwargs:
            kwargs.setdefault('linestyle', kwargs.pop('ls'))
        if 'lw' in kwargs:
            kwargs.setdefault('linewidth', kwargs.pop('lw'))
        # You can set `facecolor` with an array for each patch,
        # while you can only set `facecolors` with a value for all.

        zipped = np.broadcast(x, y, s)
        patches = [Circle((x_, y_), s_) for x_, y_, s_ in zipped]
        collection = PatchCollection(patches, **kwargs)
        if c is not None:
            c = np.broadcast_to(c, zipped.shape).ravel()
            collection.set_array(c)
            collection.set_clim(vmin, vmax)

        ax = plt.gca()
        ax.add_collection(collection)
        ax.autoscale_view()
        # plt.draw_if_interactive()
        if c is not None:
            plt.sci(collection)
        # return collection

    #------------------------------------------------------------
    # def plot_svg(self, frame, rdel=''):
    def plot_svg(self, frame):
        # global current_idx, axes_max
        global current_frame
        current_frame = frame
        fname = "snapshot%08d.svg" % frame
        full_fname = os.path.join(self.output_dir, fname)
        # with debug_view:
        # print("plot_svg:", full_fname)
        # print("-- plot_svg:", full_fname)
        if not os.path.isfile(full_fname):
            print("Once output files are generated, click the slider.")
            return

        xlist = deque()
        ylist = deque()
        rlist = deque()
        rgb_list = deque()

        #  print('\n---- ' + fname + ':')
        #        tree = ET.parse(fname)
        tree = ET.parse(full_fname)
        root = tree.getroot()
        #  print('--- root.tag ---')
        #  print(root.tag)
        #  print('--- root.attrib ---')
        #  print(root.attrib)
        #  print('--- child.tag, child.attrib ---')
        numChildren = 0
        for child in root:
            #    print(child.tag, child.attrib)
            #    print("keys=",child.attrib.keys())
            if self.use_defaults and ('width' in child.attrib.keys()):
                self.axes_max = float(child.attrib['width'])
                # print("debug> found width --> axes_max =", axes_max)
            if child.text and "Current time" in child.text:
                svals = child.text.split()
                # remove the ".00" on minutes
                self.title_str += "   cells: " + svals[2] + "d, " + svals[
                    4] + "h, " + svals[7][:-3] + "m"

            # print("width ",child.attrib['width'])
            # print('attrib=',child.attrib)
            # if (child.attrib['id'] == 'tissue'):
            if ('id' in child.attrib.keys()):
                # print('-------- found tissue!!')
                tissue_parent = child
                break

        # print('------ search tissue')
        cells_parent = None

        for child in tissue_parent:
            # print('attrib=',child.attrib)
            if (child.attrib['id'] == 'cells'):
                # print('-------- found cells, setting cells_parent')
                cells_parent = child
                break
            numChildren += 1

        num_cells = 0
        #  print('------ search cells')
        for child in cells_parent:
            #    print(child.tag, child.attrib)
            #    print('attrib=',child.attrib)
            for circle in child:  # two circles in each child: outer + nucleus
                #  circle.attrib={'cx': '1085.59','cy': '1225.24','fill': 'rgb(159,159,96)','r': '6.67717','stroke': 'rgb(159,159,96)','stroke-width': '0.5'}
                #      print('  --- cx,cy=',circle.attrib['cx'],circle.attrib['cy'])
                xval = float(circle.attrib['cx'])

                # map SVG coords into comp domain
                xval = (xval - self.svg_xmin
                        ) / self.svg_xrange * self.x_range + self.xmin

                s = circle.attrib['fill']
                # print("s=",s)
                # print("type(s)=",type(s))
                if (s[0:3] == "rgb"
                    ):  # if an rgb string, e.g. "rgb(175,175,80)"
                    rgb = list(map(int, s[4:-1].split(",")))
                    rgb[:] = [x / 255. for x in rgb]
                else:  # otherwise, must be a color name
                    rgb_tuple = mplc.to_rgb(mplc.cnames[s])  # a tuple
                    rgb = [x for x in rgb_tuple]

                # test for bogus x,y locations (rwh TODO: use max of domain?)
                too_large_val = 10000.
                if (np.fabs(xval) > too_large_val):
                    print("bogus xval=", xval)
                    break
                yval = float(circle.attrib['cy'])
                yval = (yval - self.svg_xmin
                        ) / self.svg_xrange * self.y_range + self.ymin
                if (np.fabs(yval) > too_large_val):
                    print("bogus xval=", xval)
                    break

                rval = float(circle.attrib['r'])
                # if (rgb[0] > rgb[1]):
                #     print(num_cells,rgb, rval)
                xlist.append(xval)
                ylist.append(yval)
                rlist.append(rval)
                rgb_list.append(rgb)

                # For .svg files with cells that *have* a nucleus, there will be a 2nd
                if (self.show_nucleus == 0):
                    #if (not self.show_nucleus):
                    break

            num_cells += 1

            # if num_cells > 3:   # for debugging
            #   print(fname,':  num_cells= ',num_cells," --- debug exit.")
            #   sys.exit(1)
            #   break

            # print(fname,':  num_cells= ',num_cells)

        xvals = np.array(xlist)
        yvals = np.array(ylist)
        rvals = np.array(rlist)
        rgbs = np.array(rgb_list)
        # print("xvals[0:5]=",xvals[0:5])
        # print("rvals[0:5]=",rvals[0:5])
        # print("rvals.min, max=",rvals.min(),rvals.max())

        # rwh - is this where I change size of render window?? (YES - yipeee!)
        #   plt.figure(figsize=(6, 6))
        #   plt.cla()
        # if (self.substrates_toggle.value):
        self.title_str += " (" + str(num_cells) + " agents)"
        # title_str = " (" + str(num_cells) + " agents)"
        # else:
        # mins= round(int(float(root.find(".//current_time").text)))  # TODO: check units = mins
        # hrs = int(mins/60)
        # days = int(hrs/24)
        # title_str = '%dd, %dh, %dm' % (int(days),(hrs%24), mins - (hrs*60))
        plt.title(self.title_str)

        plt.xlim(self.xmin, self.xmax)
        plt.ylim(self.ymin, self.ymax)

        #   plt.xlim(axes_min,axes_max)
        #   plt.ylim(axes_min,axes_max)
        #   plt.scatter(xvals,yvals, s=rvals*scale_radius, c=rgbs)

        # TODO: make figsize a function of plot_size? What about non-square plots?
        # self.fig = plt.figure(figsize=(9, 9))

        #        axx = plt.axes([0, 0.05, 0.9, 0.9])  # left, bottom, width, height
        #        axx = fig.gca()
        #        print('fig.dpi=',fig.dpi) # = 72

        #   im = ax.imshow(f.reshape(100,100), interpolation='nearest', cmap=cmap, extent=[0,20, 0,20])
        #   ax.xlim(axes_min,axes_max)
        #   ax.ylim(axes_min,axes_max)

        # convert radii to radii in pixels
        # ax2 = self.fig.gca()
        # N = len(xvals)
        # rr_pix = (ax2.transData.transform(np.vstack([rvals, rvals]).T) -
        #             ax2.transData.transform(np.vstack([np.zeros(N), np.zeros(N)]).T))
        # rpix, _ = rr_pix.T

        # markers_size = (144. * rpix / self.fig.dpi)**2   # = (2*rpix / fig.dpi * 72)**2
        # markers_size = markers_size/4000000.
        # print('max=',markers_size.max())

        #rwh - temp fix - Ah, error only occurs when "edges" is toggled on
        if (self.show_edge):
            try:
                # plt.scatter(xvals,yvals, s=markers_size, c=rgbs, edgecolor='black', linewidth=0.5)
                self.circles(xvals,
                             yvals,
                             s=rvals,
                             color=rgbs,
                             edgecolor='black',
                             linewidth=0.5)
                # cell_circles = self.circles(xvals,yvals, s=rvals, color=rgbs, edgecolor='black', linewidth=0.5)
                # plt.sci(cell_circles)
            except (ValueError):
                pass
        else:
            # plt.scatter(xvals,yvals, s=markers_size, c=rgbs)
            self.circles(xvals, yvals, s=rvals, color=rgbs)

        # if (self.show_tracks):
        #     for key in self.trackd.keys():
        #         xtracks = self.trackd[key][:,0]
        #         ytracks = self.trackd[key][:,1]
        #         plt.plot(xtracks[0:frame],ytracks[0:frame],  linewidth=5)

        # plt.xlim(self.axes_min, self.axes_max)
        # plt.ylim(self.axes_min, self.axes_max)
        #   ax.grid(False)
#        axx.set_title(title_str)
# plt.title(title_str)

#---------------------------------------------------------------------------
# assume "frame" is cell frame #, unless Cells is togggled off, then it's the substrate frame #
# def plot_substrate(self, frame, grid):

    def plot_substrate(self, frame):
        # global current_idx, axes_max, gFileId, field_index

        # print("plot_substrate(): frame*self.substrate_delta_t  = ",frame*self.substrate_delta_t)
        # print("plot_substrate(): frame*self.svg_delta_t  = ",frame*self.svg_delta_t)
        self.title_str = ''

        # Assume: # .svg files >= # substrate files
        #        if (self.cells_toggle.value):

        # if (self.substrates_toggle.value and frame*self.substrate_delta_t <= self.svg_frame*self.svg_delta_t):
        # if (self.substrates_toggle.value and (frame % self.modulo == 0)):
        if (self.substrates_toggle.value):
            # self.fig = plt.figure(figsize=(14, 15.6))
            self.fig = plt.figure(figsize=(15.0, 12.5))
            self.substrate_frame = int(frame / self.modulo)
            # print("plot_substrate(): self.substrate_frame=",self.substrate_frame)

            # if (self.substrate_frame > (self.num_substrates-1)):
            # self.substrate_frame = self.num_substrates-1

            # print('self.substrate_frame = ',self.substrate_frame)
            # if (self.cells_toggle.value):
            #     self.modulo = int((self.num_svgs - 1) / (self.num_substrates - 1))
            #     self.substrate_frame = frame % self.modulo
            # else:
            #     self.substrate_frame = frame
            fname = "output%08d_microenvironment0.mat" % self.substrate_frame
            xml_fname = "output%08d.xml" % self.substrate_frame
            # fullname = output_dir_str + fname

            #        fullname = fname
            full_fname = os.path.join(self.output_dir, fname)
            # print("--- plot_substrate(): full_fname=",full_fname)
            full_xml_fname = os.path.join(self.output_dir, xml_fname)
            #        self.output_dir = '.'

            #        if not os.path.isfile(fullname):
            if not os.path.isfile(full_fname):
                print("Once output files are generated, click the slider."
                      )  # No:  output00000000_microenvironment0.mat
                return

    #        tree = ET.parse(xml_fname)
            tree = ET.parse(full_xml_fname)
            xml_root = tree.getroot()
            mins = round(int(float(xml_root.find(
                ".//current_time").text)))  # TODO: check units = mins
            hrs = int(mins / 60)
            days = int(hrs / 24)
            self.title_str = 'substrate: %dd, %dh, %dm' % (int(days),
                                                           (hrs % 24), mins -
                                                           (hrs * 60))

            info_dict = {}
            #        scipy.io.loadmat(fullname, info_dict)
            scipy.io.loadmat(full_fname, info_dict)
            M = info_dict['multiscale_microenvironment']
            #     global_field_index = int(mcds_field.value)
            #     print('plot_substrate: field_index =',field_index)
            f = M[
                self.
                field_index, :]  # 4=tumor cells field, 5=blood vessel density, 6=growth substrate
            # plt.clf()
            # my_plot = plt.imshow(f.reshape(400,400), cmap='jet', extent=[0,20, 0,20])

            # self.fig = plt.figure(figsize=(18.0,15))  # this strange figsize results in a ~square contour plot

            # plt.subplot(grid[0:1, 0:1])
            # main_ax = self.fig.add_subplot(grid[0:1, 0:1])  # works, but tiny upper-left region
            #main_ax = self.fig.add_subplot(grid[0:2, 0:2])
            # main_ax = self.fig.add_subplot(grid[0:, 0:2])
            #main_ax = self.fig.add_subplot(grid[:-1, 0:])   # nrows, ncols
            #main_ax = self.fig.add_subplot(grid[0:, 0:])   # nrows, ncols
            #main_ax = self.fig.add_subplot(grid[0:4, 0:])   # nrows, ncols

            # main_ax = self.fig.add_subplot(grid[0:3, 0:])   # nrows, ncols
            # main_ax = self.fig.add_subplot(111)   # nrows, ncols

            # plt.rc('font', size=10)  # TODO: does this affect the Cell plots fonts too? YES. Not what we want.

            #     fig.set_tight_layout(True)
            #     ax = plt.axes([0, 0.05, 0.9, 0.9 ]) #left, bottom, width, height
            #     ax = plt.axes([0, 0.0, 1, 1 ])
            #     cmap = plt.cm.viridis # Blues, YlOrBr, ...
            #     im = ax.imshow(f.reshape(100,100), interpolation='nearest', cmap=cmap, extent=[0,20, 0,20])
            #     ax.grid(False)

            # print("substrates.py: ------- numx, numy = ", self.numx, self.numy )
            if (self.numx == 0):  # need to parse vals from the config.xml
                # print("--- plot_substrate(): full_fname=",full_fname)
                fname = os.path.join(self.output_dir, "config.xml")
                tree = ET.parse(fname)
                xml_root = tree.getroot()
                xmin = float(xml_root.find(".//x_min").text)
                xmax = float(xml_root.find(".//x_max").text)
                dx = float(xml_root.find(".//dx").text)
                ymin = float(xml_root.find(".//y_min").text)
                ymax = float(xml_root.find(".//y_max").text)
                dy = float(xml_root.find(".//dy").text)
                self.numx = math.ceil((xmax - xmin) / dx)
                self.numy = math.ceil((ymax - ymin) / dy)

            xgrid = M[0, :].reshape(self.numy, self.numx)
            ygrid = M[1, :].reshape(self.numy, self.numx)

            num_contours = 15
            levels = MaxNLocator(nbins=num_contours).tick_values(
                self.cmap_min.value, self.cmap_max.value)
            contour_ok = True
            if (self.cmap_fixed.value):
                try:
                    # substrate_plot = main_ax.contourf(xgrid, ygrid, M[self.field_index, :].reshape(self.numy, self.numx), levels=levels, extend='both', cmap=self.field_cmap.value, fontsize=self.fontsize)
                    substrate_plot = plt.contourf(
                        xgrid,
                        ygrid,
                        M[self.field_index, :].reshape(self.numy, self.numx),
                        levels=levels,
                        extend='both',
                        cmap=self.field_cmap.value,
                        fontsize=self.fontsize)
                except:
                    contour_ok = False
                    # print('got error on contourf 1.')
            else:
                try:
                    # substrate_plot = main_ax.contourf(xgrid, ygrid, M[self.field_index, :].reshape(self.numy,self.numx), num_contours, cmap=self.field_cmap.value)
                    substrate_plot = plt.contourf(
                        xgrid,
                        ygrid,
                        M[self.field_index, :].reshape(self.numy, self.numx),
                        num_contours,
                        cmap=self.field_cmap.value)
                except:
                    contour_ok = False
                    # print('got error on contourf 2.')

            if (contour_ok):
                # main_ax.set_title(self.title_str, fontsize=self.fontsize)
                plt.title(self.title_str, fontsize=self.fontsize)
                # main_ax.tick_params(labelsize=self.fontsize)
                # cbar = plt.colorbar(my_plot)
                # cbar = self.fig.colorbar(substrate_plot, ax=main_ax)
                cbar = self.fig.colorbar(substrate_plot)
                cbar.ax.tick_params(labelsize=self.fontsize)
                # cbar = main_ax.colorbar(my_plot)
                # cbar.ax.tick_params(labelsize=self.fontsize)
            # axes_min = 0
            # axes_max = 2000

            # main_ax.set_xlim([self.xmin, self.xmax])
            # main_ax.set_ylim([self.ymin, self.ymax])
            plt.xlim(self.xmin, self.xmax)
            plt.ylim(self.ymin, self.ymax)

            # if (frame == 0):  # maybe allow substrate grid display later
            #     xs = np.linspace(self.xmin,self.xmax,self.numx)
            #     ys = np.linspace(self.ymin,self.ymax,self.numy)
            #     hlines = np.column_stack(np.broadcast_arrays(xs[0], ys, xs[-1], ys))
            #     vlines = np.column_stack(np.broadcast_arrays(xs, ys[0], xs, ys[-1]))
            #     grid_lines = np.concatenate([hlines, vlines]).reshape(-1, 2, 2)
            #     line_collection = LineCollection(grid_lines, color="gray", linewidths=0.5)
            #     # ax = main_ax.gca()
            #     main_ax.add_collection(line_collection)
            #     # ax.set_xlim(xs[0], xs[-1])
            #     # ax.set_ylim(ys[0], ys[-1])

        # Now plot the cells (possibly on top of the substrate)
        if (self.cells_toggle.value):
            if (not self.substrates_toggle.value):
                self.fig = plt.figure(figsize=(12, 12))
            # self.plot_svg(frame)
            self.svg_frame = frame
            # print('plot_svg with frame=',self.svg_frame)
            self.plot_svg(self.svg_frame)

        # plt.subplot(grid[2, 0])
        # oxy_ax = self.fig.add_subplot(grid[2:, 0:1])
        #oxy_ax = self.fig.add_subplot(grid[:2, 2:])

        #oxy_ax = self.fig.add_subplot(grid[:-1, 0:2])  # nrows, ncols
        #oxy_ax = self.fig.add_subplot(grid[2:3, 0:1])  # nrows, ncols

        # oxy_ax = self.fig.add_subplot(grid[4:4, 0:1])  # invalid
#        main_ax = self.fig.add_subplot(grid[0:1, 0:1])

# experiment with small plot of oxygen (or whatever)
# oxy_ax = self.fig.add_subplot(grid[3:4, 0:1])  # nrows, ncols
# x = np.linspace(0, 500)
# oxy_ax.plot(x, 300*np.sin(x))

#---------------------------------------------------------------------------

    def plot_plots(self, frame):
        # if (self.first_time):
        #     self.svg_delta_t = 1
        #     self.substrate_delta_t = 1
        #     self.first_time = False

        if (self.substrates_toggle.value):
            self.fig = plt.figure(figsize=(14, 15.6))
        else:  # only cells being displayed (maybe)
            self.fig = plt.figure(figsize=(12, 12))
        # grid = plt.GridSpec(4, 3, wspace=0.10, hspace=0.2)   # (nrows, ncols)
        # self.plot_substrate(frame, grid)
        self.plot_substrate(frame)
Esempio n. 29
0
    def dsc_config(dsc_value):
        values = config.read()
        ds_db = Dropdown(options=["1"],
                         value="1",
                         description='Database:',
                         disabled=False,
                         layout=Layout(width='140px'))

        try:
            with open(f"{config.get_value(['paths','temp'])}tb_prefix",
                      'r') as f:
                code_value = f.read()
        except Exception:
            code_value = dsc_value

        ds_code = Combobox(
            value=code_value,
            placeholder='abc',
            options=[m for m in data_options.eu_ms()] + [''],
            description='AOI code:',
            ensure_option=False,
            disabled=False,
            layout=Layout(width='200px'),
            tooltip='Lowercase AOI code name for the dataset (5chr max).')
        ds_year = BoundedIntText(value=int(dsy.value),
                                 min=1980,
                                 max=2100,
                                 step=1,
                                 description='Dataset year:',
                                 disabled=False,
                                 layout=Layout(width='180px'))
        ds_desc = Text(value=values['ds_conf'][dsc_value]['desc'],
                       description='Description:',
                       disabled=False)

        info_map_text = [
            "Set default map view options. ",
            "You can get automatically the dataset ", "center coordinates."
        ]

        lat, lon = values['ds_conf'][dsc_value]['center'].split(",")
        map_cent_lat = FloatText(value=float(lat),
                                 description='Lat:',
                                 disabled=False,
                                 layout=Layout(width='160px'))
        map_cent_lon = FloatText(value=float(lon),
                                 description='Lon:',
                                 disabled=False,
                                 layout=Layout(width='160px'))
        map_zoom = BoundedIntText(value=values['ds_conf'][dsc_value]['zoom'],
                                  min=0,
                                  max=20,
                                  step=1,
                                  description='Zoom:',
                                  disabled=False,
                                  layout=Layout(width='140px'))
        bt_get_center = Button(layout=Layout(width='40px'),
                               icon='bullseye',
                               tooltip='Get center point from database.')

        ds_box = HBox([ds_code, ds_year, ds_desc])
        map_box = HBox([
            Label("Map center: "), map_cent_lat, map_cent_lon, bt_get_center,
            map_zoom
        ])

        info_config = Label(
            """Change 'AOI code' value to create a new configuration set or 
            leave the same 'AOI code' value to configure the selected one.""")

        db = int(values['ds_conf'][dsc_value]['db'])

        def get_tb_list():
            tbls = database.tables(db, None, False)
            if tbls is None:
                return []
            else:
                return tbls

        tb_dc = Dropdown(options=get_tb_list(),
                         value=config.autoselect(
                             values['ds_conf'][dsc_value]['years'][str(
                                 ds_year.value)]['tables']['dias_catalog'],
                             get_tb_list(), False),
                         description='DIAS catalog:',
                         disabled=False)
        tb_pr = Dropdown(options=get_tb_list(),
                         value=config.autoselect(
                             values['ds_conf'][dsc_value]['years'][str(
                                 ds_year.value)]['tables']['parcels'],
                             get_tb_list(), False),
                         description='Parcels:',
                         disabled=False)

        def get_pr_columns():
            try:
                colms = database.table_columns(tb_pr.value, 1, None)
                if colms is None:
                    return []
                else:
                    return colms
            except Exception:
                return []

        tc_id = Dropdown(options=get_pr_columns(),
                         value=config.autoselect(
                             values['ds_conf'][dsc_value]['years'][str(
                                 ds_year.value)]['columns']['parcels_id'],
                             get_pr_columns(), False),
                         description='Parcels ID:',
                         disabled=False,
                         layout=Layout(width='180px'))
        tc_cn = Dropdown(options=get_pr_columns(),
                         value=config.autoselect(
                             values['ds_conf'][dsc_value]['years'][str(
                                 ds_year.value)]['columns']['crop_names'],
                             get_pr_columns(), False),
                         description='Crop names:',
                         disabled=False,
                         layout=Layout(width='180px'))
        tc_cc = Dropdown(options=get_pr_columns(),
                         value=config.autoselect(
                             values['ds_conf'][dsc_value]['years'][str(
                                 ds_year.value)]['columns']['crop_codes'],
                             get_pr_columns(), False),
                         description='Crop codes:',
                         disabled=False,
                         layout=Layout(width='180px'))

        def on_tb_pr_change(change):
            tc_id.options = get_pr_columns()
            tc_cn.options = get_pr_columns()
            tc_cc.options = get_pr_columns()

        tb_pr.observe(on_tb_pr_change, 'value')

        parcel_box = HBox([tb_pr, tc_id, tc_cn, tc_cc])

        tb_s2 = Dropdown(options=get_tb_list(),
                         value=config.autoselect(
                             values['ds_conf'][dsc_value]['years'][str(
                                 ds_year.value)]['tables']['s2'],
                             get_tb_list(), False),
                         description='S2 signatures:',
                         disabled=False)
        tb_bs = Dropdown(options=get_tb_list(),
                         value=config.autoselect(
                             values['ds_conf'][dsc_value]['years'][str(
                                 ds_year.value)]['tables']['bs'],
                             get_tb_list(), False),
                         description='Backscattering:',
                         disabled=False)
        tb_6c = Dropdown(options=get_tb_list(),
                         value=config.autoselect(
                             values['ds_conf'][dsc_value]['years'][str(
                                 ds_year.value)]['tables']['c6'],
                             get_tb_list(), False),
                         description='6 day coherence:',
                         disabled=False)

        wb_save = Button(description='Save', disabled=False, icon='save')

        @bt_get_center.on_click
        def bt_get_center_on_click(b):
            import json
            center_json = json.loads(
                database.getTableCentroid(tb_pr.value)['center'][0])
            map_cent_lat.value = round(center_json['coordinates'][1], 2)
            map_cent_lon.value = round(center_json['coordinates'][0], 2)
            map_zoom.value = 10

        @wb_save.on_click
        def wb_save_on_click(b):
            progress.clear_output()
            dscode = ds_code.value
            config.update([
                'ds_conf', dscode, 'years',
                str(ds_year.value), 'tables', 'dias_catalog'
            ], str(tb_dc.value))
            config.update([
                'ds_conf', dscode, 'years',
                str(ds_year.value), 'tables', 'parcels'
            ], str(tb_pr.value))
            config.update([
                'ds_conf', dscode, 'years',
                str(ds_year.value), 'columns', 'parcels_id'
            ], str(tc_id.value))
            config.update([
                'ds_conf', dscode, 'years',
                str(ds_year.value), 'columns', 'crop_names'
            ], str(tc_cn.value))
            config.update([
                'ds_conf', dscode, 'years',
                str(ds_year.value), 'columns', 'crop_codes'
            ], str(tc_cc.value))
            config.update([
                'ds_conf', dscode, 'years',
                str(ds_year.value), 'tables', 's2'
            ], str(tb_s2.value))
            config.update([
                'ds_conf', dscode, 'years',
                str(ds_year.value), 'tables', 'bs'
            ], str(tb_bs.value))
            config.update([
                'ds_conf', dscode, 'years',
                str(ds_year.value), 'tables', 'c6'
            ], str(tb_6c.value))
            config.update(['ds_conf', dscode, 'db'], str(ds_db.value))
            config.update(['ds_conf', dscode, 'desc'], str(ds_desc.value))
            config.update(['ds_conf', dscode, 'center'],
                          f"{map_cent_lat.value},{map_cent_lon.value}")
            config.update(['ds_conf', dscode, 'zoom'], str(map_zoom.value))
            config.update(['set', 'ds_conf'], str(dscode))
            config.update(['set', 'ds_year'], str(ds_year.value))
            values = config.read()
            ds_c = values['set']['ds_conf']
            ds_y = values['set']['ds_year']
            dsc.options = [d for d in values['ds_conf']]
            dsy.options = [int(y) for y in values['ds_conf'][ds_c]['years']]
            dsc.value = ds_c
            dsy.value = int(ds_y)
            outlog("The configurations are saved.")

        return VBox([
            info_config, ds_box, parcel_box, tb_dc, tb_s2, tb_bs, tb_6c,
            Label(''.join(info_map_text)), map_box, wb_save
        ])
Esempio n. 30
0
def log_explorer(run_manager) -> VBox:  # noqa: C901
    def _update_fname_dropdown(
        run_manager,
        fname_dropdown,
        only_running_checkbox,
        only_failed_checkbox,
        sort_by_dropdown,
        contains_text,
    ):
        def on_click(_):
            current_value = fname_dropdown.value
            fnames = _get_fnames(run_manager, only_running_checkbox.value)
            if only_failed_checkbox.value:
                fnames = _failed_job_logs(fnames, run_manager,
                                          only_running_checkbox.value)
            if contains_text.value.strip() != "":
                fnames = _files_that_contain(fnames,
                                             contains_text.value.strip())
            fnames = _sort_fnames(sort_by_dropdown.value, run_manager, fnames)
            fname_dropdown.options = fnames
            with suppress(Exception):
                fname_dropdown.value = current_value
            fname_dropdown.disabled = not fnames

        return on_click

    def _last_editted(fname: Path) -> float:
        try:
            return fname.stat().st_mtime
        except FileNotFoundError:
            return -1.0

    async def _tail_log(fname: Path, textarea: Textarea) -> None:
        T = -2.0  # to make sure the update always triggers
        while True:
            await asyncio.sleep(2)
            try:
                T_new = _last_editted(fname)
                if T_new > T:
                    textarea.value = _read_file(fname)
                    T = T_new
            except asyncio.CancelledError:
                return
            except Exception:
                pass

    def _tail(
        dropdown,
        tail_button,
        textarea,
        update_button,
        only_running_checkbox,
        only_failed_checkbox,
    ):
        tail_task = None
        ioloop = asyncio.get_running_loop()

        def on_click(_):
            nonlocal tail_task
            if tail_task is None:
                fname = dropdown.options[dropdown.index]
                tail_task = ioloop.create_task(_tail_log(fname, textarea))
                tail_button.description = "cancel tail log"
                tail_button.button_style = "danger"
                tail_button.icon = "window-close"
                dropdown.disabled = True
                update_button.disabled = True
                only_running_checkbox.disabled = True
                only_failed_checkbox.disabled = True
            else:
                tail_button.description = "tail log"
                tail_button.button_style = "info"
                tail_button.icon = "refresh"
                dropdown.disabled = False
                only_running_checkbox.disabled = False
                only_failed_checkbox.disabled = False
                update_button.disabled = False
                tail_task.cancel()
                tail_task = None

        return on_click

    def _on_dropdown_change(textarea):
        def on_change(change):
            if (change["type"] == "change" and change["name"] == "value"
                    and change["new"] is not None):
                textarea.value = _read_file(change["new"])

        return on_change

    def _click_button_on_change(button):
        def on_change(change):
            if change["type"] == "change" and change["name"] == "value":
                button.click()

        return on_change

    fnames = _get_fnames(run_manager, only_running=False)
    # no need to sort `fnames` because the default sort_by option is alphabetical
    text = _read_file(fnames[0]) if fnames else ""
    textarea = Textarea(text, layout=dict(width="auto"), rows=20)
    sort_by_dropdown = Dropdown(
        description="Sort by",
        options=[
            "Alphabetical", "CPU %", "Mem %", "Last editted", "Loss", "npoints"
        ],
    )
    contains_text = Text(description="Has string")
    fname_dropdown = Dropdown(description="File name", options=fnames)
    fname_dropdown.observe(_on_dropdown_change(textarea))
    only_running_checkbox = Checkbox(description="Only files of running jobs",
                                     indent=False)
    only_failed_checkbox = Checkbox(
        description="Only files of failed jobs (might include false positives)",
        indent=False,
    )
    update_button = Button(description="update file list",
                           button_style="info",
                           icon="refresh")
    update_button.on_click(
        _update_fname_dropdown(
            run_manager,
            fname_dropdown,
            only_running_checkbox,
            only_failed_checkbox,
            sort_by_dropdown,
            contains_text,
        ))
    sort_by_dropdown.observe(_click_button_on_change(update_button))
    only_running_checkbox.observe(_click_button_on_change(update_button))
    only_failed_checkbox.observe(_click_button_on_change(update_button))
    tail_button = Button(description="tail log",
                         button_style="info",
                         icon="refresh")
    tail_button.on_click(
        _tail(
            fname_dropdown,
            tail_button,
            textarea,
            update_button,
            only_running_checkbox,
            only_failed_checkbox,
        ))
    title = HTML("<h2><tt>adaptive_scheduler.widgets.log_explorer</tt></h2>")
    return VBox(
        [
            title,
            only_running_checkbox,
            only_failed_checkbox,
            update_button,
            sort_by_dropdown,
            contains_text,
            fname_dropdown,
            tail_button,
            textarea,
        ],
        layout=Layout(border="solid 2px gray"),
    )
Esempio n. 31
0
        <style>
        .output {
            display: flex;
            align-items: center;
            text-align: right;
        }
        </style>
        """), arg)


EMPTY = '--'


def dropdown_eventhandler(change):
    if (change.new == EMPTY):
        clear_output(wait=True)
        _display(dropdown)
    else:
        clear_output(wait=True)
        _display(dropdown)
        _display(Markdown(f'ros_{change.new}.md'))


dropdown = Dropdown(options=['--', '1', '2', '3', '4'],
                    value='--',
                    description='Пункт ↑:',
                    disabled=False)

dropdown.observe(dropdown_eventhandler, names='value')
_display(dropdown)
Esempio n. 32
0
def widget_box(path):
    map_view_box = Output()
    file_info = glob.glob(f"{path}*_information.json")[0]

    with open(file_info, 'r') as f:
        info_data = json.loads(f.read())

    pid = info_data['ogc_fid'][0]
    crop_name = info_data['cropname'][0]
    area = info_data['area'][0]

    ci_path = f"{path}{pid}_chip_images/"
    csv_lists = glob.glob(f"{ci_path}{pid}_images_list.*.csv")
    bands_list = [i.split('.')[-2] for i in csv_lists]

    ci_band = Dropdown(options=view_images.available_options(
        path, pid, False, False),
                       disabled=False,
                       layout=Layout(width='140px'))
    ci_cloud = Checkbox(value=False,
                        description='Cloud free',
                        disabled=True,
                        indent=False,
                        layout=Layout(width='140px'))

    def ci_band_changed(b):
        #         m.substitute_layer()
        map_view_box.clear_output()
        #         m.clear_layers()
        #         m.clear_controls()
        with map_view_box:
            display(show_m())

    ci_band.observe(ci_band_changed)

    parcel_info = Label(
        f"Crop ID: {pid} Crop type: {crop_name},  Area: {area:.2f} sqm")

    display(HBox([parcel_info, ci_band]))

    #     if os.path.exists(ci_path):

    def show_m():

        multipoly = []
        multycent = []
        geom = view_spatial.trasform_geometry(info_data)
        poly = geom['coordinates'][0][0]
        #     poly = view_spatial.swap_xy(geom['coordinates'][0])[0]
        multipoly.append(poly)
        cent = view_spatial.centroid(poly)
        multycent.append(cent)

        cent = view_spatial.centroid(multycent)
        m = Map(center=cent, zoom=16, basemap=basemaps.OpenStreetMap.Mapnik)

        polygon = Polygon(locations=multipoly,
                          name='Parcel polygon',
                          color="yellow",
                          fill_color=None)

        m.add_layer(polygon)
        basemap2 = basemap_to_tiles(basemaps.Esri.WorldImagery)

        poly_text = HTML()
        poly_text.value = f"""Parcel ID: {pid}<br>
                                    Crop name: {crop_name}<br>
                                    Area: {area:.2f} sqm<br>
                                    Coordinates: {cent}
                                    """
        poly_text.placeholder = "HTML"
        poly_text.description = ""

        # Popup with a given location on the map:
        poly_popup = Popup(child=poly_text,
                           close_button=False,
                           auto_close=False,
                           close_on_escape_key=False)
        m.add_layer(poly_popup)

        # Popup associated to a layer
        polygon.popup = poly_popup

        # Layers control
        show_poly = Checkbox(value=True,
                             description='Polygon',
                             disabled=False,
                             indent=False,
                             layout=Layout(width='140px'))
        show_sat = Checkbox(value=False,
                            description='High res basemap',
                            disabled=False,
                            indent=False,
                            layout=Layout(width='140px'))

        def polygon_changed(b):
            try:
                if show_poly.value is True:
                    m.add_layer(polygon)
                else:
                    m.remove_layer(polygon)
            except Exception:
                pass

        show_poly.observe(polygon_changed)

        def show_sat_changed(b):
            try:
                if show_sat.value is True:
                    m.add_layer(basemap2)
                else:
                    m.remove_layer(basemap2)
            except Exception:
                pass

        show_sat.observe(show_sat_changed)

        try:
            csv_list = f"{ci_path}{pid}_images_list.{ci_band.value[0]}.csv"
            df = view_images.create_df(ci_path, pid, ci_band.value)

            geotiff = f"{ci_path}{df['imgs'][0]}.{ci_band.value[0]}.tif"
            bounds = view_spatial.bounds(geotiff)

            images = {}
            for i, row in df.iterrows():
                str_date = str(row['date'].date()).replace('-', '')
                workdir = os.getcwd().split('/')[-1]
                img_tc = f"{ci_path}{('').join(ci_band.value)}_{str_date}.png"

                # Create false color image if it does not exist
                # Merge bands (images path, export image path, bands list)
                if not os.path.isfile(img_tc):
                    imgs_path = f"{ci_path}{row['imgs']}"
                    view_images.merge_bands(imgs_path, img_tc, ci_band.value)
                values = config.read()

                # Set the current environment
                if eval(values['set']['jupyterlab']) is True:
                    image_path = f'files/{workdir}/{img_tc}'
                else:
                    image_path = img_tc
                images[i] = ImageOverlay(url=image_path,
                                         name=str_date,
                                         bounds=(bounds))

            # Time slider
            slider = IntSlider(value=1,
                               min=1,
                               max=len(images),
                               step=1,
                               description=str(df['date'][0].date()),
                               disabled=False,
                               continuous_update=False,
                               orientation='horizontal',
                               readout=True,
                               readout_format='d')
            show_chip = Checkbox(value=True,
                                 description='Chip image',
                                 disabled=False,
                                 indent=False,
                                 layout=Layout(width='140px'))

            def on_ci_band_change(change):
                pass

            ci_band.observe(on_ci_band_change, 'value')

            def show_chip_changed(b):
                try:
                    if show_chip.value is True:
                        m.add_layer(images[slider.value - 1])
                    else:
                        m.remove_layer(images[slider.value - 1])
                except Exception:
                    pass

            show_chip.observe(show_chip_changed)

            # Slider control
            play = Play(value=1,
                        min=1,
                        max=len(images),
                        step=1,
                        interval=1000,
                        description="Press play",
                        disabled=False)

            def slider_changed(b):
                if show_chip.value is True:
                    try:
                        m.substitute_layer(images[b['old'] - 1],
                                           images[b['new'] - 1])
                    except Exception:
                        pass
                    slider.description = str(df['date'][slider.value -
                                                        1].date())

            slider.observe(slider_changed)
            jslink((play, 'value'), (slider, 'value'))
            time_box = HBox([slider, play])
            time_control = WidgetControl(widget=time_box,
                                         position='bottomleft')
            m.add_control(time_control)
            m.add_layer(images[0])

            map_options = VBox([show_poly, show_chip, show_sat])
        except Exception as err:
            map_options = VBox([show_poly, show_sat])
            print(err)

        layers_control = WidgetControl(widget=map_options,
                                       position='topright',
                                       max_width=150)
        m.add_control(layers_control)
        return m

    with map_view_box:
        display(show_m())

    return map_view_box
Esempio n. 33
0
    def _field_folder(self, **kwargs):
        """Folder that houses field GUI controls."""
        folder = super(DemoUniverse, self)._field_folder(**kwargs)
        uni_field_lists = _ListDict([
            ('Hydrogenic', ['1s',   '2s',   '2px', '2py', '2pz',
                            '3s',   '3px',  '3py', '3pz',
                            '3d-2', '3d-1', '3d0', '3d+1', '3d+2']),
            ('Gaussian', ['s', 'px', 'py', 'pz', 'd200', 'd110',
                          'd101', 'd020', 'd011', 'd002', 'f300',
                          'f210', 'f201', 'f120', 'f111', 'f102',
                          'f030', 'f021', 'f012', 'f003']),
            ('SolidHarmonic', [str(i) for i in range(8)])])
        kind_widgets = _ListDict([
            (key, Dropdown(options=vals))
            for key, vals in uni_field_lists.items()])
        ml_widgets = _ListDict([
            (str(l), Dropdown(options=[str(i) for i in range(-l, l+1)]))
            for l in range(8)])
        fopts = list(uni_field_lists.keys())
        folder.update(kind_widgets, relayout=True)
        folder.update(ml_widgets, relayout=True)

        def _field(c):
            fk = uni_field_lists[c.new][0]
            for scn in self.active():
                scn.field = c.new
                scn.field_kind = fk
            folder.deactivate(c.old)
            folder[c.new].value = fk
            folder.activate(c.new, enable=True)
            if c.new == 'SolidHarmonic':
                folder.activate(fk, enable=True)
            else:
                aml = [key for key in folder._get(keys=True)
                       if key.isnumeric()]
                if aml:
                    folder.deactivate(*aml)
            folder._set_gui()

        def _field_kind(c):
            for scn in self.active():
                scn.field_kind = c.new
                if scn.field == 'SolidHarmonic':
                    scn.field_ml = folder[c.new].options[0]
                    folder.activate(c.new, enable=True)
                    folder.deactivate(c.old)
                    if scn.field_ml != '0':
                        folder.deactivate('0')
                else:
                    aml = [i for i in folder._get(keys=True)
                           if i.isnumeric()]
                    if aml:
                        folder.deactivate(*aml)
            folder._set_gui()

        def _field_ml(c):
            for scn in self.active(): scn.field_ml = c.new

        for key, obj in kind_widgets.items():
            folder.deactivate(key)
            obj.observe(_field_kind, names='value')
        for key, obj in ml_widgets.items():
            folder.deactivate(key)
            obj.observe(_field_ml, names='value')
        fopts = Dropdown(options=fopts)
        fopts.observe(_field, names='value')
        folder.insert(1, 'fopts', fopts)
        folder.activate('Hydrogenic', enable=True, update=True)
        folder.move_to_end('alpha', 'iso', 'nx', 'ny', 'nz')
        return folder
Esempio n. 34
0
class TrajectoryPlayer(DOMWidget):
    # should set default values here different from desired defaults
    # so `observe` can be triggered
    step = Int(0).tag(sync=True)
    sync_frame = Bool(True).tag(sync=True)
    interpolate = Bool(False).tag(sync=False)
    delay = Float(0.0).tag(sync=True)
    parameters = Dict().tag(sync=True)
    iparams = Dict().tag(sync=False)
    _interpolation_t = Float().tag(sync=False)
    _iterpolation_type = CaselessStrEnum(['linear', 'spline']).tag(sync=False)
    spin = Bool(False).tag(sync=False)
    _spin_x = Int(1).tag(sync=False)
    _spin_y = Int(0).tag(sync=False)
    _spin_z = Int(0).tag(sync=False)
    _spin_speed = Float(0.005).tag(sync=False)
    camera = CaselessStrEnum(['perspective', 'orthographic'],
                             default_value='perspective').tag(sync=False)
    _render_params = Dict().tag(sync=False)
    _real_time_update = Bool(False).tag(sync=False)

    widget_tab = Any(None).tag(sync=False)
    widget_repr = Any(None).tag(sync=False)
    widget_repr_parameters = Any(None).tag(sync=False)
    widget_quick_repr = Any(None).tag(sync=False)
    widget_general = Any(None).tag(sync=False)
    widget_picked = Any(None).tag(sync=False)
    widget_preference = Any(None).tag(sync=False)
    widget_extra = Any(None).tag(sync=False)
    widget_theme = Any(None).tag(sync=False)
    widget_help = Any(None).tag(sync=False)
    widget_export_image = Any(None).tag(sync=False)
    widget_component_slider = Any(None).tag(sync=False)
    widget_repr_slider = Any(None).tag(sync=False)
    widget_repr_choices = Any(None).tag(sync=False)
    widget_repr_control_buttons = Any(None).tag(sync=False)
    widget_repr_add = Any(None).tag(sync=False)
    widget_accordion_repr_parameters = Any(None).tag(sync=False)
    widget_repr_parameters_dialog = Any(None).tag(sync=False)
    widget_repr_name = Any(None).tag(sync=False)
    widget_component_dropdown = Any(None).tag(sync=False)
    widget_drag = Any(None).tag(sync=False)

    def __init__(self,
                 view,
                 step=1,
                 delay=100,
                 sync_frame=False,
                 min_delay=40):
        self._view = view
        self.step = step
        self.sync_frame = sync_frame
        self.delay = delay
        self.min_delay = min_delay
        self._interpolation_t = 0.5
        self._iterpolation_type = 'linear'
        self.iparams = dict(t=self._interpolation_t,
                            step=1,
                            type=self._iterpolation_type)
        self._render_params = dict(factor=4,
                                   antialias=True,
                                   trim=False,
                                   transparent=False)

        self._widget_names = [w for w in dir(self) if w.startswith('wiget_')]
        self.observe(self._on_widget_built,
                     names=[
                         'widget_repr_parameters', 'widget_repr',
                         'widget_preference'
                     ])

    def _on_widget_built(self, change):
        widget = change['new']
        if widget is not None:
            widget.layout.padding = '5%'

    def _update_padding(self, padding=default.DEFAULT_PADDING):
        widget_collection = [
            self.widget_general, self.widget_repr, self.widget_preference,
            self.widget_repr_parameters, self.widget_help, self.widget_extra,
            self.widget_picked
        ]
        for widget in widget_collection:
            if widget is not None:
                widget.layout.padding = padding

    def _create_all_widgets(self):
        if self.widget_tab is None:
            self.widget_tab = self._display()

        old_index = self.widget_tab.selected_index
        for index, _ in enumerate(self.widget_tab.children):
            self.widget_tab.selected_index = index

        self.widget_tab.selected_index = old_index

    def smooth(self):
        self.interpolate = True

    @observe('camera')
    def on_camera_changed(self, change):
        camera_type = change['new']
        self._view._remote_call("setParameters",
                                target='Stage',
                                kwargs=dict(cameraType=camera_type))

    @property
    def frame(self):
        return self._view.frame

    @frame.setter
    def frame(self, value):
        self._view.frame = value

    @property
    def count(self):
        return self._view.count

    @observe('sync_frame')
    def update_sync_frame(self, change):
        value = change['new']
        if value:
            self._view._set_sync_frame()
        else:
            self._view._set_unsync_frame()

    @observe("delay")
    def update_delay(self, change):
        delay = change['new']
        self._view._set_delay(delay)

    @observe('parameters')
    def update_parameters(self, change):
        params = change['new']
        self.sync_frame = params.get("sync_frame", self.sync_frame)
        self.delay = params.get("delay", self.delay)
        self.step = params.get("step", self.step)

    @observe('_interpolation_t')
    def _interpolation_t_changed(self, change):
        self.iparams['t'] = change['new']

    @observe('spin')
    def on_spin_changed(self, change):
        self.spin = change['new']
        if self.spin:
            self._view._set_spin([self._spin_x, self._spin_y, self._spin_z],
                                 self._spin_speed)
        else:
            # stop
            self._view._set_spin(None, None)

    @observe('_spin_x')
    def on_spin_x_changed(self, change):
        self._spin_x = change['new']
        if self.spin:
            self._view._set_spin([self._spin_x, self._spin_y, self._spin_z],
                                 self._spin_speed)

    @observe('_spin_y')
    def on_spin_y_changed(self, change):
        self._spin_y = change['new']
        if self.spin:
            self._view._set_spin([self._spin_x, self._spin_y, self._spin_z],
                                 self._spin_speed)

    @observe('_spin_z')
    def on_spin_z_changed(self, change):
        self._spin_z = change['new']
        if self.spin:
            self._view._set_spin([self._spin_x, self._spin_y, self._spin_z],
                                 self._spin_speed)

    @observe('_spin_speed')
    def on_spin_speed_changed(self, change):
        self._spin_speed = change['new']
        if self.spin:
            self._view._set_spin([self._spin_x, self._spin_y, self._spin_z],
                                 self._spin_speed)

    def _display(self):
        box_factory = [(self._make_general_box, 'General'),
                       (self._make_widget_repr, 'Representation'),
                       (self._make_widget_preference, 'Preference'),
                       (self._make_theme_box, 'Theme'),
                       (self._make_extra_box, 'Extra'), (Box, 'Hide'),
                       (self._show_website, 'Help')]

        tab = _make_delay_tab(box_factory, selected_index=-1)
        # tab = _make_autofit(tab)
        tab.layout.align_self = 'center'
        tab.layout.align_items = 'stretch'

        self.widget_tab = tab

        return self.widget_tab

    def _make_button_center(self):
        button = Button(description=' Center', icon='fa-bullseye')

        @button.on_click
        def on_click(button):
            self._view.center()

        return button

    def _make_button_theme(self):
        button = Button(description='Oceans16')

        @button.on_click
        def on_click(button):
            from nglview import theme
            display(theme.oceans16())
            self._view._remote_call('cleanOutput', target='Widget')

        return button

    def _make_button_reset_theme(self, hide_toolbar=False):
        from nglview import theme

        if hide_toolbar:
            button = Button(description='Simplified Default')

            @button.on_click
            def on_click(button):
                theme.reset(hide_toolbar=True)
        else:
            button = Button(description='Default')

            @button.on_click
            def on_click(button):
                theme.reset()

        return button

    def _make_widget_preference(self, width='100%'):
        def make_func():
            parameters = self._view._full_stage_parameters

            def func(pan_speed=parameters.get('panSpeed', 0.8),
                     rotate_speed=parameters.get('rotateSpeed', 2),
                     zoom_speed=parameters.get('zoomSpeed', 1.2),
                     clip_dist=parameters.get('clipDist', 10),
                     camera_fov=parameters.get('cameraFov', 40),
                     clip_far=parameters.get('clipFar', 100),
                     clip_near=parameters.get('clipNear', 0),
                     fog_far=parameters.get('fogFar', 100),
                     fog_near=parameters.get('fogNear', 50),
                     impostor=parameters.get('impostor', True),
                     light_intensity=parameters.get('lightIntensity', 1),
                     quality=parameters.get('quality', 'medium'),
                     sample_level=parameters.get('sampleLevel', 1)):

                self._view.parameters = dict(panSpeed=pan_speed,
                                             rotateSpeed=rotate_speed,
                                             zoomSpeed=zoom_speed,
                                             clipDist=clip_dist,
                                             clipFar=clip_far,
                                             clipNear=clip_near,
                                             cameraFov=camera_fov,
                                             fogFar=fog_far,
                                             fogNear=fog_near,
                                             impostor=impostor,
                                             lightIntensity=light_intensity,
                                             quality=quality,
                                             sampleLevel=sample_level)

            return func

        def make_widget_box():
            widget_sliders = interactive(make_func(),
                                         pan_speed=(0, 10, 0.1),
                                         rotate_speed=(0, 10, 1),
                                         zoom_speed=(0, 10, 1),
                                         clip_dist=(0, 200, 5),
                                         clip_far=(0, 100, 1),
                                         clip_near=(0, 100, 1),
                                         camera_fov=(15, 120, 1),
                                         fog_far=(0, 100, 1),
                                         fog_near=(0, 100, 1),
                                         light_intensity=(0, 10, 0.02),
                                         quality=['low', 'medium', 'high'],
                                         sample_level=(-1, 5, 1))

            for child in widget_sliders.children:
                if isinstance(child, (IntSlider, FloatSlider)):
                    child.layout.width = default.DEFAULT_SLIDER_WIDTH
            return widget_sliders

        if self.widget_preference is None:
            widget_sliders = make_widget_box()
            reset_button = Button(description='Reset')
            widget_sliders.children = [
                reset_button,
            ] + list(widget_sliders.children)

            @reset_button.on_click
            def on_click(reset_button):
                self._view.parameters = self._view._original_stage_parameters
                self._view._full_stage_parameters = self._view._original_stage_parameters
                widget_sliders.children = [
                    reset_button,
                ] + list(make_widget_box().children)

            self.widget_preference = _relayout_master(widget_sliders,
                                                      width=width)
        return self.widget_preference

    def _show_download_image(self):
        # "interactive" does not work for True/False in ipywidgets 4 yet.
        button = Button(description=' Screenshot', icon='fa-camera')

        @button.on_click
        def on_click(button):
            self._view.download_image()

        return button

    def _make_button_url(self, url, description):
        button = Button(description=description)

        @button.on_click
        def on_click(button):
            display(Javascript(js_utils.open_url_template.format(url=url)))

        return button

    def _show_website(self, ngl_base_url=default.NGL_BASE_URL):
        buttons = [
            self._make_button_url(url.format(ngl_base_url), description)
            for url, description in
            [("'http://arose.github.io/nglview/latest/'",
              "nglview"), (
                  "'{}/index.html'",
                  "NGL"), ("'{}/tutorial-selection-language.html'",
                           "Selection"),
             ("'{}/tutorial-molecular-representations.html'",
              "Representation")]
        ]
        self.widget_help = _make_autofit(HBox(buttons))
        return self.widget_help

    def _make_button_qtconsole(self):
        from nglview import js_utils
        button = Button(description='qtconsole', tooltip='pop up qtconsole')

        @button.on_click
        def on_click(button):
            js_utils.launch_qtconsole()

        return button

    def _make_text_picked(self):
        ta = Textarea(value=json.dumps(self._view.picked),
                      description='Picked atom')
        ta.layout.width = '300px'
        return ta

    def _refresh(self, component_slider, repr_slider):
        """update representation and component information
        """
        self._view._request_repr_parameters(component=component_slider.value,
                                            repr_index=repr_slider.value)
        self._view._remote_call('requestReprInfo', target='Widget')
        self._view._handle_repr_dict_changed(change=dict(
            new=self._view._repr_dict))

    def _make_button_repr_control(self, component_slider, repr_slider,
                                  repr_selection):
        button_refresh = Button(description=' Refresh',
                                tooltip='Get representation info',
                                icon='fa-refresh')
        button_center_selection = Button(description=' Center',
                                         tooltip='center selected atoms',
                                         icon='fa-bullseye')
        button_center_selection._ngl_name = 'button_center_selection'
        button_hide = Button(description=' Hide',
                             icon='fa-eye-slash',
                             tooltip='Hide/Show current representation')
        button_remove = Button(description=' Remove',
                               icon='fa-trash',
                               tooltip='Remove current representation')
        button_repr_parameter_dialog = Button(
            description=' Dialog',
            tooltip='Pop up representation parameters control dialog')

        @button_refresh.on_click
        def on_click_refresh(button):
            self._refresh(component_slider, repr_slider)

        @button_center_selection.on_click
        def on_click_center(center_selection):
            self._view.center_view(selection=repr_selection.value,
                                   component=component_slider.value)

        @button_hide.on_click
        def on_click_hide(button_hide):
            component = component_slider.value
            repr_index = repr_slider.value

            if button_hide.description == 'Hide':
                hide = True
                button_hide.description = 'Show'
            else:
                hide = False
                button_hide.description = 'Hide'

            self._view._remote_call('setVisibilityForRepr',
                                    target='Widget',
                                    args=[component, repr_index, not hide])

        @button_remove.on_click
        def on_click_remove(button_remove):
            self._view._remove_representation(component=component_slider.value,
                                              repr_index=repr_slider.value)
            self._view._request_repr_parameters(
                component=component_slider.value, repr_index=repr_slider.value)

        @button_repr_parameter_dialog.on_click
        def on_click_repr_dialog(_):
            from nglview.widget_box import DraggableBox
            if self.widget_repr_parameters is not None and self.widget_repr_choices:
                self.widget_repr_parameters_dialog = DraggableBox(
                    [self.widget_repr_choices, self.widget_repr_parameters])
                self.widget_repr_parameters_dialog._ipython_display_()
                self.widget_repr_parameters_dialog._dialog = 'on'

        bbox = _make_autofit(
            HBox([
                button_refresh, button_center_selection, button_hide,
                button_remove, button_repr_parameter_dialog
            ]))
        return bbox

    def _make_widget_repr(self):
        # TODO: class?
        if self.widget_repr is None:
            self.widget_repr_name = Text(value='',
                                         description='representation')
            self.widget_repr_name._ngl_name = 'repr_name_text'
            repr_selection = Text(value=' ', description='selection')
            repr_selection._ngl_name = 'repr_selection'
            repr_selection.width = self.widget_repr_name.width = default.DEFAULT_TEXT_WIDTH

            max_n_components = max(self._view.n_components - 1, 0)
            self.widget_component_slider = IntSlider(value=0,
                                                     max=max_n_components,
                                                     min=0,
                                                     description='component')
            self.widget_component_slider._ngl_name = 'component_slider'

            cvalue = ' '
            self.widget_component_dropdown = Dropdown(value=cvalue,
                                                      options=[
                                                          cvalue,
                                                      ],
                                                      description='component')
            self.widget_component_dropdown._ngl_name = 'component_dropdown'

            self.widget_repr_slider = IntSlider(
                value=0,
                description='representation',
                width=default.DEFAULT_SLIDER_WIDTH)
            self.widget_repr_slider._ngl_name = 'repr_slider'
            self.widget_repr_slider.visible = True

            self.widget_component_slider.layout.width = default.DEFAULT_SLIDER_WIDTH
            self.widget_repr_slider.layout.width = default.DEFAULT_SLIDER_WIDTH
            self.widget_component_dropdown.layout.width = self.widget_component_dropdown.max_width = default.DEFAULT_TEXT_WIDTH

            # turn off for now
            self.widget_component_dropdown.layout.display = 'none'
            self.widget_component_dropdown.description = ''

            # self.widget_accordion_repr_parameters = Accordion()
            self.widget_accordion_repr_parameters = Tab()
            self.widget_repr_parameters = self._make_widget_repr_parameters(
                self.widget_component_slider, self.widget_repr_slider,
                self.widget_repr_name)
            self.widget_accordion_repr_parameters.children = [
                self.widget_repr_parameters,
                Box()
            ]
            self.widget_accordion_repr_parameters.set_title(0, 'Parameters')
            self.widget_accordion_repr_parameters.set_title(1, 'Hide')
            self.widget_accordion_repr_parameters.selected_index = 1

            checkbox_reprlist = Checkbox(value=False, description='reprlist')
            checkbox_reprlist._ngl_name = 'checkbox_reprlist'
            self.widget_repr_choices = self._make_repr_name_choices(
                self.widget_component_slider, self.widget_repr_slider)
            self.widget_repr_choices._ngl_name = 'reprlist_choices'

            self.widget_repr_add = self._make_add_widget_repr(
                self.widget_component_slider)

            def on_update_checkbox_reprlist(change):
                self.widget_repr_choices.visible = change['new']

            checkbox_reprlist.observe(on_update_checkbox_reprlist,
                                      names='value')

            def on_repr_name_text_value_changed(change):
                name = change['new'].strip()
                old = change['old'].strip()

                should_update = (self._real_time_update and old and name
                                 and name in REPRESENTATION_NAMES
                                 and name != change['old'].strip())

                if should_update:
                    component = component_slider.value
                    repr_index = repr_slider.value
                    self._view._remote_call(
                        'setRepresentation',
                        target='Widget',
                        args=[change['new'], {}, component, repr_index])
                    self._view._request_repr_parameters(component, repr_index)

            def on_component_or_repr_slider_value_changed(change):
                self._view._request_repr_parameters(
                    component=self.widget_component_slider.value,
                    repr_index=self.widget_repr_slider.value)
                self.widget_component_dropdown.options = tuple(
                    self._view._ngl_component_names)

                if self.widget_accordion_repr_parameters.selected_index >= 0:
                    self.widget_repr_parameters.name = self.widget_repr_name.value
                    self.widget_repr_parameters.repr_index = self.widget_repr_slider.value
                    self.widget_repr_parameters.component_index = self.widget_component_slider.value

            def on_repr_selection_value_changed(change):
                if self._real_time_update:
                    component = self.widget_component_slider.value
                    repr_index = self.widget_repr_slider.value
                    self._view._set_selection(change['new'],
                                              component=component,
                                              repr_index=repr_index)

            def on_change_component_dropdown(change):
                choice = change['new']
                if choice:
                    self.widget_component_slider.value = self._view._ngl_component_names.index(
                        choice)

            self.widget_component_dropdown.observe(
                on_change_component_dropdown, names='value')

            self.widget_repr_slider.observe(
                on_component_or_repr_slider_value_changed, names='value')
            self.widget_component_slider.observe(
                on_component_or_repr_slider_value_changed, names='value')
            self.widget_repr_name.observe(on_repr_name_text_value_changed,
                                          names='value')
            repr_selection.observe(on_repr_selection_value_changed,
                                   names='value')

            self.widget_repr_control_buttons = self._make_button_repr_control(
                self.widget_component_slider, self.widget_repr_slider,
                repr_selection)

            blank_box = Box([Label("")])

            all_kids = [
                self.widget_repr_control_buttons, blank_box,
                self.widget_repr_add, self.widget_component_dropdown,
                self.widget_repr_name, repr_selection,
                self.widget_component_slider, self.widget_repr_slider,
                self.widget_repr_choices, self.widget_accordion_repr_parameters
            ]

            vbox = VBox(all_kids)

            self._view._request_repr_parameters(
                component=self.widget_component_slider.value,
                repr_index=self.widget_repr_slider.value)

            self.widget_repr = _relayout_master(vbox, width='100%')

            self._refresh(self.widget_component_slider,
                          self.widget_repr_slider)

            setattr(self.widget_repr, "_saved_widgets", [])
            for _box in self.widget_repr.children:
                if hasattr(_box, 'children'):
                    for kid in _box.children:
                        self.widget_repr._saved_widgets.append(kid)

            return self.widget_repr

    def _make_widget_repr_parameters(self,
                                     component_slider,
                                     repr_slider,
                                     repr_name_text=None):
        name = repr_name_text.value if repr_name_text is not None else ' '
        widget = self._view._display_repr(component=component_slider.value,
                                          repr_index=repr_slider.value,
                                          name=name)
        widget._ngl_name = 'repr_parameters_box'
        return widget

    def _make_button_export_image(self):
        slider_factor = IntSlider(value=4, min=1, max=10, description='scale')
        checkbox_antialias = Checkbox(value=True, description='antialias')
        checkbox_trim = Checkbox(value=False, description='trim')
        checkbox_transparent = Checkbox(value=False, description='transparent')
        filename_text = Text(value='Screenshot', description='Filename')
        delay_text = FloatText(value=1,
                               description='delay (s)',
                               tooltip='hello')

        start_text, stop_text, step_text = (IntText(value=0,
                                                    description='start'),
                                            IntText(value=self._view.count,
                                                    description='stop'),
                                            IntText(value=1,
                                                    description='step'))

        start_text.layout.max_width = stop_text.layout.max_width = step_text.layout.max_width \
                = filename_text.layout.max_width = delay_text.layout.max_width = default.DEFAULT_TEXT_WIDTH

        button_movie_images = Button(description='Export Images')

        def download_image(filename):
            self._view.download_image(factor=slider_factor.value,
                                      antialias=checkbox_antialias.value,
                                      trim=checkbox_trim.value,
                                      transparent=checkbox_transparent.value,
                                      filename=filename)

        @button_movie_images.on_click
        def on_click_images(button_movie_images):
            for i in range(start_text.value, stop_text.value, step_text.value):
                self._view.frame = i
                time.sleep(delay_text.value)
                download_image(filename=filename_text.value + str(i))
                time.sleep(delay_text.value)

        vbox = VBox([
            button_movie_images,
            start_text,
            stop_text,
            step_text,
            delay_text,
            filename_text,
            slider_factor,
            checkbox_antialias,
            checkbox_trim,
            checkbox_transparent,
        ])

        form_items = _relayout(vbox, form_item_layout)
        form = Box(form_items, layout=_make_box_layout())
        # form = _relayout_master(vbox)
        return form

    def _make_resize_notebook_slider(self):
        resize_notebook_slider = IntSlider(min=300,
                                           max=2000,
                                           description='resize notebook')

        def on_resize_notebook(change):
            width = change['new']
            self._view._remote_call('resizeNotebook',
                                    target='Widget',
                                    args=[
                                        width,
                                    ])

        resize_notebook_slider.observe(on_resize_notebook, names='value')
        return resize_notebook_slider

    def _make_add_widget_repr(self, component_slider):
        dropdown_repr_name = Dropdown(options=REPRESENTATION_NAMES,
                                      value='cartoon')
        repr_selection = Text(value='*', description='')
        repr_button = Button(description='Add',
                             tooltip="""Add representation.
        You can also hit Enter in selection box""")
        repr_button.layout = Layout(width='auto', flex='1 1 auto')

        dropdown_repr_name.layout.width = repr_selection.layout.width = default.DEFAULT_TEXT_WIDTH

        def on_click_or_submit(button_or_text_area):
            self._view.add_representation(
                selection=repr_selection.value.strip(),
                repr_type=dropdown_repr_name.value,
                component=component_slider.value)

        repr_button.on_click(on_click_or_submit)
        repr_selection.on_submit(on_click_or_submit)
        add_repr_box = HBox([repr_button, dropdown_repr_name, repr_selection])
        add_repr_box._ngl_name = 'add_repr_box'

        return add_repr_box

    def _make_repr_playground(self):
        vbox = VBox()
        children = []

        rep_names = REPRESENTATION_NAMES[:]
        excluded_names = ['ball+stick', 'distance']
        for name in excluded_names:
            rep_names.remove(name)

        repr_selection = Text(value='*')
        repr_selection.layout.width = default.DEFAULT_TEXT_WIDTH
        repr_selection_box = HBox([Label('selection'), repr_selection])
        setattr(repr_selection_box, 'value', repr_selection.value)

        for index, name in enumerate(rep_names):
            button = ToggleButton(description=name)

            def make_func():
                def on_toggle_button_value_change(change, button=button):
                    selection = repr_selection.value
                    new = change['new']  # True/False
                    if new:
                        self._view.add_representation(button.description,
                                                      selection=selection)
                    else:
                        self._view._remove_representations_by_name(
                            button.description)

                return on_toggle_button_value_change

            button.observe(make_func(), names='value')
            children.append(button)

        button_clear = Button(description='clear',
                              button_style='info',
                              icon='fa-eraser')

        @button_clear.on_click
        def on_clear(button_clear):
            self._view.clear()
            for kid in children:
                # unselect
                kid.value = False

        vbox.children = children + [repr_selection, button_clear]
        _make_autofit(vbox)
        self.widget_quick_repr = vbox
        return self.widget_quick_repr

    def _make_repr_name_choices(self, component_slider, repr_slider):
        repr_choices = Dropdown()

        def on_chose(change):
            repr_name = change['new']
            repr_index = repr_choices.options.index(repr_name)
            repr_slider.value = repr_index

        repr_choices.observe(on_chose, names='value')
        repr_choices.layout.width = default.DEFAULT_TEXT_WIDTH

        self.widget_repr_choices = repr_choices
        return self.widget_repr_choices

    def _make_drag_widget(self):
        button_drag = Button(description='widget drag: off',
                             tooltip='dangerous')
        drag_nb = Button(description='notebook drag: off', tooltip='dangerous')
        button_reset_notebook = Button(description='notebook: reset',
                                       tooltip='reset?')
        button_dialog = Button(description='dialog', tooltip='make a dialog')
        button_split_half = Button(description='split screen',
                                   tooltip='try best to make a good layout')

        @button_drag.on_click
        def on_drag(button_drag):
            if button_drag.description == 'widget drag: off':
                self._view._set_draggable(True)
                button_drag.description = 'widget drag: on'
            else:
                self._view._set_draggable(False)
                button_drag.description = 'widget drag: off'

        @drag_nb.on_click
        def on_drag_nb(button_drag):
            if drag_nb.description == 'notebook drag: off':
                js_utils._set_notebook_draggable(True)
                drag_nb.description = 'notebook drag: on'
            else:
                js_utils._set_notebook_draggable(False)
                drag_nb.description = 'notebook drag: off'

        @button_reset_notebook.on_click
        def on_reset(button_reset_notebook):
            js_utils._reset_notebook()

        @button_dialog.on_click
        def on_dialog(button_dialog):
            self._view._remote_call('setDialog', target='Widget')

        @button_split_half.on_click
        def on_split_half(button_dialog):
            from nglview import js_utils
            import time
            js_utils._move_notebook_to_the_left()
            js_utils._set_notebook_width('5%')
            time.sleep(0.1)
            self._view._remote_call('setDialog', target='Widget')

        drag_box = HBox([
            button_drag, drag_nb, button_reset_notebook, button_dialog,
            button_split_half
        ])
        drag_box = _make_autofit(drag_box)
        self.widget_drag = drag_box
        return drag_box

    def _make_spin_box(self):
        checkbox_spin = Checkbox(self.spin, description='spin')
        spin_x_slide = IntSlider(self._spin_x,
                                 min=-1,
                                 max=1,
                                 description='spin_x')
        spin_y_slide = IntSlider(self._spin_y,
                                 min=-1,
                                 max=1,
                                 description='spin_y')
        spin_z_slide = IntSlider(self._spin_z,
                                 min=-1,
                                 max=1,
                                 description='spin_z')
        spin_speed_slide = FloatSlider(self._spin_speed,
                                       min=0,
                                       max=0.2,
                                       step=0.001,
                                       description='spin speed')
        # spin
        link((checkbox_spin, 'value'), (self, 'spin'))
        link((spin_x_slide, 'value'), (self, '_spin_x'))
        link((spin_y_slide, 'value'), (self, '_spin_y'))
        link((spin_z_slide, 'value'), (self, '_spin_z'))
        link((spin_speed_slide, 'value'), (self, '_spin_speed'))

        spin_box = VBox([
            checkbox_spin, spin_x_slide, spin_y_slide, spin_z_slide,
            spin_speed_slide
        ])
        spin_box = _relayout_master(spin_box, width='75%')
        return spin_box

    def _make_widget_picked(self):
        self.widget_picked = self._make_text_picked()
        picked_box = HBox([
            self.widget_picked,
        ])
        return _relayout_master(picked_box, width='75%')

    def _make_export_image_widget(self):
        if self.widget_export_image is None:
            self.widget_export_image = HBox([self._make_button_export_image()])
        return self.widget_export_image

    def _make_extra_box(self):
        if self.widget_extra is None:
            extra_list = [(self._make_drag_widget, 'Drag'),
                          (self._make_spin_box, 'Spin'),
                          (self._make_widget_picked, 'Picked'),
                          (self._make_repr_playground, 'Quick'),
                          (self._make_export_image_widget, 'Image')]

            extra_box = _make_delay_tab(extra_list, selected_index=0)
            self.widget_extra = extra_box
        return self.widget_extra

    def _make_theme_box(self):
        if self.widget_theme is None:
            self.widget_theme = Box([
                self._make_button_theme(),
                self._make_button_reset_theme(hide_toolbar=False),
                self._make_button_reset_theme(hide_toolbar=True)
            ])
        return self.widget_theme

    def _make_general_box(self):
        if self.widget_general is None:
            step_slide = IntSlider(value=self.step,
                                   min=-100,
                                   max=100,
                                   description='step')
            delay_text = IntSlider(value=self.delay,
                                   min=10,
                                   max=1000,
                                   description='delay')
            toggle_button_interpolate = ToggleButton(
                self.interpolate,
                description='Smoothing',
                tooltip='smoothing trajectory')
            link((toggle_button_interpolate, 'value'), (self, 'interpolate'))

            background_color_picker = ColorPicker(value='white',
                                                  description='background')
            camera_type = Dropdown(value=self.camera,
                                   options=['perspective', 'orthographic'],
                                   description='camera')

            link((step_slide, 'value'), (self, 'step'))
            link((delay_text, 'value'), (self, 'delay'))
            link((toggle_button_interpolate, 'value'), (self, 'interpolate'))
            link((camera_type, 'value'), (self, 'camera'))
            link((background_color_picker, 'value'),
                 (self._view, 'background'))

            center_button = self._make_button_center()
            render_button = self._show_download_image()
            qtconsole_button = self._make_button_qtconsole()
            center_render_hbox = _make_autofit(
                HBox([
                    toggle_button_interpolate, center_button, render_button,
                    qtconsole_button
                ]))

            v0_left = VBox([
                step_slide,
                delay_text,
                background_color_picker,
                camera_type,
                center_render_hbox,
            ])

            v0_left = _relayout_master(v0_left, width='100%')
            self.widget_general = v0_left
        return self.widget_general

    def _create_all_tabs(self):
        tab = self._display()
        for index, _ in enumerate(tab.children):
            # trigger ceating widgets
            tab.selected_index = index

    def _simplify_repr_control(self):
        for widget in self.widget_repr._saved_widgets:
            if not isinstance(widget, Tab):
                widget.layout.display = 'none'
        self.widget_repr_choices.layout.display = 'flex'
        self.widget_accordion_repr_parameters.selected_index = 0
Esempio n. 35
0
class RADashBoard:

  def __init__(self):
    self.out_cp = Output()
    display(self.out_cp)
    self.objDict = {}
    self.objinfoDict = {}
    self.title = 'Research & Applications Dashboard'
    self.nx   = 1
    self.ny   = 1
    self.panelWidth  = [250,500]
    self.panelHeight = [250,500]
    #self.ob  =   OpenAQGui().createCP()
    self.ob  =  QueryOpenAq().getCP()
    self.state = 0
    self.gridGap = 15
    self.gridPad = 15
    self.panelBorder = 3
    self.dbBorder =5
    self.cpView  = 0
    self.pwdDict= {}
    self.createMainCP = True
    self.accList =['NASA Earth Data']
  
  def addAccount(accname):
    self.accList.append(accname)

  def addObject(self,obj,short_name, desc):
    self.objDict[short_name] = obj
    self.objinfoDict[short_name] = desc

  def displayCP(self):
    
    self.rowSW = Dropdown(options=[1,2,3,4],value=1,description='Rows:',
                          disabled=False,layout={'width':'150px'}
                         )
    self.colSW = Dropdown(options=[1,2,3,4],value=1,description='Columns:',
                            disabled=False,layout={'width':'150px'}
                          )
    self.row  = Dropdown(options=[1,2,3,4],value=1,
                         description='# of row:',disabled=True)
    self.col  = Dropdown(options=[1,2,3,4],value=1,
                         description='# of col:',disabled=True)
    self.obj  = Dropdown(options=[],value=None,
                         description='Object:',disabled=True)
    self.conDB = Button(description='Configure Dashboard',disabled=False,
                          layout={'width':'150px','border':'3px outset'}
                         )
    self.topLabel = HTML(disabled=False,layout={'width': 'auto'})
      
    self.topLabel.value = ( '<div style="background-color: #C0C0C0 ;'+ 
                            'padding: 1em 0em 0em 0em;border-bottom-style:groove;border-width:4px">'+
                           '<b><font size="4"><center><h2>'+self.title+'</h2></center></font></b></div>')
    self.rule = HTML(disabled=True,layout=Layout(width='auto',padding='0px'))
      
    self.rule.value = ( '<div >'+'<hr></div>')
    self.cpMain   = VBox([ 
                          HBox([self.topLabel],layout={'justify_content':'center','flex_flow':'column'}),
                          HBox([
                                HBox([self.rowSW],layout={'justify_content':'flex-start'}),
                                HBox([self.colSW],layout={'justify_content':'flex-end'})
                               ],layout={'padding':'15px'}
                              ),
                          HBox([self.conDB],layout={'justify_content':'center','padding':'15px'})
                               ],layout={'border':'3px groove','width': '400px'}
                        )
    self.rowSW.observe(self.rowSWCB,names='value')
    self.colSW.observe(self.colSWCB,names='value')
    self.conDB.on_click(self.configDBCB)
    with self.out_cp:
      display(self.cpMain)

  def rowSWCB(self,change):
    if change['type'] == 'change':

      # set the city to the new user selected value given 
      # by the "value" attribute in the city selection widget.

      self.ny    = int(self.rowSW.value)
      

  def colSWCB(self,change):
    if change['type'] == 'change':

      # set the city to the new user selected value given 
      # by the "value" attribute in the city selection widget.

      self.nx    = int(self.colSW.value)
      

  def rowSWCB(self,change):
    if change['type'] == 'change':

      # set the city to the new user selected value given 
      # by the "value" attribute in the city selection widget.

      self.ny    = int(self.rowSW.value)
      

  def colSWCB(self,change):
    if change['type'] == 'change':

      # set the city to the new user selected value given 
      # by the "value" attribute in the city selection widget.

      self.nx    = int(self.colSW.value)
      


  def configDBCB(self,b):

    self.out_cp.clear_output()

    self.objList = [*(self.objDict)]

    pw = self.panelWidth[0]

    lw = (pw*self.nx)+((self.nx-1)*self.gridGap)+(self.gridPad*2)

    gw = lw + (2*self.dbBorder)

    lw1 = lw-2

    self.topLabel.layout = {'width': str(lw-2)+'px'}

    gap = str(self.gridGap)+'px'

    pd = str(self.gridPad)

    pad = pd+'px '+pd+'px '+pd+'px '+pd+'px'

    self.gridDB1 = GridspecLayout(self.ny,self.nx,
                                  layout={
                                          'scroll':'False',
                                          'grid_gap':gap,
                                          'padding':pad
                                          }
                                  )
    self.objSW = [ ([0] * self.nx) for y in range(self.ny) ]
    self.objinfoTW = [ ([0] * self.nx) for y in range(self.ny) ]
    self.pwTW = [ ([0] * self.nx) for y in range(self.ny) ]
    self.phTW = [ ([0] * self.nx) for y in range(self.ny) ]

    txw = str(int(0.96*float(self.panelWidth[0])))+'px'
    pw = str(self.panelWidth[0])+'px'
    ph = str(self.panelHeight[0])+'px'
    pb = str(self.panelBorder)+'px groove'

    for i in range(0,self.ny):
      for j in range(0,self.nx):
        desc = 'Panel('+str(i+1)+','+str(j+1)+'):'
        self.objSW[i][j]  = Dropdown(options=self.objList,value=self.objList[0],
                                    description=desc,disabled=False,
                                    layout={'width':txw})
        objinfo = self.objinfoDict[self.objList[0]]
        self.objinfoTW[i][j] = Textarea(value=objinfo,placeholder='',description='',
                                    disabled=False,layout={'width':txw,'border':'2px inset'})
        self.pwTW[i][j] = Text(value=str(self.panelWidth[1]),placeholder='',description='Panel Width:',
                                    disabled=False,layout={'width':txw,'border':'2px inset'})
        self.phTW[i][j] = Text(value=str(self.panelHeight[1]),placeholder='',description='Panel Height',
                                    disabled=False,layout={'width':txw,'border':'2px inset'})
        
        self.gridDB1[i,j] = VBox([self.objSW[i][j],self.pwTW[i][j],self.phTW[i][j],self.objinfoTW[i][j]],layout={'border':'2px solid black'})

        self.objSW[i][j].observe(functools.partial(self.objSWCB, irow_=i, jcol_=j),names='value')
        self.phTW[i][j].observe(functools.partial(self.phTWCB, irow_=i, jcol_=j),names='value')

    gp  = str(self.gridPad)+'px'
    dbb = str(self.dbBorder)+'px groove'
    dbw = str(gw)+'px'

    self.pmLabel = HTML(disabled=False,layout={'width': 'auto','flex_flow':'column'})
    
    self.pmLabel.value = ( '<div style="background-color: #C0C0C0 ;'+ 
                           'border-top-style:groove;border-width:3px'
                           'padding: 1em 0em 0em 0em;border-bottom-style:groove;border-width:3px">'+
                           '<b><font size="4"><center><h3>Password Manager</h3></center></font></b></div>')
    self.accSW = Dropdown(options=self.accList,value=self.accList[0],
                                    description='Account:',disabled=False,
                                    layout={'width':txw})
    self.usrTW = Text(value='',placeholder='',description='Username:'******'width':txw})
    
    self.pwdPW = Password(value='',placeholder='',description='Password:'******'width':txw})
    self.addPWD = Button(description='Add Account',disabled=False,
                        layout={'width':'150px','border':'3px outset'}
                        )
    self.createDB = Button(description='Create Dashboard',disabled=False,
                        layout={'width':'150px','border':'3px outset'}
                        )
    self.addPWD.on_click(self.addPWDCB)
    self.createDB.on_click(self.createDBCB)
    self.reconfigDB = Button(description='Reconfigure Dashboard',disabled=False,
                        layout={'width':'180px','border':'3px outset'}
                        )
    self.reconfigDB.on_click(self.reconfigDBCB)
    
    self.cp   = VBox([ 
                       HBox([self.topLabel],layout={'flex_flow':'column'}),
                       HBox([self.gridDB1]),
                       HBox([self.pmLabel],layout={'flex_flow':'column'}),
                       VBox([self.accSW,self.usrTW,self.pwdPW]),
                       HBox([self.addPWD],layout={'justify_content':'center'}),
                       self.rule,
                       HBox([self.reconfigDB,self.createDB],layout={'justify_content':'center','padding':gp})
                     ],layout={'border':dbb,'width':dbw}
                    )
    with self.out_cp:
      self.out_cp.clear_output()
      display(self.cp)
  def objSWCB(self,change,irow_,jcol_):
    self.objinfoTW[irow_][jcol_].value =self.objinfoDict[self.objSW[irow_][jcol_].value]

  def phTWCB(self,change,irow_,jcol_):
    self.objinfoTW[irow_][jcol_].value =('Hint: Set the same height of all the panels in'+ 
                                         ' a row for optimal panel layout')
    

  def addPWDCB(self,b):
    self.pwdDict[self.accSW.value]={'user':self.usrTW.value,'password':self.pwdPW.value}
    

  def createDBCB(self,b):
    self.out_cp.clear_output()
    wd = [0]*self.ny
    for i in range(self.ny):
      for j in range(self.nx):
        wd[i] += int(self.pwTW[i][j].value)

    tpw = max(wd)
    lw = tpw+((self.nx-1)*self.gridGap)+(self.gridPad*2)
    self.topLabel.layout = {'width': 'auto'}
    gw = lw + (2*self.dbBorder)
    gap = str(self.gridGap)+'px'
    pd = str(self.gridPad)
    pad = pd+'px '+pd+'px '+pd+'px '+pd+'px'
    self.gridDB2  = GridspecLayout(self.ny,self.nx,
                                  layout={
                                          'scroll':'True',
                                          'grid_gap':gap,
                                          'padding':pad
                                          }
                                  )
    ph = str(self.panelHeight[1])+'px'
    pb = str(self.panelBorder)+'px groove'

    for i in range(0,self.ny):
      for j in range(0,self.nx):
        pw = self.pwTW[i][j].value+'px'
        ph = self.phTW[i][j].value+'px'
        obj = self.objDict[self.objSW[i][j].value]()
        obj.pwdDict = self.pwdDict
        obj.spacer.layout={'width':pw}
        obj = obj.getCP()
        obj.layout={'overflow_x':'visible','overflow_y':'visible'}
        self.gridDB2[i,j] = HBox([obj],layout={'height': ph,'width': pw,'border':pb})
    gp  = str(self.gridPad)+'px'
    dbb = str(self.dbBorder)+'px groove'
    dbw = str(gw)+'px'

    self.cp   = VBox([ VBox([self.topLabel,self.gridDB2],layout={'flex_flow':'column'}),
                       HBox([self.reconfigDB],layout={'justify_content':'center','padding':gp})
                     ],layout={'border':dbb,'width':dbw}
                    )
    with self.out_cp:
      self.out_cp.clear_output()
      display(self.cp)
  def reconfigDBCB(self,b):
    with self.out_cp:
      self.out_cp.clear_output()
      self.topLabel.layout={'flex_flow':'column'}
      display(self.cpMain)
Esempio n. 36
0
class Accesses():
    def __init__(self, model, update_selection):
        self.model = model
        self.update_selection = update_selection
        self.colormap = np.copy(newc)
        self.colorpickers = {}
        self.custom_layer_preset = None
        self.all_tags =  self.model.curr_trace.tags # includes spacetime and thread
        self.layer_options = [
            ('None', [0]), ('accesses-read', [READ_HIT, READ_MISS, COMP_R_MISS]), ('accesses-write', [WRITE_HIT, WRITE_MISS, COMP_W_MISS]),
            ('hits-all', [WRITE_HIT, READ_HIT]), ('hits-read', [READ_HIT]),  ('hits-write', [WRITE_HIT]),  
            ('misses-all', [READ_MISS, WRITE_MISS, COMP_R_MISS, COMP_W_MISS]), ('misses-reads', [READ_MISS, COMP_R_MISS]),
            ('misses-writes', [WRITE_MISS, COMP_W_MISS]), ('misses-capacity-all', [WRITE_MISS, READ_MISS]),
            ('misses-capacity-reads', [READ_MISS]), ('misses-capacity-writes', [WRITE_MISS]), ('misses-compulsory-all', [WRITE_MISS, READ_MISS]),
            ('misses-compulsory-reads', [COMP_R_MISS]), ('misses-compulsory-writes', [COMP_W_MISS])
         ]

        i_val = 9
        for tag in self.all_tags:
           i_layer = (tag.display_name(), tag)
           i_val += 1
           self.layer_options.append(i_layer)

        self.widgets = self.init_widgets()

    def init_widgets(self):
        #######################################################################
        '''
            Helper functions to help with wrapping widgets in layouts and initializing UI
            elements
        '''
        def clr_picker(enum_color, cache=False, miss_acc=False):
            '''

            '''
            def handle_color_picker(change):
                print(enum_color, change)
                self.colormap[enum_color] = to_rgba(change.new, 1)
                self.model.plot.colormap = ListedColormap(self.colormap)
                self.model.plot.backend.plot.update_image()
            

            if cache:
                clr_picker = ColorPicker(concise=True, value=to_hex(self.colormap[enum_color][0:3]), 
                        disabled=False, layout=Layout(width="30px"))
            else:
                clr_picker = ColorPicker(concise=True, value=to_hex(self.colormap[enum_color][0:3]), 
                        disabled=False, layout=Layout(width="25px", margin="0 4px 0 4px"))
            
            clr_picker.observe(handle_color_picker, names='value')
            self.colorpickers[enum_color] = clr_picker

            clr_picker.observing = True
            return clr_picker



        def ParentBox(parent_widgets):
            # Create wrapper to combine clrpicker checkbox and dropdown 
            return HBox([clr_picker(enum_color=parent_widgets.enum_color), parent_widgets.check_widget , parent_widgets.dropdown_widget], 
                        layout=Layout(align_items="center", overflow="hidden", justify_content="flex-start"))


        #######################################################################
        # drop down menue for color view selection
        self.dropdown = Dropdown(options=C_VIEW_OPTIONS,
                            value='None',
                            disabled=False,
                            layout={'width': 'min-content'}
                            )
        self.dropdown.observe(self.update_presets, names='value')
        self.dropdown.observing = True
        dropdown_row = HBox([GridBox([Label(value='Layer Preset:'), self.dropdown],
                            layout=Layout(grid_template_rows="30px", grid_template_columns="120px 200px"))], 
                            layout=Layout( padding="0px 0px 14px 100px"))
        
        #######################################################################

        # Primary layers
        self.layer1_widgets = ParentWidgets(label='1', tooltip="Layer1", enum_color=9, clr=6.1, 
                                            init_layer_val=[0], layer_options=self.layer_options, compute=self.compute_layers)
        self.layer2_widgets = ParentWidgets(label='2', tooltip="Layer2", enum_color=8, clr=5.5, 
                                            init_layer_val=[0], layer_options=self.layer_options, compute=self.compute_layers)
        self.layer3_widgets = ParentWidgets(label='3', tooltip="Layer3", enum_color=7, clr=5.1,
                                            init_layer_val=[0], layer_options=self.layer_options, compute=self.compute_layers)
        self.layer4_widgets = ParentWidgets(label='4', tooltip="Layer4", enum_color=6, clr=4.4, 
                                            init_layer_val=[0], layer_options=self.layer_options, compute=self.compute_layers)
        self.layer5_widgets = ParentWidgets(label='5', tooltip="Layer5", enum_color=5, clr=3.5, 
                                            init_layer_val=[0], layer_options=self.layer_options, compute=self.compute_layers)
        self.layer6_widgets = ParentWidgets(label='6', tooltip="Layer6", enum_color=4, clr=3.1, 
                                            init_layer_val=[0], layer_options=self.layer_options, compute=self.compute_layers)
        self.layer7_widgets = ParentWidgets(label='7', tooltip="Layer7", enum_color=3, clr=2.4, 
                                            init_layer_val=[0], layer_options=self.layer_options, compute=self.compute_layers)
        self.layer8_widgets = ParentWidgets(label='8', tooltip="Layer8", enum_color=2, clr=1.4, 
                                            init_layer_val=[0], layer_options=self.layer_options, compute=self.compute_layers)
    
        self.layers = [self.layer1_widgets, self.layer2_widgets, self.layer3_widgets, self.layer4_widgets,
                       self.layer5_widgets, self.layer6_widgets, self.layer7_widgets, self.layer8_widgets]

        
        # Wrap parent widgets in a layout with a color picker
        layer1 = ParentBox(self.layer1_widgets)
        layer2 = ParentBox(self.layer2_widgets)
        layer3 = ParentBox(self.layer3_widgets)
        layer4 = ParentBox(self.layer4_widgets)
        layer5 = ParentBox(self.layer5_widgets)
        layer6 = ParentBox(self.layer6_widgets)
        layer7 = ParentBox(self.layer7_widgets)
        layer8 = ParentBox(self.layer8_widgets)



        grid_elements = [layer1, vdiv, layer2, 
                            Whdiv, hdiv, Whdiv,
                            layer3, vdiv, layer4,
                            Whdiv, hdiv, Whdiv,
                            layer5, vdiv, layer6,
                            Whdiv, hdiv, Whdiv,
                            layer7, vdiv, layer8,
                            Whdiv, hdiv, Whdiv,
                        ]
        row_template = "50px 2px 50px 2px 50px 2px 50px 2px 50px 2px"
        column_template = "180px 2px 180px"


        # Add pseudo grid and wrap primary boxes in ipywidget
        gridbox = HBox([GridBox(grid_elements,
                                layout=Layout(grid_template_rows=row_template, grid_template_columns=column_template))], 
                                layout=Layout( padding="0 0 0 14px"))

        # cache_icon = v.Icon(children=['fa-database'], v_on='tooltip.on')
        # cache_icon_tp = v.Tooltip(bottom=True, v_slots=[{'name': 'activator', 'variable': 'tooltip', 'children': cache_icon}], children=["Cache"])

        # cache_clrpkr = clr_picker(3, cache=True)

        # reset_clrs = v.Btn(v_on='tooltip.on', icon=True, children=[v.Icon(children=['refresh'])])
        # reset_clrs.on_event('click', self.reset_colormap)
        # reset_clrs_tp = v.Tooltip(bottom=True, v_slots=[{'name': 'activator', 'variable': 'tooltip', 'children': reset_clrs}], children=["Reset all colors"])
        # cache_row = HBox([cache_icon_tp, cache_clrpkr, reset_clrs_tp],
        #                 layout=Layout(padding="0 20px 20px 20px", align_items="center", justify_content="space-between"))  ## , cache_row
        return VBox([dropdown_row, gridbox])

    # @debounced(0.2)
    def compute_layers(self, change):
        
        # reset the layer value of old selections
        # tags threads and accesses use seperate queries
        if type(change['old']) is SpaceTimeTag :
            addr_low = float(change['old'].address[0])
            addr_high = float(change['old'].address[1]) + 1
            indx_low = float(change['old'].access[0])
            indx_high = float(change['old'].access[1]) + 1

            # !See Explantion Below
            self.model.curr_trace.df.Temp1 = self.model.curr_trace.df.func.where(
                (addr_low <= self.model.curr_trace.df.Address), 1.0 , 2.0)

            self.model.curr_trace.df.Temp2 = self.model.curr_trace.df.func.where(
                (addr_high >= self.model.curr_trace.df.Address), 1.0 , 3.0)

            self.model.curr_trace.df.TempA = self.model.curr_trace.df.func.where(
                (self.model.curr_trace.df.Temp1 == self.model.curr_trace.df.Temp2), 1.0 , 6.0)

            self.model.curr_trace.df.Temp3 = self.model.curr_trace.df.func.where(
                ( indx_low <= self.model.curr_trace.df.index ), 1.0 , 4.0)
            self.model.curr_trace.df.Temp4 = self.model.curr_trace.df.func.where(
                ( indx_high >= self.model.curr_trace.df.index ), 1.0, 5.0)
            self.model.curr_trace.df.TempB = self.model.curr_trace.df.func.where(
                (self.model.curr_trace.df.Temp3 == self.model.curr_trace.df.Temp4), 1.0 , 7.0)
            
            self.model.curr_trace.df[LAYER] = self.model.curr_trace.df.func.where(
                (self.model.curr_trace.df.TempA == self.model.curr_trace.df.TempB), 
                0.4 , self.model.curr_trace.df.Layer)
           

        elif type(change['old']) is ThreadTag:
            t_id = change['old'].thread_id
            self.model.curr_trace.df[LAYER] = self.model.curr_trace.df.func.where(self.model.curr_trace.df.ThreadID == t_id, 1, self.model.curr_trace.df.Layer)
        else:
            for atype in change['old']:
                self.model.curr_trace.df[LAYER] = self.model.curr_trace.df.func.where(self.model.curr_trace.df.Access == atype, 1 , self.model.curr_trace.df.Layer)
        

        for layer in reversed(self.layers):
            # check if the layer checkbox is enabled first
            if layer.check.v_model == True:
                # do not update none layers and layer.dropdown_widget.value == change['new'] 
                if layer.dropdown_widget.value != [0] :
                    # tags threads and accesses use seperate queries
                    if type(layer.dropdown_widget.value) is SpaceTimeTag :
                        addr_low = float(layer.dropdown_widget.value.address[0])
                        addr_high = float(layer.dropdown_widget.value.address[1]) + 1
                        indx_low = float(layer.dropdown_widget.value.access[0])
                        indx_high = float(layer.dropdown_widget.value.access[1]) + 1

                        # df.func.where has a bug where it can only evaluate single boolean value expressions
                        #   EX. self.model.curr_trace.df.Address >= addr_low and self.model.curr_trace.df.Address <= addr_high
                        #   results in only the first comparison being evaluated.
                        # Thus we must seperate the upper and lower bound calculations, this is not efficient but has minimal
                        # impact on perfomance.
                       
                        # create temp layer to find which accesses belong to tag.
                        self.model.curr_trace.df.Temp1 = self.model.curr_trace.df.func.where(
                            (addr_low <= self.model.curr_trace.df.Address), 1.0 , 2.0)

                        self.model.curr_trace.df.Temp2 = self.model.curr_trace.df.func.where(
                            (addr_high >= self.model.curr_trace.df.Address), 1.0 , 3.0)

                        self.model.curr_trace.df.TempA = self.model.curr_trace.df.func.where(
                            (self.model.curr_trace.df.Temp1 == self.model.curr_trace.df.Temp2), 1.0 , 6.0)

                        self.model.curr_trace.df.Temp3 = self.model.curr_trace.df.func.where(
                            ( indx_low <= self.model.curr_trace.df.index ), 1.0 , 4.0)
                        self.model.curr_trace.df.Temp4 = self.model.curr_trace.df.func.where(
                            ( indx_high >= self.model.curr_trace.df.index ), 1.0, 5.0)
                        self.model.curr_trace.df.TempB = self.model.curr_trace.df.func.where(
                            (self.model.curr_trace.df.Temp3 == self.model.curr_trace.df.Temp4), 1.0 , 7.0)
                        
                        self.model.curr_trace.df[LAYER] = self.model.curr_trace.df.func.where(
                            self.model.curr_trace.df.TempA == self.model.curr_trace.df.TempB, 
                            layer.clr , self.model.curr_trace.df.Layer)

                    elif type(layer.dropdown_widget.value) is ThreadTag:
                        t_id = layer.dropdown_widget.value.thread_id
                        self.model.curr_trace.df[LAYER] = self.model.curr_trace.df.func.where(
                            self.model.curr_trace.df.ThreadID == t_id, layer.clr , self.model.curr_trace.df.Layer)
                    else:
                        for atype in layer.dropdown_widget.value:
                            self.model.curr_trace.df[LAYER] = self.model.curr_trace.df.func.where(
                                self.model.curr_trace.df.Access == atype, layer.clr , self.model.curr_trace.df.Layer)
                    
            else:
                for atype in layer.dropdown_widget.value:
                    self.model.curr_trace.df[LAYER] = self.model.curr_trace.df.func.where(
                        self.model.curr_trace.df.Access == atype, 1, self.model.curr_trace.df.Layer)

        self.model.plot.colormap = ListedColormap(self.colormap)
        self.model.plot.backend.plot.update_grid()

    def update_presets(self, change):
        new_preset = change.new
        if new_preset == 'None':
            for layer in self.layers:
                layer.update_selection([0])
        elif new_preset == 'AccessType':
            self.layers[0].update_selection([COMP_W_MISS])
            self.layers[1].update_selection([WRITE_MISS])
            self.layers[2].update_selection([COMP_R_MISS])
            self.layers[3].update_selection([COMP_R_MISS])
            self.layers[4].update_selection([WRITE_HIT])
            self.layers[5].update_selection([READ_HIT])
     
        elif new_preset == 'TAG':
            layer_index = 0
            for layer_option in reversed(self.layer_options):
                if type(layer_option[1]) is SpaceTimeTag and layer_index < len(self.layers):
                    if layer_option[0] != 'Stack' and layer_option[0] != 'Heap':
                        self.layers[layer_index].update_selection(layer_option[1])
                        layer_index += 1
        elif new_preset == 'THREAD':
            layer_index = 0
            for layer_option in reversed(self.layer_options):
                if type(layer_option[1]) is ThreadTag and layer_index < len(self.layers):
                    self.layers[layer_index].update_selection(layer_option[1])
                    layer_index += 1
        elif new_preset == 'Custom':
            if self.custom_layer_preset is not None:
                for (index, layer_option) in enumerate(self.custom_layer_preset):
                    for option in self.layer_options:
                        if option[0] == layer_option:
                            self.layers[index].update_selection(option[1])

    def set_custom_presets(self, layer_preset):
        self.custom_layer_preset = layer_preset
        self.dropdown.value = 'Custom'


    def reset_colormap(self, *_):
        self.colormap = np.copy(newc)
        for clr, clr_picker in self.colorpickers.items():
            if clr < TOP_READ:
                clr_picker.observing = False
                clr_picker.value = to_hex(self.colormap[enum_color][0:3])
                clr_picker.observing = True
        self.model.plot.colormap = ListedColormap(self.colormap)
        self.model.plot.backend.plot._update_image()
Esempio n. 37
0
    def _init_gui(self, **kwargs):
        """Initialize generic GUI controls and observe callbacks."""
        mainopts = super(TensorContainer, self)._init_gui(**kwargs)
        scn = self.scenes[0]
        alo = Layout(width='74px')
        rlo = Layout(width='235px')
        if self._df is not None:
            scn.txx = self._df.loc[0,'xx']
            scn.txy = self._df.loc[0,'xy']
            scn.txz = self._df.loc[0,'xz']
            scn.tyx = self._df.loc[0,'yx']
            scn.tyy = self._df.loc[0,'yy']
            scn.tyz = self._df.loc[0,'yz']
            scn.tzx = self._df.loc[0,'zx']
            scn.tzy = self._df.loc[0,'zy']
            scn.tzz = self._df.loc[0,'zz']
        xs = [FloatText(value=scn.txx , layout=alo),
              FloatText(value=scn.txy , layout=alo),
              FloatText(value=scn.txz , layout=alo)]
        ys = [FloatText(value=scn.tyx , layout=alo),
              FloatText(value=scn.tyy , layout=alo),
              FloatText(value=scn.tyz , layout=alo)]
        zs = [FloatText(value=scn.tzx , layout=alo),
              FloatText(value=scn.tzy , layout=alo),
              FloatText(value=scn.tzz , layout=alo)]
        #scale =  FloatSlider(max=10.0, step=0.01, readout=True, value=1.0)
        opt = [0] if self._df is None else [int(x) for x in self._df.index.values]
        tensorIndex = Dropdown(options=opt, value=opt[0], layout=rlo)
        tdxlabel = Label(value='Select the tensor index:')
        def _x0(c):
            for scn in self.active(): scn.txx = c.new
        def _x1(c):
            for scn in self.active(): scn.txy = c.new
        def _x2(c):
            for scn in self.active(): scn.txz = c.new
        def _y0(c):
            for scn in self.active(): scn.tyx = c.new
        def _y1(c):
            for scn in self.active(): scn.tyy = c.new
        def _y2(c):
            for scn in self.active(): scn.tyz = c.new
        def _z0(c):
            for scn in self.active(): scn.tzx = c.new
        def _z1(c):
            for scn in self.active(): scn.tzy = c.new
        def _z2(c):
            for scn in self.active(): scn.tzz = c.new
        xs[0].observe(_x0, names='value')
        xs[1].observe(_x1, names='value')
        xs[2].observe(_x2, names='value')
        ys[0].observe(_y0, names='value')
        ys[1].observe(_y1, names='value')
        ys[2].observe(_y2, names='value')
        zs[0].observe(_z0, names='value')
        zs[1].observe(_z1, names='value')
        zs[2].observe(_z2, names='value')
        rlo = Layout(width='234px')
        xbox = HBox(xs, layout=rlo)
        ybox = HBox(ys, layout=rlo)
        zbox = HBox(zs, layout=rlo)
        geom = Button(icon='cubes', description=' Geometry', layout=_wlo)

        def _change_tensor(tdx=0):
            carts = ['x','y','z']
            for i, bra in enumerate(carts):
                for j, ket in enumerate(carts):
                    if i == 0:
                        xs[j].value = self._df.loc[tdx,bra+ket]
                    elif i == 1:
                        ys[j].value = self._df.loc[tdx,bra+ket]
                    elif i == 2:
                        zs[j].value = self._df.loc[tdx,bra+ket]

        def _geom(b):
            for scn in self.active(): scn.geom = not scn.geom

        def _tdx(c):
            for scn in self.active(): scn.tdx = c.new
            _change_tensor(c.new)

        geom.on_click(_geom)
        tensorIndex.observe(_tdx, names="value")
        mainopts.update([('geom', geom),
                         ('tlbl', tdxlabel),
                         ('tidx', tensorIndex),
                         ('xbox', xbox),
                         ('ybox', ybox),
                         ('zbox', zbox)])
        return mainopts
Esempio n. 38
0
class MyRenderer(JupyterRenderer):
    """
    An inherited class of the PythonOCC JupyterRenderer with only slight modifications

    :param size:
    :param compute_normals_mode:
    :param default_shape_color:
    :param default_edge_color:
    :param default_vertex_color:
    :param pick_color:
    :param background_color:
    """
    def __init__(
        self,
        size=(640, 480),
        compute_normals_mode=NORMAL.SERVER_SIDE,
        default_shape_color=format_color(166, 166, 166),  # light grey
        default_edge_color=format_color(32, 32, 32),  # dark grey
        default_vertex_color=format_color(8, 8, 8),  # darker grey
        pick_color=format_color(232, 176, 36),  # orange
        background_color="white",
    ):
        super().__init__(
            size,
            compute_normals_mode,
            default_shape_color,
            default_edge_color,
            default_vertex_color,
            pick_color,
            background_color,
        )
        from ipywidgets import Dropdown

        self._toggle_geom_visibility_button = self.create_button(
            "Geom", "Toggle Geom Visibility", False,
            self.toggle_all_geom_visibility)
        self._toggle_mesh_visibility_button = self.create_button(
            "Mesh", "Toggle Mesh Visibility", False,
            self.toggle_mesh_visibility)

        self._controls.pop(0)
        self._controls.pop(0)

        fem_sets = ["None"]
        self._fem_sets_opts = Dropdown(options=fem_sets,
                                       value=fem_sets[0],
                                       tooltip="Select a set",
                                       disabled=False)
        self._fem_sets_opts.observe(self._on_changed_fem_set, "value")

        self._controls.insert(0, self._toggle_geom_visibility_button)
        self._controls.insert(1, self._toggle_mesh_visibility_button)
        self._controls.pop(-1)
        self._controls.pop(-1)
        self._controls.append(self._fem_sets_opts)
        # self._controls.append(p1)
        # self._controls.append(p2)
        self._refs = dict()
        self._fem_refs = dict()

    def visible_check(self, obj, obj_type="geom"):
        from ada import Beam, Part, Plate

        if obj.name not in self._refs.keys():
            raise ValueError(f'object "{obj.name}" not found')
        adaobj = self._refs[obj.name]

        if obj_type == "geom" and type(adaobj) in (Beam, Plate):
            obj.visible = not obj.visible

        if obj_type == "mesh" and issubclass(type(adaobj), Part) is True:
            obj.visible = not obj.visible

    def toggle_all_geom_visibility(self, *kargs):
        for c in self._displayed_non_pickable_objects.children:
            self.visible_check(c)

        for c in self._displayed_pickable_objects.children:
            self.visible_check(c)

    def toggle_mesh_visibility(self, *kargs):
        for c in self._displayed_non_pickable_objects.children:
            self.visible_check(c, "mesh")

        for c in self._displayed_pickable_objects.children:
            self.visible_check(c, "mesh")

    def DisplayMesh(self,
                    part,
                    edge_color=None,
                    vertex_color=None,
                    vertex_width=2):
        """

        :param part:
        :param edge_color:
        :param vertex_color:
        :param vertex_width:
        :type part: ada.Part
        """

        from OCC.Core.BRep import BRep_Builder
        from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakeVertex
        from OCC.Core.gp import gp_Pnt
        from OCC.Core.TopoDS import TopoDS_Compound

        # edge_color = format_color(*part.colour) if edge_color is None else edge_color
        rgb = randint(0, 255), randint(0, 255), randint(0, 255)
        edge_color = format_color(*rgb) if edge_color is None else edge_color
        vertex_color = self._default_vertex_color if vertex_color is None else vertex_color

        pmesh_id = "%s" % uuid.uuid4().hex

        BB = BRep_Builder()
        compound = TopoDS_Compound()
        BB.MakeCompound(compound)
        vertices_list = []

        def togp(n_):
            return gp_Pnt(float(n_[0]), float(n_[1]), float(n_[2]))

        for vertex in map(togp, part.fem.nodes):
            vertex_to_add = BRepBuilderAPI_MakeVertex(vertex).Shape()
            BB.Add(compound, vertex_to_add)
            vertices_list.append([vertex.X(), vertex.Y(), vertex.Z()])

        attributes = {
            "position": BufferAttribute(vertices_list, normalized=False)
        }
        mat = PointsMaterial(color=vertex_color,
                             sizeAttenuation=False,
                             size=vertex_width)
        geom = BufferGeometry(attributes=attributes)
        points_geom = Points(geometry=geom, material=mat, name=pmesh_id)
        lmesh_id = "%s" % uuid.uuid4().hex
        edges_nodes = list(
            chain.from_iterable(
                filter(None,
                       [grab_nodes(el, part.fem)
                        for el in part.fem.elements])))
        np_edge_vertices = np.array(edges_nodes, dtype=np.float32)
        np_edge_indices = np.arange(np_edge_vertices.shape[0], dtype=np.uint32)
        vertex_col = tuple([x / 255 for x in rgb])
        edge_geometry = BufferGeometry(
            attributes={
                "position": BufferAttribute(np_edge_vertices),
                "index": BufferAttribute(np_edge_indices),
                "color": BufferAttribute(
                    [vertex_col for n in np_edge_vertices]),
            })
        edge_material = LineBasicMaterial(vertexColors="VertexColors",
                                          linewidth=5)

        edge_geom = LineSegments(
            geometry=edge_geometry,
            material=edge_material,
            type="LinePieces",
            name=lmesh_id,
        )
        output = [points_geom, edge_geom]

        for elem in output:
            self._shapes[elem.name] = compound
            self._refs[elem.name] = part
            self._displayed_pickable_objects.add(elem)

        self._fem_sets_opts.options = ["None"] + [
            f"{part.fem.name}.{s.name}" for s in filter(
                lambda x: "internal" not in x.metadata.keys(), part.fem.sets)
        ]
        self._fem_refs[part.fem.name] = (part.fem, edge_geometry)

    def DisplayAdaShape(self, shp):
        """

        :param shp:
        :type shp: ada.Shape
        :return:
        """
        res = self.DisplayShape(
            shp.geom,
            transparency=shp.transparent,
            opacity=shp.opacity,
            shape_color=shp.colour,
            render_edges=False,
        )
        for r in res:
            self._refs[r.name] = shp

    def DisplayBeam(self, beam):
        """

        :param beam:
        :type beam: ada.Beam
        """

        try:
            if "ifc_file" in beam.metadata.keys():
                from ada.core.ifc_utils import get_representation

                a = beam.parent.get_assembly()
                ifc_f = a.get_ifc_source_by_name(beam.metadata["ifc_file"])
                ifc_elem = ifc_f.by_guid(beam.guid)
                geom, color, alpha = get_representation(
                    ifc_elem, a.ifc_settings)
            else:
                geom = beam.solid
            res = self.DisplayShape(geom,
                                    shape_color=beam.colour,
                                    render_edges=True)
        except BaseException as e:
            logging.debug(
                f'Unable to create solid for "{beam.name}" due to {e}')
            return None

        for r in res:
            self._refs[r.name] = beam

    def DisplayPlate(self, plate):
        """

        :param plate:
        :type plate: ada.Plate
        """

        geom = self._ifc_geom_to_shape(
            plate._ifc_geom) if plate._ifc_geom is not None else plate.solid
        # self.AddShapeToScene(geom)
        try:
            res = self.DisplayShape(geom,
                                    shape_color=plate.colour_webgl,
                                    opacity=0.5)
        except BaseException as e:
            logging.error(e)
            return None

        for r in res:
            self._refs[r.name] = plate

    def DisplayPipe(self, pipe):
        """

        :param pipe:
        :type pipe: ada.Pipe
        """
        # self.AddShapeToScene(geom)
        res = []

        for i, geom in enumerate(pipe.geometries):
            try:
                res += self.DisplayShape(geom,
                                         shape_color=pipe.colour_webgl,
                                         opacity=0.5)
            except BaseException as e:
                logging.error(e)
                continue

        for r in res:
            self._refs[r.name] = pipe

    def DisplayWall(self, wall):
        """

        :param wall:
        :type wall: ada.Wall
        """
        try:
            res = self.DisplayShape(wall.solid,
                                    shape_color=wall.colour,
                                    opacity=0.5)
        except BaseException as e:
            logging.error(e)
            return None

        for r in res:
            self._refs[r.name] = wall

    def DisplayAdaPart(self, part):
        """

        :return:
        :type part: ada.Part
        """
        all_shapes = [
            shp for p in part.get_all_subparts() for shp in p.shapes
        ] + part.shapes
        all_beams = [bm for p in part.get_all_subparts()
                     for bm in p.beams] + [bm for bm in part.beams]
        all_plates = [pl for p in part.get_all_subparts()
                      for pl in p.plates] + [pl for pl in part.plates]
        all_pipes = [
            pipe for p in part.get_all_subparts() for pipe in p.pipes
        ] + [pipe for pipe in part.pipes]
        all_walls = [
            wall for p in part.get_all_subparts() for wall in p.walls
        ] + [wall for wall in part.walls]

        for wall in all_walls:
            for insert in wall._inserts:
                all_shapes.append(insert.shapes[0])

        list(map(self.DisplayAdaShape, all_shapes))
        list(filter(None, map(self.DisplayBeam, all_beams)))
        list(filter(None, map(self.DisplayPlate, all_plates)))
        list(filter(None, map(self.DisplayPipe, all_pipes)))
        list(filter(None, map(self.DisplayWall, all_walls)))
        list(
            map(
                self.DisplayMesh,
                filter(
                    lambda x: len(x.fem.elements) != 0,
                    part.get_all_parts_in_assembly(include_self=True),
                ),
            ))

    def DisplayObj(self, obj):
        from ada import Beam, Part, Pipe, Plate, Shape

        if issubclass(type(obj), Part) is True:
            self.DisplayAdaPart(obj)
        elif type(obj) is Beam:
            self.DisplayBeam(obj)
        elif type(obj) is Plate:
            self.DisplayPlate(obj)
        elif type(obj) is Pipe:
            self.DisplayPipe(obj)
        elif issubclass(type(obj), Shape):
            self.DisplayAdaShape(obj)
        else:
            raise ValueError(f'type "{type(obj)}" Not Recognized')

    def _ifc_geom_to_shape(self, ifc_geom):
        from OCC.Core import BRepTools
        from OCC.Core.TopoDS import TopoDS_Compound

        if type(ifc_geom) is TopoDS_Compound:
            geom = ifc_geom
        elif type(ifc_geom.solid) is not TopoDS_Compound:
            brep_data = ifc_geom.solid.brep_data
            ss = BRepTools.BRepTools_ShapeSet()
            ss.ReadFromString(brep_data)
            nb_shapes = ss.NbShapes()
            geom = ss.Shape(nb_shapes)
        else:
            geom = ifc_geom.solid
        return geom

    # Override and modify parent methods
    def DisplayShape(
        self,
        shp,
        shape_color=None,
        render_edges=False,
        edge_color=None,
        edge_deflection=0.05,
        vertex_color=None,
        quality=1.0,
        transparency=False,
        opacity=1.0,
        topo_level="default",
        update=False,
        selectable=True,
    ):
        """
        Displays a topods_shape in the renderer instance.

        :param shp: the TopoDS_Shape to render
        :param shape_color: the shape color, in html corm, eg '#abe000'
        :param render_edges: optional, False by default. If True, compute and dislay all
                      edges as a linear interpolation of segments.

        :param edge_color: optional, black by default. The color used for edge rendering,
                    in html form eg '#ff00ee'

        :param edge_deflection: optional, 0.05 by default
        :param vertex_color: optional
        :param quality: optional, 1.0 by default. If set to something lower than 1.0,
                      mesh will be more precise. If set to something higher than 1.0,
                      mesh will be less precise, i.e. lower numer of triangles.

        :param transparency: optional, False by default (opaque).
        :param opacity: optional, float, by default to 1 (opaque). if transparency is set to True,
                 0. is fully opaque, 1. is fully transparent.

        :param topo_level: "default" by default. The value should be either "compound", "shape", "vertex".
        :param update: optional, False by default. If True, render all the shapes.
        :param selectable: if True, can be doubleclicked from the 3d window
        """
        if edge_color is None:
            edge_color = self._default_edge_color
        if shape_color is None:
            shape_color = self._default_shape_color
        if vertex_color is None:
            vertex_color = self._default_vertex_color

        output = []  # a list of all geometries created from the shape
        # is it list of gp_Pnt ?
        from OCC.Core.gp import gp_Pnt
        from OCC.Extend.TopologyUtils import is_edge, is_wire

        if isinstance(shp, list) and isinstance(shp[0], gp_Pnt):
            result = self.AddVerticesToScene(shp, vertex_color)
            output.append(result)
        # or a 1d element such as edge or wire ?
        elif is_wire(shp) or is_edge(shp):
            result = self.AddCurveToScene(shp, edge_color, edge_deflection)
            output.append(result)
        elif topo_level != "default":
            from OCC.Extend.TopologyUtils import TopologyExplorer

            t = TopologyExplorer(shp)
            map_type_and_methods = {
                "Solid": t.solids,
                "Face": t.faces,
                "Shell": t.shells,
                "Compound": t.compounds,
                "Compsolid": t.comp_solids,
            }
            for subshape in map_type_and_methods[topo_level]():
                result = self.AddShapeToScene(
                    subshape,
                    shape_color,
                    render_edges,
                    edge_color,
                    vertex_color,
                    quality,
                    transparency,
                    opacity,
                )
                output.append(result)
        else:
            result = self.AddShapeToScene(
                shp,
                shape_color,
                render_edges,
                edge_color,
                vertex_color,
                quality,
                transparency,
                opacity,
            )
            output.append(result)

        if selectable:  # Add geometries to pickable or non pickable objects
            for elem in output:
                self._displayed_pickable_objects.add(elem)

        if update:
            self.Display()

        return output

    def AddShapeToScene(
        self,
        shp,
        shape_color=None,  # the default
        render_edges=False,
        edge_color=None,
        vertex_color=None,
        quality=1.0,
        transparency=False,
        opacity=1.0,
    ):
        # first, compute the tesselation
        tess = ShapeTesselator(shp)
        tess.Compute(compute_edges=render_edges,
                     mesh_quality=quality,
                     parallel=True)
        # get vertices and normals
        vertices_position = tess.GetVerticesPositionAsTuple()

        number_of_triangles = tess.ObjGetTriangleCount()
        number_of_vertices = len(vertices_position)

        # number of vertices should be a multiple of 3
        if number_of_vertices % 3 != 0:
            raise AssertionError("Wrong number of vertices")
        if number_of_triangles * 9 != number_of_vertices:
            raise AssertionError("Wrong number of triangles")

        # then we build the vertex and faces collections as numpy ndarrays
        np_vertices = np.array(vertices_position, dtype="float32").reshape(
            int(number_of_vertices / 3), 3)
        # Note: np_faces is just [0, 1, 2, 3, 4, 5, ...], thus arange is used
        np_faces = np.arange(np_vertices.shape[0], dtype="uint32")

        # set geometry properties
        buffer_geometry_properties = {
            "position": BufferAttribute(np_vertices),
            "index": BufferAttribute(np_faces),
        }
        if self._compute_normals_mode == NORMAL.SERVER_SIDE:
            # get the normal list, converts to a numpy ndarray. This should not raise
            # any issue, since normals have been computed by the server, and are available
            # as a list of floats
            np_normals = np.array(tess.GetNormalsAsTuple(),
                                  dtype="float32").reshape(-1, 3)
            # quick check
            if np_normals.shape != np_vertices.shape:
                raise AssertionError("Wrong number of normals/shapes")
            buffer_geometry_properties["normal"] = BufferAttribute(np_normals)

        # build a BufferGeometry instance
        shape_geometry = BufferGeometry(attributes=buffer_geometry_properties)

        # if the client has to render normals, add the related js instructions
        if self._compute_normals_mode == NORMAL.CLIENT_SIDE:
            shape_geometry.exec_three_obj_method("computeVertexNormals")

        # then a default material
        shp_material = self._material(shape_color,
                                      transparent=transparency,
                                      opacity=opacity)

        # and to the dict of shapes, to have a mapping between meshes and shapes
        mesh_id = "%s" % uuid.uuid4().hex
        self._shapes[mesh_id] = shp

        # finally create the mesh
        shape_mesh = Mesh(geometry=shape_geometry,
                          material=shp_material,
                          name=mesh_id)

        # edge rendering, if set to True
        if render_edges:
            edges = list(
                map(
                    lambda i_edge: [
                        tess.GetEdgeVertex(i_edge, i_vert)
                        for i_vert in range(tess.ObjEdgeGetVertexCount(i_edge))
                    ],
                    range(tess.ObjGetEdgeCount()),
                ))
            edge_list = _flatten(list(map(_explode, edges)))
            lines = LineSegmentsGeometry(positions=edge_list)
            mat = LineMaterial(linewidth=1, color=edge_color)
            edge_lines = LineSegments2(lines, mat, name=mesh_id)
            self._displayed_non_pickable_objects.add(edge_lines)

        return shape_mesh

    def build_display(self,
                      position=None,
                      rotation=None,
                      camera_type="orthographic"):
        """

        :param position: Camera Position
        :param rotation: Camera Rotation
        :param camera_type: Camera Type "orthographic" or "perspective"
        """
        import itertools
        import math

        from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeSphere
        from OCC.Display.WebGl.jupyter_renderer import Axes, Grid, _add
        from pythreejs import (
            AmbientLight,
            CombinedCamera,
            DirectionalLight,
            OrbitControls,
            Picker,
            Renderer,
            Scene,
        )

        # Get the overall bounding box
        if self._shapes:
            self._bb = BoundingBox([self._shapes.values()])
        else:  # if nothing registered yet, create a fake bb
            self._bb = BoundingBox([[BRepPrimAPI_MakeSphere(5.0).Shape()]])
        bb_max = self._bb.max
        orbit_radius = 1.5 * self._bb._max_dist_from_center()

        # Set up camera
        camera_target = self._bb.center
        camera_position = _add(
            self._bb.center,
            self._scale(
                [1, 1, 1] if position is None else self._scale(position)))
        camera_zoom = self._camera_initial_zoom

        self._camera = CombinedCamera(position=camera_position,
                                      width=self._size[0],
                                      height=self._size[1])
        self._camera.up = (0.0, 0.0, 1.0)
        self._camera.mode = camera_type
        self._camera_target = camera_target
        self._camera.position = camera_position

        if rotation is not None:
            self._camera.rotation = rotation
        # Set up lights in every of the 8 corners of the global bounding box
        positions = list(
            itertools.product(*[(-orbit_radius, orbit_radius)] * 3))
        key_lights = [
            DirectionalLight(color="white", position=pos, intensity=0.5)
            for pos in positions
        ]
        ambient_light = AmbientLight(intensity=0.1)

        # Set up Helpers
        self.axes = Axes(bb_center=self._bb.center, length=bb_max * 1.1)
        self.horizontal_grid = Grid(bb_center=self._bb.center,
                                    maximum=bb_max,
                                    colorCenterLine="#aaa",
                                    colorGrid="#ddd")
        self.vertical_grid = Grid(bb_center=self._bb.center,
                                  maximum=bb_max,
                                  colorCenterLine="#aaa",
                                  colorGrid="#ddd")

        # Set up scene
        temp_elems = [
            ambient_light, self.horizontal_grid.grid, self.vertical_grid.grid,
            self._camera
        ]
        environment = self.axes.axes + key_lights + temp_elems

        scene_shp = Scene(children=[
            self._displayed_pickable_objects,
            self._displayed_non_pickable_objects
        ] + environment)

        # Set up Controllers
        self._controller = OrbitControls(controlling=self._camera,
                                         target=camera_target,
                                         target0=camera_target)
        # Update controller to instantiate camera position
        self._camera.zoom = camera_zoom
        self._update()

        # setup Picker
        self._picker = Picker(controlling=self._displayed_pickable_objects,
                              event="dblclick")
        self._picker.observe(self.click)

        self._renderer = Renderer(
            camera=self._camera,
            background=self._background,
            background_opacity=self._background_opacity,
            scene=scene_shp,
            controls=[self._controller, self._picker],
            width=self._size[0],
            height=self._size[1],
            antialias=True,
        )

        # set rotation and position for each grid
        self.horizontal_grid.set_position((0, 0, 0))
        self.horizontal_grid.set_rotation((math.pi / 2.0, 0, 0, "XYZ"))

        self.vertical_grid.set_position((0, -bb_max, 0))

        self._savestate = (self._camera.rotation, self._controller.target)

    def click(self, value):
        """called whenever a shape  or edge is clicked"""
        obj = value.owner.object
        self.clicked_obj = obj
        if self._current_mesh_selection != obj:
            if self._current_mesh_selection is not None:
                self._current_mesh_selection.material.color = self._current_selection_material_color
                self._current_mesh_selection.material.transparent = False
                self._current_mesh_selection = None
                self._current_selection_material_color = None
                self._shp_properties_button.value = "Compute"
                self._shp_properties_button.disabled = True
                self._toggle_shp_visibility_button.disabled = True
                self._remove_shp_button.disabled = True
                self._current_shape_selection = None
            if obj is not None:
                self._shp_properties_button.disabled = False
                self._toggle_shp_visibility_button.disabled = False
                self._remove_shp_button.disabled = False
                id_clicked = obj.name  # the mesh id clicked
                self._current_mesh_selection = obj
                self._current_selection_material_color = obj.material.color
                obj.material.color = self._selection_color
                # selected part becomes transparent
                obj.material.transparent = True
                obj.material.opacity = 0.5
                # get the shape from this mesh id
                selected_shape = self._shapes[id_clicked]
                try:
                    html_value = self._click_ada_to_html(obj)
                except BaseException as e:
                    html_value = f'An error occured: "{str(e)}"'
                self.html.value = f'<div style="margin: 0 auto; width:300px;">{html_value}</div>'
                self._current_shape_selection = selected_shape
            else:
                self.html.value = "<b>Shape type:</b> None<br><b>Shape id:</b> None"

            # then execute calbacks
            for callback in self._select_callbacks:
                callback(self._current_shape_selection)

    def _click_ada_to_html(self, obj):
        """

        :param obj:
        :return:
        """
        from ada import Beam, Part, Pipe, Plate, Shape, Wall
        from ada.fem.utils import get_eldata

        def write_metadata_to_html(met_d):
            table_str = ""
            for subkey, val in met_d.items():
                if type(val) is dict:
                    table_str += f"<tr></tr><td><b>{subkey}:</b></td></tr></tr>"
                    table_str += write_metadata_to_html(val)
                else:
                    table_str += f"<tr><td>{subkey}</td><td>{val}</td></tr>"
            return table_str

        part_name = self._refs[
            obj.name].name if obj.name in self._refs.keys() else obj.name
        selected_part = self._refs[
            obj.name] if obj.name in self._refs.keys() else None
        html_value = "<b>Name:</b> {part_name}".format(part_name=part_name)
        if issubclass(type(selected_part), Part):
            assert isinstance(selected_part, Part)
            html_value += ", <b>Type:</b> FEM Mesh<br><br>"
            html_value += "<b>Mesh Info</b> <br>"
            fem_data = get_eldata(selected_part.fem)
            html_value += "{fem_data}<br>".format(fem_data=", ".join(
                [f"(<b>{x}</b>: {y})" for x, y in fem_data.items()]))
            vol_cog_str = ", ".join(
                [f"{x:.3f}" for x in selected_part.fem.nodes.vol_cog])
            cog = selected_part.fem.elements.calc_cog()
            cog_str = ", ".join([f"{x:.3f}" for x in cog.p])
            html_value += f"<b>Vol:</b> {cog.tot_vol:.3f} <b>COG:</b> ({vol_cog_str}) <br>"
            html_value += f"<b>Mass:</b> {cog.tot_mass:.1f}  <b>COG:</b> ({cog_str}) <br>"
            html_value += f"<b>Beam mass:</b> {cog.bm_mass:.1f}<br>"
            html_value += f"<b>Shell mass:</b> {cog.sh_mass:.1f}<br>"
            html_value += f"<b>Node mass:</b> {cog.no_mass:.1f}<br>"
            html_value += (
                "<br><br>Note! Mass calculations are calculated based on <br>beam offsets "
                "(which is not shown in the viewer yet).")
        elif type(selected_part) is Beam:
            assert isinstance(selected_part, Beam)
            html_value += ", <b>Type:</b> Beam<br>"
            bm = selected_part
            html_value += f"<b>Nodes:</b> <b>n1:</b> {bm.n1.p}, <b>n2:</b> {bm.n2.p}<br>"
            html_value += f"<b>Ori:</b> <b>xv:</b> {bm.xvec}, <b>yv:</b> {bm.yvec}, <b>up:</b> {bm.up}<br>"
            html_value += f"<b>Angle:</b> {bm._angle} degrees<br>"
            html_value += f"<b>Section:</b> {bm.section.name}, <b>type:</b> {bm.section.type}<br>"
            html_value += f"<b>Material:</b> {bm.material.name}<br>"
        elif type(selected_part) is Plate:
            html_value += ", <b>Type:</b> Plate<br>"
        elif type(selected_part) is Shape:
            assert isinstance(selected_part, Shape)
            html_value += ", <b>Type:</b> Shape<br>"
            table_str = f'<div style="height:{self._size[1]}px;overflow:auto;line-height:1.0">'
            table_str += '<font size="2px" face="Arial" >'
            table_str += '<table style="width:100%;border: 1px solid black;"><tr><th>Key</th><th>Value</th></tr>'
            table_str += write_metadata_to_html(selected_part.metadata)
            table_str += "</table></font></div>"
            html_value += table_str
        elif type(selected_part) is Pipe:
            html_value += ", <b>Type:</b> Pipe<br>"
        elif type(selected_part) is Wall:
            html_value += ", <b>Type:</b> Wall<br>"
        else:
            html_value += f'<b>Type:</b> Object type "{type(selected_part)}" not recognized by ADA<br>'

        return html_value

    def _on_changed_fem_set(self, p):
        indata = p["new"]
        tmp_data = indata.split(".")
        pref = tmp_data[0]
        setref = tmp_data[1]
        fem = self._fem_refs[pref][0]
        edge_geom = self._fem_refs[pref][1]
        edges_nodes = list(
            chain.from_iterable(
                filter(None,
                       [grab_nodes(el, fem, True) for el in fem.elements])))
        dark_grey = (0.66, 0.66, 0.66)
        color_array = np.array(
            [dark_grey for x in edge_geom.attributes["color"].array],
            dtype="float32")

        color = (1, 0, 0)
        if setref in fem.elsets.keys():
            fem_set = fem.elsets[setref]
            set_edges_nodes = list(
                chain.from_iterable(
                    filter(
                        None,
                        [grab_nodes(el, fem, True)
                         for el in fem_set.members])))

            res1 = [locate(edges_nodes, i) for i in set_edges_nodes]
            set_edges_indices = chain.from_iterable(res1)
            for i in set_edges_indices:
                color_array[i] = color
        elif setref in fem.nsets.keys():
            print(f'Set "{setref}" is a node set (which is not yet supported)')
        else:
            logging.error(
                f'Unrecognized set "{setref}". Not belonging to node or elements'
            )
        edge_geom.attributes["color"].array = color_array

    def highlight_elem(self, elem_id, fem_name):
        """

        :param elem_id: Can be int or list of ints
        :param fem_name:
        :return:
        """
        fem = self._fem_refs[fem_name][0]
        edge_geom = self._fem_refs[fem_name][1]
        if type(elem_id) is int:
            el = fem.elements.from_id(elem_id)
            elem_nodes = grab_nodes(el, fem, True)
        elif type(elem_id) in (tuple, list):
            elem_nodes = list(
                chain.from_iterable(
                    filter(None, [
                        grab_nodes(fem.elements.from_id(el), fem, True)
                        for el in elem_id
                    ])))
        else:
            raise ValueError(f'Unrecognized type "{type(elem_id)}"')

        edges_nodes = list(
            chain.from_iterable(
                filter(None,
                       [grab_nodes(el, fem, True) for el in fem.elements])))
        res1 = [locate(edges_nodes, i) for i in elem_nodes]
        set_edges_indices = chain.from_iterable(res1)
        dark_grey = (0.66, 0.66, 0.66)
        color_array = np.array(
            [dark_grey for x in edge_geom.attributes["color"].array],
            dtype="float32")
        color = (1, 0, 0)
        for i in set_edges_indices:
            color_array[i] = color
        edge_geom.attributes["color"].array = color_array