diff --git a/hnn_core/gui/gui.py b/hnn_core/gui/gui.py index 25744fd99..26819ca16 100644 --- a/hnn_core/gui/gui.py +++ b/hnn_core/gui/gui.py @@ -16,7 +16,7 @@ from ipywidgets import (HTML, Accordion, AppLayout, BoundedFloatText, BoundedIntText, Button, Dropdown, FileUpload, FloatLogSlider, FloatText, GridspecLayout, HBox, - IntText, Label, Layout, Output, RadioButtons, Tab, + IntText, Layout, Output, RadioButtons, Tab, Text, VBox, interactive_output) import hnn_core @@ -26,7 +26,6 @@ _read_legacy_params) from hnn_core.viz import plot_dipole - THEMECOLOR = "#8A2BE2" @@ -125,9 +124,15 @@ def _get_cell_specific_widgets(layout, style, location, data=None): return widgets_list, widgets_dict -def _get_rhythmic_widget(name, tstop_widget, layout, style, location, - data=None, default_weights_ampa=None, - default_weights_nmda=None, default_delays=None): +def _get_rhythmic_widget(name, + tstop_widget, + layout, + style, + location, + data=None, + default_weights_ampa=None, + default_weights_nmda=None, + default_delays=None): default_data = { 'tstart': 0., 'tstart_std': 0., @@ -166,17 +171,18 @@ def _get_rhythmic_widget(name, tstop_widget, layout, style, location, **kwargs) widgets_list, widgets_dict = _get_cell_specific_widgets( - layout, style, location, + layout, + style, + location, data={ 'weights_ampa': default_weights_ampa, 'weights_nmda': default_weights_nmda, 'delays': default_delays, }, ) - drive_box = VBox([ - HTML(value=f"
Location: {location}
"), tstart, tstart_std, tstop, - burst_rate, burst_std, repeats, seedcore - ] + widgets_list) + drive_box = VBox( + [tstart, tstart_std, tstop, burst_rate, burst_std, repeats, seedcore] + + widgets_list) drive = dict(type='Rhythmic', name=name, tstart=tstart, @@ -191,8 +197,14 @@ def _get_rhythmic_widget(name, tstop_widget, layout, style, location, return drive, drive_box -def _get_poisson_widget(name, tstop_widget, layout, style, location, data=None, - default_weights_ampa=None, default_weights_nmda=None, +def _get_poisson_widget(name, + tstop_widget, + layout, + style, + location, + data=None, + default_weights_ampa=None, + default_weights_nmda=None, default_delays=None): default_data = { 'tstart': 0.0, @@ -246,9 +258,7 @@ def _get_poisson_widget(name, tstop_widget, layout, style, location, data=None, widgets_list.extend([HTML(value="Rate constants")] + list(widgets_dict['rate_constant'].values())) - drive_box = VBox( - [HTML(value=f"Location: {location}
"), tstart, tstop, seedcore] + - widgets_list) + drive_box = VBox([tstart, tstop, seedcore] + widgets_list) drive = dict( type='Poisson', name=name, @@ -262,8 +272,13 @@ def _get_poisson_widget(name, tstop_widget, layout, style, location, data=None, return drive, drive_box -def _get_evoked_widget(name, layout, style, location, data=None, - default_weights_ampa=None, default_weights_nmda=None, +def _get_evoked_widget(name, + layout, + style, + location, + data=None, + default_weights_ampa=None, + default_weights_nmda=None, default_delays=None): default_data = { 'mu': 0, @@ -298,10 +313,7 @@ def _get_evoked_widget(name, layout, style, location, data=None, }, ) - drive_box = VBox([ - HTML(value=f"Location: {location}
"), mu, sigma, numspikes, - seedcore - ] + widgets_list) + drive_box = VBox([mu, sigma, numspikes, seedcore] + widgets_list) drive = dict(type='Evoked', name=name, mu=mu, @@ -314,14 +326,20 @@ def _get_evoked_widget(name, layout, style, location, data=None, return drive, drive_box -def add_drive_widget(drive_type, drive_boxes, drive_widgets, drives_out, - tstop_widget, location, +def add_drive_widget(drive_type, + drive_boxes, + drive_widgets, + drives_out, + tstop_widget, + location, prespecified_drive_name=None, prespecified_drive_data=None, prespecified_weights_ampa=None, prespecified_weights_nmda=None, prespecified_delays=None, - render=True, expand_last_drive=True, event_seed=14): + render=True, + expand_last_drive=True, + event_seed=14): """Add a widget for a new drive.""" layout = Layout(width='270px', height='auto') style = {'description_width': '150px'} @@ -372,8 +390,9 @@ def add_drive_widget(drive_type, drive_boxes, drive_widgets, drives_out, default_delays=prespecified_delays, ) - if drive_type in ['Evoked', 'Poisson', 'Rhythmic', 'Bursty', - 'Gaussian']: + if drive_type in [ + 'Evoked', 'Poisson', 'Rhythmic', 'Bursty', 'Gaussian' + ]: drive_boxes.append(drive_box) drive_widgets.append(drive) @@ -384,7 +403,8 @@ def add_drive_widget(drive_type, drive_boxes, drive_widgets, drives_out, 1 if expand_last_drive else None, ) for idx, drive in enumerate(drive_widgets): - accordion.set_title(idx, drive['name']) + accordion.set_title(idx, + f"{drive['name']} ({drive['location']})") display(accordion) @@ -399,34 +419,51 @@ def update_plot_window(variables, _plot_out, plot_type): with _plot_out: if plot_type['new'] == 'spikes': - fig, ax = plt.subplots() - variables['net'].cell_response.plot_spikes_raster(ax=ax) + if variables['net'].cell_response: + fig, ax = plt.subplots() + variables['net'].cell_response.plot_spikes_raster(ax=ax) + else: + print("No cell response data") elif plot_type['new'] == 'current dipole': - fig, ax = plt.subplots() - # variables['dpls'][0].plot(ax=ax) - plot_dipole(variables['dpls'], ax=ax, average=True) + if variables['dpls'] is not None: + fig, ax = plt.subplots() + plot_dipole(variables['dpls'], ax=ax, average=True) + else: + print("No dipole data") elif plot_type['new'] == 'input histogram': # BUG: got error here, need a better way to handle exception - fig, ax = plt.subplots() - variables['net'].cell_response.plot_spikes_hist(ax=ax) + if variables['net'].cell_response: + fig, ax = plt.subplots() + variables['net'].cell_response.plot_spikes_hist(ax=ax) + else: + print("No cell response data") elif plot_type['new'] == 'PSD': - fig, ax = plt.subplots() - variables['dpls'][0].plot_psd(fmin=0, fmax=50, ax=ax) + if variables['dpls'] is not None: + fig, ax = plt.subplots() + variables['dpls'][0].plot_psd(fmin=0, fmax=50, ax=ax) + else: + print("No dipole data") elif plot_type['new'] == 'spectogram': - freqs = np.arange(10., 100., 1.) - n_cycles = freqs / 8. - fig, ax = plt.subplots() - variables['dpls'][0].plot_tfr_morlet(freqs, - n_cycles=n_cycles, - ax=ax) + if variables['dpls'] is not None: + freqs = np.arange(10., 100., 1.) + n_cycles = freqs / 8. + fig, ax = plt.subplots() + variables['dpls'][0].plot_tfr_morlet(freqs, + n_cycles=n_cycles, + ax=ax) + else: + print("No dipole data") elif plot_type['new'] == 'network': - fig = plt.figure() - ax = fig.add_subplot(111, projection='3d') - variables['net'].plot_cells(ax=ax) + if variables['net']: + fig = plt.figure() + ax = fig.add_subplot(111, projection='3d') + variables['net'].plot_cells(ax=ax) + else: + print("No network data") def load_drives(variables, params, log_out, drives_out, drive_widgets, @@ -450,8 +487,12 @@ def load_drives(variables, params, log_out, drives_out, drive_widgets, should_render = idx == (len(drive_names) - 1) add_drive_widget( - specs['type'].capitalize(), drive_boxes, - drive_widgets, drives_out, tstop, specs['location'], + specs['type'].capitalize(), + drive_boxes, + drive_widgets, + drives_out, + tstop, + specs['location'], prespecified_drive_name=drive_name, prespecified_drive_data=specs['dynamics'], prespecified_weights_ampa=specs['weights_ampa'], @@ -581,13 +622,17 @@ def run_button_clicked(log_out, drive_widgets, variables, tstep, tstop, variables['backend'] = JoblibBackend(n_jobs=joblib_cores.value) print(f"Using Joblib with {joblib_cores.value} core(s).") with variables['backend']: - simulation_status.value = "Running..." + simulation_status.value = """