def simpleSnr(time, flux, results): """ calculate a simple snr on the planet based on the depth and scatter after you remove the planet model from the data. """ model = BoxLeastSquares(time, flux) fmodel = model.model(time, results[0], results[3], results[1]) flatten = median_subtract(flux - fmodel, 12) noise = np.std(flatten) snr = results[2] / noise return snr
def plot_bls_folds(time,flux,results,ticid, zoom=True): num=4 #max number of possible planet candidates plt.figure(figsize=(8,12)) s=np.std(flux) for i,r in enumerate(results): plt.subplot(num,1,i+1) phase = (time - r[1] + 0.5*r[0]) % r[0] - 0.5*r[0] model = BoxLeastSquares(time,flux) fmodel = model.model(time,results[i,0],results[i,3],results[i,1]) order=np.argsort(phase) plt.plot(phase[order]*24,fmodel[order],'g.-', ms=3) plt.plot(phase*24,flux,'k.',label="TIC %u P=%6.2f d" % (ticid, results[i,0])) #plt.title(str(ticid) + " Per: " + str(results[i,0]) ) if zoom: plt.xlim(-5.7*results[i,3]*24,5.7*results[i,3]*24) plt.ylim(-2.9*r[2], 4*s) plt.legend(fontsize=8)
def _create_interact_ui(doc, minp=minimum_period, maxp=maximum_period, resolution=resolution): """Create BLS interact user interface.""" if minp is None: minp = 0.3 if maxp is None: maxp = (lc.time[-1] - lc.time[0]) / 2 time_format = '' if lc.time_format == 'bkjd': time_format = ' - 2454833 days' if lc.time_format == 'btjd': time_format = ' - 2457000 days' # Some sliders duration_slider = Slider(start=0.01, end=0.5, value=0.05, step=0.01, title="Duration [Days]", width=400) npoints_slider = Slider(start=500, end=10000, value=resolution, step=100, title="BLS Resolution", width=400) # Set up the period values, BLS model and best period period_values = np.logspace(np.log10(minp), np.log10(maxp), npoints_slider.value) period_values = period_values[(period_values > duration_slider.value) & (period_values < maxp)] model = BoxLeastSquares(lc.time, lc.flux) result = model.power(period_values, duration_slider.value) loc = np.argmax(result.power) best_period = result.period[loc] best_t0 = result.transit_time[loc] # Some Buttons double_button = Button(label="Double Period", button_type="danger", width=100) half_button = Button(label="Half Period", button_type="danger", width=100) text_output = Paragraph(text="Period: {} days, T0: {}{}".format( np.round(best_period, 7), np.round(best_t0, 7), time_format), width=350, height=40) # Set up BLS source bls_source = prepare_bls_datasource(result, loc) bls_help_source = prepare_bls_help_source(bls_source, npoints_slider.value) # Set up the model LC mf = model.model(lc.time, best_period, duration_slider.value, best_t0) mf /= np.median(mf) mask = ~(convolve(np.asarray(mf == np.median(mf)), Box1DKernel(2)) > 0.9) model_lc = LightCurve(lc.time[mask], mf[mask]) model_lc = model_lc.append( LightCurve([(lc.time[0] - best_t0) + best_period / 2], [1])) model_lc = model_lc.append( LightCurve([(lc.time[0] - best_t0) + 3 * best_period / 2], [1])) model_lc_source = ColumnDataSource( data=dict(time=np.sort(model_lc.time), flux=model_lc.flux[np.argsort(model_lc.time)])) # Set up the LC nb = int(np.ceil(len(lc.flux) / 5000)) lc_source = prepare_lightcurve_datasource(lc[::nb]) lc_help_source = prepare_lc_help_source(lc) # Set up folded LC nb = int(np.ceil(len(lc.flux) / 10000)) f = lc.fold(best_period, best_t0) f_source = prepare_folded_datasource(f[::nb]) f_help_source = prepare_f_help_source(f) f_model_lc = model_lc.fold(best_period, best_t0) f_model_lc = LightCurve([-0.5], [1]).append(f_model_lc) f_model_lc = f_model_lc.append(LightCurve([0.5], [1])) f_model_lc_source = ColumnDataSource( data=dict(phase=f_model_lc.time, flux=f_model_lc.flux)) def _update_light_curve_plot(event): """If we zoom in on LC plot, update the binning.""" mint, maxt = fig_lc.x_range.start, fig_lc.x_range.end inwindow = (lc.time > mint) & (lc.time < maxt) nb = int(np.ceil(inwindow.sum() / 5000)) temp_lc = lc[inwindow] lc_source.data = { 'time': temp_lc.time[::nb], 'flux': temp_lc.flux[::nb] } def _update_folded_plot(event): loc = np.argmax(bls_source.data['power']) best_period = bls_source.data['period'][loc] best_t0 = bls_source.data['transit_time'][loc] # Otherwise, we can just update the best_period index minphase, maxphase = fig_folded.x_range.start, fig_folded.x_range.end f = lc.fold(best_period, best_t0) inwindow = (f.time > minphase) & (f.time < maxphase) nb = int(np.ceil(inwindow.sum() / 10000)) f_source.data = { 'phase': f[inwindow].time[::nb], 'flux': f[inwindow].flux[::nb] } # Function to update the widget def _update_params(all=False, best_period=None, best_t0=None): if all: # If we're updating everything, recalculate the BLS model minp, maxp = fig_bls.x_range.start, fig_bls.x_range.end period_values = np.logspace(np.log10(minp), np.log10(maxp), npoints_slider.value) ok = (period_values > duration_slider.value) & (period_values < maxp) if ok.sum() == 0: return period_values = period_values[ok] result = model.power(period_values, duration_slider.value) ok = np.isfinite(result['power']) & np.isfinite(result['duration']) &\ np.isfinite(result['transit_time']) & np.isfinite(result['period']) bls_source.data = dict(period=result['period'][ok], power=result['power'][ok], duration=result['duration'][ok], transit_time=result['transit_time'][ok]) loc = np.nanargmax(bls_source.data['power']) best_period = bls_source.data['period'][loc] best_t0 = bls_source.data['transit_time'][loc] minpow, maxpow = bls_source.data['power'].min( ) * 0.95, bls_source.data['power'].max() * 1.05 fig_bls.y_range.start = minpow fig_bls.y_range.end = maxpow # Otherwise, we can just update the best_period index minphase, maxphase = fig_folded.x_range.start, fig_folded.x_range.end f = lc.fold(best_period, best_t0) inwindow = (f.time > minphase) & (f.time < maxphase) nb = int(np.ceil(inwindow.sum() / 10000)) f_source.data = { 'phase': f[inwindow].time[::nb], 'flux': f[inwindow].flux[::nb] } mf = model.model(lc.time, best_period, duration_slider.value, best_t0) mf /= np.median(mf) mask = ~(convolve(np.asarray(mf == np.median(mf)), Box1DKernel(2)) > 0.9) model_lc = LightCurve(lc.time[mask], mf[mask]) model_lc_source.data = { 'time': np.sort(model_lc.time), 'flux': model_lc.flux[np.argsort(model_lc.time)] } f_model_lc = model_lc.fold(best_period, best_t0) f_model_lc = LightCurve([-0.5], [1]).append(f_model_lc) f_model_lc = f_model_lc.append(LightCurve([0.5], [1])) f_model_lc_source.data = { 'phase': f_model_lc.time, 'flux': f_model_lc.flux } vertical_line.update(location=best_period) fig_folded.title.text = 'Period: {} days \t T0: {}{}'.format( np.round(best_period, 7), np.round(best_t0, 7), time_format) text_output.text = "Period: {} days, \t T0: {}{}".format( np.round(best_period, 7), np.round(best_t0, 7), time_format) # Callbacks def _update_upon_period_selection(attr, old, new): """When we select a period we should just update a few things, but we should not recalculate model """ if len(new) > 0: new = new[0] best_period = bls_source.data['period'][new] best_t0 = bls_source.data['transit_time'][new] _update_params(best_period=best_period, best_t0=best_t0) def _update_model_slider(attr, old, new): """If the duration slider is updated, then update the whole model set.""" _update_params(all=True) def _update_model_slider_EVENT(event): """If we update the duration slider, we should update the whole model set. This is the same as the _update_model_slider but it has a different call signature... """ _update_params(all=True) def _double_period_event(): fig_bls.x_range.start *= 2 fig_bls.x_range.end *= 2 _update_params(all=True) def _half_period_event(): fig_bls.x_range.start /= 2 fig_bls.x_range.end /= 2 _update_params(all=True) # Help Hover Call Backs def _update_folded_plot_help_reset(event): f_help_source.data['phase'] = [ (np.max(f.time) - np.min(f.time)) * 0.98 + np.min(f.time) ] f_help_source.data['flux'] = [ (np.max(f.flux) - np.min(f.flux)) * 0.98 + np.min(f.flux) ] def _update_folded_plot_help(event): f_help_source.data['phase'] = [ (fig_folded.x_range.end - fig_folded.x_range.start) * 0.95 + fig_folded.x_range.start ] f_help_source.data['flux'] = [ (fig_folded.y_range.end - fig_folded.y_range.start) * 0.95 + fig_folded.y_range.start ] def _update_lc_plot_help_reset(event): lc_help_source.data['time'] = [ (np.max(lc.time) - np.min(lc.time)) * 0.98 + np.min(lc.time) ] lc_help_source.data['flux'] = [ (np.max(lc.flux) - np.min(lc.flux)) * 0.9 + np.min(lc.flux) ] def _update_lc_plot_help(event): lc_help_source.data['time'] = [ (fig_lc.x_range.end - fig_lc.x_range.start) * 0.95 + fig_lc.x_range.start ] lc_help_source.data['flux'] = [ (fig_lc.y_range.end - fig_lc.y_range.start) * 0.9 + fig_lc.y_range.start ] def _update_bls_plot_help_event(event): bls_help_source.data['period'] = [ bls_source.data['period'][int(npoints_slider.value * 0.95)] ] bls_help_source.data['power'] = [ (np.max(bls_source.data['power']) - np.min(bls_source.data['power'])) * 0.98 + np.min(bls_source.data['power']) ] def _update_bls_plot_help(attr, old, new): bls_help_source.data['period'] = [ bls_source.data['period'][int(npoints_slider.value * 0.95)] ] bls_help_source.data['power'] = [ (np.max(bls_source.data['power']) - np.min(bls_source.data['power'])) * 0.98 + np.min(bls_source.data['power']) ] # Create all the figures. fig_folded = make_folded_figure_elements(f, f_model_lc, f_source, f_model_lc_source, f_help_source) fig_folded.title.text = 'Period: {} days \t T0: {}{}'.format( np.round(best_period, 7), np.round(best_t0, 5), time_format) fig_bls, vertical_line = make_bls_figure_elements( result, bls_source, bls_help_source) fig_lc = make_lightcurve_figure_elements(lc, model_lc, lc_source, model_lc_source, lc_help_source) # Map changes # If we click a new period, update bls_source.selected.on_change('indices', _update_upon_period_selection) # If we change the duration, update everything, including help button for BLS duration_slider.on_change('value', _update_model_slider) duration_slider.on_change('value', _update_bls_plot_help) # If we increase resolution, update everything npoints_slider.on_change('value', _update_model_slider) # Make sure the vertical line always goes to the best period. vertical_line.update(location=best_period) # If we pan in the BLS panel, update everything fig_bls.on_event(PanEnd, _update_model_slider_EVENT) fig_bls.on_event(Reset, _update_model_slider_EVENT) # If we pan in the LC panel, rebin the points fig_lc.on_event(PanEnd, _update_light_curve_plot) fig_lc.on_event(Reset, _update_light_curve_plot) # If we pan in the Folded panel, rebin the points fig_folded.on_event(PanEnd, _update_folded_plot) fig_folded.on_event(Reset, _update_folded_plot) # Deal with help button fig_bls.on_event(PanEnd, _update_bls_plot_help_event) fig_bls.on_event(Reset, _update_bls_plot_help_event) fig_folded.on_event(PanEnd, _update_folded_plot_help) fig_folded.on_event(Reset, _update_folded_plot_help_reset) fig_lc.on_event(PanEnd, _update_lc_plot_help) fig_lc.on_event(Reset, _update_lc_plot_help_reset) # Buttons double_button.on_click(_double_period_event) half_button.on_click(_half_period_event) # Layout the widget doc.add_root( layout([[fig_bls, fig_folded], fig_lc, [ Spacer(width=70), duration_slider, Spacer(width=50), npoints_slider ], [ Spacer(width=70), double_button, Spacer(width=70), half_button, Spacer(width=300), text_output ]]))
def generate_plots_s3(ticid,sector,cam,ccd, \ bls_bucket="tesssearchresults", \ detrend_bucket="tesssearchresults", \ ffilc_bucket="straw-lightcurves", \ outpath="/Users/smullally/TESS/lambdaSearch/strawTests/blsResults/s0001-kdwarf/plots/"): """ Given a TICID, sector, camera, ccd and the bucket locations. generate a one page plot for each signal found by the bls using the information in those files. bls_bucket contains the search results csv file. detrend_bucket contains the detrend fits file. ffi_bucket contains the raw light curve fits files. returns hdus and a dictionary of the csv. """ rootname = "tic%012u_s%04u-%1u-%1u" % (ticid, sector, cam, ccd) path = "tic%012u/" % ticid bls_name = "%s_plsearch.csv" % rootname det_name = "%s_detrend.fits" % rootname lc_name = "%s_stlc.fits" % rootname if detrend_bucket[0] == "/": det_hdu = fits.open(detrend_bucket + path + det_name) bls = np.loadtxt(bls_bucket + path + bls_name, delimiter=',') else: det_hdu = loadFitsFromUri(detrend_bucket, path, det_name) bls = loadCsvFromUri(bls_bucket, path, bls_name) if ffilc_bucket[0] == "/": raw_hdu = fits.open(ffilc_bucket + path + lc_name) else: raw_hdu = loadFitsFromUri(ffilc_bucket, path, lc_name) #Get the number of signals found by the bls. if len(bls.shape) == 1: N = 1 bls = bls.reshape((1, 7)) #print(bls.shape) else: N = bls.shape[0] time_raw = raw_hdu[1].data['TIME'] raw = raw_hdu[1].data['SAP_FLUX'] time_det = det_hdu[1].data['TIME'] detrend = det_hdu[1].data['DETREND_FLUX'] #plt.plot(time_det,detrend,'.') head = raw_hdu[1].header try: ave_im = raw_hdu[2].data except: ave_im = np.zeros((10, 10)) meta = {} meta['sector'] = sector meta['cam'] = cam meta['ccd'] = ccd try: meta['imloc'] = (head['CUBECOL'], head['CUBEROW']) except: meta['imloc'] = (head['APCEN_Y'], head['APCEN_X']) meta['radius'] = head['AP_RAD'] for i in range(N): #print(i) meta['period'] = bls[i, 0] meta['dur'] = bls[i, 3] meta['epoch'] = bls[i, 1] meta['snr'] = bls[i, 4] meta['depth'] = bls[i, 2] meta['ntrans'] = bls[i, 5] meta['id'] = ticid meta['pn'] = i + 1 #print(meta) bls_object = BoxLeastSquares(time_det, detrend) model = bls_object.model(time_det, meta['period'], \ meta['dur'], meta['epoch']) out_name = "%s-%02i_plot.png" % (rootname, meta['pn']) output = outpath + out_name plt.figure(figsize=(10, 12)) report.summaryPlot1(time_raw, raw, time_det, detrend, model, ave_im, meta) plt.savefig(output) print(output)
def _create_interact_ui(doc, minp=minimum_period, maxp=maximum_period, resolution=resolution): """Create BLS interact user interface.""" if minp is None: minp = 0.3 if maxp is None: maxp = (lc.time[-1].value - lc.time[0].value) / 2 # TODO: consider to accept Time as minp / maxp, and convert it to unitless days time_format = "" if lc.time.format == "bkjd": time_format = " - 2454833 days" if lc.time.format == "btjd": time_format = " - 2457000 days" # Some sliders duration_slider = Slider( start=0.01, end=0.5, value=0.05, step=0.01, title="Duration [Days]", width=400, ) npoints_slider = Slider( start=500, end=10000, value=resolution, step=100, title="BLS Resolution", width=400, ) # Set up the period values, BLS model and best period period_values = np.logspace(np.log10(minp), np.log10(maxp), npoints_slider.value) period_values = period_values[(period_values > duration_slider.value) & (period_values < maxp)] model = BoxLeastSquares(lc.time, lc.flux) result = model.power(period_values, duration_slider.value) loc = np.argmax(result.power) best_period = result.period[loc] best_t0 = result.transit_time[loc] # Some Buttons double_button = Button(label="Double Period", button_type="danger", width=100) half_button = Button(label="Half Period", button_type="danger", width=100) text_output = Paragraph( text="Period: {} days, T0: {}{}".format( _round_strip_unit(best_period, 7), _round_strip_unit(best_t0, 7), time_format, ), width=350, height=40, ) # Set up BLS source bls_source = prepare_bls_datasource(result, loc) bls_source_units = dict( transit_time_format=result["transit_time"].format, transit_time_scale=result["transit_time"].scale, period=result["period"].unit, ) bls_help_source = prepare_bls_help_source(bls_source, npoints_slider.value) # Set up the model LC mf = model.model(lc.time, best_period, duration_slider.value, best_t0) mf /= np.median(mf) mask = ~(convolve(np.asarray(mf == np.median(mf)), Box1DKernel(2)) > 0.9) model_lc = _to_lc(lc.time[mask], mf[mask]) model_lc_source = _to_ColumnDataSource( data=dict(time=model_lc.time, flux=model_lc.flux)) # Set up the LC nb = int(np.ceil(len(lc.flux) / 5000)) lc_source = prepare_lightcurve_datasource(lc[::nb]) lc_help_source = prepare_lc_help_source(lc) # Set up folded LC nb = int(np.ceil(len(lc.flux) / 10000)) f = lc.fold(best_period, best_t0) f_source = prepare_folded_datasource(f[::nb]) f_help_source = prepare_f_help_source(f) f_model_lc = model_lc.fold(best_period, best_t0) f_model_lc = _to_lc(_as_1d(f.time.min()), [1]).append(f_model_lc) f_model_lc = f_model_lc.append(_to_lc(_as_1d(f.time.max()), [1])) f_model_lc_source = _to_ColumnDataSource( data=dict(phase=f_model_lc.time, flux=f_model_lc.flux)) def _update_light_curve_plot(event): """If we zoom in on LC plot, update the binning.""" mint, maxt = fig_lc.x_range.start, fig_lc.x_range.end inwindow = (lc.time.value > mint) & (lc.time.value < maxt) nb = int(np.ceil(inwindow.sum() / 5000)) temp_lc = lc[inwindow] _update_source(lc_source, { "time": temp_lc.time[::nb], "flux": temp_lc.flux[::nb] }) def _update_folded_plot(event): loc = np.argmax(bls_source.data["power"]) best_period = bls_source.data["period"][loc] best_t0 = bls_source.data["transit_time"][loc] # Otherwise, we can just update the best_period index minphase, maxphase = fig_folded.x_range.start, fig_folded.x_range.end f = lc.fold(best_period, best_t0) inwindow = (f.time > minphase) & (f.time < maxphase) nb = int(np.ceil(inwindow.sum() / 10000)) _update_source( f_source, { "phase": f[inwindow].time[::nb], "flux": f[inwindow].flux[::nb] }, ) # Function to update the widget def _update_params(all=False, best_period=None, best_t0=None): if all: # If we're updating everything, recalculate the BLS model minp, maxp = fig_bls.x_range.start, fig_bls.x_range.end period_values = np.logspace(np.log10(minp), np.log10(maxp), npoints_slider.value) ok = (period_values > duration_slider.value) & (period_values < maxp) if ok.sum() == 0: return period_values = period_values[ok] result = model.power(period_values, duration_slider.value) ok = (_isfinite(result["power"]) & _isfinite(result["duration"]) & _isfinite(result["transit_time"]) & _isfinite(result["period"])) ok_result = dict( period=result["period"] [ok], # useful for accessing values with units needed later power=result["power"][ok], duration=result["duration"][ok], transit_time=result["transit_time"][ok], ) _update_source(bls_source, ok_result) loc = np.nanargmax(ok_result["power"]) best_period = ok_result["period"][loc] best_t0 = ok_result["transit_time"][loc] minpow, maxpow = ( bls_source.data["power"].min() * 0.95, bls_source.data["power"].max() * 1.05, ) fig_bls.y_range.start = minpow fig_bls.y_range.end = maxpow # Otherwise, we can just update the best_period index minphase, maxphase = fig_folded.x_range.start, fig_folded.x_range.end f = lc.fold(best_period, best_t0) inwindow = (f.time > minphase) & (f.time < maxphase) nb = int(np.ceil(inwindow.sum() / 10000)) _update_source( f_source, { "phase": f[inwindow].time[::nb], "flux": f[inwindow].flux[::nb] }, ) mf = model.model(lc.time, best_period, duration_slider.value, best_t0) mf /= np.median(mf) mask = ~(convolve(np.asarray(mf == np.median(mf)), Box1DKernel(2)) > 0.9) model_lc = _to_lc(lc.time[mask], mf[mask]) _update_source(model_lc_source, { "time": model_lc.time, "flux": model_lc.flux }) f_model_lc = model_lc.fold(best_period, best_t0) f_model_lc = _to_lc(_as_1d(f.time.min()), [1]).append(f_model_lc) f_model_lc = f_model_lc.append(_to_lc(_as_1d(f.time.max()), [1])) _update_source(f_model_lc_source, { "phase": f_model_lc.time, "flux": f_model_lc.flux }) vertical_line.update(location=best_period.value) fig_folded.title.text = "Period: {} days \t T0: {}{}".format( _round_strip_unit(best_period, 7), _round_strip_unit(best_t0, 7), time_format, ) text_output.text = "Period: {} days, \t T0: {}{}".format( _round_strip_unit(best_period, 7), _round_strip_unit(best_t0, 7), time_format, ) # Callbacks def _update_upon_period_selection(attr, old, new): """When we select a period we should just update a few things, but we should not recalculate model""" if len(new) > 0: new = new[0] best_period = (bls_source.data["period"][new] * bls_source_units["period"]) best_t0 = Time( bls_source.data["transit_time"][new], format=bls_source_units["transit_time_format"], scale=bls_source_units["transit_time_scale"], ) _update_params(best_period=best_period, best_t0=best_t0) def _update_model_slider(attr, old, new): """If the duration slider is updated, then update the whole model set.""" _update_params(all=True) def _update_model_slider_EVENT(event): """If we update the duration slider, we should update the whole model set. This is the same as the _update_model_slider but it has a different call signature... """ _update_params(all=True) def _double_period_event(): fig_bls.x_range.start *= 2 fig_bls.x_range.end *= 2 _update_params(all=True) def _half_period_event(): fig_bls.x_range.start /= 2 fig_bls.x_range.end /= 2 _update_params(all=True) # Help Hover Call Backs def _update_folded_plot_help_reset(event): f_help_source.data["phase"] = [_at_ratio(f.time, 0.95)] f_help_source.data["flux"] = [_at_ratio(f.flux, 0.95)] def _update_folded_plot_help(event): f_help_source.data["phase"] = [_at_ratio(fig_folded.x_range, 0.95)] f_help_source.data["flux"] = [_at_ratio(fig_folded.y_range, 0.95)] def _update_lc_plot_help_reset(event): lc_help_source.data["time"] = [_at_ratio(lc.time, 0.98)] lc_help_source.data["flux"] = [_at_ratio(lc.flux, 0.95)] def _update_lc_plot_help(event): lc_help_source.data["time"] = [_at_ratio(fig_lc.x_range, 0.98)] lc_help_source.data["flux"] = [_at_ratio(fig_lc.y_range, 0.95)] def _update_bls_plot_help_event(event): # cannot use _at_ratio helper for period, because period is log scaled. bls_help_source.data["period"] = [ bls_source.data["period"][int(npoints_slider.value * 0.95)] ] bls_help_source.data["power"] = [ _at_ratio(bls_source.data["power"], 0.98) ] def _update_bls_plot_help(attr, old, new): bls_help_source.data["period"] = [ bls_source.data["period"][int(npoints_slider.value * 0.95)] ] bls_help_source.data["power"] = [ _at_ratio(bls_source.data["power"], 0.98) ] # Create all the figures. fig_folded = make_folded_figure_elements(f, f_model_lc, f_source, f_model_lc_source, f_help_source) fig_folded.title.text = "Period: {} days \t T0: {}{}".format( _round_strip_unit(best_period, 7), _round_strip_unit(best_t0, 5), time_format, ) fig_bls, vertical_line = make_bls_figure_elements( result, bls_source, bls_help_source) fig_lc = make_lightcurve_figure_elements(lc, model_lc, lc_source, model_lc_source, lc_help_source) # Map changes # If we click a new period, update bls_source.selected.on_change("indices", _update_upon_period_selection) # If we change the duration, update everything, including help button for BLS duration_slider.on_change("value", _update_model_slider) duration_slider.on_change("value", _update_bls_plot_help) # If we increase resolution, update everything npoints_slider.on_change("value", _update_model_slider) # Make sure the vertical line always goes to the best period. vertical_line.update(location=best_period.value) # If we pan in the BLS panel, update everything fig_bls.on_event(PanEnd, _update_model_slider_EVENT) fig_bls.on_event(Reset, _update_model_slider_EVENT) # If we pan in the LC panel, rebin the points fig_lc.on_event(PanEnd, _update_light_curve_plot) fig_lc.on_event(Reset, _update_light_curve_plot) # If we pan in the Folded panel, rebin the points fig_folded.on_event(PanEnd, _update_folded_plot) fig_folded.on_event(Reset, _update_folded_plot) # Deal with help button fig_bls.on_event(PanEnd, _update_bls_plot_help_event) fig_bls.on_event(Reset, _update_bls_plot_help_event) fig_folded.on_event(PanEnd, _update_folded_plot_help) fig_folded.on_event(Reset, _update_folded_plot_help_reset) fig_lc.on_event(PanEnd, _update_lc_plot_help) fig_lc.on_event(Reset, _update_lc_plot_help_reset) # Buttons double_button.on_click(_double_period_event) half_button.on_click(_half_period_event) # Layout the widget doc.add_root( layout([ [fig_bls, fig_folded], fig_lc, [ Spacer(width=70), duration_slider, Spacer(width=50), npoints_slider, ], [ Spacer(width=70), double_button, Spacer(width=70), half_button, Spacer(width=300), text_output, ], ]))