# Notebook from nicoelbert/deepflash2
Path: nbs/08_gui.ipynb

#default_exp gui
from nbdev.showdoc import show_doc_____no_output_____

# Graphical user interface

> Simple GUI with ipywidgets._____no_output_____

#hide
import shutil_____no_output_____#export
import os, sys, shutil, time, zipfile, urllib, subprocess
import numpy as np, pandas as pd
import logging, datetime
import traceback

import ipywidgets as w
from ipywidgets.embed import embed_minimal_html
import IPython.display as d
from IPython.utils.io import ask_yes_no
from IPython.core.getipython import get_ipython

from pathlib import Path
from fastcore.foundation import store_attr
from fastcore.basics import GetAttr
from fastai.data.transforms import get_files
import segmentation_models_pytorch as smp
import matplotlib.pyplot as plt

from deepflash2.utils import unzip, get_label_fn, download_sample_data
from deepflash2.learner import EnsembleLearner, Config, _optim_dict
from deepflash2.gt import GTEstimator
from deepflash2.models import ARCHITECTURES, ENCODERS, get_pretrained_options
from deepflash2.losses import LOSSES

try:
    from google import colab
    COLAB = True
    from google.colab import data_table
except ImportError:
    COLAB = False

GRID_COLS = 2
COLS_PRED_KEEP = ['file','ensemble','n_models','uncertainty_score']
COLS_PRED_KEEP_DS = COLS_PRED_KEEP+['dice_score']
COLS_PRED_KEEP_CP = COLS_PRED_KEEP+['mean_average_precision', 'average_precision_at_iou_50']
SAMPLE_DATA_URL = 'https://github.com/matjesg/deepflash2/releases/download/sample_data/'_____no_output_____

Logging_____no_output_____

#export
log_dir = Path.home()/'.deepflash2'/'logs'
log_dir.mkdir(exist_ok=True, parents=True)
today = datetime.date.today().strftime("%Y-%m-%d")
logging.basicConfig(filename=log_dir/f'{today}.log',
                    level=logging.DEBUG,
                    format='%(asctime)s %(levelname)s %(name)s %(message)s')
logger=logging.getLogger(__name__)

err_out= w.Output()
#oops_url = 'https://cdn-icons-png.flaticon.com/512/260/260190.png'
oops_url = 'https://cdn-icons-png.flaticon.com/512/1049/1049967.png'

def exception_handler(exception_type, exception, tb):
    first_error = traceback.format_exc(0).split('\n')[0].split(':')[1]
    err_html = f'''

        <p style="float: left;padding: 0px 10px 0px 0px;<">

Something went wrong! Watch the tutorials for help.
 Last error: {first_error}

    '''
    with err_out:
        display(w.HTML(err_html))
        display(w.HTML('
'))
    err_out.clear_output(True)
    logger.error(exception, exc_info=True)_____no_output_____

## Helper Functions_____no_output_____

#export
tooltip_css = """"""

def set_css_in_cell_output():
    d.display(d.HTML(tooltip_css))

try: get_ipython().events.register('pre_run_cell', set_css_in_cell_output)
except: pass_____no_output_____#export
def _html_wrap(name, tooltip='', url=None):
    'Wrapper function to create html with tooltip and link to URL'
    if not url:
        return f'
ⓘ {tooltip}
{name}'
    else:
        open_tab = 'rel="noopener noreferrer" target="_blank"'#open new tab
        return f"""
ⓘ {tooltip} More information.
{name}"""_____no_output_____#export
def _connect_to_drive(path=None):
    "Connect to Google Drive and return path"
    path = path or Path('.')
    if COLAB:
        subprocess.call(['rm', '-rf', '/content/sample_data/'])
        with colab.output.temporary():
            con = ask_yes_no("Connect to Google Drive? (yes/no)")
        if con:
            with colab.output.temporary(): colab.drive.mount('/content/gdrive/')
            #path = Path('/content/gdrive/My Drive')
    return path_____no_output_____#export
def _get_model_list(n):
    return ["ensemble"]+[f'model_{x}' for x in range(1, n+1)]_____no_output_____

## Widgets_____no_output_____### Base Widgets_____no_output_____

#export
class ZipUpload():
    "Widgets upload and extract zip files"
    def __init__(self, path=None, layout=None):
        self.path = path or Path('.')
        layout = layout or w.Layout(width='100%')
        self.widget = w.FileUpload(description='Upload .zip', accept='.zip',
                                   multiple=True,layout=layout)
        self.widget.observe(self.extract_content, 'value')

    def extract_content(self, c):
        zip_file = self.path/'upload.zip'
        for fname in self.widget.value:
            content = self.widget.value[fname]['content']
            with open(zip_file, 'wb') as f: f.write(content)
            unzip(self.path, zip_file)_____no_output_____t = ZipUpload()
t.widget_____no_output_____#export
class ItemsPerPage:
    "Dropdown to show n items per page"

    def __init__(self, path=None, plot_fn=None, items=dict(), srt=True, srt_by='name', srt_index=0, **kwargs):

        self.path = path or Path('.')
        self.plot_fn = plot_fn
        self.items = items
        self.kwargs = kwargs
        self.current_page = 0

        # Widgets and Layout
        self.drp = w.Dropdown(options=[1,5,10,20,50,100], layout=w.Layout(width='auto', min_width='1px'))
        drp_lbl = w.HTML(' Items per Page')
        self.srt = w.Dropdown(index=srt_index, options=['ascending', 'descending'], layout=w.Layout(width='auto', min_width='1px'))
        self.srt.layout.display = "none"
        up_right = w.HBox([self.srt, drp_lbl, self.drp])
        lyt = w.Layout(width='100px')
        self.nxt = w.Button(description='Next', layout=lyt)
        self.prv = w.Button(description='Previous', layout=lyt)
        self.lbl = w.Label()
        self.exp = w.Button(description='Export View', layout=lyt)
        up_left = w.HBox([self.prv, self.lbl, self.nxt, self.exp])
        up = w.HBox([up_left, up_right], layout=w.Layout(justify_content='space-between'))
        self.out = w.Output()
        self.widget = w.VBox([up, self.out])

        # Callbacks
        self.drp.observe(self.on_value_change, 'value')
        self.nxt.on_click(self.on_button_clicked)
        self.prv.on_click(self.on_button_clicked)
        self.exp.on_click(self.on_export_clicked)
        self.lbl.value = self.page_lbl
        self.on_srt_change({'new': self.srt.options[srt_index]})

        if srt:
            self.srt.layout.display = "block"
            self.srt.observe(self.on_srt_change, 'value')
            self.srt.description= f'Sort by {srt_by}'

    @property
    def page_lbl(self):
        return f'Page {self.current_page+1} of {self.max_pages}'

    @property
    def max_pages(self):
        return int(np.ceil(len(self.items)/self.drp.value))

    def on_srt_change(self, change):
        reverse = True if change['new']=='descending' else False
        self.items = dict(sorted(self.items.items(), key=lambda x: x[1], reverse=reverse))
        self.on_button_clicked('')

    def on_value_change(self, change):
        self.on_button_clicked('')

    def on_button_clicked(self, b):
        if isinstance(b, w.Button):
            if all([b.description=='Next', self.current_page<(self.max_pages-1)]):
                self.current_page +=1
            elif all([b.description=='Previous', self.current_page>0]):
                self.current_page -=1
            else: return
        slc = slice(self.current_page*self.drp.value,(self.current_page+1)*self.drp.value)
        self.lbl.value = self.page_lbl
        with self.out:
            self.out.clear_output()
            if self.plot_fn:
                self.plot_fn(files=list(self.items.keys())[slc], **self.kwargs)
                plt.show()

    def on_export_clicked(self, b):
        embed_minimal_html(self.path/'export.html', views=[self.out], title='Output export')
        with self.out: display(f'Saved current view to {self.path/"export.html"}')
        if COLAB: colab.files.download(self.path/'export.html')_____no_output_____t = ItemsPerPage(srt_index=1)
t.widget_____no_output_____#export
class BaseParamWidget:
    'Parameter Widget Base Class'

    def __init__(self, config=None):
        config = config or Config()
        self.set_config(config)

        for k,v in self.params.items():
            setattr(v, 'name', k)
            v.observe(self.on_change, 'value')

    def set_config(self, config):
        self.config = config
        for k,v in self.params.items():
            v.value = getattr(config, k)

    def on_change(self, change):
        setattr(self.config, change['owner'].name, change['new'])

    def on_reset_clicked(self, b):
        self.set_config(Config())

    def on_close_clicked(self, b):
        self.widget.layout.display = "none"   _____no_output_____#export
class BaseUI:
    'Base UI for different steps'
    #_defaults = 'config'
    def __init__(self, config=None, path=None):
        self.config = config or Config()
        self.path = path or Path('.')

    def hide(self):
        self.main_box.layout.display = "none"
        self.sb_acc.layout.display = "none"

    def show(self):
        self.main_box.layout.display = "block"
        self.sb_acc.layout.display = "block"

    def sidebar_change(self, change):
        if change['name']=='selected_index':
            if change['old'] is not None:
                self.main[list(self.sb.keys())[change['old']]].layout.display = "none"
            if change['new'] is not None:
                self.main[list(self.sb.keys())[change['new']]].layout.display = "block" _____no_output_____

#### Path Widgets_____no_output_____

#export
# adapted from https://stackoverflow.com/questions/48056345/jupyter-lab-browsing-the-remote-file-system-inside-a-notebook
class PathSelector():
    "Widgets to browse and select files or directories"
    def __init__(self,start_dir,select_name='Select',select_file=False,tooltip=None):
        self.file        = None
        self.select_file = select_file
        self.hidden      = True
        self.tooltip     = tooltip or 'Click to select directory'

        #Get (and create) dir
        path = Path(start_dir).resolve()
        path.mkdir(parents=True, exist_ok=True)
        self.start_dir, self.cwd, self.path = path, path, path

        #Path Button
        self.button      = w.Button(tooltip=self.tooltip, layout=w.Layout(width='auto'))
        self.button.on_click(self.on_button_clicked)

        #Save Button
        self.button_select = w.Button(description='Save', tooltip='Save Selection', layout=w.Layout(width='auto'))
        self.button_select.on_click(self.on_button_select_clicked)

        #Reset Button
        self.button_reset = w.Button(description='Reset', layout=w.Layout(width='auto'))
        self.button_reset.on_click(self.on_button_reset_clicked)

        #Close Button
        self.button_close = w.Button(description='Close', layout=w.Layout(width='auto'))
        self.button_close.on_click(self.on_button_close_clicked)

        #SelectMultiple
        self.select      = w.SelectMultiple(options=['init'],value=(),rows=10,description='', layout=w.Layout(min_width='50px'))
        self.select.observe(self.on_update,'value')

        #Display
        self.refresh(self.path)
        self.button.description = select_name
        self.hide()

        self.dialog = w.VBox([w.HBox([self.button_select, self.button_reset, self.button_close]),
                              self.select])

    def show(self):
        self.hidden = False
        self.button.button_style = "info"
        self.button_select.layout.display = "block"
        self.button_close.layout.display = "block"
        self.button_reset.layout.display = "block"
        self.select.layout.display = "block"

    def hide(self):
        self.hidden = True
        self.button.button_style = ""
        self.button_select.layout.display = "none"
        self.button_close.layout.display = "none"
        self.button_reset.layout.display = "none"
        self.select.layout.display = "none"

    def set_path(self, path):
        path = Path(path).resolve()
        path.mkdir(parents=True, exist_ok=True)
        self.start_dir, self.cwd, self.path = path, path, path
        self.refresh('')

    def on_button_clicked(self, b):
        self.refresh('')
        if self.hidden: self.show()
        else: self.hide()

    def on_button_select_clicked(self, b):
        self.path = self.cwd
        self.button.description = f'{self.path.name}'
        self.hide()

    def on_button_reset_clicked(self, b):
        self.cwd = self.start_dir
        self.refresh('')

    def on_button_close_clicked(self, b):
        self.hide()

    def on_update(self,change):
        if len(change['new']) > 0:
            self.refresh(change['new'][0])

    def refresh(self,item):
        path = self.cwd/item

        if path.is_file():
            if self.select_file:
                self.file = path
            else:
                self.select.value = ()

        else: # os.path.isdir(path)
            self.file = None
            self.cwd  = path.resolve()

            # Build list of files and dirs
            keys = ['[..]'] if self.cwd != self.start_dir else []
            for item in sorted(path.iterdir()):
                if item.is_dir():
                    keys.append('['+item.name+']')
                else:
                    keys.append(item.name)

            # Create list of output values
            vals = []
            for k in keys:
                if k[0] == '[':
                    vals.append(k[1:-1]) # strip off brackets
                else:
                    vals.append(k)

            # Update widget
            self.select.options = list(zip(keys,vals))
            with self.select.hold_trait_notifications():
                self.select.value = ()_____no_output_____t = PathSelector('')
display(t.button, t.dialog)_____no_output_____#export
class PathDownloads(PathSelector):
    "Widgets to browse and download files or directories"
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        #Download Button
        if COLAB:
            self.button_select.description = 'Download'
            self.button_select.tooltip = 'Download entire folder or selected file'

        else:
            self.button_select.description = 'Download on Google Colab only'
            self.button_select.disabled = True

    def on_button_select_clicked(self, b):
        if not self.file:
            shutil.make_archive(self.cwd.name, 'zip', self.cwd)
            colab.files.download(f'{self.cwd.name}.zip')
        else:
            for f in self.select.value:
                colab.files.download(self.cwd/f)_____no_output_____t = PathDownloads('', select_file=True)
display(t.button, t.dialog)_____no_output_____#export
class PathConfig(PathSelector):
    "Widgets to browse and and load config file"
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        #Download Button
        self.button_select.description = 'Load'
        self.button_select.tooltip = 'Load selected configuration file (.json)'

        #Ouput
        self.output = w.Output()
        self.dialog = w.VBox([self.dialog,self.output])

    def on_button_select_clicked(self, b):
        pass_____no_output_____t = PathConfig('', select_file=True)
display(t.button, t.dialog)_____no_output_____

#### Table Widget_____no_output_____

#export
class ResultWidget:
    'Widget to show results from panads DataFrames'

    def __init__(self):

        #Start Button
        tt_start = 'Show results'
        self.run = w.Button(description='Update', tooltip=tt_start)

        #Close Button
        tt_close = 'Close widget'
        self.button_close = w.Button(description='Close', tooltip=tt_close)

        #Output
        self.output = w.Output()

        #Box
        self.widget = w.Accordion(children=[w.VBox([w.HBox([self.run, self.button_close]), self.output])])
        self.widget.set_title(0, 'Results')
        self.widget.layout.display = "none"
        self.button_close.on_click(self.on_close_clicked)

    def on_close_clicked(self, b):
        self.widget.layout.display = "none"  _____no_output_____t = ResultWidget()
t.widget.layout.display = "block"
t.widget_____no_output_____

### Grund Truth Estimation Widgets_____no_output_____#### Sidebars_____no_output_____

#export
_dgt = {
    'exp' : ('Expert Masks*', 'The parent folder containing sub-folders with segmentation masks, one folder per expert.', 'https://matjesg.github.io/deepflash2/add_information.html#Ground-Truth-Estimation'),
    'instance_labels'  : ('Instance Labels', 'Are you providing instance labels (class-aware and instance-aware)?'),
    'up_gt': ('Upload Data', 'Upload a zip file. It will be extracted automatically and must contain sub-folders with segmentation masks, one folder per expert.'),
    'sd'  : ('Sample Data', 'Sample data for demonstration and testing.'),
    'staple': ("STAPLE", "Simultaneous truth and performance level estimation (STAPLE)", "https://pubmed.ncbi.nlm.nih.gov/15250643/"),
    'mv'  :("Majority Voting", "Pixelwise majority voting to obtain the reference segmentation.", "https://simpleitk.org/doxygen/latest/html/classitk_1_1simple_1_1LabelVotingImageFilter.html"),
    'instance_segmentation_metrics': ("Instance Metrics", "Compute instance segmentation metrics: mean Average Precision (mAP) and Average Precsion (AP) at IoU 0.5.", "https://cellpose.readthedocs.io/en/latest/api.html#cellpose.metrics.average_precision"),
    'majority_vote_undec': ("MV undecided", "If majority voting is undecided, set pixels to this class label.", "https://simpleitk.org/doxygen/latest/html/classitk_1_1simple_1_1LabelVotingImageFilter.html"),
}_____no_output_____#export
class GTDataSB(BaseParamWidget, GetAttr):
    'Layout for Grund Truth Estimation "Data" Section'
    _default = 'config'

    #Hints
    txt = 'Provide binary masks or masks with instance labels'
    hints = w.Label(txt)

    params = {
        'instance_labels':w.ToggleButtons(options=[('Yes', True), ('No', False)],tooltips=
                                          ['You are providing instance labels (class-aware and instance-aware)',
                                           'You are not providing only class-aware labels']),
    }
    params['instance_labels'].style.button_width = '50px'
    #Grid
    grid = w.GridspecLayout(6, GRID_COLS, width='100%',  grid_gap="0px", align_items='center')
    grid[0, 0] = w.HTML(_html_wrap(*_dgt['exp']))
    grid[1, 0] = w.HTML(_html_wrap(*_dgt['instance_labels']))
    grid[1, 1:]= params['instance_labels']
    grid[3, :] = w.HTML('
')
    grid[4, 0] = w.HTML(_html_wrap(*_dgt['up_gt']))
    grid[5, 0] = w.HTML(_html_wrap(*_dgt['sd']))

    #Data Upload
    sd = w.Button(description='Load Sample Data',layout=w.Layout(width='auto'),tooltip='Click to download sample data')
    grid[5, 1:] = sd

    #Load Data
    run = w.Button(description='Load Data*', layout=w.Layout(width='auto'))
    grid[2, 1:] = run

    #Final Widget
    widget = w.VBox([hints, grid])

    def __init__(self, path=None, **kwargs):
        super().__init__(**kwargs)
        path = path or Path('.')
        self.msk  = PathSelector(path, 'Select Parent Folder')
        self.grid[0, 1:] = self.msk.button
        self.du =  ZipUpload(path)
        self.grid[4, 1:] = self.du.widget_____no_output_____t=GTDataSB()
t.widget_____no_output_____#export
class GTEstSB(BaseParamWidget, GetAttr):
    'Layout for Grund Truth Estimation "Data" Section'
    _default = 'config'

    #Hints
    txt = 'Select algorithm for ground truth estimation'
    hints = w.HTML(txt)

    params = {
        'majority_vote_undec': w.IntText(layout= w.Layout(width='auto')),
        'instance_segmentation_metrics':w.ToggleButtons(options=[('Yes', True), ('No', False)]),
    }
    params['instance_segmentation_metrics'].style.button_width = '50px'
    grid = w.GridspecLayout(7, GRID_COLS, width='100%',  grid_gap="0px", align_items='center')

    #Labels
    grid[0, 0] = w.HTML(_html_wrap(*_dgt['staple']))
    grid[1, 0] = w.HTML(_html_wrap(*_dgt['mv']))
    grid[2, :] = w.HTML('
')
    grid[3, 1:]= params['instance_segmentation_metrics']
    grid[3, 0] = w.HTML(_html_wrap(*_dgt['instance_segmentation_metrics']))
    grid[4, 1:]= params['majority_vote_undec']
    grid[4, 0] = w.HTML(_html_wrap(*_dgt['majority_vote_undec']))
    grid[5, 0] = w.HTML('Results Table')
    grid[6, 0] = w.HTML('Downloads')

    #Run Staple
    staple = w.Button(description='Run', layout=w.Layout(width='auto'),
                      tooltip='Run simultaneous truth and performance level estimation')
    setattr(staple, 'name', 'STAPLE')
    grid[0, 1:] = staple

    #Run MV
    mv = w.Button(description='Run', layout=w.Layout(width='auto'),
                  tooltip='Run Majority Voting')
    setattr(mv, 'name', 'majority_voting')
    grid[1, 1:] = mv

    # Result Widget
    open_results = w.Button(description='Open', layout=w.Layout(width='auto'))
    grid[5, 1:] = open_results

    #Final Widget
    widget = w.VBox([hints,grid])

    def __init__(self, path=None, **kwargs):
        super().__init__(**kwargs)
        path = path or Path('.')
        self.down  = PathDownloads(path, 'Select', tooltip='Click to download file or directory')
        self.grid[6, 1:] = self.down.button    _____no_output_____t=GTEstSB()
t.widget_____no_output_____

#### Grund Truth Estimation UI_____no_output_____

#export
class GTEstUI(BaseUI):
    'UI for ground truth estimation'

    sections = ['1 - Expert Segmentations', '2 - Ground Truth Estimation', '3 - Intercoder Reliability']

    def __init__(self, hide=False, **kwargs):
        super().__init__(**kwargs)

        #Sidebar
        self.sb = {
            'data':GTDataSB(self.path, config=self.config),
            'gt':GTEstSB(self.path, config=self.config)
        }

        #Sidebar Accordion
        self.sb_acc = w.Accordion(children=[x.widget for x in self.sb.values()], layout=w.Layout(grid_area='sidebar'))
        for i, name in enumerate(self.sections):
            self.sb_acc.set_title(i, name)
        self.sb_acc.observe(self.sidebar_change)

        self.sb['gt'].open_results.on_click(self.open_results)

        #Extra
        self.xtr = {
            'result':ResultWidget()
        }

        #Main
        self.main = {
            'msk':self.sb['data'].msk.dialog,
            'gt_down':self.sb['gt'].down.dialog,
            'result':self.xtr['result'].widget,
             **{k:w.Output() for k in self.sb.keys()}
        }
        self.main_box = w.VBox(list(self.main.values()))

        if hide: self.hide()

    def open_results(self, b):
        self.main['result'].layout.display = "block"    _____no_output_____t=GTEstUI()
t.sb_acc_____no_output_____

### Train Widgets_____no_output_____#### Sidebars_____no_output_____

#export
_dtrain = {
    'img' : ('Image Folder*', 'One folder containing all training images.', 'https://matjesg.github.io/deepflash2/add_information.html#Training'),
    'msk' : ('Mask Folder*', 'One folder containing all segmentation masks. We highly recommend using ground truth estimation from multiple experts.'),
    'n_classes': ('No. of Classes', 'Number of classes: e.g., 2 for binary segmentation (foreground and background class).'),
    'instance_labels'  : ('Instance Labels', 'Are you providing instance labels (class-aware and instance-aware)?'),
    'up'  : ('Upload Data', 'Upload a zip file. It will be extracted automatically and must contain the correct folder structure.', 'https://matjesg.github.io/deepflash2/add_information.html#Training'),
    'sd'  : ('Sample Data', 'Get sample data for demonstration and testing.'),
    'pretrained': ('Pretrained*', 'Select pretrained weights from the model libray or "new" to use an untrained model (random initialization).', 'https://matjesg.github.io/deepflash2/model_library.html'),
    'n_models'   : ('No. of Models', "Number of models within an ensemble; If you're experimenting with parameters, try only one model first; Depending on the data, ensembles should at least comprise 3-5 models"),
    's'   : ('Select', 'Train all models (ensemble) or (re-)train specific model.'),
    #'n_iter': ('Train Iterations', 'How many times a single model is trained on a mini-batch of the training data.', 'https://matjesg.github.io/deepflash2/add_information.html#Training-Epochs-and-Iterations'),
    #'base_lr': ('Learning Rate', '''Base learning rate for fine-tuning the model. The learning rate controls how quickly or slowly a neural network model learns.
 - Best learning rate depend on your data and other settings, e.g., the optimize \n - Use the learning rate finder to find the best learning rate for your dataset''', 'https://docs.fast.ai/callback.schedule.html#Learner.fine_tune'),
    'lrf' : ('LR Finder', 'Click Open to get more information.'),
    'mw'  : ('Loss Function', 'Click "Customize" to get more information.'),
    'ts'  : ('Train Settings', 'Click "Customize" to get more information.'),
    'cfg_load' : ('Configuration', 'Select configuration file (.json) from previous experiments.'),
    'cfg_save' : ('Configuration', 'Save current configuration to file (.json).'),
    'tta' : ('Use TTA', 'Enable test-time augmentation for prediction (more reliable and accurate, but slow).'),
    's_val': ('Select', 'Select model for validation. Select "Ensemble" to validate all models.'),
    'mdl' : ('Model Folder', '(Optional) One folder containing the all models of the ensemble. If not selected, latest models from Training will be selected.'),
    #'ood' : ('OOD Detection', '(Optional) For inference/prediction: Train a support-vector machine (SVM) for the detection of out-of-distribution (OOD) or anomalous data.'),
    'cache'  : ('Clear Cache', 'Delete cached files used for validation and visualization. This will not affect the final results.'),
}_____no_output_____#export
class TrainDataSB(BaseParamWidget, GetAttr):
    'Layout for "Training Data" Section'
    _default = 'config'

    #Hints
    txt = 'Provide training images and segmentation masks'
    hints = w.Label(txt)

    params = {
        'n_classes': w.IntSlider(value=2, min=2, max=10, step=1, layout=w.Layout(width='auto', min_width='1px')),
        'instance_labels':w.ToggleButtons(options=[('Yes', True), ('No', False)],tooltips=['You are providing instance labels (class-aware and instance-aware)',
                                                                               'You are not providing only class-aware labels']),
    }

    params['instance_labels'].style.button_width = '50px'
    grid = w.GridspecLayout(9, GRID_COLS, width='100%',  grid_gap="0px", align_items='center')

    #Labels
    grid[0, 0] = w.HTML(_html_wrap(*_dtrain['img']))
    grid[1, 0] = w.HTML(_html_wrap(*_dtrain['msk']))
    grid[2, 0] = w.HTML(_html_wrap(*_dtrain['n_classes']))
    grid[2, 1:]= params['n_classes']
    grid[3, 0] = w.HTML(_html_wrap(*_dtrain['instance_labels']))
    grid[3, 1:]= params['instance_labels']
    grid[5, :] = w.HTML('
')
    grid[6, 0] = w.HTML(_html_wrap(*_dtrain['up']))
    grid[7, 0] = w.HTML(_html_wrap(*_dtrain['sd']))
    grid[8,0] = w.HTML(_html_wrap(*_dtrain['cfg_load']))

    sd = w.Button(description='Load Sample Data',layout=w.Layout(width='auto'), tooltip='Click to download sample data')
    grid[7, 1:] = sd

    #Load Data
    run = w.Button(description='Load Data*', layout=w.Layout(width='auto', min_width='1px'))
    grid[4, 1:] = run

    #Final Widget
    widget = w.VBox([hints,grid])

    def __init__(self, path=None, **kwargs):
        super().__init__(**kwargs)
        path = path or Path('.')
        self.img  = PathSelector(path, 'Select')
        self.grid[0, 1:] = self.img.button
        self.msk  = PathSelector(path, 'Select')
        self.grid[1, 1:] = self.msk.button
        #Load Config
        self.cfg = PathConfig(path, 'Select Config File', select_file=True)
        self.grid[8, 1:] = self.cfg.button
        #Data Upload
        self.du =  ZipUpload(path)
        self.grid[6, 1:] = self.du.widget_____no_output_____t=TrainDataSB('')
t.widget_____no_output_____#export
class TrainModelSB(BaseParamWidget, GetAttr):
    'Layout for "Ensemble Training"'
    _default = 'config'

    #Hints
    txt = 'Train Model Ensemble'
    hints = w.Label(txt)

    params = {
        #'pretrained': w.Dropdown(options=_pretrained, continuous_update=True, layout=w.Layout(width='auto', min_width='1px')),
        'n_models': w.IntSlider(min=1, max=5, step=1, continuous_update=True, orientation='horizontal', layout=w.Layout(width='auto', min_width='1px')),
        #'n_iter':w.IntSlider(min=100, max=1e4, step=100, continuous_update=True,orientation='horizontal', layout=w.Layout(width='auto', min_width='1px')),
        #'base_lr': w.FloatText(description='', layout=w.Layout(width='auto', min_width='1px'))
    }

    sel = w.Dropdown(options=[],continuous_update=True, layout=w.Layout(width='auto', min_width='1px'))

    #Grid
    grid = w.GridspecLayout(8, GRID_COLS, width='100%',  grid_gap="0px", align_items='center')
    #grid[0, 0] = w.Label('Model Arch')
    #grid[0, 0] = w.HTML(_html_wrap(*_dtrain['pretrained']))
    #grid[0, 1:]= params['pretrained']
    grid[0, 0] = w.HTML(_html_wrap(*_dtrain['n_models']))
    grid[0, 1:]= params['n_models']
    #grid[1, 0] = w.HTML(_html_wrap(*_dtrain['n_iter']))
    #grid[1, 1:]= params['n_iter']
    grid[1, 0] = w.HTML(_html_wrap(*_dtrain['s']))
    grid[1, 1:]= sel
    #grid[4, 0] = w.Label('MAY TAKE SOME HOURS')
    grid[3, :] = w.HTML('
')
    #grid[5, 0] = w.HTML(_html_wrap(*_dtrain['base_lr']))
    #grid[5, 1:]= params['base_lr']
    grid[4, 0] = w.HTML(_html_wrap(*_dtrain['mw']))
    grid[5, 0] = w.HTML(_html_wrap(*_dtrain['ts']))
    grid[6, 0] = w.HTML(_html_wrap(*_dtrain['lrf']))
    grid[7, 0] = w.HTML(_html_wrap(*_dtrain['cfg_save']))

    #Run
    run = w.Button(description='Start Training', layout=w.Layout(width='auto'))
    grid[2, 1:] = run

    #Custom Loss
    open_mw = w.Button(description='Customize', layout=w.Layout(width='auto'))
    grid[4, 1:] = open_mw

    #Custom Train Settings
    open_par = w.Button(description='Customize', layout=w.Layout(width='auto'))
    grid[5, 1:] = open_par

    #Custom LR Finder
    open_lrfinder = w.Button(description='Open', layout=w.Layout(width='auto'))
    grid[6, 1:] = open_lrfinder

    # Save config
    cfg_save = w.Button(description='Save Config', layout=w.Layout(width='auto'))
    grid[7, 1:] = cfg_save

    #Final Widget
    widget = w.VBox([hints,grid])

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.sel.options = _get_model_list(self.config.n_models)
        self.params['n_models'].observe(self.sel_update, 'value')

    def sel_update(self, change):
        self.sel.options = _get_model_list(change['new'])_____no_output_____t=TrainModelSB()
t.widget_____no_output_____#export
class TrainValidSB(BaseParamWidget, GetAttr):
    'Layout for "Validation" Section'
    _default = 'config'

    #Hints
    txt = 'Validate Model Ensemble'
    hints = w.Label(txt)

    params = {
        'tta': w.ToggleButtons(options=[('Yes', True), ('No', False)],
                               tooltips=['Enable Test-Time Augmentation','Disable Test-Time Augmentation'])
    }

    params['tta'].style.button_width = '50px'

    #Grid
    grid = w.GridspecLayout(9, GRID_COLS, width='100%',  grid_gap="0px", align_items='center')
    grid[0, 0] = w.HTML(_html_wrap(*_dtrain['s_val']))
    grid[1, 0] = w.HTML(_html_wrap(*_dtrain['tta']))
    grid[1, 1:]= params['tta']
    grid[3, :] = w.HTML('
')
    grid[4, :] = w.Label('Load exisiting models')
    grid[5, 0] = w.HTML(_html_wrap(*_dtrain['mdl']))
    grid[6, :] = w.HTML('
')
    grid[7, 0] = w.HTML('Downloads')
    #grid[8, 0] = w.HTML(_html_wrap(*_dtrain['cache']))

    #Model
    sel = w.Dropdown(continuous_update=True, layout=w.Layout(width='auto', min_width='1px'))
    grid[0, 1:] = sel

    #Res
    run = w.Button(description='Run Validation', layout=w.Layout(width='auto'))
    grid[2, 1:] = run

    #Res
    #ood = w.Button(description='Train OOD Model', layout=w.Layout(width='auto'))
    #grid[6, 1:] = ood

    #cache = w.Button(description='Clear', layout=w.Layout(width='auto'))
    #grid[8, 1:] = cache

    #Final Widget
    widget = w.VBox([hints,grid])

    def __init__(self, path=None, **kwargs):
        super().__init__(**kwargs)
        path = path or Path('.')
        self.sel.options = _get_model_list(self.config.n_models)
        self.down  = PathDownloads(path, 'Select', tooltip='Click to download models, predictions or validation results')
        self.grid[7, 1:] = self.down.button
        self.ens  = PathSelector(path, 'Select')
        self.grid[5, 1:] = self.ens.button

    def sel_update(self, change):
        self.sel.options = _get_model_list(change['new'])_____no_output_____t=TrainValidSB()
t.widget_____no_output_____

#### Pop-Up Widgets_____no_output_____

#export
class LRWidget:
    'Widget for Learning Rate Finder'

    #Start Button
    tt_start = 'Start the Learning Rate Finder'
    run = w.Button(description='Start', tooltip=tt_start)

    #Close Button
    tt_close = 'Close Learning Rate Finder. ATTENTION: This will not interrupt the execution)'
    button_close = w.Button(description='Close', tooltip=tt_close)

    #Lbl
    html = _html_wrap('More information', '',
                      'https://docs.fast.ai/callback.schedule.html#Learner.lr_find')
    lbl = w.HTML(html)

    #Output
    output = w.Output()

    #Box
    widget = w.Accordion(children=[w.VBox([w.HBox([run, button_close]), lbl, output])])
    widget.set_title(0, 'Learning Rate Finder')

    def __init__(self):
        self.widget.layout.display = "none"
        self.button_close.on_click(self.on_close_clicked)

    def on_close_clicked(self, b):
        self.widget.layout.display = "none"  _____no_output_____t = LRWidget()
t.widget.layout.display = "block"
t.widget_____no_output_____#export
class BasePopUpParamWidget(BaseParamWidget):
    'Parameter Pop-Up Widget Base Class'

    #Reset Button
    tt_reset = 'Reset to defaults'
    button_reset = w.Button(description='Reset', tooltip=tt_reset)

    #Close Button
    tt_close = 'Close Widget'
    button_close = w.Button(description='Close', tooltip=tt_close)

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        self.button_reset.on_click(self.on_reset_clicked)
        self.button_close.on_click(self.on_close_clicked) _____no_output_____#export
_dparam= {
    'n_models'   : ('No. of Models', "Number of models within an ensemble; If you're experimenting with parameters, try only one model first; Depending on the data, ensembles should at least comprise 3-5 models"),
    'n_iter': ('Train Iterations', 'How many times a single model is trained on a mini-batch of the training data.', 'https://matjesg.github.io/deepflash2/add_information.html#Training-Epochs-and-Iterations'),
    'base_lr': ('Learning Rate', '''Base learning rate for fine-tuning the model. The learning rate controls how quickly or slowly a neural network model learns.
 - Best learning rate depend on your data and other settings, e.g., the optimize \n - Use the learning rate finder to find the best learning rate for your dataset''', 'https://docs.fast.ai/callback.schedule.html#Learner.fine_tune'),
    'arch' : ('Model Architecture', 'The architecture of the deep learning model.', 'https://matjesg.github.io/deepflash2/models.html'),
    'encoder_name' : ('Encoder', 'Encoders for architectures from Segmentation Models Pytorch.', 'https://github.com/qubvel/segmentation_models.pytorch#encoders-'),
    'encoder_weights' : ('Encoder Weights', 'Pretrained encoders weights for architectures from Segmentation Models Pytorch.', 'https://github.com/qubvel/segmentation_models.pytorch#encoders-'),
    'batch_size' : ('Mini-Batch Size', 'The number of samples that will be propagated through the network during one iteration; 4 works best in our experiements; 4-8 works good for mixed precision training'),
    'mixed_precision_training'   : ('Mixed Precision Training', 'Mixed Precision Training', 'https://docs.fast.ai/callback.fp16.html'),
    'weight_decay'  : ('Weight Decay', 'Weight Decay.', 'https://arxiv.org/abs/1711.05101'),
    'optim'  : ('Optimizer', 'Optimizer.', 'https://docs.fast.ai/optimizer.html'),
    'sample_mult' : ('Sample Multiplier', 'Defines how many are tiles are sampled from each image per epoch. Set to 0 for auto-mode.'),
    'flip'  : ('Flip', 'Randomly flip a training image.', 'https://matjesg.github.io/deepflash2/data.html#Data-augmentation'),
    'rot': ('Rotation (max. degrees)', 'Randomly rotate a training image up to max. degrees.', 'https://matjesg.github.io/deepflash2/data.html#Data-augmentation'),
    'gamma_limit_lower': ('Gamma (lower limit)', 'Random Gamma augmentation lower gamma limit.', 'https://albumentations.ai/docs/api_reference/augmentations/transforms/#albumentations.augmentations.transforms.RandomGamma'),
    'gamma_limit_upper': ('Gamma (upper limit)', 'Random Gamma augmentation upper gamma limit.', 'https://albumentations.ai/docs/api_reference/augmentations/transforms/#albumentations.augmentations.transforms.RandomGamma'),
    'brightness_limit': ('Brightness (limit)', 'Factor range for changing brightness.', 'https://albumentations.ai/docs/api_reference/augmentations/transforms/#albumentations.augmentations.transforms.RandomBrightnessContrast'),
    'contrast_limit': ('Contrast (limit)', 'Factor range for changing contrast.', 'https://albumentations.ai/docs/api_reference/augmentations/transforms/#albumentations.augmentations.transforms.RandomBrightnessContrast'),
    'CLAHE_clip_limit': ('CLAHE (clip limit)', 'Contrast Limited Adaptive Histogram Equalization (CLAHE). Set upper threshold value for contrast limiting.', 'https://albumentations.ai/docs/api_reference/augmentations/transforms/#albumentations.augmentations.transforms.CLAHE'),
    'distort_limit': ('GridDistortion (limit)', 'GridDistortion in the range (-distort_limit, distort_limit).', 'https://albumentations.ai/docs/api_reference/augmentations/transforms/#albumentations.augmentations.transforms.GridDistortion'),
    #'zoom_sigma': ('Zoom standard deviation', 'Standard deviation of the Guassian that zooms in or out of the image.', 'https://matjesg.github.io/deepflash2/data.html#RandomTileDataset'),
}_____no_output_____#export
class ParamWidget(BasePopUpParamWidget, GetAttr):
    'Widget for custom training parameters'
    _default = 'config'
    params = {
        #'n_models': w.IntSlider(min=1, max=5, step=1, continuous_update=True, orientation='horizontal', layout=w.Layout(width='auto', min_width='1px')),
        'n_iter':w.IntSlider(min=100, max=1e4, step=100, continuous_update=True,orientation='horizontal', layout=w.Layout(width='auto', min_width='1px')),
        'base_lr': w.FloatText(description='', layout=w.Layout(width='auto', min_width='1px')),
        'arch' : w.Dropdown(options=ARCHITECTURES, layout=w.Layout(width='auto', min_width='1px')),
        'encoder_name' : w.Dropdown(options=ENCODERS, layout=w.Layout(width='auto', min_width='1px')),
        'encoder_weights' : w.Dropdown(options=['imagenet'],layout=w.Layout(width='auto', min_width='1px'), continuous_update=True),
        'batch_size':w.IntSlider(min=2, max=32, step=2,layout=w.Layout(width='auto', min_width='1px')),
        'mixed_precision_training': w.ToggleButtons(options=[('Yes', True), ('No', False)],
                              tooltips=['Enable Mixed-Precision Training','Disable Mixed-Precision Training']),
        'weight_decay':w.FloatText(min=0, max=1,layout=w.Layout(width='auto', min_width='1px')),
        'optim':w.Dropdown(options=_optim_dict.keys(), layout=w.Layout(width='auto', min_width='1px')),
        'sample_mult' : w.IntText(layout= w.Layout(width='auto')),
        'flip':w.ToggleButtons(options=[('Yes', True), ('No', False)]),
        'rot':w.IntSlider(min=0, max=360, step=5, layout=w.Layout(width='auto', min_width='1px')),
        #'zoom_sigma':w.FloatSlider(min=0, max=1, layout=w.Layout(width='auto', min_width='1px')),#w.FloatText(layout=w.Layout(width='auto', min_width='1px'))
        'gamma_limit_lower':w.IntSlider(min=0, max=255, step=10, layout=w.Layout(width='auto', min_width='1px')),
        'gamma_limit_upper':w.IntSlider(min=0, max=255, step=10, layout=w.Layout(width='auto', min_width='1px')),
        'brightness_limit':w.FloatSlider(min=0, max=1, layout=w.Layout(width='auto', min_width='1px')),
        'contrast_limit':w.FloatSlider(min=0, max=1, layout=w.Layout(width='auto', min_width='1px')),
        'CLAHE_clip_limit':w.FloatSlider(min=0, max=1, layout=w.Layout(width='auto', min_width='1px')),
        'distort_limit':w.FloatSlider(min=0, max=1, layout=w.Layout(width='auto', min_width='1px')),
    }

    params['mixed_precision_training'].style.button_width = '25px'
    params['flip'].style.button_width = '25px'

    #Close Button
    tt_show = 'Show example'
    button_show = w.Button(description='Show', tooltip=tt_show)

    #Hint
    lbl = w.Label('Settings are saved automatically')

    #Grid
    grid = w.GridspecLayout(20, 2, width='400px',  grid_gap="0px", align_items='center')
    i=0
    for k in params:
        grid[i, 0] = w.HTML(_html_wrap(*_dparam[k]))
        grid[i, 1] = params[k]
        i += 1
        if i==10:
            grid[i, :] = w.HTML('
')
            i += 1
            grid[i, :] = w.HTML('Data Augmentation')
            i += 1

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        self.widget = w.Accordion(children=[w.VBox([w.HBox([self.button_reset, self.button_close]),self.lbl,self.grid])])
        self.widget.set_title(0, 'Training Parameters')
        self.widget.layout.display = "none"
        self.params['encoder_name'].observe(self.on_encoder_change, 'value')
        #self.params['n_models'].observe(self.sel_update, 'value')

    def on_encoder_change(self, change):
        self.params['encoder_weights'].options = get_pretrained_options(change['new'])

    #def sel_update(self, change):
    #    self.sel.options = _get_model_list(change['new'])_____no_output_____t=ParamWidget(config=Config(batch_size=8))
t.widget.layout.display = "block"
t.widget_____no_output_____#export
_dmw= {
    'loss': ('Loss Function', 'Objective function to minimize during training.', 'https://matjesg.github.io/deepflash2/losses.html'),
    'loss_alpha' :('alpha', 'Loss coefficient for FocalLoss and TverskyLoss.', 'https://kornia.readthedocs.io/en/latest/losses.html#kornia.losses.TverskyLoss'),
    'loss_beta' :('beta', 'Loss coefficient for TverskyLoss.', 'https://kornia.readthedocs.io/en/latest/losses.html#kornia.losses.TverskyLoss'),
    'loss_gamma' :('gamma', 'FocalLoss power factor for dampening weight (focal strength).', 'https://github.com/qubvel/segmentation_models.pytorch/blob/master/segmentation_models_pytorch/losses/focal.py'),
    'loss_smooth_factor': ('smooth_factor', 'SoftCrossEntropyLoss factor to smooth target (e.g. if smooth_factor=0.1 then [1, 0, 0] -> [0.9, 0.05, 0.05])', 'https://github.com/qubvel/segmentation_models.pytorch/blob/master/segmentation_models_pytorch/losses/soft_ce.py'),
}_____no_output_____#export
class MWWidget(BasePopUpParamWidget, GetAttr):
    'Widget to customize loss functions'
    _default = 'config'
    params = {
        'loss' : w.Dropdown(options=LOSSES, layout=w.Layout(width='auto', min_width='1px')),
        'loss_alpha' : w.FloatText(layout= w.Layout(width='auto')),
        'loss_beta' : w.FloatText(layout= w.Layout(width='auto')),
        'loss_gamma' : w.FloatText(layout= w.Layout(width='auto')),
        'loss_smooth_factor': w.FloatText(layout= w.Layout(width='auto'))
    }
    out = w.Output()

    #Hint
    lbl = w.HTML('Settings are saved automatically.')

    #Grid
    grid = w.GridspecLayout(5, 2, width='400px',  grid_gap="0px", align_items='center')
    i=0
    for k in params:
        grid[i, 0] = w.HTML(_html_wrap(*_dmw[k]))
        grid[i, 1] = params[k]
        i += 1

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        self.widget = w.Accordion(children=[w.VBox([w.HBox([self.button_reset, self.button_close]),
                                           self.lbl,
                                           self.grid,
                                           self.out])]
                         )
        self.widget.set_title(0, 'Loss Function')
        self.widget.layout.display = "none"
        self.params['loss'].observe(self.on_arch_change, 'value')
        self.on_arch_change({'new':'CrossEntropyDiceLoss'})

    def on_arch_change(self, change):
        enable = ['loss']
        if change['new'] ==  'FocalLoss': enable += ['loss_gamma', 'loss_alpha']
        elif change['new'] ==  'TverskyLoss': enable +=  ['loss_beta', 'loss_alpha']
        elif change['new'] ==  'SoftCrossEntropyLoss': enable +=  ['loss_smooth_factor']
        for k,v in self.params.items():
            if k in enable: v.disabled = False
            else: v.disabled = True            _____no_output_____t=MWWidget(config=Config())
t.widget.layout.display = "block"
t.widget_____no_output_____

#### Train UI_____no_output_____

#export
class TrainUI(BaseUI):
    'UI for ensemble training'
    sections = ['1 - Data', '2 - Ensemble Training', '3 - Validation']

    def __init__(self, hide=False, **kwargs):
        super().__init__(**kwargs)

        #Sidebar
        self.sb = {
            'data':TrainDataSB(path=self.path, config=self.config),
            'train':TrainModelSB(config=self.config),
            'valid':TrainValidSB(path=self.path, config=self.config),
        }
        self.sb['train'].open_lrfinder.on_click(self.open_lrfinder)
        self.sb['train'].open_mw.on_click(self.open_mw)
        self.sb['train'].open_par.on_click(self.open_par)
        #Update model options from train in valid
        self.sb['train'].params['n_models'].observe(self.sb['valid'].sel_update, 'value')

        #Sidebar Accordion
        self.sb_acc = w.Accordion(children=[x.widget for x in self.sb.values()], layout=w.Layout(grid_area='sidebar'))
        for i, name in enumerate(self.sections):
            self.sb_acc.set_title(i, name)
        self.sb_acc.observe(self.sidebar_change)

        #Extra
        self.xtr = {
            'lr':LRWidget(),
            'mw':MWWidget(config=self.config),
            'param':ParamWidget(config=self.config)
        }

        #Main
        self.main = {
            'img':self.sb['data'].img.dialog,
            'msk':self.sb['data'].msk.dialog,
            'cfg':self.sb['data'].cfg.dialog,
            'lr':self.xtr['lr'].widget,
            'mw':self.xtr['mw'].widget,
            'param':self.xtr['param'].widget,
            'ens':self.sb['valid'].ens.dialog,
            'down':self.sb['valid'].down.dialog,
             **{k:w.Output() for k in self.sb.keys()}
        }
        self.main_box = w.VBox(list(self.main.values()))
        if hide: self.hide()

    def set_config(self, config):
        self.sb['data'].set_config(config)
        self.sb['train'].set_config(config)
        self.xtr['param'].set_config(config)
        self.xtr['mw'].set_config(config)

    def open_lrfinder(self, b):
        self.main['lr'].layout.display = "block"

    def open_mw(self, b):
        self.main['mw'].layout.display = "block"

    def open_par(self, b):
        self.main['param'].layout.display = "block"
_____no_output_____t=TrainUI('')
t.sb_acc_____no_output_____

### Prediction Widgets_____no_output_____#### Sidebars_____no_output_____

#export
_dpred = {
    'img_pred' : ('Image Folder*', 'One folder containing all new images for prediction.', 'https://matjesg.github.io/deepflash2/add_information.html#Prediction'),
    'mdl' : ('Model Folder', 'One folder containing the all models of the ensemble. If not selected, latest models from Training will be selected.'),
    'msk_pred' : ('Test Mask Folder', 'For testing on new data. One folder containing all segmentation masks.'),
    'up_pred' : ('Upload Data', 'Upload a zip file with images or models.'),
    'sd': ('Sample Data', 'Get sample data and models. DEMONSTRATION PURPOSES ONLY!'),
    's_pred'  : ('Select', 'Ensemble or model to be used for prediction.'),
    'min_pixel_export': ('Minimum Size', 'Minimumen ROI size (number of pixels) to be included in ImageJ export'),
    'imagej'  : ('ImageJ Export', 'Export predicted masks to ImageJ ROI sets. '),
    'cache'  : ('Clear Cache', 'Delete cached files used for ensembling and visualization. This will not affect the final results.'),
    'cellpose_export_class': ('Class', 'Select class for instance segmentation. Repeat for each class.'),
    'cellpose_model' :  ('Cellpose model', 'Pretrained cellpose model to be used on the softmax predictons of deepflash2. Try nuclei model first.', 'https://cellpose.readthedocs.io/en/latest/settings.html?highlight=diameter#cytoplasm-model-cyto'),
    'cellpose_diameter': ('ROI diameter', 'ROI diameter in pixels. 0 for automated estimation.', 'https://cellpose.readthedocs.io/en/latest/settings.html?highlight=diameter#diameter'),
}_____no_output_____#export
class PredInputSB(BaseParamWidget, GetAttr):
    'Layout for "Data and Ensemble" Section'

    params = {
        'instance_labels':w.ToggleButtons(options=[('Yes', True), ('No', False)],tooltips=
                                  ['You are providing instance labels (class-aware and instance-aware)',
                                   'You are not providing only class-aware labels']),
    }

    params['instance_labels'].style.button_width = '50px'
    grid = w.GridspecLayout(10, GRID_COLS, width='100%',  grid_gap="0px", align_items='center')

    #Hints
    txt = 'Provide images and models'
    hints = w.Label(txt)

    #Labels
    grid[0, 0] = w.HTML(_html_wrap(*_dpred['img_pred']))
    grid[1, 0] = w.HTML(_html_wrap(*_dpred['mdl']))
    grid[3, :] = w.HTML('
')
    grid[4, :] = w.HTML('Evaulation (hold-out test set)')
    grid[5, 0] = w.HTML(_html_wrap(*_dpred['msk_pred']))
    grid[6, 0] = w.HTML(_html_wrap(*_dtrain['instance_labels']))
    grid[6, 1:]= params['instance_labels']
    grid[7, :] = w.HTML('
')
    grid[8, 0] = w.HTML(_html_wrap(*_dpred['up_pred']))
    grid[9, 0] = w.HTML(_html_wrap(*_dpred['sd']))

    sd = w.Button(description='Load Sample Data',layout=w.Layout(width='auto'), tooltip='Click to download sample data and models')
    grid[9, 1:] = sd

    #Load Data
    run = w.Button(description='Load*', layout=w.Layout(width='auto', min_width='1px'))
    grid[2, 1:] = run

    #Final Widget
    widget = w.VBox([hints,grid])

    def __init__(self, path=None, **kwargs):
        super().__init__(**kwargs)
        path = path or Path('.')
        self.img  = PathSelector(path, 'Select')
        self.grid[0, 1:] = self.img.button
        self.ens  = PathSelector(path, 'Select')
        self.grid[1, 1:] = self.ens.button
        self.msk  = PathSelector(path, 'Select')
        self.grid[5, 1:] = self.msk.button
        #Data Upload
        self.du = ZipUpload(path)
        self.grid[8, 1:] = self.du.widget_____no_output_____t=PredInputSB('')
t.widget_____no_output_____#export
class PredSB(BaseParamWidget, GetAttr):
    'Layout for "Prediction and Quality Control" Section'
    _default = 'config'

    #Hints
    txt = 'Predict segmentations'
    hints = w.Label(txt)

    params = {
        'pred_tta': w.ToggleButtons(options=[('Yes', True), ('No', False)],
                                    tooltips=['Enable Test-Time Augmentation','Disable Test-Time Augmentation']),
        'min_pixel_export' : w.IntText(layout= w.Layout(width='auto')),
    }
    params['pred_tta'].style.button_width = '50px'

    #Grid
    grid = w.GridspecLayout(7, GRID_COLS, width='100%',  grid_gap="0px", align_items='center')
    #grid[0, 0] = w.HTML(_html_wrap(*_dpred['s_pred']))
    grid[0, 0] = w.HTML(_html_wrap(*_dtrain['tta']))
    grid[0, 1:] = params['pred_tta']
    grid[2, :] = w.HTML('
')
    grid[3, 0] = w.HTML(_html_wrap(*_dpred['min_pixel_export']))
    grid[3, 1:] = params['min_pixel_export']
    grid[4, 0] = w.HTML(_html_wrap(*_dpred['imagej']))
    grid[5, 0] = w.HTML('Results Table')
    grid[6, 0] = w.HTML('Downloads')
    #grid[6, 0] = w.HTML(_html_wrap(*_dpred['cache']))

    #Res
    run = w.Button(description='Run Prediction*', layout=w.Layout(width='auto'))
    grid[1, 1:] = run

    #Res
    rois = w.Button(description='Export ROIs', layout=w.Layout(width='auto'))
    grid[4, 1:] = rois

    # Result Widget
    open_results = w.Button(description='Open', layout=w.Layout(width='auto'))
    grid[5, 1:] = open_results

    #Final Widget
    widget = w.VBox([hints,grid])

    def __init__(self, path=None, **kwargs):
        super().__init__(**kwargs)
        path = path or Path('.')
        self.down  = PathDownloads(path, 'Select', tooltip='Click to download')
        self.grid[6, 1:] = self.down.button    _____no_output_____t=PredSB()
t.widget_____no_output_____#export
class CellposeSB(BaseParamWidget, GetAttr):
    'Layout for instance separation with cellpose'
    _default = 'config'

    #Hints
    txt = 'Get instance segmentations'
    hints = w.Label(txt)

    params = {
        'cellpose_export_class':w.IntText(layout= w.Layout(width='auto')),
        'cellpose_model': w.Dropdown(options=['nuclei', 'cyto', 'cyto2'], layout=w.Layout(width='auto', min_width='1px')),
        'cellpose_diameter' : w.IntText(layout= w.Layout(width='auto')),
        'min_pixel_export' : w.IntText(layout= w.Layout(width='auto')),
    }

    #Grid
    grid = w.GridspecLayout(9, GRID_COLS, width='100%',  grid_gap="0px", align_items='center')
    #grid[0, 0] = w.HTML(_html_wrap(*_dpred['s_pred']))
    grid[0, 0] = w.HTML(_html_wrap(*_dpred['cellpose_export_class']))
    grid[0, 1:] = params['cellpose_export_class']
    grid[1, 0] = w.HTML(_html_wrap(*_dpred['cellpose_model']))
    grid[1, 1:] = params['cellpose_model']
    grid[2, 0] = w.HTML(_html_wrap(*_dpred['cellpose_diameter']))
    grid[2, 1:] = params['cellpose_diameter']
    grid[3, 0] = w.HTML(_html_wrap(*_dpred['min_pixel_export']))
    grid[3, 1:] = params['min_pixel_export']
    grid[5, :] = w.HTML('
')
    grid[6, 0] = w.HTML(_html_wrap(*_dpred['imagej']))
    grid[7, 0] = w.HTML('Results Table')
    grid[8, 0] = w.HTML('Downloads')
    #grid[6, 0] = w.HTML(_html_wrap(*_dpred['cache']))

    #Res
    run = w.Button(description='Run Cellpose*', layout=w.Layout(width='auto'))
    grid[4, 1:] = run

    #Res
    rois = w.Button(description='Export ROIs', layout=w.Layout(width='auto'))
    grid[6, 1:] = rois

    # Result Widget
    open_results_cp = w.Button(description='Open', layout=w.Layout(width='auto'))
    grid[7, 1:] = open_results_cp

    #Final Widget
    widget = w.VBox([hints,grid])

    def __init__(self, path=None, **kwargs):
        super().__init__(**kwargs)
        path = path or Path('.')
        self.down  = PathDownloads(path, 'Select', tooltip='Click to download')
        self.grid[8, 1:] = self.down.button    _____no_output_____t=CellposeSB()
t.widget_____no_output_____

#### Prediction UI_____no_output_____

#export
class PredUI(BaseUI):
    'UI for prediction of new data'

    sections = ['1 - Data and Model Ensemble',
                '2 - Prediction and Quality Control',
                '3 - Cellpose Instance Segmentation']

    def __init__(self, hide=False, **kwargs):
        super().__init__(**kwargs)

        #Sidebar
        self.sb = {
            'data':PredInputSB(path=self.path, config=self.config),
            'pred':PredSB(path=self.path, config=self.config),
            'cellpose':CellposeSB(path=self.path, config=self.config),
        }

        #Sidebar Accordion
        self.sb_acc = w.Accordion(children=[x.widget for x in self.sb.values()], layout=w.Layout(grid_area='sidebar'))
        for i, name in enumerate(self.sections):
            self.sb_acc.set_title(i, name)
        self.sb_acc.observe(self.sidebar_change)

        self.sb['pred'].open_results.on_click(self.open_results)
        self.sb['cellpose'].open_results_cp.on_click(self.open_results_cp)

        #Extra
        self.xtr = {
            'result':ResultWidget(),
            'result_cp':ResultWidget()
        }

        #Main
        self.main = {
            'img':self.sb['data'].img.dialog,
            'ens':self.sb['data'].ens.dialog,
            'msk':self.sb['data'].msk.dialog,
            'down':self.sb['pred'].down.dialog,
            'down2':self.sb['cellpose'].down.dialog,
            'result':self.xtr['result'].widget,
            'result_cp':self.xtr['result_cp'].widget,
             **{k:w.Output() for k in self.sb.keys()}
        }
        self.main_box = w.VBox(list(self.main.values()))

        if hide: self.hide()

    def open_results(self, b):
        self.main['result'].layout.display = "block"

    def open_results_cp(self, b):
        self.main['result_cp'].layout.display = "block"   _____no_output_____t=PredUI('')
t.sb_acc_____no_output_____

## GUI_____no_output_____

#export
class GUI(GetAttr):
    'GUI for deepflash2'
    _default = 'config'

    #Header and Footer
    head = "

"
    header = w.HTML(value=head, layout=w.Layout(width='auto', grid_area='header'))
    #foot = "

"
    foot = "
"
    footer = w.HTML(value=foot, layout=w.Layout(width='100%', grid_area='footer'))

    #Category Buttons
    cat_btns = {
        'gt':w.Button(description='GT Estimation', layout=w.Layout(flex='1 1 0%',width='auto'),
                     tooltip='Derive reference segmentations from segmentations of multiple experts.'),
        'train':w.Button(description='Training', layout=w.Layout(flex='1 1 0%',width='auto'),
                        tooltip='Train deep learning ensembles for segmentation of fluorescent labels in microscopy images.'),
        'pred':w.Button(description='Prediction', layout=w.Layout(flex='1 1 0%', width='auto'),
                       tooltip='Predict segmentation masks on new data using customized models')
    }
    cat_btns_box = w.Box(children=list(cat_btns.values()), layout=w.Layout(grid_area='cat_btns'))

    def __init__(self, path=Path('.'), reinit=False):
        # Activate better exception logging
        get_ipython()._showtraceback = exception_handler
        # Allow 100% GUI width
        display(w.HTML(""))
        self.config = Config()
        self.base_path = path.resolve()
        self.config.project_dir = str(self.base_path/self.project_dir) if self.project_dir=='deepflash2' else self.project_dir

        #Project Dir
        self.proj = PathSelector(self.base_path, 'Select Project Folder', tooltip='Project Folder \ndefault: <deepflash2>')
        self.proj.button.button_style='info'
        self.proj.button_select.on_click(self.set_project_dir)

        #Click Category Buttons
        for v in self.cat_btns.values():
            v.on_click(self.cat_clicked)

        #Categories
        self.gt = GTEstUI(hide=True, path=self.proj_path, config=self.config)
        self.train = TrainUI(hide=True,path=self.proj_path, config=self.config)
        self.pred = PredUI(hide=True, path=self.proj_path, config=self.config)
        self.cat = {'gt':self.gt, 'train':self.train, 'pred':self.pred}

        #Connect Buttons
        ## GT Estimation
        self.gt.sb['data'].run.on_click(self.gt_data_run_clicked)
        self.gt.sb['data'].sd.on_click(self.gt_data_sd_clicked)
        self.gt.sb['gt'].staple.on_click(self.gt_ref_clicked)
        self.gt.sb['gt'].mv.on_click(self.gt_ref_clicked)
        self.gt.xtr['result'].run.on_click(self.gt_show_results_clicked)
        self.gt_to_train = w.Button(description='Continue to training with estimated ground truth.', layout=w.Layout(width='auto'))
        self.gt_to_train.on_click(self.gt_to_train_clicked)

        ## Train
        self.train.sb['data'].run.on_click(self.train_data_run_clicked)
        self.train.sb['data'].sd.on_click(self.train_data_sd_clicked)
        self.train.sb['data'].cfg.button_select.on_click(self.train_data_load_cfg_clicked)
        self.train.sb['train'].run.on_click(self.train_run_clicked)
        self.train.sb['train'].cfg_save.on_click(self.train_cfg_save_clicked)
        self.train.sb['valid'].run.on_click(self.train_valid_run_clicked)
        self.train.sb['valid'].ens.button_select.on_click(self.train_valid_ens_save_clicked)
        #self.train.sb['valid'].cache.on_click(self.train_valid_cache_clicked)
        self.train.xtr['lr'].run.on_click(self.lr_start_clicked)

        ## Pred
        self.pred.sb['data'].run.on_click(self.pred_data_run_clicked)
        self.pred.sb['data'].msk.button_select.on_click(self.pred_data_msk_save_clicked)
        self.pred.sb['data'].sd.on_click(self.pred_data_sd_clicked)
        self.pred.sb['pred'].run.on_click(self.pred_run_clicked)
        self.pred.sb['pred'].rois.on_click(self.pred_rois_clicked)
        self.pred.xtr['result'].run.on_click(self.pred_show_results_clicked)
        self.pred.sb['cellpose'].run.on_click(self.cellpose_run_clicked)
        self.pred.sb['cellpose'].rois.on_click(self.cellpose_rois_clicked)
        self.pred.xtr['result_cp'].run.on_click(self.pred_cp_show_results_clicked)
        #self.pred.sb['pred'].cache.on_click(self.pred_cache_clicked)

        # Init Project
        self._init_proj()

        self.star_info = w.Label('*Required')
        self.star_info.layout.display = "none"

        box_sb = w.VBox(children=[x.sb_acc for x in self.cat.values()]+[self.star_info], layout=w.Layout(grid_area='sidebar'))
        box_main = w.VBox(children=[x.main_box for x in self.cat.values()], layout=w.Layout(grid_area='main'))
        box_proj = w.VBox(children=[self.proj.button, self.proj.dialog], layout=w.Layout(grid_area='proj', flex_flow='column', align_items='flex-start'))
        self.box_err = w.VBox(children=[err_out], layout=w.Layout(grid_area='error'))
        self.tmp = w.Output(layout=w.Layout(grid_area='tmp'))

        self.gb = w.GridBox(children=[self.header, self.cat_btns_box, box_proj, box_sb, box_main, self.footer, self.tmp, self.box_err],
                       layout=w.Layout(
                           width='100%',
                           grid_template_columns='350px auto',
                           grid_gap='0px 0px',
                           grid_template_areas='''
                           "header header"
                           "cat_btns proj"
                           "sidebar main"
                           "footer footer"
                           "error error"
                           "tmp tmp"
                           '''))
        display(self.gb)

    @property
    def proj_path(self):
        return Path(self.project_dir).absolute()

    def _set_download_dirs(self):
        self.gt.sb['gt'].down.set_path(self.proj_path/self.gt_dir)
        self.train.sb['valid'].down.set_path(self.proj_path/self.train_dir)
        self.pred.sb['pred'].down.set_path(self.proj_path/self.pred_dir)
        self.pred.sb['cellpose'].down.set_path(self.proj_path/self.pred_dir)
        #Models dir
        self.pred.sb['data'].ens.path = self.proj_path/self.train_dir/self.ens_dir

    def _set_selection_dirs(self):
        self.gt.sb['data'].msk.set_path(self.proj_path)
        self.train.sb['data'].img.set_path(self.proj_path)
        self.train.sb['data'].msk.set_path(self.proj_path)
        self.train.sb['data'].cfg.set_path(self.proj_path)
        self.pred.sb['data'].img.set_path(self.proj_path)
        self.pred.sb['data'].msk.set_path(self.proj_path)

        self.train.sb['valid'].ens.set_path(self.proj_path)
        self.pred.sb['data'].ens.set_path(self.proj_path)

    def _init_proj(self):
        self.el, self.el_pred, self.gt_est = None, None, None
        self._set_download_dirs()
        self.test_masks_provided = False

    def set_project_dir(self, b):
        self.proj.button.button_style=''
        self.config.project_dir = str(self.proj.path)
        self._set_selection_dirs()
        self._init_proj()

    def cat_clicked(self, b):
        self.star_info.layout.display = "block"
        for k,v in self.cat_btns.items():
            if v==b:
                v.button_style = 'info'
                self.cat[k].show()
            else:
                v.button_style = ''
                self.cat[k].hide()

    def set_config(self, config):
        self.config=config
        self.train.set_config(config)

    # GT Estimation
    def gt_data_run_clicked(self, b):
        out = self.gt.main['data']
        out.clear_output()
        exp_folder = self.gt.sb['data'].msk.path.relative_to(self.proj_path)
        with out:
            self.gt_est = GTEstimator(exp_folder, config=self.config, path=self.proj_path)
            items = {x:x for x in self.gt_est.masks.keys()}
            ipp = ItemsPerPage(self.proj_path, self.gt_est.show_data, items=items)
            display(ipp.widget)

    def gt_data_sd_clicked(self, b):
        out = self.gt.main['data']
        out.clear_output()
        with out:
            path = self.proj_path/'deepflash2_sample_data'/'expert_segmentations'
            display(w.HTML(f'Dowloading expert sample data into {path.relative_to(self.proj_path)}...'))
            download_sample_data(SAMPLE_DATA_URL, 'wue1_cFOS_expert_segmentation_samples.zip', path, extract=True)
            self.gt.sb['data'].msk.path = path
            self.gt_data_run_clicked('')

    def gt_to_train_clicked(self, b):
        self.train.sb['data'].msk.refresh(self.gt_save_dir)
        self.train.sb['data'].msk.on_button_select_clicked("")
        self.cat_clicked(self.cat_btns['train'])

    def gt_ref_clicked(self, b):
        out = self.gt.main['gt']
        out.clear_output()
        self.gt_save_dir = (self.proj_path/self.gt_dir/b.name).relative_to(self.proj_path)
        with out:
            assert type(self.gt_est)==GTEstimator, 'Please load data first!'
            display(w.HTML('Please watch the logs below. The final results will be displayed here.'))
        if COLAB:
            with colab.output.temporary():
                display(w.HTML('Temporary Logs:'))
                self.gt_est.gt_estimation(method=b.name, save_dir=self.gt_save_dir)
        else:
            with self.tmp:
                display(w.HTML('Temporary Logs:'))
                self.gt_est.gt_estimation(method=b.name, save_dir=self.gt_save_dir)
                self.tmp.clear_output()
        out.clear_output()
        with out:
            display(w.HTML('Ground Truth Estimation finished:'))
            display(w.HTML(f'- {b.name} segmentation masks saved to folder: {self.gt_save_dir}.'))
            display(w.HTML(f'- {b.name} similiarity results are saved to folder: {self.gt_dir}.'))
            display(w.HTML(f'- Inspect the results by opening the "Results table"'))
            display(w.HTML(f'- Download masks and results in the "Downloads" Section.'))
            display(self.gt_to_train)
            display(d.Markdown('---'))

            items = {x:x for x in self.gt_est.masks.keys()}
            ipp = ItemsPerPage(self.proj_path, self.gt_est.show_gt, items=items, method=b.name)
            display(ipp.widget)

    # GT results table
    def gt_show_results_clicked(self, b):
        out = self.gt.xtr['result'].output
        out.clear_output()
        with out:
            df = self.gt_est.df_res.round(3)
            if COLAB:
                display(data_table.DataTable(df, include_index=False, num_rows_per_page=10, min_width='1'))
            else:
                display(df)

    # Train
    def train_data_run_clicked(self, b):
        out = self.train.main['data']
        out.clear_output()
        with out: display(w.HTML('Loading data. Please wait'))
        image_folder = self.train.sb['data'].img.path.relative_to(self.proj_path)
        mask_folder = self.train.sb['data'].msk.path.relative_to(self.proj_path)
        ensemble_path = self.proj_path/self.train_dir/self.ens_dir

        with out:
            self.el = EnsembleLearner(image_folder, mask_folder, self.config, self.proj_path, ensemble_path=ensemble_path)
            items = {x:x for x in self.el.files}
            ipp = ItemsPerPage(self.proj_path, self.el.ds.show_data, items=items, overlay=True if self.n_classes==2 else False)
            display(ipp.widget)

    def train_data_sd_clicked(self, b):
        out = self.train.main['data']
        out.clear_output()
        with out:
            path = self.proj_path/'deepflash2_sample_data'
            display(w.HTML(f'Dowloading sample data into {path.relative_to(self.proj_path)}'))
            download_sample_data(SAMPLE_DATA_URL, 'wue1_cFOS_small.zip', path, extract=True)
            self.train.sb['data'].img.path = path/'images'
            self.train.sb['data'].msk.path = path/'masks'
            self.train_data_run_clicked(b)

    def train_data_load_cfg_clicked(self, b):
        cfg = self.train.sb['data'].cfg
        cfg.output.clear_output()
        with cfg.output:
            path = cfg.cwd/cfg.select.value[0]
            self.config.load(path)
        for ui in [*self.train.sb.values(),*self.train.xtr.values()]:
            if hasattr(ui, 'set_config'): ui.set_config(self.config)
        time.sleep(3)
        cfg.output.clear_output()

    def train_cfg_save_clicked(self, b):
        timestr = time.strftime("%Y%m%d%H%M")
        path = self.proj_path/self.train_dir/f'config_{timestr}'
        with self.train.main['train']: self.config.save(path)

    def train_run_clicked(self, b):
        out = self.train.main['train']
        out.clear_output()
        with out:
            assert type(self.el)==EnsembleLearner, 'Please load data first!'
            display(w.HTML('Starting training. This may take up to a few hours - depending on your hardware, the number of models, and training iterations.'))
            display(w.HTML('Please watch the logs below. The final results will be displayed here.'))

        sel = self.train.sb['train'].sel.value
        self.el.set_n(self.n_models)
        for i in range(1, self.n_models+1):
            if (sel != 'ensemble') and (sel != f'model_{i}'): continue
            with out: display(w.HTML(f'Training of model {i}'))
            tout = colab.output.temporary() if COLAB else self.tmp

            with tout:
                display(w.HTML('Temporary Logs:'))
                self.el.fit(i)
                if not COLAB: self.tmp.clear_output()

            with out:
                display(w.HTML(f'Metrics for model {i} of {self.n_models}'))
                self.el.recorder[i].plot_metrics()

    def train_valid_run_clicked(self, b):
        out = self.train.main['valid']
        out.clear_output()
        sel = self.train.sb['valid'].sel.value
        model_no = None if sel == 'ensemble' else int(sel[6:])
        export_dir = self.proj_path/self.train_dir/self.val_dir
        tout = colab.output.temporary() if COLAB else self.tmp

        with out:
            assert type(self.el)==EnsembleLearner, 'Please load data first!'
            assert len(self.el.models)>0, 'Please train models first!'
            display(f'Validating {sel}. This may take a while!')

        with tout:
            display(w.HTML('Temporary Logs:'))
            df_val = self.el.get_valid_results(model_no, export_dir=export_dir, use_tta=self.tta)
            if not COLAB: self.tmp.clear_output()

        out.clear_output()
        with out:
            items = {x.file:f'{x.model_no}_{x.file}' for _,x in df_val.iterrows()}
            ipp = ItemsPerPage(self.proj_path,self.el.show_valid_results, items=items, srt_by='model/name')
            display(ipp.widget)

    def train_valid_ens_save_clicked(self, b):
        path = self.train.sb['valid'].ens.path
        with self.train.main['valid']: self.el.load_ensemble(path)

    def train_valid_cache_clicked(self, b):
        with self.train.main['valid']: self.el.clear_tmp()

    #Lr finder
    def lr_start_clicked(self, b):
        out = self.train.xtr['lr'].output
        out.clear_output()
        tout = colab.output.temporary() if COLAB else self.tmp
        with out:
            display(w.HTML('Starting Learning Rate Finder.'))
            display(w.HTML('Please watch the logs below. The final results will be displayed here.'))

        with tout:
            display(w.HTML('Temporary Logs:'))
            sug_lrs, rec = self.el.lr_find(show_plot=False)
            if not COLAB: self.tmp.clear_output()
        with out:
            display(sug_lrs)
            rec.plot_lr_find()
            plt.show()

    #Train Settings
    def par_open(self,b):
        self.par.widget.layout.display = "block"

    # Prediction
    def pred_data_msk_save_clicked(self, b):
        self.test_masks_provided = True

    def pred_data_run_clicked(self, b):
        out = self.pred.main['data']
        out.clear_output()
        with out: display(w.HTML('Loading data. Please wait'))
        image_dir = self.pred.sb['data'].img.path.relative_to(self.proj_path)
        ensemble_path = self.pred.sb['data'].ens.path
        mask_dir = self.pred.sb['data'].msk.path.relative_to(self.proj_path) if self.test_masks_provided else None
        out.clear_output()
        with out:
            self.el_pred = EnsembleLearner(image_dir, mask_dir=mask_dir, config=self.config, path=self.proj_path, stats=(0,0), ensemble_path=ensemble_path)
            items = {x:x for x in self.el_pred.files}
            ipp = ItemsPerPage(self.proj_path, self.el_pred.ds.show_data, items=items)
            display(ipp.widget)

    def pred_data_sd_clicked(self, b):
        out = self.pred.main['data']
        tout = colab.output.temporary() if COLAB else self.tmp

        with out:
            display(w.HTML('Dowloading sample data. Please watch the logs below...'))

        with tout:
            display(w.HTML('Temporary Logs:'))
            path = self.proj_path/'deepflash2_sample_data'
            display(f'Dowloading sample data into {path.relative_to(self.proj_path)}')
            download_sample_data(SAMPLE_DATA_URL, 'wue1_cFOS_small.zip', path, extract=True)
            display(f'Dowloading trained models for sample data into {path.relative_to(self.proj_path)}')
            for fold in [1,2]:
                download_sample_data(SAMPLE_DATA_URL, f'Unet_resnet34_2classes-fold{fold}.pth', path/'models')
            self.pred.sb['data'].img.path = path/'images'
            self.pred.sb['data'].msk.path = path/'masks'
            self.pred.sb['data'].ens.path = path/'models'
            self.test_masks_provided = True
            self.pred_data_run_clicked(b)
            if not COLAB: self.tmp.clear_output()

    def pred_run_clicked(self, b, use_tta=None, show=True):
        use_tta = use_tta or self.pred_tta
        out = self.pred.main['pred']
        out.clear_output()
        tout = colab.output.temporary() if COLAB else self.tmp
        export_dir = self.pred.sb['pred'].down.path

        with out:
            assert type(self.el_pred)==EnsembleLearner, 'Please load data first!'
            display(w.HTML('Predicting segmentation masks. Please wait...'))

        with tout:
            display(w.HTML('Temporary Logs:'))
            self.el_pred.get_ensemble_results(self.el_pred.files, export_dir=export_dir, use_tta=use_tta)
            if not COLAB: self.tmp.clear_output()

        if show:
            with out:
                if self.test_masks_provided:
                    display(w.HTML('Calculating metrics...'))
                    self.el_pred.score_ensemble_results()
                display(f'Saving scoring results to {export_dir}')
                self.el_pred.df_ens.to_csv(export_dir/f'scored_prediction.csv', index=False)
                self.el_pred.df_ens.to_excel(export_dir/f'scored_prediction.xlsx')
                items = {r.file:r.uncertainty_score for _, r in self.el_pred.df_ens.iterrows()}
                display(f'A high uncertainty score indicates ambiguos or out-of-distribution data.')
                ipp = ItemsPerPage(self.proj_path, self.el_pred.show_ensemble_results, items=items, srt_index=1, srt_by='Uncertainty score', unc_metric='uncertainty_score')
                display(ipp.widget)

    def pred_rois_clicked(self, b):
        export_dir = self.pred.sb['pred'].down.path
        output_folder=Path(export_dir)/'ROI_sets'
        out = self.pred.main['pred']
        tout = colab.output.temporary() if COLAB else self.tmp

        with out: display(w.HTML('Exporting cellpose ROIs to ImageJ ROI Sets...'))
        with tout:
            display(w.HTML('Temporary Logs:'))
            display(w.HTML('Exporting ROIs to ImageJ ROI Sets...'))
            self.el_pred.export_imagej_rois(output_folder, min_pixel=self.min_pixel_export)
            if not COLAB: self.tmp.clear_output()

        with out:
            display(f'Saved ROIs to {output_folder}. Click on `Select` to to download.')

    # Pred results table
    def pred_show_results_clicked(self, b):
        out = self.pred.xtr['result'].output
        out.clear_output()
        with out:
            cols = COLS_PRED_KEEP_DS if self.test_masks_provided else COLS_PRED_KEEP
            df = self.el_pred.df_ens[cols].round(3)
            if COLAB:
                display(data_table.DataTable(df, include_index=False, num_rows_per_page=10, min_width='1'))
            else:
                display(df)

    def cellpose_run_clicked(self, b, show=True):
        out = self.pred.main['cellpose']
        out.clear_output()
        tout = colab.output.temporary() if COLAB else self.tmp
        export_dir = self.pred.sb['cellpose'].down.path

        with out:
            assert type(self.el_pred)==EnsembleLearner, 'Please load data first!'
            display(w.HTML('Starting cellpose prediction. Please wait...'))

        with tout:
            display(w.HTML('Temporary Logs:'))
            self.el_pred.get_cellpose_results(export_dir=export_dir)
            if not COLAB: self.tmp.clear_output()

        if show:
            with out:
                if self.test_masks_provided:
                    display(w.HTML('Calculating instance segmentation metrics...'))
                    self.el_pred.score_cellpose_results(label_fn=self.el_pred.label_fn)
                display(w.HTML(f'Saving scoring results to {export_dir}'))
                self.el_pred.df_ens.to_csv(export_dir/f'scored_prediction.csv', index=False)
                self.el_pred.df_ens.to_excel(export_dir/f'scored_prediction.xlsx')
                items = {r.file:r.uncertainty_score for _, r in self.el_pred.df_ens.iterrows()}
                display(f'A high uncertainty score indicates ambiguos or out-of-distribution data.')
                ipp = ItemsPerPage(self.proj_path, self.el_pred.show_cellpose_results, items=items, srt_index=1, srt_by='Uncertainty score', unc_metric='uncertainty_score')
                display(ipp.widget)

    def cellpose_rois_clicked(self, b):
        export_dir = self.pred.sb['cellpose'].down.path
        output_folder=Path(export_dir)/'cellpose_ROI_sets'
        out = self.pred.main['cellpose']
        tout = colab.output.temporary() if COLAB else self.tmp
        with out: display(w.HTML('Exporting cellpose ROIs to ImageJ ROI Sets...'))
        with tout:
            display(w.HTML('Temporary Logs:'))
            self.el_pred.export_cellpose_rois(output_folder)
            if not COLAB: self.tmp.clear_output()
        with out: display(f'Saved ROIs to {output_folder}. Click on `Select` to to download.')

    # Pred results table
    def pred_cp_show_results_clicked(self, b):
        out = self.pred.xtr['result_cp'].output
        out.clear_output()
        with out:
            cols = COLS_PRED_KEEP_DS if self.test_masks_provided else COLS_PRED_KEEP_CP
            df = self.el_pred.df_ens[cols].round(3)
            out = self.gt.main['data']
            if COLAB:
                display(data_table.DataTable(df, include_index=False, num_rows_per_page=10, min_width='1'))
            else:
                display(df)

    def pred_cache_clicked(self, b):
        with self.pred.main['pred']: self.el_pred.clear_tmp()    _____no_output_____t = GUI()_____no_output_____shutil.rmtree(t.train_dir)
shutil.rmtree(t.pred_dir)
shutil.rmtree(t.gt_dir)_____no_output_____

## Export -_____no_output_____

#hide
from nbdev.export import *
notebook2script()_____no_output_____


# Notebook from MrBlu1204/Python
Path: T&T Lab 9.ipynb

# T&T Lab 9 - 3rd Feb
## Manish Ranjan Behera (1828249)_____no_output_____

tup1 = ('physics', 'chemistry', 'biology', 'english',97, 100,88,92)_____no_output_____tup1_____no_output_____tup1[2]_____no_output_____tup2 = (1, 2, 3, 4, 5, 6, 7 )_____no_output_____tup3=tup1+tup2
print(tup3)('physics', 'chemistry', 'biology', 'english', 97, 100, 88, 92, 1, 2, 3, 4, 5, 6, 7)
tup4=tup2*5
print(tup4)(1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7)

### Pick the 3rd 4th and 5th Object of a tuple and create a new Tuple for the same_____no_output_____

tup5=tup1[2:5]
print(tup5)('biology', 'english', 97)

### Find the occurence of the element_____no_output_____

tup4=(1,23,5,5,7,2,9,10)
for i in set(tup4):
    count=0
    for j in tup4:
        if i==j:
            count+=1
    print(i,count)1 1
2 1
5 2
7 1
9 1
10 1
23 1

### Write a Python program calculate the product, multiplying all the numbers  with 35_____no_output_____

print(tup2)
for i in tup2:
    print(i*35)(1, 2, 3, 4, 5, 6, 7)
35
70
105
140
175
210
245

### Write a Python program to replace last value of tuples in a list.
Sample list: [(10, 20, 40), (40, 50, 60), (70, 80, 90)]

Expected Output: [(10, 20, 100), (40, 50, 100), (70, 80, 100)]_____no_output_____

tupList=[(10, 20, 40), (40, 50, 60), (70, 80, 90)]
for i in range(0,len(tupList)) :
    temp=list(tupList[i])
    temp[-1]=100
    tupList[i]=tuple(temp)
print(tupList)[(10, 20, 100), (40, 50, 100), (70, 80, 100)]

### Write a Python program to find the length of a tuple_____no_output_____

len(tup3)_____no_output_____print()_____no_output_____


# Notebook from Nidhimidha/Leagues
Path: notebooks/.ipynb_checkpoints/Cosine Similarity-checkpoint.ipynb

# Weekend Movie Trip_____no_output_______Dataset Summary__ -
MovieLens-100K Dataset describes ratings given by various users to various movies from MovieLens, a movie recommendation service. It contains 100,000 ratings from 1000 users on 1700 movies. The dataset was released on 4/1998.

Users were selected at random for inclusion. All selected users had rated at least 1 movies. Each user is represented by an id, age, sex, occupation and zipcode. The data are contained in the files u.data(ratings information), u.user(user information), u.item(movies information).

This dataset can be downloaded at https://grouplens.org/datasets/movielens/100k/.

In this notebook, I have used K-Neighbours classifier approach to recommend similar interest movies to the users. I didn't spend much time on it and most of it is from the reference, was just curious to see and compare the results.

References:

https://beckernick.github.io/matrix-factorization-recommender/

https://www.kaggle.com/shadow1409/movie-recommender_____no_output_____

import pandas as pd
import numpy as np
from sklearn.metrics import pairwise_distances
from scipy.spatial.distance import cosine, correlation
_____no_output_____users_cols = ['user_id', 'age', 'sex', 'occupation', 'zip_code']
users = pd.read_csv('../data/external/ml-100k/u.user', sep='|', names=users_cols, parse_dates=True)

users.head()_____no_output_____movie_cols = ['movie_id', 'title', 'release_date', 'video_release_date', 'imdb_url']
movies = pd.read_csv('../data/external/ml-100k/u.item', sep='|', names=movie_cols, usecols=range(5),encoding='latin-1')

movies.head(3)_____no_output_____rating_cols = ['user_id', 'movie_id', 'rating', 'unix_timestamp']
ratings = pd.read_csv('../data/external/ml-100k/u.data', sep='\t', names=rating_cols)
ratings.head()
_____no_output_____avg_user_ratings_df = ratings.groupby(['user_id'], as_index=False)['rating'].mean()
avg_user_ratings_df.head()_____no_output_____avg_user_ratings_df.info()<class 'pandas.core.frame.DataFrame'>
Int64Index: 943 entries, 0 to 942
Data columns (total 2 columns):
user_id    943 non-null int64
rating     943 non-null float64
dtypes: float64(1), int64(1)
memory usage: 22.1 KB
avg_movie_ratings_df = ratings.groupby(['movie_id'], as_index=False)['rating'].mean()
avg_movie_ratings_df.head()_____no_output_____avg_movie_ratings_df.info()<class 'pandas.core.frame.DataFrame'>
Int64Index: 1682 entries, 0 to 1681
Data columns (total 2 columns):
movie_id    1682 non-null int64
rating      1682 non-null float64
dtypes: float64(1), int64(1)
memory usage: 39.4 KB
#Merging movie data with their ratings
movie_ratings = pd.merge(movies, ratings)
movie_ratings.head()
_____no_output_____#Merging movies and their ratings with the users
df = pd.merge(movie_ratings, users)
df.head()
_____no_output_____df.drop(df.columns[[3,4,7]], axis=1, inplace=True)_____no_output_____ratings.drop( "unix_timestamp", inplace = True, axis = 1 )
movies.drop(movies.columns[[3,4]], inplace = True, axis = 1 )_____no_output_____#Pivot Table(This creates a matrix of users and movie_ratings)
ratings_matrix = ratings.pivot_table(index=['movie_id'],columns=['user_id'],values='rating').reset_index(drop=True)
ratings_matrix.fillna( 0, inplace = True )
_____no_output_____ratings_matrix.head()_____no_output_____#Cosine Similarity(Creates a cosine matrix of similaraties ..... which is the pairwise distances
# between two items )

movie_similarity = 1 - pairwise_distances( ratings_matrix.values, metric="cosine" )
_____no_output_____np.fill_diagonal( movie_similarity, 0 )
_____no_output_____ratings_matrix = pd.DataFrame( movie_similarity )_____no_output_____try:
    user_inp="Toy Story (1995)"
    inp=movies[movies['title']==user_inp].index.tolist()
    inp=inp[0]

    movies['similarity'] = ratings_matrix.iloc[inp]
    movies.columns = ['movie_id', 'title', 'release_date','similarity']
    movies.head(5)

except:
    print("Sorry, the movie is not in the database!")

print("Recommended movies based on your choice of ",user_inp ,": \n", movies.sort_values( ["similarity"], ascending = False )[1:20])
Recommended movies based on your choice of  Toy Story (1995) :
      movie_id                                         title release_date  \
180       181                     Return of the Jedi (1983)  14-Mar-1997
120       121                 Independence Day (ID4) (1996)  03-Jul-1996
116       117                              Rock, The (1996)  07-Jun-1996
404       405                    Mission: Impossible (1996)  22-May-1996
150       151  Willy Wonka and the Chocolate Factory (1971)  01-Jan-1971
221       222               Star Trek: First Contact (1996)  22-Nov-1996
99        100                                  Fargo (1996)  14-Feb-1997
236       237                          Jerry Maguire (1996)  13-Dec-1996
173       174                Raiders of the Lost Ark (1981)  01-Jan-1981
6           7                         Twelve Monkeys (1995)  01-Jan-1995
117       118                                Twister (1996)  10-May-1996
171       172               Empire Strikes Back, The (1980)  01-Jan-1980
27         28                              Apollo 13 (1995)  01-Jan-1995
256       257                           Men in Black (1997)  04-Jul-1997
203       204                     Back to the Future (1985)  01-Jan-1985
68         69                           Forrest Gump (1994)  01-Jan-1994
94         95                                Aladdin (1992)  01-Jan-1992
78         79                          Fugitive, The (1993)  01-Jan-1993
741       742                                 Ransom (1996)  08-Nov-1996

     similarity
180    0.699925
120    0.689786
116    0.664555
404    0.641322
150    0.638158
221    0.636727
99     0.630601
236    0.624075
173    0.622382
6      0.620979
117    0.609357
171    0.597971
27     0.592877
256    0.591641
203    0.587955
68     0.582770
94     0.581974
78     0.579142
741    0.577303


# Notebook from Ashton-Sidhu/Blog
Path: _notebooks/2020-03-27-intro-to-igviz.ipynb

# Intro to Interactive Graph Visualizations
> Build interactive graph network visualizations.

- toc: true
- badges: true
- comments: true
- categories: [jupyter, graph, visualization]
- image: images/igviz/intro.png_____no_output_____Over the last couple of months I have started to explore more with Graphs and network analysis as it pertains to user behaviour in cyber security. One of the main pain points I found early on was visualizing the network, the node properties and edges in a neat, visually appealing way. Alot of the default plotting options are built on Matplotlib, which is well, let's just say suboptimal for this type of visualization.

![](https://github.com/Ashton-Sidhu/Blog/blob/master/_notebooks/igviz/matplotlib_blah.png?raw=1)

Instead of playing around with the Matplotlib axes api, I wanted something a little bit more robust, easier to use out of the box, visually appealing and neat while maximizing the possible amount of information that can be displayed on the graph._____no_output_____In comes my favourite visualization library Plotly. Plotly already had some [documentation](https://plotly.com/python/network-graphs) on how to visualize graphs, but it was still a fairly lengthy process. The goal was to find (or create) a uniform api that follows the `.plot` standard, with some customizability, but for graphs. Hence, why I made this little package called [Interactive Graph Visualizations (igviz)](https://github.com/Ashton-Sidhu/plotly-graph)._____no_output_____> Note: Currently, only Networkx is supported but the next step is expanding it to Apache's `Graphx`._____no_output_____To install run `pip install igviz`_____no_output_____

import networkx as nx
import igviz as ig_____no_output_____

Create a random graph for demonstration purposes and assign every node a property called `prop` and every edge a property called "edge_prop" and make the values 12 and 3._____no_output_____

G = nx.random_geometric_graph(200, 0.125)
nx.set_node_attributes(G, 12, "prop")
nx.set_edge_attributes(G, 3, "edge_prop")_____no_output_____

Now we plot!

> Note: This also works with Directed and Multigraphs. Directed Graphs will show the arrows from node to node.

## The Basics

> Tip: All the example notebooks can be found [here](https://github.com/Ashton-Sidhu/plotly-graph/tree/master/examples).

By default, the nodes are sized and coloured by the degree of itself. The degree of a node is just the number of edge's (lines connecting 2 nodes) it has. You can see the degree of the node by hovering over it!_____no_output_____

fig = ig.plot(G)
fig.show()_____no_output_____

> Tip: When it comes to customizability, you can change the how the nodes are sized (`size_method`) to either be static, based off a node's property or your own custom sizing method.

> Tip: The color's can be changed (`color_method`) to be a static color (hex, plain text, etc.), based off a node's property or your own custom color method._____no_output_____There are more options, and more to come, but those are the ones that greatly impact the visualization and information of your graph._____no_output_____## Customizing the Graph Appearance_____no_output_____Here all the nodes are set to the same size and the colour is set to a light red while displaying the `prop` property on hover._____no_output_____> Tip: To display Node's properties when you hover it, specify a list for the `node_text` parameter of node properties you want to have displayed. By default only degree is shown._____no_output_____

fig = ig.plot(
    G, # Your graph
    title="My Graph",
    size_method="static", # Makes node sizes the same
    color_method="#ffcccb", # Makes all the node colours black,
    node_text=["prop"], # Adds the 'prop' property to the hover text of the node
    annotation_text="Visualization made by igviz & plotly.", # Adds a text annotation to the graph
)

fig.show()_____no_output_____

Here, the sizing and color method is based off the `prop` property of every node as well as we're displaying the `prop` property on hover._____no_output_____

fig = ig.plot(
    G,
    title="My Graph",
    size_method="prop", # Makes node sizes the size of the "prop" property
    color_method="prop", # Colors the nodes based off the "prop" property and a color scale,
    node_text=["prop"], # Adds the 'prop' property to the hover text of the node
)

fig.show()_____no_output_____

To add your own sizing and color methods, pass in a list of a color or size pertaining to each node in the graph to the `size_method` and `color_method` parameters.

> Tip: To change the colorscale, change the `colorscale` parameter!_____no_output_____

color_list = []
sizing_list = []

for node in G.nodes():
    size_and_color = G.degree(node) * 3

    color_list.append(size_and_color)
    sizing_list.append(size_and_color)

fig = ig.plot(
    G,
    title="My Graph",
    size_method=sizing_list, # Makes node sizes the size of the "prop" property
    color_method=color_list, # Colors the nodes based off the "prop" property and a color scale,
    node_text=["prop"], # Adds the 'prop' property to the hover text of the node
)

fig.show()_____no_output_____

### Labels_____no_output_____You can also add labels to both nodes and edges as well as add hover text to the edges based on their attributes._____no_output_____

ig.plot(
    G,
    node_label="prop", # Display the "prop" attribute as a label on the node
    node_label_position="top center", # Display the node label directly above the node
    edge_text=["edge_prop"], # Display the "edge_prop" attribute on hover over the edge
    edge_label="edge_prop", # Display the "edge_prop" attribute on the edge
    edge_label_position="bottom center", # Display the edge label below the edge
)_____no_output_____

## Layouts_____no_output_____You can change the way your graph is oragnized and laid out by specifying a type of layout. Networkx comes with predefined layouts to use and we can apply them through `layout`.

By default, igviz looks for the `pos` node property and if it doesn't exist it will default to a random layout.

The supported layouts are:

  - random (default): Position nodes uniformly at random in the unit square. For every node, a position is generated by choosing each of dim coordinates uniformly at random on the interval [0.0, 1.0).

  - circular: Position nodes on a circle.

  - kamada: Position nodes using Kamada-Kawai path-length cost-function.

  - planar: Position nodes without edge intersections, if possible (if the Graph is planar).

  - spring: Position nodes using Fruchterman-Reingold force-directed algorithm.

  - spectral: Position nodes using the eigenvectors of the graph Laplacian.

  - spiral: Position nodes in a spiral layout.
  _____no_output_____

fig = ig.plot(
    G,
    title="My Graph",
    layout="kamada"
)

fig.show()_____no_output_____

To add your own `pos` property you can set it via the `nx.set_node_attributes` function.

```
pos_dict = {
    0: [1, 2], # X, Y coordinates for Node 0
    1: [1.5, 3], # X, Y coordinates for Node 1
    ...
}

nx.set_node_attributes(G, pos_dict, "pos")

fig = ig.plot(G)

fig.show()
```_____no_output_____## Feedback_____no_output_____I encourage all feedback about this post or Igviz. You can e-mail me at sidhuashton@gmail.com or leave a comment on the post.

Any bug or feature requests, please create an issue on the Github repo. I welcome all feature requests and any contributions. This project is a great starter if you’re looking to contribute to an open source project — you can always message me if you need assistance getting started._____no_output_____> Tip: If you like the project, give it a star!_____no_output_____