def log_progress(sequence, every=None, size=None, name='Items'): """Copied from https://github.com/alexanderkuk/log-progress""" from ipywidgets import IntProgress, HTML, VBox from IPython.display import display is_iterator = False if size is None: try: size = len(sequence) except TypeError: is_iterator = True if size is not None: if every is None: if size <= 200: every = 1 else: every = int(size / 200) # every 0.5% else: assert every is not None, 'sequence is iterator, set every' if is_iterator: progress = IntProgress(min=0, max=1, value=1) progress.bar_style = 'info' else: progress = IntProgress(min=0, max=size, value=0) label = HTML() box = VBox(children=[label, progress]) display(box) index = 0 try: for index, record in enumerate(sequence, 1): if index == 1 or index % every == 0: if is_iterator: label.value = '{name}: {index} / ?'.format(name=name, index=index) else: progress.value = index label.value = u'{name}: {index} / {size}'.format( name=name, index=index, size=size) yield record except: progress.bar_style = 'danger' raise else: progress.bar_style = 'success' progress.value = index label.value = "{name}: {index}".format(name=name, index=str(index or '?'))
def log_progress(sequence, every=None, size=None): from ipywidgets import IntProgress, HTML, VBox from IPython.display import display is_iterator = False if size is None: try: size = len(sequence) except TypeError: is_iterator = True if size is not None: if every is None: if size <= 200: every = 1 else: every = size / 200 # every 0.5% else: assert every is not None, 'sequence is iterator, set every' if is_iterator: progress = IntProgress(min=0, max=1, value=1) progress.bar_style = 'info' else: progress = IntProgress(min=0, max=size, value=0) label = HTML() box = VBox(children=[label, progress]) display(box) index = 0 try: for index, record in enumerate(sequence, 1): if index == 1 or index % every == 0: if is_iterator: label.value = '{index} / ?'.format(index=index) else: progress.value = index label.value = u'{index} / {size}'.format( index=index, size=size ) yield record except: progress.bar_style = 'danger' raise else: progress.bar_style = 'success' progress.value = index label.value = str(index or '?')
def plot_float_field(): value = current_value.value key = current_value.key html = widgets[params.current_casedir]["html"].get(key) html_str = """ <p style="font-size: 300%%; text-align: center; line-height: %s"> %s """ % (pxheight[1], str(value)) if html is None: html = HTML(html_str, width=pxwidth[1], height=pxheight[1]) html.value = html_str widgets.container.children = [html]
def log_progress(sequence, every=None, size=None, start_time=None, name='Items'): """ Function to provide a progress bar. --- This function is useful only when this program is run as a Jupyter notebook. In order to use this, run `jupyter nbextension enable --py --sys-prefix widgetsnbextension` prior to launching the notebook server. """ from ipywidgets import IntProgress, HTML, VBox, HBox from IPython.display import display, Javascript from IPython.display import HTML as html import datetime import uuid image_id = "loading_image_{}".format(str(uuid.uuid4())) is_iterator = False if size is None: try: size = len(sequence) except TypeError: is_iterator = True if size is not None: if every is None: if size <= 200: every = 1 else: every = int(size / 200) # every 0.5% else: assert every is not None, 'sequence is iterator, set every' if start_time is None: start_time = datetime.datetime.now() if is_iterator: progress = IntProgress(min=0, max=1, value=1) progress.bar_style = 'info' else: progress = IntProgress(min=0, max=size, value=0) label = HTML() loading_image = HTML("<img id='{}' src='images/loading.gif' width=50 align=right alt='Loading Image.' />".format(image_id)) box = VBox(children=[label, HBox([progress, loading_image])]) display(box) #display(loading_image) index = 0 try: for index, record in enumerate(sequence, 1): if start_time is not None: time_elapsed = datetime.datetime.now() - start_time else: time_elapsed = datetime.datetime.now() if index == 1 or index % every == 0: if is_iterator: label.value = '{name}: {index} / ? | Time Elapsed: {time_elapsed}'.format( name=name, index=index, time_elapsed=time_elapsed ) else: progress.value = index if index == size: progress.value = index-1 label.value = u'{name}: {index} / {size} | Time Elapsed: {time_elapsed}'.format( name=name, index=index, size=size, time_elapsed=time_elapsed ) yield record except: progress.bar_style = 'danger' hide_command = """document.getElementById('{}').style.display='none';""".format(image_id) display(Javascript(hide_command)) else: progress.bar_style = 'success' hide_command = """document.getElementById('{}').style.display='none';""".format(image_id) display(Javascript(hide_command)) if start_time is not None: time_elapsed = datetime.datetime.now() - start_time else: time_elapsed = datetime.datetime.now() progress.value = index label.value = "{name}: {index} | Total Time: {time_elapsed}".format( name=name, index=str(index or '?'), time_elapsed=time_elapsed )
def setup(): "Setup dashboard" current_value = ParamDict() widgets = ParamDict() gui = None read_params = "" # Setup sizes documentwidth = int(_documentwidth * relwidth) documentheight = int(_documentheight * relwidth) _width = [0.2, 0.6, 0.2] dpi = 80 #pcwidth = [str(100*x)+"%" for x in _width] pxwidth = [str(documentwidth * x) + "px" for x in _width] inwidth = [documentwidth * x / dpi for x in _width] _height = [0.05, 0.9, 0.05] #pcheight = [str(100*x)+"%" for x in _height] pxheight = [str(documentheight * x) + "px" for x in _height] inheight = [documentheight * x / dpi for x in _height] # Create and populate gui container gui = VBox(width=pxwidth[1], height=pxwidth[1]) rows = [ HBox(width=str(documentwidth) + "px"), HBox(width=str(documentwidth) + "px"), HBox(width=str(documentwidth) + "px") ] header = HTML( """<h1 style="background-color: #FFFFFF">cbcdashboard</h1>""") gui.children = [header] + rows containers = [ [ HBox(width=pxwidth[0], height=pxheight[0]), HBox(width=pxwidth[1], height=pxheight[0]), HBox(width=pxwidth[2], height=pxheight[0]) ], [ HBox(width=pxwidth[0], height=pxheight[1]), HBox(width=pxwidth[1], height=pxheight[1]), HBox(width=pxwidth[2], height=pxheight[1]) ], [ HBox(width=pxwidth[0], height=pxheight[2]), HBox(width=pxwidth[1], height=pxheight[2]), HBox(width=pxwidth[2], height=pxheight[2]) ], ] for i in range(3): rows[i].children = containers[i] # for c in containers[i]: # c.children = [HTML("Loading...")] containers[2][0].children = (HTML("License: LGPLv3 or later"), ) containers[2][2].children = (HTML("cbcpost version 2016.1"), ) containers[0][0].children = (HTML("Directory: " + casedir), ) containers[0][2].children = () # Display loading gui display(gui) # Create variable containers coverage = dict() history = dict() read_params = "" params = ParamDict( updated_plot=False, current_plot=None, displayed_field=None, play=False, is_batch=False, single_mode=True, current_casedir=None, ) fields = ParamDict( timedependent_function=None, constant_function=None, timedependent_float=None, constant_float=None, time=dict(), ) current_value = ParamDict( value=None, #html = None, key=None, ts=None, x=None, type=None, legend=None, xlabel=None, ) num_all = 0 #current_casedir = None casedirs = dict() # Create containers for matplotlib and pandas matplotlib_figure = plt.figure(1, figsize=(inwidth[1], inheight[1])) matplotlib_widget = HTML(mpld3.fig_to_html(matplotlib_figure)) pandas_widget = FlexBox(width=pxwidth[1], height=pxheight[1]) pandas_widget.pack = "center" pandas_widget.align = "center" pandas_widget.children = (HTML(""), ) pandas_df = pd.DataFrame() # Check is case directory is a batch directory pp = PostProcessor(dict(casedir=casedir)) read_params = read_parameters(pp) params.is_batch = "BatchParams" in read_params # Set current case direcotry based on selections def set_current_casedir(): "Set current case directory" num_all = np.count_nonzero( [w.value == "all" for w in widgets.batch_params.children]) if num_all == 0: params.current_casedir = casedirs[tuple([ (w.description, w.value) for w in widgets.batch_params.children ])] else: params.current_casedir = None def get_boundary(): "Get boundary of 3D field (since only boundary is visualized in 3D mode)" key = widgets.available_fields.value ts = widgets.slider.value u = coverage[key][ts]._oldcall() bdry = get_boundary._precomputed.get(key) if bdry is None: bdry = Boundary(key) bdry.before_first_compute(lambda x: u) return bdry.compute(lambda x: u) get_boundary._precomputed = dict() def read_history(cd=None): "Read history from casedir cd" if cd is None: cd = casedir coverage[cd] = dict() cv = coverage[cd] pp = PostProcessor(dict(casedir=cd)) replay = Replay(pp) history[cd] = replay._fetch_history() hist = history[cd] for ts in hist: for k, v in hist[ts].items(): f = cv.setdefault(k, dict()) if isinstance(v, Loadable) and v.function is not None: if v.function.ufl_domain().topological_dimension() == 3: v._oldcall = v.__call__ v.__call__ = get_boundary f[ts] = v constant_float = set() constant_function = set() timedependent_float = set() timedependent_function = set() for f in cv: if f == "t": fields.time[cd] = np.array(cv[f].values()) continue is_constant = len(cv[f]) == 1 is_function = cv[f].values()[0].function is not None if is_constant and is_function: constant_function.add(f) elif is_constant and not is_function: constant_float.add(f) elif not is_constant and is_function: timedependent_function.add(f) elif not is_constant and not is_function: timedependent_float.add(f) if fields.constant_float is None and len(constant_float) > 0: fields.constant_float = list(constant_float) else: fields.constant_float = list( set(fields.constant_float).intersection(constant_float)) if fields.timedependent_float is None and len(timedependent_float) > 0: fields.timedependent_float = timedependent_float else: fields.timedependent_float = list( set(fields.timedependent_float).intersection( timedependent_float)) if fields.constant_function is None and len(constant_function) > 0: fields.constant_function = list(constant_function) else: fields.constant_function = list( set(fields.constant_function).intersection(constant_function)) if fields.timedependent_function is None and len( timedependent_function) > 0: fields.timedependent_function = list(timedependent_function) else: fields.timedependent_function = list( set(fields.timedependent_function).intersection( timedependent_function)) # Read back casedir(s) if params.is_batch: batch_params = read_params["Params"] for d in os.listdir(casedir): subcasedir = os.path.join(casedir, d) subparams = read_parameters(PostProcessor( dict(casedir=subcasedir))) subparams = extract_batch_params(subparams, batch_params) key = [] if not all(k in subparams for k in batch_params): continue for k in batch_params: assert k in subparams key.append((k, subparams[k])) key = tuple(key) casedirs[key] = subcasedir else: casedirs[()] = casedir N = len(casedirs.values()) fb = FlexBox(width=pxwidth[1], height=pxheight[0]) fb.pack = "center" fb.align = "center" desc = HTML( """<p style="font-align: center"> Loading casedirs 0%% (0/%d)""" % N) #desc.align_self = "center" progress = FloatProgress(min=0, max=N) fb.children = [desc, progress] containers[0][1].children = (fb, ) for i, cd in enumerate(casedirs.values()): read_history(cd) desc.value = """<p style="font-align: center"> Loading casedirs %d%% (%d/%d)""" % ( int((i + 1) * 100. / N), i + 1, N) progress.value = i def fix_html(s, name): """x3dom.js has some bug that causes infinite recursion. A fixed version is moved to the UiO home area, at "http://folk.uio.no/oyvinev/x3dom-full.js""" S = re.sub(r"http://www.x3dom.org/download/x3dom.js", "http://folk.uio.no/oyvinev/x3dom-full.js", s, count=1) S = re.sub(r"<x3d", r'<x3d id="%s"' % name, S, count=1) S = re.sub('width="500.000000px" height="400.000000px"', 'width="%s" height="%s"' % (pxwidth[1], pxheight[1]), S, count=1) return S def compute_colors(u, p, is_cell_based=False): """To avoid re-reading from dolfin.X3DOM, recomputes only colors for functions More or less taken directly from X3DOM.cpp in dolfin""" vv = u.compute_vertex_values() mesh = u.function_space().mesh() dim = u.ufl_domain().topological_dimension() if not is_cell_based: # Compute or get vertex set vertex_set = compute_colors._vertex_sets.get(u.id()) if vertex_set is None: vertex_set = set() for f in cells(mesh): for v in vertices(f): vertex_set.add(v.index()) compute_colors._vertex_sets[u.id()] = vertex_set # Compute magnitude of function, since vectors are not supported in X3Dom if len(u.ufl_shape) == 1: N = len(vv) / dim _vv = vv[:N]**2 for i in range(1, dim): _vv += vv[i * N:(i + 1) * N]**2 vv = np.sqrt(_vv) value_data = np.zeros(len(vertex_set)) #[None]*len(vertex_set) for i, v in enumerate(vertex_set): value_data[i] = vv[v] else: facet_set = compute_colors._facet_sets.get(u.id()) if facet_set is None: if dim == 3: iterator = facets num_facets = mesh.num_facets() else: iterator = cells num_facets = mesh.num_cells() facet_set = np.array(np.zeros((num_facets, dim + 1))) for f in iterator(mesh): facet_set[f.index(), :] = f.entities(0) facet_set = facet_set.astype(int) compute_colors._facet_sets[u.id] = facet_set values = vv[facet_set] value_data = np.mean(values, axis=1) # Compute new value range, and set if value_range is set to default value_min = np.min(value_data) value_max = np.max(value_data) if widgets.value_range.default is True: widgets.value_range.unobserve_all() widgets.value_range.min = value_min widgets.value_range.max = value_max widgets.value_range.value = (value_min, value_max) widgets.value_range.step = (value_max - value_min) / 200. widgets.value_range.observe(widgets.value_range.handler, "value") value_min, value_max = widgets.value_range.value # Compute new colors if value_max == value_min: scale = 1.0 else: scale = 255.0 / (value_max - value_min) cindex = (scale * np.abs(value_data - value_min)).astype(int) cindex[cindex < 0] = 0 cindex[cindex > 255] = 255 cmap = p.get_color_map().reshape(-1, 3) colors = cmap[cindex].flatten() return colors compute_colors._vertex_sets = dict() # Cache for storing vertex sets compute_colors._facet_sets = dict() # Cache for storing facet sets #compute_colors._edges = dict() # Insert colors into HTML-representation of x3d-object def insert_colors(name, colors): """Insert colors into HTML-representation of x3d-object. This is done through a simple javascript.""" colors_str = " ".join(["%.3g" % c for c in colors]) javascript = """ var elems = document.getElementsByTagName("x3d") var i = 0 for ( i=0; i<elems.length; ++i) { if (elems[i].id == "%s") { break; } } try{ elems[i].getElementsByTagName("color")[0].color = "%s" } catch(err) {} """ % (name, colors_str) #document.getElementById("%s").color = "%s";""" %(name,name,name,colors_str) display(Javascript(javascript)) return def get_combinations(): "Get combinations based on selected batch params" combinations = [] for ckey, cd in casedirs.iteritems(): _ckey = ParamDict(ckey) if all([ w.value == _ckey[w.description] or w.value == "all" for w in widgets.batch_params.children ]): combinations.append(ckey) return combinations def compute_current_value(): "Compute the currently selected value" key = widgets.available_fields.value for k in current_value: current_value[k] = None current_value.key = key children = widgets.batch_params.children which_all = dict((w.description, batch_params[w.description]) for w in children if w.value == "all") num_all = len(which_all) combinations = get_combinations() cds = [casedirs[c] for c in combinations] if key in fields.constant_float and num_all == 0: current_value.type = "float" current_value.value = coverage[ params.current_casedir][key].values()[0]() elif key in fields.constant_function + fields.timedependent_function: current_value.type = "function" ts = widgets.slider.value current_value.ts = ts t = coverage[params.current_casedir]["t"][ts] current_value.x = t u = coverage[params.current_casedir][key][ts]() current_value.value = u elif num_all == 2 and key in fields.constant_float: current_value.type = "pandas" import pandas as pd cname, columns = which_all.items()[0] rname, index = which_all.items()[1] ##from IPython import embed #embed() value_data = np.zeros( (len(batch_params[rname]), len(batch_params[cname]))) for ci, c in enumerate(columns): for ri, r in enumerate(index): for comb, cd in zip(combinations, cds): _comb = ParamDict(comb) if _comb[cname] == c and _comb[rname] == r: value_data[ri, ci] = coverage[cd][key].values()[0]() df = pd.DataFrame(data=value_data, columns=columns, index=index) df.columns.name = "%s\%s" % tuple(which_all.keys()[::-1]) current_value.value = df else: current_value.type = "matplotlib" if key in fields.timedependent_float: values = [[]] * len(combinations) x = [[]] * len(combinations) legend = [""] * len(combinations) for i, cd in enumerate(cds): comb = ParamDict(combinations[i]) #_cd = dict(cd) timesteps = coverage[cd][key].keys() x[i] = np.array(fields.time[cd][timesteps]) _values = coverage[cd][key].values() _values = [_v() for _v in _values] legend[i] = ", ".join( "%s=%s" % (k, v) for k, v in dict(combinations[i]).items() if k in which_all) values[i] = _values current_value.legend = legend current_value.xlabel = "Time" current_value.x = x elif key in fields.constant_float: x = [np.array(which_all.values()[0])] values = [0.0] * len(combinations) for i, cd in enumerate(cds): values[i] = coverage[cd][key].values()[0]() values = [values] current_value.xlabel = which_all.keys()[0] current_value.x = x current_value.value = values ################################# # Plot fields def plot_function_field(): params.updated_plot = False key = current_value.key u = current_value.value p = X3DOMParameters() p.set_representation(p.Representation_surface_with_edges) dm = u.function_space().dofmap() rank = len(u.ufl_shape) dim = u.ufl_domain().topological_dimension() is_cell_based = dm.max_element_dofs() == dim**rank if widgets[params.current_casedir]["html"][key] is None: s = fix_html(X3DOM.html(u, p), key) m = re.findall('<shape>.*?</shape>', s, flags=re.DOTALL) if len(m) == 2: if "indexedLineSet" in m[0]: m = [m[1], m[0]] assert "indexedLineSet" in m[1] plot_function_field._edges[u.id()] = m[1] s = re.sub(m[1], "<!-- INDEXED LINE SET GOES HERE -->", s) plot_function_field._html[u.id()] = s widgets[params.current_casedir]["html"][key] = HTML(s) s = plot_function_field._html[u.id()] m = plot_function_field._edges.get(u.id()) if widgets.edge_cb.value and m is not None: s = re.sub("<!-- INDEXED LINE SET GOES HERE -->", m, s) widgets[params.current_casedir]["html"][key].value = s widgets.container.children = [ widgets[params.current_casedir]["html"][key] ] colors = compute_colors(u, p, is_cell_based) insert_colors(key, colors) params.displayed_field = key params.updated_plot = True plot_function_field._edges = dict() plot_function_field._html = dict() def plot_float_field(): value = current_value.value key = current_value.key html = widgets[params.current_casedir]["html"].get(key) html_str = """ <p style="font-size: 300%%; text-align: center; line-height: %s"> %s """ % (pxheight[1], str(value)) if html is None: html = HTML(html_str, width=pxwidth[1], height=pxheight[1]) html.value = html_str widgets.container.children = [html] def plot_matplotlib_field(values=None, x=None, legend=None): # Cannot use matplotlib inline backend, changing it temporarily #backend = plt.get_backend() #print "Backend: ", backend #plt.switch_backend(u"TkAgg") matplotlib_figure.clear() plt.figure(matplotlib_figure.number) key = current_value.key x = current_value.x value = current_value.value legend = current_value.legend xlabel = current_value.xlabel #plot_type = widgets.plot_type.value #print "Plot type: ", plot_type for _x, v in zip(x, value): plt.plot(_x, v) """ if plot_type == "plot": plt.plot(_x,v) else: base = widgets.log_scale.value print "Base: ", base if plot_type == "semilogx": plt.semilogx(_x,v, basex=base) elif plot_type == "semilogy": plt.semilogy(_x,v, basey=base) elif plot_type == "loglog": plt.loglog(_x,v, basex=base, basey=base) print _x, v """ if legend is not None and not (len(legend) == 1 and legend[0] == ""): plt.legend(legend) #plt.draw() plt.xlabel(xlabel) plt.ylabel(key) plt.tight_layout() plt.draw() #plt.show() html = mpld3.fig_to_html(matplotlib_figure) #html = mpld3.fig_to_d3(plt.gcf()) html = html.replace('"text": "None"', '"text": ""') matplotlib_widget.value = html widgets.container.children = [matplotlib_widget] #plt.switch_backend(backend) def plot_pandas_field(): value = current_value.value styles = [ dict( selector="table", props=[ #("width", "500px"), ("border-collapse", "collapse"), ]), dict(selector="th", props=[("font-size", "36px"), ("text-align", "center"), ("height", "100%"), ("background-color", "#D7D7D7"), ("min-width", "150px"), ("padding", "12px")]), dict(selector="tr", props=[("text-align", "right"), ("padding", "12px"), ("font-size", "28px")]) ] mat = value.as_matrix() #/100000 shape = mat.shape mat = mat.flatten() mat2 = mat.astype(str) precision = 4 def determine_formatting(df): if np.min(df.as_matrix()) < 10**-(precision - 2): return lambda x: ("%%.%de" % (precision)) % x else: def _format_float(x): s = "%f" % x if "." in s: s = s[:max(s.index('.'), precision + 1)] if s[-1] == ".": s = s[:-1] return s return _format_float format_float = determine_formatting(value) for i in range(len(mat)): mat2[i] = format_float(mat[i]) mat2 = mat2.reshape(shape) global pandas_df pandas_df = pd.DataFrame(data=mat2, columns=value.columns, index=value.index) style = pandas_df.style.set_table_styles(styles) html = re.sub('<th class="blank">', '<th class="blank"> %s' % value.columns.name, style._repr_html_(), count=1) pandas_widget.children[0].value = html widgets.container.children = [pandas_widget] def plot_field(): "Plot field. This method is called on every scene change in the gui" compute_current_value() type = current_value.type if type == "function": cbc_log(20, "Plotting function field") widgets.value_range.visible = True widgets.edge_cb.visible = True widgets.slider.visible = True widgets.play_pause_button.visible = True #widgets.plot_type.visible = False #widgets.log_scale.visible = False # Bug if these are added on first render, without function plot, # they are still shown. Therefore, adding them here c = list(containers[2][1].children) if widgets.value_range not in c: c.append(widgets.value_range) if widgets.edge_cb not in c: c.append(widgets.edge_cb) containers[2][1].children = tuple(c) #widgets.time.visible = True if current_value.key not in fields.timedependent_function: widgets.slider.disabled = True widgets.play_pause_button.disabled = True else: widgets.slider.disabled = False widgets.play_pause_button.disabled = False plot_function_field() elif type == "matplotlib": cbc_log(20, "Plotting matplotlib field") widgets.value_range.visible = False widgets.slider.visible = False widgets.play_pause_button.visible = False widgets.edge_cb.visible = False """ c = list(containers[2][1].children) if not widgets.plot_type in c: c.append(widgets.plot_type) if not widgets.log_scale in c: c.append(widgets.log_scale) containers[2][1].children = tuple(c) if widgets.plot_type.value == "plot": widgets.log_scale.visible = False else: widgets.log_scale.visible = True widgets.plot_type.visible = True """ #if current_value.xlabel == "Time": # widgets.time.visible = False plot_matplotlib_field() elif type == "float": cbc_log(20, "Plotting float field") widgets.value_range.visible = False widgets.edge_cb.visible = False widgets.slider.visible = False widgets.play_pause_button.visible = False #widgets.plot_type.visible = False #widgets.log_scale.visible = False #widgets.time.visible = True plot_float_field() elif type == "pandas": cbc_log(20, "Plotting pandas field") widgets.value_range.visible = False widgets.edge_cb.visible = False widgets.slider.visible = False widgets.play_pause_button.visible = False #widgets.plot_type.visible = False #widgets.log_scale.visible = False #widgets.time.visible = True plot_pandas_field() else: raise RuntimeError("Unable to recognize field type %s" % type) ################################### # Event handlers def change_batch_param(change): "Event handler for when a batch param is changed" #new = change["new"] old = change["old"] dd = change["owner"] global num_all num_all = np.count_nonzero( [c.value == "all" for c in widgets.batch_params.children]) if num_all > 0: widgets.slider.disable = True else: widgets.slider.disable = False widgets.slider.value = widgets.slider.value set_current_casedir() if num_all > 2: dd.value = old else: setup_available_fields() plot_field() def snap_to_timestep(change): "Set timesteps to timestep slider" cv = coverage.get(params.current_casedir) if cv is None: slider.disabled = True return else: slider.disabled = False key = widgets.available_fields.value try: ts = change["new"] old = change["old"] except: ts = change.value old = ts + 1 if ts not in cv[key]: possible_ts = np.array(cv[key].keys()) if widgets.play_pause_button.play: possible_ts = possible_ts[(possible_ts - ts) > 0] idx = np.argmin(np.abs(possible_ts - ts)) new_ts = possible_ts[idx] slider.value = new_ts if slider.value == old: return else: plot_field() def field_changed(changed): "Handle event where selected field changed" new = changed["new"] old = changed["old"] widgets.value_range.default = True cv = coverage.get(params.current_casedir) if cv is None: slider.disabled = True plot_field() return slider.disabled = False if new != old: min_ts, max_ts, step_ts, valid = get_timestepping(new) cbc_log( 20, "In field-changed: Time-step range=%d-%d" % (min_ts, max_ts)) widgets.slider.min = -1e16 widgets.slider.max = 1e16 widgets.slider.min = min_ts widgets.slider.max = max_ts widgets.slider.step = step_ts #value_range.value="-" #value_range.value = None if not valid: widgets.slider.value = widgets.slider.value plot_field() def value_range_changed(change): "Handle value range changed" vr = widgets.value_range cbc_log(20, "In value range changed: change=" + str(change)) cbc_log(20, "In value range changed: default=" + str(vr.default)) cbc_log(20, "In value range changed: visible=" + str(vr.visible)) cbc_log(20, "In value range changed: value=" + str(vr.value)) r = vr.max - vr.min cbc_log(20, "In value range changed: range=" + str(r)) min, max = vr.value if r < 1e-12 or (abs(min - vr.min) / r < 1e-4 and abs(max - vr.max) / r < 1e-4): vr.default = True else: if r < 1e-12: vr.default = True else: vr.default = False cbc_log(20, "In value range changed (after): default=" + str(vr.default)) plot_field() ########################### # Helper functions def setup_available_fields(): num_all = np.count_nonzero( [c.value == "all" for c in widgets.batch_params.children]) af = widgets.available_fields af.options = [] current = af.value if num_all == 0: for k in fields: if k == "time": continue af.options += fields[k] af.options = list(sorted(af.options)) else: for k in fields: if "float" in k: af.options += fields[k] if current not in af.options: if len(af.options) > 0: af.value = available_fields.options[0] cbc_log(20, "In setup_available_fields: af.options=" + str(af.options)) cbc_log(20, "In setup_available_fields: af.value=" + str(af.value)) def get_timestepping(key): cv = coverage[params.current_casedir] possible_ts = np.array(cv[key].keys()) if len(possible_ts) > 1: possible_ts.sort() step = np.min(possible_ts[1:] - possible_ts[:-1]) else: step = 1 min_ts = np.min(possible_ts) max_ts = np.max(possible_ts) return min_ts, max_ts, step, slider.value in possible_ts def play(btn): while btn.play and slider.value < slider.max: params.updated_plot = False slider.value += 1 time.sleep(0.1) while not params.updated_plot: time.sleep(0.03) btn.description = "Play" btn.tooltip = "Play sequence" btn.play = False def play_pause(btn): if btn.play: btn.description = "Play" btn.tooltip = "Play sequence" btn.play = False else: btn.description = "Pause" btn.tooltip = "Pause playback" btn.play = True t = threading.Thread(target=play, args=(play_pause_button, )) t.start() def to_html(s, fontsize=None): if not isinstance(s, str): s = str(s) if fontsize is not None: _s = '<pre style="font-size: %dpx">' % fontsize s = _s + s #+"<\pre>" else: s = '<pre>' + s return s # Create all widgets batch_params_container = VBox(width=pxwidth[2], height=pxheight[1]) if params.is_batch: batch_params_container.visible = False children = [] for k, v in batch_params.items(): w = Dropdown( description=k, options=["all"] + list(v), value=v[0], width=str(float(pxwidth[2][:-2]) - 100) + "px", ) w.observe(change_batch_param, names="value") w.handler = change_batch_param children.append(w) batch_params_container.children = children batch_params_container.handler = None widgets["batch_params"] = batch_params_container set_current_casedir() # Define slider for timesteps slider = IntSlider(min=0, max=1, step=1, value=0, height=pxheight[0]) slider.handler = snap_to_timestep slider.observe(snap_to_timestep, names='value') slider.on_displayed(snap_to_timestep) widgets["slider"] = slider # Define drop down list of available fields available_fields = Dropdown( width=str(float(pxwidth[1][:-2]) / 3) + "px", font_size=64, ) available_fields.handler = field_changed available_fields.observe(field_changed, names="value") widgets["available_fields"] = available_fields # Define value range slider value_range = FloatRangeSlider() value_range.handler = value_range_changed value_range.observe(value_range_changed, "value") value_range.default = False widgets["value_range"] = value_range # Define play button play_pause_button = Button(description="Play", width="80px", height=str(float(pxheight[0][:-2]) - 7) + "px") play_pause_button.play = False play_pause_button.on_click(play_pause) play_pause_button.handler = play_pause widgets["play_pause_button"] = play_pause_button widgets["parameters"] = HTML(to_html(read_params, fontsize=11), width=pxwidth[0], height=pxheight[1]) widgets.parameters.handler = None widgets.parameters.layout.overflow_y = "scroll" widgets.parameters.layout.overflow_x = "scroll" container = Box(height=pxheight[1], width=pxwidth[1]) widgets["container"] = container widgets.container.handler = None for c in casedirs.values(): widgets[c] = dict() widgets[c]["html"] = dict() for k in fields.timedependent_function + fields.constant_function: widgets[c]["html"][k] = None def edge_cb_changed(change): plot_field() edge_cb = Checkbox(description="Edges", value=False) edge_cb.handler = edge_cb_changed edge_cb.observe(edge_cb_changed, names="value") widgets["edge_cb"] = edge_cb """ # TODO: Log scale does not seem to work in mpld3 def plot_type_changed(change): if change["new"] == "plot": widgets.log_scale.visible = False else: widgets.log_scale.visible = True plot_field() plot_type = Dropdown(description="Plot type", options=["plot", "loglog", "semilogx", "semilogy"], value = "plot" ) plot_type.observe(plot_type_changed, names="value") widgets["plot_type"] = plot_type log_scale = FloatText(description="Log base", value=10.0) def log_value_wait(change): time.sleep(1) f = change["owner"] if f.value != change["new"]: return plot_field() def log_value_change(change): t = threading.Thread(target=wait, args=(change,)) t.daemon = True t.start() log_scale.observe(log_value_change, names="value") widgets["log_scale"] = log_scale """ # Populate gui with newly created widget containers[0][1].children = (widgets.available_fields, widgets.play_pause_button, widgets.slider ) #, widgets.time) containers[1][0].children = (widgets.parameters, ) containers[1][1].children = (widgets.container, ) containers[1][2].children = (widgets.batch_params, ) # Bug that shows children even when display=False. Set them when required first time. #containers[2][1].children = (widgets.value_range,widgets.edge_cb) containers[2][1].children = () setup_available_fields() value_range.value = (value_range.min, value_range.max) figures = dict(pandas=pandas_df, matplotlib=matplotlib_figure) return current_value, widgets, figures, gui