def modify_document(self, doc): self.tb.lock() sink = bokehgui.vec_sink_f_proc(self.tb.get_num_channels(), "", 1) self.tb.connect((self.mag_to_zW, 0), (sink, 0)) self.tb.unlock() log_cds = ColumnDataSource(data=self.lw.get_table()) blw = BokehLogWatcher(doc, log_cds) logging.getLogger().addHandler(blw) def cleanup_session(session_context): self.tb.lock() self.tb.disconnect((self.mag_to_zW, 0), (sink, 0)) self.tb.unlock() logging.getLogger().removeHandler(blw) doc.on_session_destroyed(cleanup_session) doc.title = "Gal Scan GUI" plot_lst = [] plot = vec_sink_f(doc, plot_lst, sink, is_message=False) plot.initialize(update_time=100, legend_list=['']) plot.get_figure().aspect_ratio = 2 plot.set_y_axis([0, 10]) plot.set_y_label("Power at feed (zW / Hz)") plot.set_x_label("Frequency (MHz)") def set_x_values(): plot.set_x_values( np.linspace( self.tb.get_sdr_frequency() - (self.tb.get_output_vector_bandwidth() / 2), self.tb.get_sdr_frequency() + (self.tb.get_output_vector_bandwidth() / 2), self.tb.get_num_channels()) / 1e6) set_x_values() plot.enable_axis_labels(True) plot.set_layout(1, 0) plot.enable_max_hold() plot.format_line(0, "blue", 1, "solid", None, 1.0) azimuth = Knob(title="Azimuth", max=360, min=0, unit="°") elevation = Knob(title="Elevation", max=360, min=0, unit="°") rx_power = Knob(title="Average RX Power", digits=4, decimals=1, unit="dB(mW/Hz)") plot.stream.js_on_change( "streaming", CustomJS( args=dict(rx_power=rx_power), code=""" const data = cb_obj.data const average = data['y0'].reduce((a,b) => a+b)/data['y0'].length rx_power.value = (10*Math.log10(average))-180 """, )) log_table = SortedDataTable( source=log_cds, columns=[ TableColumn(field="asctime", title="Time", width=140), TableColumn(field="levelname", title="Level", width=60), TableColumn(field="message", title="Message", width=1500), ], autosize_mode="none", aspect_ratio=2, sizing_mode="stretch_width", sortable=True, ) gain = Slider(title="gain", value=self.tb.get_sdr_gain(), start=0, end=65) gain.on_change('value', lambda name, old, new: self.set_gain(new)) rx = ActiveButton(label="RX enabled") rx.on_click(lambda: self.set_rx(not rx.active)) frequency = Knob(title="center frequency", writable=True, value=self.tb.get_sdr_frequency(), digits=10, decimals=0, unit="Hz") frequency.on_change('value', lambda name, old, new: self.set_frequency(new)) bandwidth = Knob(title="filter bandwidth", writable=False, value=self.tb.get_bandwidth(), digits=7, decimals=0, unit="Hz") bandwidth.on_change('value', lambda name, old, new: self.set_bandwidth(new)) reset = Button(label="Reset") def on_reset(): gain.value = run.flowgraph_defaults['sdr_gain'] frequency.value = run.flowgraph_defaults['sdr_frequency'] bandwidth.value = run.flowgraph_defaults['bandwidth'] reset.on_click(on_reset) manual = Panel(title="Manual", child=column( row(rx, gain), row(frequency, bandwidth), reset, )) run_models = {} automated_panels = [] for group, args in run.arg_groups.items(): # TODO: show grouping panel_models = [] for key, arg in args.items(): key = key.replace('-', '_') bokeh_args = arg.get('bokeh', {}) bokeh_args['name'] = key bokeh_args['tags'] = ['args'] if 'default' in arg: bokeh_args['value'] = arg['default'] if 'help' in arg: bokeh_args['title'] = arg['help'] if 'metavar' in arg: bokeh_args['title'] += " (%s)" % (arg['metavar']) type = TextInput if arg.get('type') in (float, int): type = Spinner if 'bokeh' in arg and 'start' in arg[ 'bokeh'] and 'end' in arg['bokeh']: type = Slider if 'step' not in bokeh_args: if arg['type'] == int: bokeh_args['step'] = 1 else: bokeh_args['step'] = 0.01 if arg.get('metavar') == 'Hz': if 'digits' not in bokeh_args: bokeh_args['digits'] = 10 if bokeh_args.get('max'): bokeh_args['digits'] = len("%d" % bokeh_args['max']) type = functools.partial(Knob, decimals=0, unit=arg['metavar']) del bokeh_args['step'] del bokeh_args['tags'] if 'writable' not in bokeh_args: bokeh_args['writable'] = True elif 'choices' in arg: type = Select bokeh_args['options'] = [str(x) for x in arg['choices']] if 'value' in bokeh_args: bokeh_args['value'] = str(bokeh_args['value']) elif arg.get('action') in ('store_true', 'store_false'): type = Select bokeh_args['options'] = [('0', 'False'), ('1', 'True')] bokeh_args['value'] = str(int(bokeh_args['value'])) bokeh_args['tags'] = ['boolean'] + bokeh_args.get( 'tags', []) if group.startswith("mode="): # Make this smarter if we ever have a mode=gal tab bokeh_args['disabled'] = True m = type(**bokeh_args) run_models[key] = m panel_models.append(m) automated_panels.append( Panel(title=group, child=grid(panel_models, ncols=2))) for panel in automated_panels: if panel.title.startswith("mode="): mode_str = panel.title.split('=')[1] run_models['mode'].js_on_change( 'value', CustomJS( args=dict(panel=panel, mode=mode_str), code= """panel.select(Bokeh.require("models/widgets/control").Control).forEach(c => c.disabled = (this.value != mode))""", )) plan_p = Paragraph(sizing_mode="stretch_width", ) load = UploadButton(name="load-settings", accept=".json,application/json", label="Load settings") def on_load(attr, old, new): data = json.loads(base64.b64decode(new)) for key, value in data.items(): if isinstance(run_models[key], Select): value = str(value) run_models[key].value = value load.on_change('value', on_load) save = DownloadButton(label="Save settings", filename="gal_scan_settings.json", mime_type="application/json", data=CustomJS(args=dict(run_models=run_models), code=""" const out = {} for (let k in run_models) { if (!run_models[k].disabled) { out[k] = run_models[k].value const tags = run_models[k].tags if (tags && tags.indexOf("boolean") >= 0) { out[k] = parseInt(out[k]) } } } return JSON.stringify(out, null, 2); """)) start = Button(label="Start scan") def get_args(output_dir): return run.parse_args( [output_dir], { k: int(v.value) if "boolean" in v.tags else v.value for k, v in run_models.items() if not v.disabled }, ) def on_start(): try: output_dir = os.path.join( self.runs_dir, "run_" + datetime.datetime.now().replace(microsecond=0).isoformat()) args = get_args(output_dir) self.enqueue_run(args) except SystemExit: pass start.on_click(on_start) automated = Panel(title="Plan", child=column(Tabs(tabs=automated_panels), plan_p, row(load, save, start))) # TODO: Show cancel buttons for active or queued actions queue_cds = ColumnDataSource(data=self.get_queue_data()) action_column = ActionMenuColumn( field="id", title="Action", menu=[ ("Cancel", "cancel"), ], ) def on_action_menu_click(event): if event.item == "cancel": self.cancel_action(event.value) else: logging.warn("Unknown action clicked: %s", event.item) action_column.on_event(ActionMenuClick, on_action_menu_click) queue_table = SortedDataTable( source=queue_cds, columns=[ TableColumn( field="time", title="Time", formatter=DateFormatter(format="%Y-%m-%d %H:%M:%S"), ), TableColumn(field="user", title="User"), TableColumn(field="name", title="Job"), action_column, ], highlight_field="active", sort_ascending=True, autosize_mode="fit_viewport", aspect_ratio=2, sizing_mode="stretch_width", ) queue = Panel(title="Queue", child=queue_table) results_cds = ColumnDataSource(data={"name": [], "mtime": []}) results_table = SortedDataTable( source=results_cds, columns=[ TableColumn( field="mtime", title="Time", formatter=DateFormatter(format="%Y-%m-%d %H:%M:%S"), ), TableColumn( field="name", title="Name", formatter=HTMLTemplateFormatter( template= '<a href="/runs/<%= value %>/" target="_blank"><%= value %></a>' )), ], autosize_mode="fit_viewport", aspect_ratio=2, sizing_mode="stretch_width", sortable=True, ) results = Panel(title="Results", child=results_table) tabs = Tabs(tabs=[manual, automated, queue, results]) status_p = Paragraph(sizing_mode="stretch_width", ) controls = column(row(azimuth, elevation, rx_power), status_p, tabs, log_table) def get_survey_data(): pointers = { 'ra': [], 'dec': [], 'label': [], 'colour': [], } for o in self.messier: pointers['ra'].append(o['ra']) pointers['dec'].append(o['dec']) pointers['label'].append(o['label']) pointers['colour'].append('') survey = self.active_action.get('survey') out = { 'pointers': pointers, 'status_message': 'Idle', 'plan_message': 'Invalid parameters' } if survey: groups = survey.coord_groups i = 0 for sc, colour in zip(reversed(groups), ('rgb(0, 192, 0)', 'rgb(192, 0, 0)')): sc = sc.icrs for sc in sc: pointers['ra'].append(sc.ra.to(u.degree).value) pointers['dec'].append(sc.dec.to(u.degree).value) pointers['label'].append(str(i + 1)) pointers['colour'].append(colour) i += 1 out['status_message'] = 'Time remaining on current survey: %s' % ( survey.time_remaining.to_datetime()) survey = None try: survey = run.Survey(get_args('bogus')) out['plan_message'] = 'Estimated runtime: %s' % ( survey.time_remaining.to_datetime()) if tabs.tabs[tabs.active] == automated: # TODO: Use the underlying numpy arrays sc = survey.iterator.coords_now.icrs for i, sc in enumerate(sc[:1000]): pointers['ra'].append(sc.ra.to(u.degree).value) pointers['dec'].append(sc.dec.to(u.degree).value) pointers['label'].append(str(i + 1)) pointers['colour'].append('rgb(148,0,211)') except: logging.getLogger('stderr').exception('Invalid parameters') return out sd = get_survey_data() pointers_cds = ColumnDataSource(data=sd['pointers']) def update_pointers(attr, old, new): logging.debug('Updating pointers') sd = get_survey_data() pointers_cds.data = sd['pointers'] plan_p.text = sd['plan_message'] status_p.text = sd['status_message'] update_pointers(None, None, None) log_cds.on_change('data', update_pointers) tabs.on_change('active', update_pointers) for m in run_models.values(): m.on_change('value', update_pointers) skymap = Skymap( height=600, sizing_mode="stretch_height", pointer_data_source=pointers_cds, ) skymap.on_event(Tap, lambda event: self.point(event.x, event.y)) doc.add_root(row( column( skymap, plot.get_figure(), ), controls, ), ) async def update_status(last_status={}): set_x_values() status = self.client.status skymap.latlon = (status['Latitude'], status['Longitude']) skymap.azel = (status['AzPos'], status['ElPos']) if status['CommandAzFlags'] == 'POSITION' or status[ 'CommandElFlags'] == 'POSITION': skymap.targetAzel = (status['CommandAzPos'], status['CommandElPos']) else: skymap.targetAzel = None azimuth.value = status['AzPos'] elevation.value = status['ElPos'] rx_active = status['Sequencer']['Bands'][0]['CommandRX'] if not last_status or rx_active != last_status['Sequencer'][ 'Bands'][0]['CommandRX']: if rx_active: rx.label = "RX enabled" else: rx.label = "RX disabled (50Ω load)" rx.active = rx_active queue_data = self.get_queue_data() if queue_cds.data != queue_data: queue_cds.data = queue_data with os.scandir(self.runs_dir) as it: files = list( sorted(it, reverse=True, key=lambda f: f.stat().st_mtime)) results_data = { "name": [f.name for f in files], "mtime": [int(f.stat().st_mtime * 1000) for f in files], } if results_data != results_cds.data: results_cds.data = results_data last_status.update(status) doc.add_periodic_callback(update_status, 200)
update_legend_color_bar(select_feature.value, day) def update_src_after_day_change(attr, old, new): day = ts_to_day(new) geosource.geojson = create_sample(day).to_json() # def update_label_figures_after_feature_change(attr, old, new): # label_figures.text = new TOOLTIPS = [('Область', '@ADM1_UA'), (select_feature.value, '@{' + str(select_feature.value) + '}')] plot.add_tools(HoverTool(tooltips=TOOLTIPS)) tabs.on_change('active', update_tabs) select_feature.on_change('value', update_color_mapper_and_legend_color_bar_after_feature_change) select_feature.on_change('value', update_tooltips_after_feature_change) select_feature.js_link('value', plot.title, 'text') # select_feature.on_change('value', update_label_figures_after_feature_change) slider_time.on_change('value_throttled', update_src_after_day_change) slider_time.on_change('value_throttled', update_color_mapper_and_legend_color_bar_after_day_change) curdoc().add_root(column(tabs)) curdoc().title = 'Ukraine | Hospitals | Supply'
def create(): doc = curdoc() config = pyzebra.AnatricConfig() def _load_config_file(file): config.load_from_file(file) logfile_textinput.value = config.logfile logfile_verbosity.value = config.logfile_verbosity filelist_type.value = config.filelist_type filelist_format_textinput.value = config.filelist_format filelist_datapath_textinput.value = config.filelist_datapath filelist_ranges_textareainput.value = "\n".join( map(str, config.filelist_ranges)) crystal_sample_textinput.value = config.crystal_sample lambda_textinput.value = config.crystal_lambda zeroOM_textinput.value = config.crystal_zeroOM zeroSTT_textinput.value = config.crystal_zeroSTT zeroCHI_textinput.value = config.crystal_zeroCHI ub_textareainput.value = config.crystal_UB dataFactory_implementation_select.value = config.dataFactory_implementation if config.dataFactory_dist1 is not None: dataFactory_dist1_textinput.value = config.dataFactory_dist1 if config.dataFactory_dist2 is not None: dataFactory_dist2_textinput.value = config.dataFactory_dist2 if config.dataFactory_dist3 is not None: dataFactory_dist3_textinput.value = config.dataFactory_dist3 reflectionPrinter_format_select.value = config.reflectionPrinter_format if config.algorithm == "adaptivemaxcog": algorithm_params.active = 0 threshold_textinput.value = config.threshold shell_textinput.value = config.shell steepness_textinput.value = config.steepness duplicateDistance_textinput.value = config.duplicateDistance maxequal_textinput.value = config.maxequal aps_window_textinput.value = str( tuple(map(int, config.aps_window.values()))) elif config.algorithm == "adaptivedynamic": algorithm_params.active = 1 adm_window_textinput.value = str( tuple(map(int, config.adm_window.values()))) border_textinput.value = str( tuple(map(int, config.border.values()))) minWindow_textinput.value = str( tuple(map(int, config.minWindow.values()))) reflectionFile_textinput.value = config.reflectionFile targetMonitor_textinput.value = config.targetMonitor smoothSize_textinput.value = config.smoothSize loop_textinput.value = config.loop minPeakCount_textinput.value = config.minPeakCount displacementCurve_textinput.value = "\n".join( map(str, config.displacementCurve)) else: raise ValueError("Unknown processing mode.") def upload_button_callback(_attr, _old, new): with io.BytesIO(base64.b64decode(new)) as file: _load_config_file(file) upload_div = Div(text="Open .xml config:") upload_button = FileInput(accept=".xml", width=200) upload_button.on_change("value", upload_button_callback) # General parameters # ---- logfile def logfile_textinput_callback(_attr, _old, new): config.logfile = new logfile_textinput = TextInput(title="Logfile:", value="logfile.log") logfile_textinput.on_change("value", logfile_textinput_callback) def logfile_verbosity_callback(_attr, _old, new): config.logfile_verbosity = new logfile_verbosity = TextInput(title="verbosity:", width=70) logfile_verbosity.on_change("value", logfile_verbosity_callback) # ---- FileList def filelist_type_callback(_attr, _old, new): config.filelist_type = new filelist_type = Select(title="File List:", options=["TRICS", "SINQ"], width=100) filelist_type.on_change("value", filelist_type_callback) def filelist_format_textinput_callback(_attr, _old, new): config.filelist_format = new filelist_format_textinput = TextInput(title="format:", width=290) filelist_format_textinput.on_change("value", filelist_format_textinput_callback) def filelist_datapath_textinput_callback(_attr, _old, new): config.filelist_datapath = new filelist_datapath_textinput = TextInput(title="datapath:") filelist_datapath_textinput.on_change( "value", filelist_datapath_textinput_callback) def filelist_ranges_textareainput_callback(_attr, _old, new): ranges = [] for line in new.splitlines(): ranges.append(re.findall(r"\b\d+\b", line)) config.filelist_ranges = ranges filelist_ranges_textareainput = TextAreaInput(title="ranges:", rows=1) filelist_ranges_textareainput.on_change( "value", filelist_ranges_textareainput_callback) # ---- crystal def crystal_sample_textinput_callback(_attr, _old, new): config.crystal_sample = new crystal_sample_textinput = TextInput(title="Sample Name:", width=290) crystal_sample_textinput.on_change("value", crystal_sample_textinput_callback) def lambda_textinput_callback(_attr, _old, new): config.crystal_lambda = new lambda_textinput = TextInput(title="lambda:", width=100) lambda_textinput.on_change("value", lambda_textinput_callback) def ub_textareainput_callback(_attr, _old, new): config.crystal_UB = new ub_textareainput = TextAreaInput(title="UB matrix:", height=100) ub_textareainput.on_change("value", ub_textareainput_callback) def zeroOM_textinput_callback(_attr, _old, new): config.crystal_zeroOM = new zeroOM_textinput = TextInput(title="zeroOM:", width=100) zeroOM_textinput.on_change("value", zeroOM_textinput_callback) def zeroSTT_textinput_callback(_attr, _old, new): config.crystal_zeroSTT = new zeroSTT_textinput = TextInput(title="zeroSTT:", width=100) zeroSTT_textinput.on_change("value", zeroSTT_textinput_callback) def zeroCHI_textinput_callback(_attr, _old, new): config.crystal_zeroCHI = new zeroCHI_textinput = TextInput(title="zeroCHI:", width=100) zeroCHI_textinput.on_change("value", zeroCHI_textinput_callback) # ---- DataFactory def dataFactory_implementation_select_callback(_attr, _old, new): config.dataFactory_implementation = new dataFactory_implementation_select = Select( title="DataFactory implement.:", options=DATA_FACTORY_IMPLEMENTATION, width=145, ) dataFactory_implementation_select.on_change( "value", dataFactory_implementation_select_callback) def dataFactory_dist1_textinput_callback(_attr, _old, new): config.dataFactory_dist1 = new dataFactory_dist1_textinput = TextInput(title="dist1:", width=75) dataFactory_dist1_textinput.on_change( "value", dataFactory_dist1_textinput_callback) def dataFactory_dist2_textinput_callback(_attr, _old, new): config.dataFactory_dist2 = new dataFactory_dist2_textinput = TextInput(title="dist2:", width=75) dataFactory_dist2_textinput.on_change( "value", dataFactory_dist2_textinput_callback) def dataFactory_dist3_textinput_callback(_attr, _old, new): config.dataFactory_dist3 = new dataFactory_dist3_textinput = TextInput(title="dist3:", width=75) dataFactory_dist3_textinput.on_change( "value", dataFactory_dist3_textinput_callback) # ---- BackgroundProcessor # ---- DetectorEfficency # ---- ReflectionPrinter def reflectionPrinter_format_select_callback(_attr, _old, new): config.reflectionPrinter_format = new reflectionPrinter_format_select = Select( title="ReflectionPrinter format:", options=REFLECTION_PRINTER_FORMATS, width=145, ) reflectionPrinter_format_select.on_change( "value", reflectionPrinter_format_select_callback) # Adaptive Peak Detection (adaptivemaxcog) # ---- threshold def threshold_textinput_callback(_attr, _old, new): config.threshold = new threshold_textinput = TextInput(title="Threshold:", width=145) threshold_textinput.on_change("value", threshold_textinput_callback) # ---- shell def shell_textinput_callback(_attr, _old, new): config.shell = new shell_textinput = TextInput(title="Shell:", width=145) shell_textinput.on_change("value", shell_textinput_callback) # ---- steepness def steepness_textinput_callback(_attr, _old, new): config.steepness = new steepness_textinput = TextInput(title="Steepness:", width=145) steepness_textinput.on_change("value", steepness_textinput_callback) # ---- duplicateDistance def duplicateDistance_textinput_callback(_attr, _old, new): config.duplicateDistance = new duplicateDistance_textinput = TextInput(title="Duplicate Distance:", width=145) duplicateDistance_textinput.on_change( "value", duplicateDistance_textinput_callback) # ---- maxequal def maxequal_textinput_callback(_attr, _old, new): config.maxequal = new maxequal_textinput = TextInput(title="Max Equal:", width=145) maxequal_textinput.on_change("value", maxequal_textinput_callback) # ---- window def aps_window_textinput_callback(_attr, _old, new): config.aps_window = dict( zip(("x", "y", "z"), re.findall(r"\b\d+\b", new))) aps_window_textinput = TextInput(title="Window (x, y, z):", width=145) aps_window_textinput.on_change("value", aps_window_textinput_callback) # Adaptive Dynamic Mask Integration (adaptivedynamic) # ---- window def adm_window_textinput_callback(_attr, _old, new): config.adm_window = dict( zip(("x", "y", "z"), re.findall(r"\b\d+\b", new))) adm_window_textinput = TextInput(title="Window (x, y, z):", width=145) adm_window_textinput.on_change("value", adm_window_textinput_callback) # ---- border def border_textinput_callback(_attr, _old, new): config.border = dict(zip(("x", "y", "z"), re.findall(r"\b\d+\b", new))) border_textinput = TextInput(title="Border (x, y, z):", width=145) border_textinput.on_change("value", border_textinput_callback) # ---- minWindow def minWindow_textinput_callback(_attr, _old, new): config.minWindow = dict( zip(("x", "y", "z"), re.findall(r"\b\d+\b", new))) minWindow_textinput = TextInput(title="Min Window (x, y, z):", width=145) minWindow_textinput.on_change("value", minWindow_textinput_callback) # ---- reflectionFile def reflectionFile_textinput_callback(_attr, _old, new): config.reflectionFile = new reflectionFile_textinput = TextInput(title="Reflection File:", width=145) reflectionFile_textinput.on_change("value", reflectionFile_textinput_callback) # ---- targetMonitor def targetMonitor_textinput_callback(_attr, _old, new): config.targetMonitor = new targetMonitor_textinput = TextInput(title="Target Monitor:", width=145) targetMonitor_textinput.on_change("value", targetMonitor_textinput_callback) # ---- smoothSize def smoothSize_textinput_callback(_attr, _old, new): config.smoothSize = new smoothSize_textinput = TextInput(title="Smooth Size:", width=145) smoothSize_textinput.on_change("value", smoothSize_textinput_callback) # ---- loop def loop_textinput_callback(_attr, _old, new): config.loop = new loop_textinput = TextInput(title="Loop:", width=145) loop_textinput.on_change("value", loop_textinput_callback) # ---- minPeakCount def minPeakCount_textinput_callback(_attr, _old, new): config.minPeakCount = new minPeakCount_textinput = TextInput(title="Min Peak Count:", width=145) minPeakCount_textinput.on_change("value", minPeakCount_textinput_callback) # ---- displacementCurve def displacementCurve_textinput_callback(_attr, _old, new): maps = [] for line in new.splitlines(): maps.append(re.findall(r"\d+(?:\.\d+)?", line)) config.displacementCurve = maps displacementCurve_textinput = TextAreaInput( title="Displ. Curve (2θ, x, y):", width=145, height=100) displacementCurve_textinput.on_change( "value", displacementCurve_textinput_callback) def algorithm_tabs_callback(_attr, _old, new): if new == 0: config.algorithm = "adaptivemaxcog" else: config.algorithm = "adaptivedynamic" algorithm_params = Tabs(tabs=[ Panel( child=column( row(threshold_textinput, shell_textinput, steepness_textinput), row(duplicateDistance_textinput, maxequal_textinput, aps_window_textinput), ), title="Peak Search", ), Panel( child=column( row(adm_window_textinput, border_textinput, minWindow_textinput), row(reflectionFile_textinput, targetMonitor_textinput, smoothSize_textinput), row(loop_textinput, minPeakCount_textinput, displacementCurve_textinput), ), title="Dynamic Integration", ), ]) algorithm_params.on_change("active", algorithm_tabs_callback) def process_button_callback(): with tempfile.TemporaryDirectory() as temp_dir: temp_file = temp_dir + "/config.xml" config.save_as(temp_file) pyzebra.anatric(temp_file, anatric_path=doc.anatric_path, cwd=temp_dir) with open(os.path.join(temp_dir, config.logfile)) as f_log: output_log.value = f_log.read() with open(os.path.join(temp_dir, config.reflectionPrinter_file)) as f_res: output_res.value = f_res.read() process_button = Button(label="Process", button_type="primary") process_button.on_click(process_button_callback) output_log = TextAreaInput(title="Logfile output:", height=320, width=465, disabled=True) output_res = TextAreaInput(title="Result output:", height=320, width=465, disabled=True) output_config = TextAreaInput(title="Current config:", height=320, width=465, disabled=True) general_params_layout = column( row(column(Spacer(height=2), upload_div), upload_button), row(logfile_textinput, logfile_verbosity), row(filelist_type, filelist_format_textinput), filelist_datapath_textinput, filelist_ranges_textareainput, row(crystal_sample_textinput, lambda_textinput), ub_textareainput, row(zeroOM_textinput, zeroSTT_textinput, zeroCHI_textinput), row( dataFactory_implementation_select, dataFactory_dist1_textinput, dataFactory_dist2_textinput, dataFactory_dist3_textinput, ), row(reflectionPrinter_format_select), ) tab_layout = row( general_params_layout, column(output_config, algorithm_params, row(process_button)), column(output_log, output_res), ) async def update_config(): output_config.value = config.tostring() doc.add_periodic_callback(update_config, 1000) return Panel(child=tab_layout, title="hdf anatric")
def extensionsDropdownChanged(event): global extension extension = event.item extensionsDropdown.on_event(MenuItemClick, extensionsDropdownChanged) # Tabs def panelActive(attr, old, new): global automatico, primer_ciclo ''' Get excecuted when the other tab is selected Changes the operation mode if a tab is changed ''' if tabs.active == 0: automatico = True primer_ciclo = True elif tabs.active == 1: automatico = False voltageV1.value = cliente.valvulas['valvula1'].get_value() voltageV2.value = cliente.valvulas['valvula2'].get_value() tabs.on_change('active', panelActive) ''' ******************** Curdoc ******************** ''' curdoc().add_root(tabs) curdoc().title = 'Experiencia 1: Control de Procesos' curdoc().add_periodic_callback(MainLoop, 150)
class EphemerisApp: to_seconds = dict(Day=86400, Hour=3600, Minute=60, Second=1) def __init__(self): # app variables self.active = True self.playAnimation = None self.start_epoch = None self.stop_epoch = None self.current_epoch = None # get initial configuration self.available_models = inspect.getmembers(StandardEphemerisModels, inspect.isfunction) self.ephemeris_model = self.available_models[0][1]() self.spice_provider = SpiceProvider() self.spice_provider.SPICE_IDS = self.ephemeris_model.objects self.spice_provider.SPICE_NAMES = { v: k for k, v in self.ephemeris_model.objects.items() } # init data sources self.plot_source = self.spice_provider.state_source self.table_source = self.spice_provider.ephemeris_source self.cum_source = self.spice_provider.cum_source # gather options from ephemeris model and spice provider self.allowed_models = { model[1]().name: model[1] for model in self.available_models } allowed_objects = [ self.spice_provider.fromId(name) for name in self.ephemeris_model.objects ] allowed_frames = self.ephemeris_model.FRAMES allowed_corrections = [name for name in SpiceProvider.CORRECTIONS] allowed_durations = [ str(v) for v in self.ephemeris_model.DURATION_DAYS ] allowed_intervals = [name for name in SpiceProvider.INTERVALS] # set up widgets self.model = Select(title="Ephemeris Model", options=list(self.allowed_models.keys())) self.center = Select(title="Center", value=self.ephemeris_model.center, options=allowed_objects) self.target = Select(title="Target", value=self.ephemeris_model.target, options=allowed_objects) self.frames = Select(title="Frame", value=self.ephemeris_model.frame, options=allowed_frames) self.planes = RadioButtonGroup(labels=['XY', 'YZ', 'XZ'], active=0) self.vector = Select(title='Vector Type', value=self.ephemeris_model.vector_type, options=allowed_corrections) self.epoch = DatePicker(title="Select Epoch", value=datetime.strftime( self.ephemeris_model.epoch, "%Y-%m-%d")) self.offset = Slider(title="Days Since Epoch", value=self.ephemeris_model.offset, start=0, end=self.ephemeris_model.duration, step=1) self.duration = Select(title="Duration (Days)", value=str(self.ephemeris_model.duration), options=allowed_durations) self.interval = Select(title="Time Step", value=str(self.ephemeris_model.step_size), options=allowed_intervals) # create buttons self.play_button = Button(label="Play") self.exportRange = Div(text="Start and Stop Epoch: ") self.update_button = Button(label="Play") self.export_button = Button(label="Export") self.infoDiv = Div( text= "<hr>All ephemeris data shown on this website was obtained from publicly available " "SPICE files located at <a href='https://naif.jpl.nasa.gov/naif/data.html'>" "https://naif.jpl.nasa.gov/naif/data.html</a>, which is hosted by the " "Navigation and Ancillary Information Facility (NAIF) at the NASA Jet Propulsion " "Laboratory. The exception is the SPICE kernel for the Parker Solar Probe, which is " "available at <a href='https://sppgway.jhuapl.edu/ancil_products'>" "https://sppgway.jhuapl.edu/ancil_products</a>, hosted by the Johns Hopkins University " "Applied Physics Laboratory. SpiceyPy is being used to process the SPICE files.", sizing_mode='stretch_width') # create plot tab objects self.plot = figure(match_aspect=True, sizing_mode="stretch_both", title="Astropynamics", tools="hover, pan, reset, save", tooltips=[("name", "@index")]) self.plot.add_tools(BoxZoomTool(match_aspect=True)) self.plot.circle('px', 'py', size='radii', source=self.plot_source, line_width=3, line_alpha=0.5, name='XY') self.plot.circle('px', 'pz', size='radii', source=self.plot_source, line_width=3, line_alpha=0.5, name='XZ').visible = False self.plot.circle('py', 'pz', size='radii', source=self.plot_source, line_width=3, line_alpha=0.5, name='YZ').visible = False self.plot.line('px', 'py', source=self.cum_source, line_width=2, line_alpha=0.5, color='red', name='XYOrbit') self.plot.line('px', 'pz', source=self.cum_source, line_width=2, line_alpha=0.5, color='red', name='XZOrbit').visible = False self.plot.line('py', 'pz', source=self.cum_source, line_width=2, line_alpha=0.5, color='red', name='YZOrbit').visible = False self.plotLayout = column(self.plot, self.offset, sizing_mode="stretch_width") self.plotTab = Panel(child=self.plotLayout, title="Display") # create data table tab objects fmt = NumberFormatter(format='0.000', text_align=TextAlign.right) columns = [ TableColumn(field="index", title="Epoch", formatter=DateFormatter(format="%m/%d/%Y %H:%M:%S")), TableColumn(field="px", title="PX", formatter=fmt, width=10), TableColumn(field="py", title="PY", formatter=fmt), TableColumn(field="pz", title="PZ", formatter=fmt), TableColumn(field="vx", title="VX", formatter=fmt), TableColumn(field="vy", title="VY", formatter=fmt), TableColumn(field="vz", title="VZ", formatter=fmt) ] self.ephemerisTable = DataTable(source=self.table_source, columns=columns, sizing_mode="stretch_both") self.ephemerisLayout = column(self.exportRange, self.ephemerisTable, sizing_mode="stretch_width") self.dataTab = Panel(child=self.ephemerisLayout, title="Table") self.kernels = Div() self.kernelTab = Panel(child=self.kernels, title="Kernels") self.tabs = Tabs(tabs=[self.plotTab, self.dataTab, self.kernelTab]) # init data self.model.value = "The Solar System" self.update_model(None, 0, self.model.value) self.update_epochs(None, 0, 0) self.update_states(None, 0, 0) self.model.on_change('value', self.update_model) self.frames.on_change('value', self.update_epochs) self.planes.on_change('active', self.update_plot_view) self.center.on_change('value', self.update_epochs) self.target.on_change('value', self.update_epochs) self.offset.on_change('value', self.update_offset) self.epoch.on_change('value', self.update_epochs) self.duration.on_change('value', self.update_epochs) self.interval.on_change('value', self.update_epochs) self.update_button.on_click(self.update_onclick) self.tabs.on_change('active', self.update_button_type) self.inputs = column(self.model, self.frames, self.planes, self.center, self.target, self.epoch, self.duration, self.interval, self.update_button) def get_layout(self): return column(row([self.inputs, self.tabs]), self.infoDiv, sizing_mode='stretch_width') def update_kenerls_tab(self): kernels = self.spice_provider.fetch_kernels() kernel_text = "<h3>Loaded Spice Kernels:</h3>\n" kernel_text += '<table>\n' for k in kernels: kernel_text += f"<tr><td><b>{k[1]}  </b></td><td>{k[0].split('/')[-1]}</td></tr>\n" self.kernels.text = kernel_text + "</table>" def update_model(self, attr, old, new): # disable callbacks self.active = False # update model and load new kernel self.ephemeris_model = self.allowed_models[new]() self.spice_provider.set_meta_kernel(self.ephemeris_model.kernel) self.spice_provider.setSpiceIds(self.ephemeris_model.objects) self.update_kenerls_tab() # set widget values allowed_objects = [ self.spice_provider.fromId(name) for name in self.ephemeris_model.objects ] allowed_frames = self.ephemeris_model.FRAMES allowed_durations = [ str(v) for v in self.ephemeris_model.DURATION_DAYS ] self.target.options = allowed_objects self.center.options = allowed_objects self.frames.options = allowed_frames self.duration.options = allowed_durations self.target.value = self.ephemeris_model.target self.center.value = self.ephemeris_model.center self.frames.value = self.ephemeris_model.frame self.planes.active = self.ephemeris_model.plane self.epoch.value = datetime.strftime(self.ephemeris_model.epoch, "%Y-%m-%d") self.duration.value = str(self.ephemeris_model.duration) self.offset.value = self.ephemeris_model.offset self.offset.end = self.ephemeris_model.duration self.interval.value = self.ephemeris_model.step_size # reinstate callbacks self.active = True # update start and stop epochs and plot self.update_epochs(None, 0, 0) def update_epochs(self, attr, old, new): self.start_epoch = datetime.strptime(self.epoch.value, "%Y-%m-%d") self.stop_epoch = self.start_epoch + \ pd.Timedelta(seconds=(int(float(self.duration.value) * EphemerisApp.to_seconds['Day']))) self.offset.value = 0 self.offset.end = int( float(self.duration.value) * EphemerisApp.to_seconds['Day'] / EphemerisApp.to_seconds[self.interval.value]) self.offset.title = f"{self.interval.value}s Since Epoch" self.exportRange.text = f"Showing epoch range:\t<b>{self.start_epoch} to {self.stop_epoch}</b>" self.update_offset(None, 0, 0) def update_offset(self, attr, old, new): scale_factor = EphemerisApp.to_seconds[self.interval.value] self.current_epoch = self.start_epoch + pd.Timedelta( seconds=(self.offset.value * scale_factor)) if self.playAnimation is None: SpiceProvider.reset_source(self.spice_provider.cum_source) self.update_states(None, 0, 0) def update_ephemeris(self, attr, old, new): self.update_epochs(attr, old, new) self.spice_provider.set_center(self.center.value) self.spice_provider.frame = self.frames.value self.spice_provider.correction = SpiceProvider.CORRECTIONS[ self.vector.value] if self.active: self.spice_provider.fetch_ephemeris_states(self.target.value, self.start_epoch, self.stop_epoch, self.interval.value) def update_states(self, attr, old, new): self.spice_provider.set_center(self.center.value) self.spice_provider.frame = self.frames.value self.spice_provider.correction = SpiceProvider.CORRECTIONS[ self.vector.value] if self.active: self.spice_provider.fetch_target_states( self.ephemeris_model.objects, self.current_epoch, self.target.value) def update_plot_view(self, attr, old, new): self.plot.select_one({"name": self.planes.labels[old]}).visible = False self.plot.select_one({"name": self.planes.labels[new]}).visible = True self.plot.select_one({ "name": self.planes.labels[old] + "Orbit" }).visible = False self.plot.select_one({ "name": self.planes.labels[new] + "Orbit" }).visible = True def animate_update(self): self.offset.value = 0 if self.offset.value > self.offset.end else self.offset.value + 1 if self.offset.value == 0: SpiceProvider.reset_source(self.spice_provider.cum_source) def animate(self, start=True): if self.update_button.label == 'Play' and start: self.update_button.label = 'Pause' self.playAnimation = curdoc().add_periodic_callback( self.animate_update, 50) elif self.playAnimation is not None: self.update_button.label = 'Play' curdoc().remove_periodic_callback(self.playAnimation) self.playAnimation = None def update_onclick(self): if self.tabs.active == 0: self.animate() elif self.tabs.active == 1: self.update_ephemeris(None, 0, 0) elif self.tabs.active == 2: self.update_kenerls_tab() def update_button_type(self, attr, old, new): self.animate(False) if self.tabs.active == 0: self.update_button.label = "Play" else: self.update_button.label = "Update" self.update_ephemeris(None, 0, 0)