class widgets_sample(object): def __init__(self): self.fig, ax = plt.subplots() plt.subplots_adjust(left=0.25, bottom=0.25) self.t = np.arange(0.0, 1.0, 0.001) a0 = 5 f0 = 3 s = a0 * np.sin(2 * np.pi * f0 * self.t) self.l, = plt.plot(self.t, s, lw=2, color='red') plt.axis([0, 1, -10, 10]) axcolor = 'lightgoldenrodyellow' axfreq = plt.axes([0.25, 0.1, 0.65, 0.03], facecolor=axcolor) axamp = plt.axes([0.25, 0.15, 0.65, 0.03], facecolor=axcolor) self.sfreq = Slider(axfreq, 'Freq', 0.1, 30.0, valinit=f0) self.samp = Slider(axamp, 'Amp', 0.1, 10.0, valinit=a0) self.sfreq.on_changed(self.update) self.samp.on_changed(self.update) resetax = plt.axes([0.8, 0.025, 0.1, 0.04]) self.button = Button(resetax, 'Reset', color=axcolor, hovercolor='0.975') self.button.on_clicked(self.reset) rax = plt.axes([0.025, 0.5, 0.15, 0.15], facecolor=axcolor) self.radio = RadioButtons(rax, ('red', 'blue', 'green', 'orange', 'gray'), active=0) self.radio.on_clicked(self.colorfunc) plt.show() def update(self, val): amp = self.samp.val freq = self.sfreq.val self.l.set_ydata(amp * np.sin(2 * np.pi * freq * self.t)) self.fig.canvas.draw_idle() def reset(self, event): self.sfreq.reset() self.samp.reset() def colorfunc(self, label): self.l.set_color(label) self.fig.canvas.draw_idle()
class WaveCal_st(): def __init__(self, ObsFilename=None, ModelFilename=None, wave_min=None, wave_max=None, cull=50, am=1.0, H2O_scale=1.0, CO_scale=1.0, CH4_scale=1.0, CO2_scale=1.0, vrad=0.0, vbary=0.0): ## SETUP MODEL ATMOSPHERE ## Envi = rfm.Environment() A = rfm.Atmosphere(filename=Envi.atm_file) A.scaleProf('H2O', H2O_scale) A.scaleProf('CO', CO_scale) A.scaleProf('CH4', CH4_scale) A.scaleProf('CO2', CO2_scale) A.writeAll('tmp.atm') self.A = A M = Model() M.RFM(atm_files=['tmp.atm'], wmin=1e4 / wave_max, wmax=1e4 / wave_min, am=am) M.blur(rpower=25000.) self.M = M ## GET MODEL SKY SPECTRUM ## ModInfo = M.getSpec() self.WaveMod = ModInfo['wavelength'] self.SkyRadMod = ModInfo['Radiance'] / np.amax(ModInfo['Radiance']) self.SkyRadMod = 1 - self.SkyRadMod scale = np.amax(self.SkyRadMod) ## GET MODEL STELLAR SPECTRUM ## a = np.loadtxt(ModelFilename, skiprows=1) StellWL, StellFlux = 1e4 / a[:, 0], a[:, 1] #plt.plot(StellWL,StellFlux) if np.all(np.diff(StellWL) > 0) != True: StellWL = np.flip(StellWL, 0) StellFlux = np.flip(StellFlux, 0) ## BROADEN STELLAR SPECTRUM ## StellFlux_Broad = self.blur_function(StellWL, StellFlux, 25000.) #print StellFlux_Broad #plt.plot(StellWL,StellFlux_Broad) #plt.show() ## SHIFT STELLAR SPECTRUM ## StellWave_Shift = self.shift_wavelength(StellWL, vrad - vbary) print StellWL print StellWave_Shift ## INTERPOLATE STELLAR SPECTRUM ONTO COMMON WAVELENGTH GRID ## self.StellFlux_Interp = np.interp(self.WaveMod, StellWave_Shift, StellFlux_Broad) ## COMBINE STELLAR AND TELLURIC SPECTRA ## assert (np.shape(self.StellFlux_Interp) == np.shape(self.SkyRadMod)) self.StellFlux_Interp = self.StellFlux_Interp / np.median( self.StellFlux_Interp) self.SkyRadMod = self.SkyRadMod / np.median(self.SkyRadMod) self.ModSpec = 1.0 * self.StellFlux_Interp + 1.0 * self.SkyRadMod ####change these to change ratios - SkyRadMod = telluric self.ModSpec = self.ModSpec / np.median(self.ModSpec) ## colors combined model to show tell vs stell contributions self.color = self.colorinmodel(self.StellFlux_Interp, self.SkyRadMod) #plt.figure() #plt.plot(self.WaveMod, self.StellFlux_Interp, label='stell') #plt.plot(self.WaveMod, self.SkyRadMod, label='tell') #plt.plot(self.WaveMod, self.ModSpec, label='stell+tell') #self.plot_multicolored_lines(self.WaveMod, self.ModSpec,self.color,label='stell(c)+tell(k)') #plt.legend(loc=0) ## GET OBSERVED SKY ## ObsInfo = nt.WaveOrder(ObsFilename).getData() WaveObsPos = np.array(ObsInfo['wl_pos']) # SkyObsPos = np.array(ObsInfo['sky_pos']) / np.median(ObsInfo['sky_pos']) # L BAND SkyObsPos = np.array(ObsInfo['flux_pos']) / np.median( ObsInfo['flux_pos']) # K BAND WaveObsNeg = np.array(ObsInfo['wl_neg']) # SkyObsNeg = np.array(ObsInfo['sky_neg']) / np.median(ObsInfo['sky_neg']) # L BAND SkyObsNeg = np.array(ObsInfo['flux_neg']) / np.median( ObsInfo['flux_neg']) # K BAND ## FIT OUT CONTINUUM ## (DP 21 JAN 16) wn_data_all = [WaveObsPos, WaveObsNeg] flux_data_all = [SkyObsPos, SkyObsNeg] merp = 16 #64 ##32 #16 factor = 64 #16 #32# 64 posneg = 0 baseline_pos, baseline_neg = np.ones(np.size(WaveObsPos)), np.ones( np.size(WaveObsNeg)) # SkyObsPos_contrmv, SkyObsNeg_contrmv = np.array(np.size(SkyObsPos)), np.array(np.size(SkyObsNeg)) for wn_data, flux_data in zip(wn_data_all, flux_data_all): points_flux, points_wn, points_count = np.zeros(merp), np.zeros( merp), np.arange(merp) for count in points_count: startpoint = count * factor endpoint = (count + 1) * factor if count == 0: startpoint = 14 if count == 15: endpoint = 1024 - 30 # if count==63 : endpoint = 1024-14 points_flux[count] = np.max(flux_data[startpoint:endpoint]) loc = np.argmax(flux_data[startpoint:endpoint]) # points_wn[count]=wn_data[loc+startpoint] points_wn[count] = loc + startpoint coeff = np.polyfit(points_wn, points_flux, 2) # coeff = np.polyfit(points_wn, points_flux, 4) print coeff # if posneg == 0 : baseline_pos = coeff[1] + coeff[0]*wn_data# + coeff[1]*wn_data**2 + coeff[0]*wn_data**3 # if posneg == 1 : baseline_neg = coeff[1] + coeff[0]*wn_data# + coeff[1]*wn_data**2 + coeff[0]*wn_data**3 if posneg == 0: baseline_pos = coeff[2] + coeff[1] * np.arange(1024) + coeff[ 0] * np.arange(1024)**2 # + coeff[0]*np.arange(1024)**3 if posneg == 1: baseline_neg = coeff[2] + coeff[1] * np.arange(1024) + coeff[ 0] * np.arange(1024)**2 # + coeff[0]*np.arange(1024)**3 # if posneg == 0 : baseline_pos = coeff[4] + coeff[3]*np.arange(1024) + coeff[2]*np.arange(1024)**2 + coeff[1]*np.arange(1024)**3 + coeff[0]*np.arange(1024)**4# + coeff[0]*np.arange(1024)**3 # if posneg == 1 : baseline_neg = coeff[4] + coeff[3]*np.arange(1024) + coeff[2]*np.arange(1024)**2 + coeff[1]*np.arange(1024)**3 + coeff[0]*np.arange(1024)**4# + coeff[0]*np.arange(1024)**3 posneg += 1 SkyObsPos_contrmv, SkyObsNeg_contrmv = SkyObsPos / baseline_pos, SkyObsNeg / baseline_neg self.ModSpec = 1 - self.ModSpec #plt.figure() #plt.plot(SkyObsPos, hold=True) #plt.plot(baseline_pos, hold=True) #plt.show() #plt.figure() #plt.plot(SkyObsNeg, hold=True) #plt.plot(baseline_neg, hold=True) #plt.show() self.ObsLabelPN = ['pos', 'neg'] ### break spec into 4 pieces #fourth = int(len(WaveObsPos)/4) #Wavepos = [] #Waveneg = [] #for val in range(fourth): # Wavepos.append(WaveObsPos[val]) # Waveneg.append(WaveObsNeg[val]) self.WaveObsPN = [WaveObsPos, WaveObsNeg] SkyObsPos_contrmv_scaled = (1 - SkyObsPos_contrmv) SkyObsNeg_contrmv_scaled = (1 - SkyObsNeg_contrmv) self.Pixels = [np.arange(len(WaveObsPos)), np.arange(len(WaveObsNeg))] self.SkyObsPN_orig = [SkyObsPos, SkyObsNeg] self.SkyObsPN = [SkyObsPos_contrmv_scaled, SkyObsNeg_contrmv_scaled] self.Coefs, self.WaveObsPN = self.FitInitDS(self.WaveObsPN, self.ObsLabelPN) secs = ['one', 'two', 'three', 'four'] for self.sec in secs: #self.sec = 'full' ### this causes it to run full spec, not in quarters print "======================" print 'QUARTER', self.sec print "======================" self.GoodFit = [False, False] self.modflux, newfl_obs = self.comparemodelanddata( self.WaveMod, self.ModSpec, self.WaveObsPN[0], self.SkyObsPN[0]) self.modellength = len(self.modflux) while (True): RawInput = raw_input('>> ').replace(" ", "").lower() if (RawInput == 'quit'): break if (RawInput == 'pos'): while (True): try: RawInput2 = raw_input( "Pos. Coefficients?: ").split(",") self.Coefs[0] = np.array(RawInput2, dtype=np.float) if self.sec == 'full': self.WaveObsPN[0] = self.DSFunc( self.Pixels[0], self.Coefs[0]) self.PlotModObs(self.WaveMod, self.modflux, self.WaveObsPN[0], newfl_obs, self.ObsLabelPN[0]) else: if len(self.modflux) == self.modellength: wvm, fm = self.Breakintofour_better( self.WaveMod, self.modflux, section=self.sec) pixels_quarter = np.arange(256) ### 1024/4 else: wvm = self.Breakintofour_better( self.WaveMod, section=self.sec) fm = self.modflux.copy() pixels_quarter = np.arange(256) fo = self.Breakintofour_better( newfl_obs, section=self.sec) wvo = self.DSFunc(pixels_quarter, self.Coefs[0]) self.PlotModObs(wvm, fm, wvo, fo, self.ObsLabelPN[0]) break except: print "Fix typo" pass if (RawInput == 'neg'): while (True): try: RawInput2 = raw_input( "Neg. Coefficients?: ").split(",") self.Coefs[1] = np.array(RawInput2, dtype=np.float) #modflux, newfl_obs = self.comparemodelanddata(self.WaveMod, self.ModSpec, self.WaveObsPN[1], self.SkyObsPN[1]) if self.sec == 'full': self.WaveObsPN[1] = self.DSFunc( self.Pixels[1], self.Coefs[1]) self.PlotModObs(self.WaveMod, self.modflux, self.WaveObsPN[1], newfl_obs, self.ObsLabelPN[1]) else: if len(self.modflux) == self.modellength: wvm, fm = self.Breakintofour_better( self.WaveMod, self.modflux, section=self.sec) pixels_quarter = np.arange(256) else: wvm = self.Breakintofour_better( self.WaveMod, section=self.sec) fm = self.modflux.copy() pixels_quarter = np.arange(256) fo = self.Breakintofour_better( newfl_obs, section=self.sec) wvo = self.DSFunc(pixels_quarter, self.Coefs[1]) self.PlotModObs(wvm, fm, wvo, fo, self.ObsLabelPN[1]) break except: print "Fix typo" pass if (RawInput == 'fit'): for i in range(0, len(self.Coefs)): if (self.GoodFit[i] != True): if self.sec == 'full': #newfl_obs[632:650] = np.nan ### takes out unassigned absorption #newfl_obs[-30:] = np.nan ## takes off mess at end self.Coefs[i], self.WaveObsPN[i] = self.FitDS( self.WaveMod, self.modflux, newfl_obs, self.Coefs[i]) self.PlotModObs(self.WaveMod, self.modflux, self.WaveObsPN[i], newfl_obs, self.ObsLabelPN[i]) else: if len(self.modflux) == self.modellength: wvm, fm = self.Breakintofour_better( self.WaveMod, self.modflux, section=self.sec) else: wvm = self.Breakintofour_better( self.WaveMod, section=self.sec) fm = self.modflux.copy() if len(self.WaveObsPN[i]) == 1024: wvo, fo = self.Breakintofour_better( self.WaveObsPN[i], newfl_obs, section=self.sec) else: fo = self.Breakintofour_better( newfl_obs, section=self.sec) wvo = self.WaveObsPN[i].copy() ### cut off edge: [-10:] = last 10 points are nan #fo[-15:] = np.nan #fo[:10] = np.nan self.Coefs[i], self.WaveObsPN[i] = self.FitDS( wvm, fm, fo, self.Coefs[i]) self.PlotModObs(wvm, fm, self.WaveObsPN[i], fo, self.ObsLabelPN[i]) RawInput2 = raw_input( "Good Fit? (yes/no): ").replace(" ", "").lower() while (True): if (RawInput2 == 'yes'): self.GoodFit[i] = True break if (RawInput2 == 'no'): break else: print "Please type yes or no." break else: print '' print '## Dispersion Solution for ' + self.ObsLabelPN[ i] + ' position is good.' if (RawInput == 'pf'): self.PrintCoefs() if self.sec == 'full': break def find_contiguous_colors(self, colors): # finds the continuous segments of colors and returns those segments segs = [] curr_seg = [] prev_color = '' for c in colors: if c == prev_color or prev_color == '': curr_seg.append(c) else: segs.append(curr_seg) curr_seg = [] curr_seg.append(c) prev_color = c segs.append(curr_seg) # the final one return segs def plot_multicolored_lines(self, x, y, colors, label=None): segments = self.find_contiguous_colors(colors) #plt.figure() start = 0 for num, seg in enumerate(segments): if num == 0: end = start + len(seg) l, = plt.gca().plot(x[start:end], y[start:end], c=seg[0], label=label) start = end else: end = start + len(seg) l, = plt.gca().plot(x[start:end], y[start:end], c=seg[0]) start = end def colorinmodel(self, stellflux, tellflux): color = [] for i, j in zip(stellflux, tellflux): if j < i: ##tell color.append('k') else: color.append('c') return color def comparemodelanddata(self, modelwave, modelflux, obswave, obsflux): ## normalizes the model and data so they're on about the same scale fl_mod = [] fl_obs = [] if np.nanmax(modelflux) > np.nanmax(obsflux): for a in modelflux: fl_mod.append(a / list(modelflux)[np.argmax(obsflux)]) for b in obsflux: fl_obs.append(b / np.nanmax(obsflux)) elif np.nanmax(modelflux) < np.nanmax(obsflux): wave_max = modelwave[np.argmax(modelflux)] for num, x in enumerate(obswave): if x > wave_max - 0.05 and x < wave_max + 0.05: index = num break else: index = 0 ### to find index of second largest flux in obs flux arr = np.array(obsflux) secondlargest = arr.argsort()[-5:][ 0] ## make number bigger to pick smaller flux index for a in modelflux: fl_mod.append(a / np.nanmax(modelflux)) for b in obsflux: #fl_obs.append((b/list(obsflux)[index])-0.05) #fl_obs.append((b/np.nanmax(obsflux))-0.05) fl_obs.append((b / list(obsflux)[secondlargest])) #-0.05) fl_mod = np.array(fl_mod) fl_obs = np.array(fl_obs) return fl_mod, fl_obs def Breakintofour_better(self, wave, flux=None, section='one'): num = len(wave) try: if section == 'one': new_wave = wave[0:int(num / 4.0)] new_flux = flux[0:int(num / 4.0)] elif section == 'two': new_wave = wave[int(num / 4.0):int(2.0 * num / 4.0)] new_flux = flux[int(num / 4.0):int(2.0 * num / 4.0)] elif section == 'three': new_wave = wave[int(2.0 * num / 4.0):int(3.0 * num / 4.0)] new_flux = flux[int(2.0 * num / 4.0):int(3.0 * num / 4.0)] elif section == 'four': new_wave = wave[int(3.0 * num / 4.0):int(4.0 * num / 4.0)] new_flux = flux[int(3.0 * num / 4.0):int(4.0 * num / 4.0)] except: if section == 'one': new_wave = wave[0:int(num / 4.0)] elif section == 'two': new_wave = wave[int(num / 4.0):int(2.0 * num / 4.0)] elif section == 'three': new_wave = wave[int(2.0 * num / 4.0):int(3.0 * num / 4.0)] elif section == 'four': new_wave = wave[int(3.0 * num / 4.0):int(4.0 * num / 4.0)] if not np.any(flux): return new_wave else: return new_wave, new_flux def Breakintofour(self, modelwave, modelflux, obswave, obsflux, section='one'): mod_num = len(modelwave) obs_num = len(obswave) if section == 'one': new_modwave = modelwave[0:int(mod_num / 4.0)] new_modflux = modelflux[0:int(mod_num / 4.0)] new_obswave = obswave[0:int(obs_num / 4.0)] new_obsflux = obsflux[0:int(obs_num / 4.0)] elif section == 'two': new_modwave = modelwave[int(mod_num / 4.0):int(2.0 * mod_num / 4.0)] new_modflux = modelflux[int(mod_num / 4.0):int(2.0 * mod_num / 4.0)] new_obswave = obswave[int(obs_num / 4.0):int(2.0 * obs_num / 4.0)] new_obsflux = obsflux[int(obs_num / 4.0):int(2.0 * obs_num / 4.0)] elif section == 'three': new_modwave = modelwave[int(2.0 * mod_num / 4.0):int(3.0 * mod_num / 4.0)] new_modflux = modelflux[int(2.0 * mod_num / 4.0):int(3.0 * mod_num / 4.0)] new_obswave = obswave[int(2.0 * obs_num / 4.0):int(3.0 * obs_num / 4.0)] new_obsflux = obsflux[int(2.0 * obs_num / 4.0):int(3.0 * obs_num / 4.0)] elif section == 'four': new_modwave = modelwave[int(3.0 * mod_num / 4.0):int(4.0 * mod_num / 4.0)] new_modflux = modelflux[int(3.0 * mod_num / 4.0):int(4.0 * mod_num / 4.0)] new_obswave = obswave[int(3.0 * obs_num / 4.0):int(4.0 * obs_num / 4.0)] new_obsflux = obsflux[int(3.0 * obs_num / 4.0):int(4.0 * obs_num / 4.0)] return new_modwave, new_modflux, new_obswave, new_obsflux def PrintCoefs(self): Clab = ['A = ', 'B = ', 'C = ', 'D = ', 'E = '] for coef, label, goodf in zip(self.Coefs, self.ObsLabelPN, self.GoodFit): print '' print 'Position = ', label print 'Good Fit = ', goodf print '-------------------' for i in range(0, len(coef)): print Clab[i], coef[i] print '' print "{}, {}, {}, {}, {}".format(coef[0], coef[1], coef[2], coef[3], coef[4]) print '' def ReadAux(self, FileName): ''' Reads in auxillary data files from Terraspec or another source. ''' FileInfo = np.loadtxt(FileName, skiprows=1, dtype='float') wn = FileInfo[:, 0] flux = FileInfo[:, 1] wl = 1.0e4 / wn if np.size(wl) > 1024: sec_out = np.where((wl >= self.WaveMin) & (wl <= self.WaveMax)) wl_out = wl[sec_out] flux_out = flux[sec_out] else: wl_out = wl flux_out = flux return wl_out, flux_out def PlotModObs(self, wave_mod, flux_mod, wave_obs, flux_obs, label, block=False): plt.close() ''' plt.figure(figsize=(20, 10)) #plt.plot(wave_mod, flux_mod, color='blue') self.plot_multicolored_lines(wave_mod,flux_mod,self.color) ### this tells stel (c) vs tel (k) lines #plt.plot(wave_obs, flux_obs, color='red') x1,x2,y1,y2 = plt.axis() plt.axis((x1, x2, np.amin([np.amin(flux_mod), np.amin(flux_obs)])-0.15, np.amax(flux_mod))) plt.title(label) ''' plt.figure(figsize=(20, 10)) self.l, = plt.plot(wave_mod, flux_mod, color='blue') #self.plot_multicolored_lines(wave_mod,flux_mod,self.color) ### this tells stel vs tel lines plt.plot(wave_obs, flux_obs, color='red') x1, x2, y1, y2 = plt.axis() plt.axis((x1, x2, np.nanmin([np.nanmin(flux_mod), np.nanmin(flux_obs)]) - 0.15, np.nanmax([np.amax(flux_mod), 1.0]))) plt.title(label) axstell = plt.axes([0.25, 0.1, 0.55, 0.03]) axtell = plt.axes([0.25, 0.15, 0.55, 0.03]) try: s0 = self.stell_val t0 = self.tell_val except AttributeError: s0 = 1 t0 = 1 self.s_stell = Slider(axstell, 'Stellar', 0.0, 10.0, valinit=s0) self.s_tell = Slider(axtell, 'Telluric', 0.0, 10.0, valinit=t0) saveax = plt.axes([0.55, 0.025, 0.1, 0.04]) button = Button(saveax, 'Save Values', hovercolor='0.975') self.s_stell.on_changed(self.update) self.s_tell.on_changed(self.update) button.on_clicked(self.save_ratios) resetax = plt.axes([0.35, 0.025, 0.1, 0.04]) button2 = Button(resetax, 'Reset', hovercolor='0.975') button2.on_clicked(self.reset) plt.show() #plt.savefig('/home/cbuzard/Desktop/temp.pdf') def save_ratios(self, event): self.stell_val = self.stell self.tell_val = self.tell print self.stell_val, self.tell_val self.modflux = self.modspec.copy( ) ### should update model to have ratios you pick everywhere def reset(self, event): self.s_stell.reset() self.s_tell.reset() def update(self, val): self.stell = self.s_stell.val self.tell = self.s_tell.val if self.sec == 'full': modspec = self.stell * self.StellFlux_Interp + self.tell * self.SkyRadMod else: stellflux, skyradmod = self.Breakintofour_better( self.StellFlux_Interp, self.SkyRadMod, section=self.sec) modspec = self.stell * stellflux + self.tell * skyradmod modspec = modspec / np.median(modspec) self.modspec = 1 - modspec self.l.set_ydata(self.modspec) def FitInitDS(self, WaveLengths, Labels): porder = 1 Coefs, WaveLengths_fit = [], [] print 'Initial Coefficients' print '====================' for wl, label in zip(WaveLengths, Labels): pixels = np.arange(len(wl)) coef = np.polyfit(pixels, wl, porder)[::-1] wl_fit = self.DSFunc(pixels, coef) print '# ' + label + ' #' print '---------------' for i in range(0, porder + 1): print i, coef[i] print '' plt.plot(pixels, wl, 'ko') plt.plot(pixels, wl_fit) plt.show() Coefs.append(coef) WaveLengths_fit.append(wl_fit) return Coefs, WaveLengths_fit def DSFunc(self, pixels, Coefs): WaveOut = np.zeros(len(pixels)) for i in range(0, len(Coefs)): if i <= 1: WaveOut = WaveOut + Coefs[i] * (pixels)**i else: WaveOut = WaveOut + Coefs[i] * (pixels / 1000.)**i return WaveOut def residual(self, params, flux_data, wl_model, flux_model): npix = len(flux_data) pixels = np.arange(npix) #if self.sec != 'full': # pixels = self.Breakintofour_better(pixels,section=self.sec) Coefs = [ params['A'].value, params['B'].value, params['C'].value, params['D'].value, params['E'].value ] #, params['F'].value] wl_fit = self.DSFunc(pixels, Coefs) flux_model_fit = np.interp(wl_fit, wl_model, flux_model, left=flux_model[0], right=flux_model[-1]) index_use = np.where(flux_data > 0.005) residual = np.subtract(flux_model_fit[index_use], flux_data[index_use]) return (residual) def FitDS(self, WLmod, Fmod, Fobs, CoefsInit): params = Parameters() params.add('A', value=CoefsInit[0], vary=True, min=CoefsInit[0] - 0.05, max=CoefsInit[0] + 0.05) params.add('B', value=CoefsInit[1], vary=True) params.add('C', value=1e-5, vary=True) params.add('D', value=1e-6, vary=True) params.add('E', value=1e-6, vary=True) # params.add('F',value=1e-6, vary=True) result = minimize(self.residual, params, args=(Fobs, WLmod, Fmod), method='least-sq') #'least-sq') params = result.params print '' print '-----' print 'A = ', params['A'] print 'B = ', params['B'] print 'C = ', params['C'] print 'D = ', params['D'] print 'E = ', params['E'] # print 'F= ', params['F'] #print 'R = ', params['R'] print 'RedChi / Success = ', result.redchi, ' / ', result.success print '' print '=====' Coefs = [ params['A'].value, params['B'].value, params['C'].value, params['D'].value, params['E'].value ] #, params['F'].value] pixels = np.arange(len(Fobs)) WLobs = self.DSFunc(pixels, Coefs) return Coefs, WLobs def blur_function(self, wave, tran, rpower): wmin = wave.min() wmax = wave.max() nx = wave.size x = np.arange(nx) A = wmin B = np.log(wmax / wmin) / nx wave_constfwhm = A * np.exp(B * x) if np.all(np.diff(wave) > 0) != True: print "wave list not increasing" wave = np.flip(wave, 0) tran = np.flip(tran, 0) tran_constfwhm = np.interp(wave_constfwhm, wave, tran) #Sanity check that the FWHM is indeed constant dwdx_constfwhm = np.diff(wave_constfwhm) fwhm_pix = wave_constfwhm[1:] / rpower / dwdx_constfwhm if (fwhm_pix.min() - fwhm_pix.max()) / fwhm_pix.max() > 1e-5: #This should not happen warnings.warn('The FWHM is not constant in units of pixels.') fwhm_pix = fwhm_pix[0] sigma_pix = fwhm_pix / 2.3548 kx = np.arange(nx) - (nx - 1) / 2. kernel = 1. / (sigma_pix * np.sqrt(2. * np.pi)) * np.exp( -kx**2 / (2. * sigma_pix**2)) tran_conv = fft.ifft( fft.fft(tran_constfwhm) * np.conj(fft.fft(kernel))) tran_conv = fft.fftshift(tran_conv).real tran_oldsampling = np.interp(wave, wave_constfwhm, tran_conv) return tran_oldsampling def shift_wavelength(self, wave, velshift): # velshift = velocity shift in km/s # vrad-vbary # c = 2.99792456e5 # speed of light in km/s wavelength_wn = 1.0e4 / wave shift_wavelength_wn = wavelength_wn / (1.0 + (velshift) / c) newwave = 1.0e4 / shift_wavelength_wn # StarSpec[:,0] / (1.0+(vrad-vbary)/c) return newwave
class PlotFrame(wx.Frame): """ PlotFrame is a custom wxPython frame to hold the panel with a Figure and WxAgg backend canvas for matplotlib plots or other figures. In this frame: self is an instance of a wxFrame; axes is an instance of MPL Axes; fig is an instance of MPL Figure; panel is an instance of wxPanel, used for the main panel, to hold canvas, an instance of MPL FigureCanvasWxAgg. """ # Main function to set everything up when the frame is created def __init__(self, title, pos, size): """ This will be executed when an instance of PlotFrame is created. It is the place to define any globals as "self.<name>". """ wx.Frame.__init__(self, None, wx.ID_ANY, title, pos, size) if len(sys.argv) < 2: self.filename = "" else: self.filename = sys.argv[1] # set some Boolean flags self.STOP = False self.data_loaded = False self.reverse_play = False self.step = 1 # Make the main Matplotlib panel for plots self.create_main_panel() # creates canvas and contents # Then add wxPython widgets below the MPL canvas # Layout with box sizers self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.EXPAND) self.sizer.AddSpacer(10) self.sizer.Add(self.toolbar, 0, wx.EXPAND) self.sizer.AddSpacer(10) # Make the control panel with a row of buttons self.create_button_bar() self.sizer.Add(self.button_bar_sizer, 0, flag=wx.ALIGN_CENTER | wx.TOP) # Make a Status Bar self.statusbar = self.CreateStatusBar() self.sizer.Add(self.statusbar, 0, wx.EXPAND) self.SetStatusText("Frame created ...") # ------------------------------------------------------- # set up the Menu Bar # ------------------------------------------------------- menuBar = wx.MenuBar() menuFile = wx.Menu() # File menu menuFile.Append(1, "&Open", "Filename(s) or wildcard list to plot") menuFile.Append(3, "Save", "Save plot as a PNG image") menuFile.AppendSeparator() menuFile.Append(10, "E&xit") menuBar.Append(menuFile, "&File") menuHelp = wx.Menu() # Help menu menuHelp.Append(11, "&About Netview") menuHelp.Append(12, "&Usage and Help") menuHelp.Append(13, "Program &Info") menuBar.Append(menuHelp, "&Help") self.SetMenuBar(menuBar) self.panel.SetSizer(self.sizer) self.sizer.Fit(self) # ------------------------------------------------------- # Bind the menu items to functions # ------------------------------------------------------- self.Bind(wx.EVT_MENU, self.OnOpen, id=1) self.Bind(wx.EVT_MENU, self.OnSave, id=3) self.Bind(wx.EVT_MENU, self.OnQuit, id=10) self.Bind(wx.EVT_MENU, self.OnAbout, id=11) self.Bind(wx.EVT_MENU, self.OnUsage, id=12) self.Bind(wx.EVT_MENU, self.OnInfo, id=13) # methods defined below to get and plot the data # Normally do the plot on request, and not here # self.get_data_params() # self.init_plot() # self.get_xyt_data() # plot_data() # ---------- end of __init__ ---------------------------- # ------------------------------------------------------- # Function to make the main Matplotlib panel for plots # ------------------------------------------------------- def create_main_panel(self): """ create_main_panel creates the main mpl panel with instances of: * mpl Canvas * mpl Figure * mpl Figure * mpl Axes with subplot * mpl Widget class Sliders and Button * mpl navigation toolbar self.axes is the instance of MPL Axes, and is where it all happens """ self.panel = wx.Panel(self) # Create the mpl Figure and FigCanvas objects. # 3.5 x 5 inches, 100 dots-per-inch # self.dpi = 100 self.fig = Figure((3.5, 5.0), dpi=self.dpi) self.canvas = FigCanvas(self.panel, wx.ID_ANY, self.fig) # Since we have only one plot, we could use add_axes # instead of add_subplot, but then the subplot # configuration tool in the navigation toolbar wouldn't work. self.axes = self.fig.add_subplot(111) # (111) == (1,1,1) --> row 1, col 1, Figure 1) # self.axes.set_title("View from: "+self.filename) # Now create some sliders below the plot after making room self.fig.subplots_adjust(left=0.1, bottom=0.20) self.axtmin = self.fig.add_axes([0.2, 0.10, 0.5, 0.03]) self.axtmax = self.fig.add_axes([0.2, 0.05, 0.5, 0.03]) self.stmin = Slider(self.axtmin, 't_min:', 0.0, 1.0, valinit=0.0) self.stmax = Slider(self.axtmax, 't_max:', 0.0, 1.0, valinit=1.0) self.stmin.on_changed(self.update_trange) self.stmax.on_changed(self.update_trange) self.axbutton = self.fig.add_axes([0.8, 0.07, 0.1, 0.07]) self.reset_button = Button(self.axbutton, 'Reset') self.reset_button.color = 'skyblue' self.reset_button.hovercolor = 'lightblue' self.reset_button.on_clicked(self.reset_trange) # Create the navigation toolbar, tied to the canvas self.toolbar = NavigationToolbar(self.canvas) def update_trange(self, event): self.t_min = self.stmin.val self.t_max = self.stmax.val # print(self.t_min, self.t_max) def reset_trange(self, event): self.stmin.reset() self.stmax.reset() def create_button_bar(self): """ create_button_bar makes a control panel bar with buttons and toggles for New Data - Play - STOP - Single Step - Forward/Back - Normal/Fast It does not create a Panel container, but simply creates Button objects with bindings, and adds them to a horizontal BoxSizer self.button_bar_sizer. This is added to the PlotFrame vertical BoxSizer, after the MPL canvas, during initialization of the frame. """ rewind_button = wx.Button(self.panel, -1, "New Data") self.Bind(wx.EVT_BUTTON, self.OnRewind, rewind_button) replot_button = wx.Button(self.panel, -1, "Play") self.Bind(wx.EVT_BUTTON, self.OnReplot, replot_button) sstep_button = wx.Button(self.panel, -1, "Single Step") self.Bind(wx.EVT_BUTTON, self.OnSstep, sstep_button) stop_button = wx.Button(self.panel, -1, "STOP") self.Bind(wx.EVT_BUTTON, self.OnStop, stop_button) # The toggle buttons need to be globally accessible self.forward_toggle = wx.ToggleButton(self.panel, -1, "Forward") self.forward_toggle.SetValue(True) self.forward_toggle.SetLabel("Forward") self.Bind(wx.EVT_TOGGLEBUTTON, self.OnForward, self.forward_toggle) self.fast_toggle = wx.ToggleButton(self.panel, -1, " Normal ") self.fast_toggle.SetValue(True) self.fast_toggle.SetLabel(" Normal ") self.Bind(wx.EVT_TOGGLEBUTTON, self.OnFast, self.fast_toggle) # Set button colors to some simple colors that are likely # to be independent on X11 color definitions. Some nice # bit maps (from a media player skin?) should be used # or the buttons and toggle state colors in OnFast() below rewind_button.SetBackgroundColour('skyblue') replot_button.SetBackgroundColour('skyblue') sstep_button.SetBackgroundColour('skyblue') stop_button.SetBackgroundColour('skyblue') self.forward_toggle.SetForegroundColour('black') self.forward_toggle.SetBackgroundColour('yellow') self.fast_toggle.SetForegroundColour('black') self.fast_toggle.SetBackgroundColour('yellow') self.button_bar_sizer = wx.BoxSizer(wx.HORIZONTAL) flags = wx.ALIGN_CENTER | wx.ALL self.button_bar_sizer.Add(rewind_button, 0, border=3, flag=flags) self.button_bar_sizer.Add(replot_button, 0, border=3, flag=flags) self.button_bar_sizer.Add(sstep_button, 0, border=3, flag=flags) self.button_bar_sizer.Add(stop_button, 0, border=3, flag=flags) self.button_bar_sizer.Add(self.forward_toggle, 0, border=3, flag=flags) self.button_bar_sizer.Add(self.fast_toggle, 0, border=3, flag=flags) # ------------------------------------------------------- # Functions to generate or read (x,y) data and plot it # ------------------------------------------------------- def get_data_params(self): # These parameters would normally be provided in a file header, # past as arguments in a function, or from other file information # Next version will bring up a dialog for dt NX NY if no file header # Here check to see if a filename should be entered from File/Open # self.filename = 'Ex_net_Vm_0001.txt' if len(self.filename) == 0: # fake a button press of File/Open self.OnOpen(wx.EVT_BUTTON) # should check here if file exists as specified [path]/filename # assume it is a bzip2 compressed file try: fp = bz2.BZ2File(self.filename) line = fp.readline() except IOError: # then assume plain text fp = open(self.filename) line = fp.readline() fp.close() # check if first line is a header line starting with '#' header = line.split() if header[0][0] == "#": self.Ntimes = int(header[1]) self.t_min = float(header[2]) self.dt = float(header[3]) self.NX = int(header[4]) self.NY = int(header[5]) else: pdentry = self.ParamEntryDialog() if pdentry.ShowModal() == wx.ID_OK: self.Ntimes = int(pdentry.Ntimes_dialog.entry.GetValue()) self.t_min = float(pdentry.tmin_dialog.entry.GetValue()) self.dt = float(pdentry.dt_dialog.entry.GetValue()) self.NX = int(pdentry.NX_dialog.entry.GetValue()) self.NY = int(pdentry.NY_dialog.entry.GetValue()) print 'Ntimes = ', self.Ntimes, ' t_min = ', self.t_min print 'NX = ', self.NX, ' NY = ', self.NY pdentry.Destroy() self.t_max = (self.Ntimes - 1) * self.dt # reset slider max and min self.stmin.valmax = self.t_max self.stmin.valinit = self.t_min self.stmax.valmax = self.t_max self.stmax.valinit = self.t_max self.stmax.set_val(self.t_max) self.stmin.reset() self.stmax.reset() fp.close() def init_plot(self): ''' init_plot creates the initial plot display. A normal MPL plot would be created here with a command "self.axes.plot(x, y)" in order to create a plot of points in the x and y arrays on the Axes subplot. Here, we create an AxesImage instance with imshow(), instead. The initial image is a blank one of the proper dimensions, filled with zeroes. ''' self.t_max = (self.Ntimes - 1) * self.dt self.axes.set_title("View of " + self.filename) # Note that NumPy array (row, col) = image (y, x) data0 = np.zeros((self.NY, self.NX)) # Define a 'cold' to 'hot' color scale based in GENESIS 2 'hot' hotcolors = [ '#000032', '#00003c', '#000046', '#000050', '#00005a', '#000064', '#00006e', '#000078', '#000082', '#00008c', '#000096', '#0000a0', '#0000aa', '#0000b4', '#0000be', '#0000c8', '#0000d2', '#0000dc', '#0000e6', '#0000f0', '#0000fa', '#0000ff', '#000af6', '#0014ec', '#001ee2', '#0028d8', '#0032ce', '#003cc4', '#0046ba', '#0050b0', '#005aa6', '#00649c', '#006e92', '#007888', '#00827e', '#008c74', '#00966a', '#00a060', '#00aa56', '#00b44c', '#00be42', '#00c838', '#00d22e', '#00dc24', '#00e61a', '#00f010', '#00fa06', '#00ff00', '#0af600', '#14ec00', '#1ee200', '#28d800', '#32ce00', '#3cc400', '#46ba00', '#50b000', '#5aa600', '#649c00', '#6e9200', '#788800', '#827e00', '#8c7400', '#966a00', '#a06000', '#aa5600', '#b44c00', '#be4200', '#c83800', '#d22e00', '#dc2400', '#e61a00', '#f01000', '#fa0600', '#ff0000', '#ff0a00', '#ff1400', '#ff1e00', '#ff2800', '#ff3200', '#ff3c00', '#ff4600', '#ff5000', '#ff5a00', '#ff6400', '#ff6e00', '#ff7800', '#ff8200', '#ff8c00', '#ff9600', '#ffa000', '#ffaa00', '#ffb400', '#ffbe00', '#ffc800', '#ffd200', '#ffdc00', '#ffe600', '#fff000', '#fffa00', '#ffff00', '#ffff0a', '#ffff14', '#ffff1e', '#ffff28', '#ffff32', '#ffff3c', '#ffff46', '#ffff50', '#ffff5a', '#ffff64', '#ffff6e', '#ffff78', '#ffff82', '#ffff8c', '#ffff96', '#ffffa0', '#ffffaa', '#ffffb4', '#ffffbe', '#ffffc8', '#ffffd2', '#ffffdc', '#ffffe6', '#fffff0' ] cmap = matplotlib.colors.ListedColormap(hotcolors) self.im = self.axes.imshow(data0, cmap=cmap, origin='lower') # http://matplotlib.sourceforge.net/examples/pylab_examples/show_colormaps.html # shows examples to use as a 'cold' to 'hot' mapping of value to color # cm.jet, cm.gnuplot and cm.afmhot are good choices, but are unlike G2 'hot' self.im.cmap = cmap # Not sure how to properly add a colorbar # self.cb = self.fig.colorbar(self.im, orientation='vertical') # refresh the canvas self.canvas.draw() def get_xyt_data(self): # Create scaled (0-1) luminance(x,y) array from ascii G-2 disk_out file # get the data to plot from the specified filename # Note that NumPy loadtxt transparently deals with bz2 compression self.SetStatusText('Data loading - please wait ....') rawdata = np.loadtxt(self.filename) # Note the difference between NumPy [row, col] order and network # x-y grid (x, y) = (col, row). We want a NumPy NY x NX, not # NX x NY, array to be used by the AxesImage object. xydata = np.resize(rawdata, (self.Ntimes, self.NY, self.NX)) # imshow expects the data to be scaled to range 0-1. Vmin = xydata.min() Vmax = xydata.max() self.ldata = (xydata - Vmin) / (Vmax - Vmin) self.data_loaded = True self.SetStatusText('Data has been loaded - click Play') def plot_data(self): ''' plot_data() shows successive frames of the data that was loaded into the ldata array. Creating a new self.im AxesImage instance for each frame is extremely slow, so the set_data method of AxesImage is used to load new data into the existing self.im for each frame. Normally 'self.canvas.draw()' would be used to display a frame, but redrawing the entire canvas, redraws the axes, labels, sliders, buttons, or anything else on the canvas. This uses a method taken from an example in Ch 7, p. 192 Matplotlib for Python developers, with draw_artist() and blit() redraw only the part that was changed. ''' if self.data_loaded == False: # bring up a warning dialog msg = """ Data for plotting has not been loaded! Please enter the file to plot with File/Open, unless it was already specified, and then click on 'New Data' to load the data to play back, before clicking 'Play'. """ wx.MessageBox(msg, "Plot Warning", wx.OK | wx.ICON_ERROR, self) return # set color limits self.im.set_clim(0.0, 1.0) self.im.set_interpolation('nearest') # 'None' is is slightly faster, but not implemented for MPL ver < 1.1 # self.im.set_interpolation('None') # do an initial draw, then save the empty figure axes self.canvas.draw() # self.bg = self.canvas.copy_from_bbox(self.axes.bbox) # However the save and restore is only needed if I change # axes legends, etc. The draw_artist(artist), and blit # are much faster than canvas.draw() and are sufficient. print 'system time (seconds) = ', time.time() # round frame_min down and frame_max up for the time window frame_min = int(self.t_min / self.dt) frame_max = min(int(self.t_max / self.dt) + 1, self.Ntimes) frame_step = self.step # Displaying simulation time to the status bar is much faster # than updating a slider progress bar, but location isn't optimum. # The check for the STOP button doesn't work because the button # click is not registered until this function exits. # check to see if self.reverse_play == True # then interchange frame_min, frame_max, and use negative step if self.reverse_play == True: frame_min = min(int(self.t_max / self.dt) + 1, self.Ntimes) - 1 frame_max = int(self.t_min / self.dt) - 1 frame_step = -self.step for frame_num in range(frame_min, frame_max, frame_step): self.SetStatusText('time: ' + str(frame_num * self.dt)) if self.STOP == True: self.t_min = frame_num * self.dt # set t_min slider ? self.STOP = False break self.im.set_data(self.ldata[frame_num]) self.axes.draw_artist(self.im) self.canvas.blit(self.axes.bbox) print 'system time (seconds) = ', time.time() # ------------------------------------------------------------------ # Define the classes and functions for getting parameter values # -------------------------------------------------------------- class ParamEntryDialog(wx.Dialog): def __init__(self): wx.Dialog.__init__(self, None, wx.ID_ANY) self.SetSize((250, 200)) self.SetTitle('Enter Data File Parameters') vbox = wx.BoxSizer(wx.VERTICAL) self.Ntimes_dialog = XDialog(self) self.Ntimes_dialog.entry_label.SetLabel('Number of entries') self.Ntimes_dialog.entry.ChangeValue(str(2501)) self.tmin_dialog = XDialog(self) self.tmin_dialog.entry_label.SetLabel('Start time (sec)') self.tmin_dialog.entry.ChangeValue(str(0.0)) self.dt_dialog = XDialog(self) self.dt_dialog.entry_label.SetLabel('Output time step (sec)') self.dt_dialog.entry.ChangeValue(str(0.0002)) self.NX_dialog = XDialog(self) self.NX_dialog.entry_label.SetLabel('Number of cells on x-axis') self.NX_dialog.entry.ChangeValue(str(32)) self.NY_dialog = XDialog(self) self.NY_dialog.entry_label.SetLabel('Number of cells on y-axis') self.NY_dialog.entry.ChangeValue(str(32)) vbox.Add(self.Ntimes_dialog, 0, wx.EXPAND | wx.ALL, border=5) vbox.Add(self.tmin_dialog, 0, wx.EXPAND | wx.ALL, border=5) vbox.Add(self.dt_dialog, 0, wx.EXPAND | wx.ALL, border=5) vbox.Add(self.NX_dialog, 0, wx.EXPAND | wx.ALL, border=5) vbox.Add(self.NY_dialog, 0, wx.EXPAND | wx.ALL, border=5) okButton = wx.Button(self, wx.ID_OK, 'Ok') # vbox.Add(okButton,flag=wx.ALIGN_CENTER|wx.TOP|wx.BOTTOM, border=10) vbox.Add(okButton, flag=wx.ALIGN_CENTER, border=10) self.SetSizer(vbox) self.SetSizerAndFit(vbox) # ------------------------------------------------------------------ # Define the functions executed on menu choices # --------------------------------------------------------------- def OnQuit(self, event): self.Close() def OnSave(self, event): file_choices = "PNG (*.png)|*.png" dlg = wx.FileDialog(self, message="Save plot as...", defaultDir=os.getcwd(), defaultFile="plot.png", wildcard=file_choices, style=wx.SAVE) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() self.canvas.print_figure(path, dpi=self.dpi) # self.flash_status_message("Saved to %s" % path) def OnAbout(self, event): msg = """ G-3 Netview ver. 1.7 Netview is a stand-alone Python application for viewing the output of GENESIS 2 and 3 network simulations. It is intended to replace GENESIS 2 SLI scripts that use the XODUS 'xview' widget. The design and operation is based on the G3Plot application for creating 2D plots of y(t) or y(x) from data files. Unlike G3Plot, the image created with Netview is an animated representation of a rectangular network with colored squares used to indicate the value of some variable at that position and time. Typically, this would be the membrane potenial of a cell soma, or a synaptic current in a dendrite segment. Help/Usage gives HTML help for using Netview. This is the main Help page. Help/Program Info provides some information about the objects and functions, and the wxPython and matplotlib classes used here. Dave Beeman, August 2012 """ dlg = wx.MessageDialog(self, msg, "About G-3 Netview", wx.OK | wx.ICON_QUESTION) dlg.ShowModal() dlg.Destroy() def OnOpen(self, event): dlg = wx.TextEntryDialog(self, "File with x,y data to plot", "File Open", self.filename, style=wx.OK | wx.CANCEL) if dlg.ShowModal() == wx.ID_OK: self.filename = dlg.GetValue() # A new filename has been entered, but the data has not been read self.data_loaded = False # print "You entered: %s" % self.filename dlg.Destroy() # This starts with the long string of HTML to display class UsageFrame(wx.Frame): text = """ <HTML> <HEAD></HEAD> <BODY BGCOLOR="#D6E7F7"> <CENTER><H1>Using G-3 Netview</H1></CENTER> <H2>Introduction and Quick Start</H2> <p>Netview is a stand-alone Python application for viewing the output of GENESIS 2 and 3 network simulations. It is intended to replace GENESIS 2 SLI scripts that use the XODUS 'xview' widget.</p> <p>The design and operation is based on the G3Plot application for creating 2D plots of y(t) or y(x) from data files. As with G3Plot, the main class PlotFrame uses a basic wxPython frame to embed a matplotlib figure for plotting. It defines some basic menu items and a control panel of buttons and toggles, each with bindings to a function to execute on a mouse click.</p> <p>Unlike G3Plot, the image created with Netview is an animated representation of a rectangular network with colored squares used to indicate the value of some variable at that position and time. Typically, this would be the membrane potenial of a cell soma, or a synaptic current in a dendrite segment.</p> <h2>Usage</h2> <p>The Menu Bar has <em>File/Open</em>, <em>File/Save</em>, and <em>File/Exit</em> choices. The Help Menu choices <em>About</em> and <em>Usage</em> give further information. The <em>Program Info</em> selection shows code documentation that is contained in some of the main function <em>docstrings</em>.</p> <p>After starting the <em>netview</em> program, enter a data file name in the dialog for File/Open, unless the filename was given as a command line argument. Then click on <strong>New Data</strong> to load the new data and initialize the plot. When the plot is cleared to black, press <strong>Play</strong>.</p> <p>The file types recognized are plain text or text files compressed with bzip2. The expected data format is one line for each output time step, with each line having the membrane potential value of each cell in the net. No time value should be given on the line. In order to properly display the data, netview needs some additional information about the network and the data. This can optionally be contained in a header line that precedes the data. If a header is not detected, a dialog will appear asking for the needed parameters.</p> <p>It is assumed that the cells are arranged on a NX x NY grid, numbered from 0 (bottom left corner) to NX*NY - 1 (upper right corner). In order to provide this information to netview, the data file should begin with a header line of the form:</p> <pre> #optional_RUNID_string Ntimes start_time dt NX NY SEP_X SEP_Y x0 y0 z0 </pre> <p>The line must start with "#" and can optionally be followed immediately by any string. Typically this is some identification string generated by the simulation run. The following parameters, separated by blanks or any whitespace, are:</p> <ul> <li>Ntimes - the number of lines in the file, exclusive of the header</li> <li>start_time - the simulation time for the first data line (default 0.0)</li> <li>dt - the time step used for output</li> <li>NX, NY - the integer dimensions of the network</li> <li>SEP_X, SEP_Y - the x,y distances between cells (optional)</li> <li>x0, y0, z0 - the location of the compartment (data source) relative to the cell origin</li> </ul> <p>The RUNID string and the last five parameters are not read or used by netview. These are available for other data analysis tools that need a RUNID and the location of each source.</p> <p>The slider bars can be used to set a time window for display, and the <strong>Reset</strong> button can set t_min and t_max back to the defaults. Use the <strong>Forward/Back</strong> toggle to reverse direction of <strong>Play</strong>, and the <strong>Normal/Fast</strong> toggle to show every tenth frame.</p> <p>The <strong>Single Step</strong> button can be used to advance a single step at a time (or 10, if in 'Fast' mode).</p> <p>The <strong>STOP</strong> button is currently not implemented</p> <p>To plot different data, enter a new filename with <strong>File/Open</strong> and repeat with <strong>New Data</strong> and <strong>Play</strong>.</p> <HR> </BODY> </HTML> """ def __init__(self, parent): wx.Frame.__init__(self, parent, -1, "Usage and Help", size=(640, 600), pos=(400, 100)) html = wx.html.HtmlWindow(self) html.SetPage(self.text) panel = wx.Panel(self, -1) button = wx.Button(panel, wx.ID_OK, "Close") self.Bind(wx.EVT_BUTTON, self.OnCloseMe, button) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(html, 1, wx.EXPAND | wx.ALL, 5) sizer.Add(panel, 0, wx.ALIGN_CENTER | wx.ALL, 5) self.SetSizer(sizer) self.Layout() def OnCloseMe(self, event): self.Close(True) # ----------- end of class UsageFrame --------------- def OnUsage(self, event): usagewin = self.UsageFrame(self) usagewin.Show(True) def OnInfo(self, event): msg = "Program information for PlotFrame obtained from docstrings:" msg += "\n" + self.__doc__ + "\n" + self.create_main_panel.__doc__ msg += self.create_button_bar.__doc__ msg += self.init_plot.__doc__ msg += self.plot_data.__doc__ dlg = wx.lib.dialogs.ScrolledMessageDialog(self, msg, "PlotFrame Documentation") dlg.ShowModal() # --------------------------------------------------------------- # Define the functions executed on control button click # --------------------------------------------------------------- def OnRewind(self, event): self.get_data_params() self.init_plot() self.get_xyt_data() def OnReplot(self, event): self.plot_data() self.canvas.draw() def OnSstep(self, event): if self.data_loaded == False: # bring up a warning dialog msg = """ Data for plotting has not been loaded! Please enter the file to plot with File/Open, unless it was already specified, and then click on 'New Data' to load the data to play back, before clicking 'Play'. """ wx.MessageBox(msg, "Plot Warning", wx.OK | wx.ICON_ERROR, self) return self.t_max = min(self.t_max + self.dt, (self.Ntimes - 1) * self.dt) self.stmax.set_val(self.t_max) frame_num = int(self.t_max / self.dt) self.SetStatusText('time: ' + str(frame_num * self.dt)) self.im.set_data(self.ldata[frame_num]) self.axes.draw_artist(self.im) self.canvas.blit(self.axes.bbox) def OnStop(self, event): self.STOP = 'True' def OnForward(self, event): state = self.forward_toggle.GetValue() if state: self.reverse_play = False self.forward_toggle.SetLabel("Forward ") self.forward_toggle.SetForegroundColour('black') self.forward_toggle.SetBackgroundColour('yellow') else: self.reverse_play = True self.forward_toggle.SetLabel(" Back ") self.forward_toggle.SetForegroundColour('red') self.forward_toggle.SetBackgroundColour('green') def OnFast(self, event): state = self.fast_toggle.GetValue() if state: # print state self.fast_toggle.SetLabel(" Normal ") self.fast_toggle.SetForegroundColour('black') self.fast_toggle.SetBackgroundColour('yellow') self.step = 1 else: # print state self.fast_toggle.SetLabel(" Fast ") self.fast_toggle.SetForegroundColour('red') self.fast_toggle.SetBackgroundColour('green') self.step = 10
class AtlasEditor(plot_support.ImageSyncMixin): """Graphical interface to view an atlas in multiple orthogonal dimensions and edit atlas labels. :attr:`plot_eds` are dictionaries of keys specified by one of :const:`magmap.config.PLANE` plane orientations to Plot Editors. Attributes: image5d: Numpy image array in t,z,y,x,[c] format. labels_img: Numpy image array in z,y,x format. channel: Channel of the image to display. offset: Index of plane at which to start viewing in x,y,z (user) order. fn_close_listener: Handle figure close events. borders_img: Numpy image array in z,y,x,[c] format to show label borders, such as that generated during label smoothing. Defaults to None. If this image has a different number of labels than that of ``labels_img``, a new colormap will be generated. fn_show_label_3d: Function to call to show a label in a 3D viewer. Defaults to None. title (str): Window title; defaults to None. fn_refresh_atlas_eds (func): Callback for refreshing other Atlas Editors to synchronize them; defaults to None. Typically takes one argument, this ``AtlasEditor`` object to refreshing it. Defaults to None. alpha_slider: Matplotlib alpha slider control. alpha_reset_btn: Maplotlib button for resetting alpha transparency. alpha_last: Float specifying the previous alpha value. interp_planes: Current :class:`InterpolatePlanes` object. interp_btn: Matplotlib button to initiate plane interpolation. save_btn: Matplotlib button to save the atlas. fn_status_bar (func): Function to call during status bar updates in :class:`pixel_display.PixelDisplay`; defaults to None. fn_update_coords (func): Handler for coordinate updates, which takes coordinates in z-plane orientation; defaults to None. """ _EDIT_BTN_LBLS = ("Edit", "Editing") def __init__(self, image5d, labels_img, channel, offset, fn_close_listener, borders_img=None, fn_show_label_3d=None, title=None, fn_refresh_atlas_eds=None, fig=None, fn_status_bar=None): """Plot ROI as sequence of z-planes containing only the ROI itself.""" super().__init__() self.image5d = image5d self.labels_img = labels_img self.channel = channel self.offset = offset self.fn_close_listener = fn_close_listener self.borders_img = borders_img self.fn_show_label_3d = fn_show_label_3d self.title = title self.fn_refresh_atlas_eds = fn_refresh_atlas_eds self.fig = fig self.fn_status_bar = fn_status_bar self.alpha_slider = None self.alpha_reset_btn = None self.alpha_last = None self.interp_planes = None self.interp_btn = None self.save_btn = None self.edit_btn = None self.color_picker_box = None self.fn_update_coords = None self._labels_img_sitk = None # for saving labels image def show_atlas(self): """Set up the atlas display with multiple orthogonal views.""" # set up the figure if self.fig is None: fig = figure.Figure(self.title) self.fig = fig else: fig = self.fig fig.clear() gs = gridspec.GridSpec(2, 1, wspace=0.1, hspace=0.1, height_ratios=(20, 1), figure=fig, left=0.06, right=0.94, bottom=0.02, top=0.98) gs_viewers = gridspec.GridSpecFromSubplotSpec(2, 2, subplot_spec=gs[0, 0]) # set up a colormap for the borders image if present cmap_borders = colormaps.get_borders_colormap(self.borders_img, self.labels_img, config.cmap_labels) coord = list(self.offset[::-1]) # editor controls, split into a slider sub-spec to allow greater # spacing for labels on either side and a separate sub-spec for # buttons and other fields gs_controls = gridspec.GridSpecFromSubplotSpec(1, 2, subplot_spec=gs[1, 0], width_ratios=(1, 1), wspace=0.15) self.alpha_slider = Slider( fig.add_subplot(gs_controls[0, 0]), "Opacity", 0.0, 1.0, valinit=plot_editor.PlotEditor.ALPHA_DEFAULT) gs_controls_btns = gridspec.GridSpecFromSubplotSpec( 1, 5, subplot_spec=gs_controls[0, 1], wspace=0.1) self.alpha_reset_btn = Button(fig.add_subplot(gs_controls_btns[0, 0]), "Reset") self.interp_btn = Button(fig.add_subplot(gs_controls_btns[0, 1]), "Fill Label") self.interp_planes = InterpolatePlanes(self.interp_btn) self.interp_planes.update_btn() self.save_btn = Button(fig.add_subplot(gs_controls_btns[0, 2]), "Save") self.edit_btn = Button(fig.add_subplot(gs_controls_btns[0, 3]), "Edit") self.color_picker_box = TextBox( fig.add_subplot(gs_controls_btns[0, 4]), None) # adjust button colors based on theme and enabled status; note # that colors do not appear to refresh until fig mouseover for btn in (self.alpha_reset_btn, self.edit_btn): enable_btn(btn) enable_btn(self.save_btn, False) enable_btn(self.color_picker_box, color=config.widget_color + 0.1) def setup_plot_ed(axis, gs_spec): # set up a PlotEditor for the given axis # subplot grid, with larger height preference for plot for # each increased row to make sliders of approx equal size and # align top borders of top images rows_cols = gs_spec.get_rows_columns() extra_rows = rows_cols[3] - rows_cols[2] gs_plot = gridspec.GridSpecFromSubplotSpec( 2, 1, subplot_spec=gs_spec, height_ratios=(1, 10 + 14 * extra_rows), hspace=0.1 / (extra_rows * 1.4 + 1)) # transform arrays to the given orthogonal direction ax = fig.add_subplot(gs_plot[1, 0]) plot_support.hide_axes(ax) plane = config.PLANE[axis] arrs_3d, aspect, origin, scaling = \ plot_support.setup_images_for_plane( plane, (self.image5d[0], self.labels_img, self.borders_img)) img3d_tr, labels_img_tr, borders_img_tr = arrs_3d # slider through image planes ax_scroll = fig.add_subplot(gs_plot[0, 0]) plane_slider = Slider(ax_scroll, plot_support.get_plane_axis(plane), 0, len(img3d_tr) - 1, valfmt="%d", valinit=0, valstep=1) # plot editor max_size = max_sizes[axis] if max_sizes else None plot_ed = plot_editor.PlotEditor( ax, img3d_tr, labels_img_tr, config.cmap_labels, plane, aspect, origin, self.update_coords, self.refresh_images, scaling, plane_slider, img3d_borders=borders_img_tr, cmap_borders=cmap_borders, fn_show_label_3d=self.fn_show_label_3d, interp_planes=self.interp_planes, fn_update_intensity=self.update_color_picker, max_size=max_size, fn_status_bar=self.fn_status_bar) return plot_ed # setup plot editors for all 3 orthogonal directions max_sizes = plot_support.get_downsample_max_sizes() for i, gs_viewer in enumerate( (gs_viewers[:2, 0], gs_viewers[0, 1], gs_viewers[1, 1])): self.plot_eds[config.PLANE[i]] = setup_plot_ed(i, gs_viewer) self.set_show_crosslines(True) # attach listeners fig.canvas.mpl_connect("scroll_event", self.scroll_overview) fig.canvas.mpl_connect("key_press_event", self.on_key_press) fig.canvas.mpl_connect("close_event", self._close) fig.canvas.mpl_connect("axes_leave_event", self.axes_exit) self.alpha_slider.on_changed(self.alpha_update) self.alpha_reset_btn.on_clicked(self.alpha_reset) self.interp_btn.on_clicked(self.interpolate) self.save_btn.on_clicked(self.save_atlas) self.edit_btn.on_clicked(self.toggle_edit_mode) self.color_picker_box.on_text_change(self.color_picker_changed) # initialize and show planes in all plot editors if self._max_intens_proj is not None: self.update_max_intens_proj(self._max_intens_proj) self.update_coords(coord, config.PLANE[0]) plt.ion() # avoid the need for draw calls def _close(self, evt): """Handle figure close events by calling :attr:`fn_close_listener` with this object. Args: evt (:obj:`matplotlib.backend_bases.CloseEvent`): Close event. """ self.fn_close_listener(evt, self) def on_key_press(self, event): """Respond to key press events. """ if event.key == "a": # toggle between current and 0 opacity if self.alpha_slider.val == 0: # return to saved alpha if available and reset if self.alpha_last is not None: self.alpha_slider.set_val(self.alpha_last) self.alpha_last = None else: # make translucent, saving alpha if not already saved # during a halve-opacity event if self.alpha_last is None: self.alpha_last = self.alpha_slider.val self.alpha_slider.set_val(0) elif event.key == "A": # halve opacity, only saving alpha on first halving to allow # further halving or manual movements while still returning to # originally saved alpha if self.alpha_last is None: self.alpha_last = self.alpha_slider.val self.alpha_slider.set_val(self.alpha_slider.val / 2) elif event.key == "up" or event.key == "down": # up/down arrow for scrolling planes self.scroll_overview(event) elif event.key == "w": # shortcut to toggle editing mode self.toggle_edit_mode(event) elif event.key == "ctrl+s" or event.key == "cmd+s": # support default save shortcuts on multiple platforms; # ctrl-s will bring up save dialog from fig, but cmd/win-S # will bypass self.save_fig(self.get_save_path()) def update_coords(self, coord, plane_src=config.PLANE[0]): """Update all plot editors with given coordinates. Args: coord: Coordinate at which to center images, in z,y,x order. plane_src: One of :const:`magmap.config.PLANE` to specify the orientation from which the coordinates were given; defaults to the first element of :const:`magmap.config.PLANE`. """ coord_rev = libmag.transpose_1d_rev(list(coord), plane_src) for i, plane in enumerate(config.PLANE): coord_transposed = libmag.transpose_1d(list(coord_rev), plane) if i == 0: self.offset = coord_transposed[::-1] if self.fn_update_coords: # update offset based on xy plane, without centering # planes are centered on the offset as-is self.fn_update_coords(coord_transposed, False) self.plot_eds[plane].update_coord(coord_transposed) def view_subimg(self, offset, shape): """Zoom all Plot Editors to the given sub-image. Args: offset: Sub-image coordinates in ``z,y,x`` order. shape: Sub-image shape in ``z,y,x`` order. """ for i, plane in enumerate(config.PLANE): offset_tr = libmag.transpose_1d(list(offset), plane) shape_tr = libmag.transpose_1d(list(shape), plane) self.plot_eds[plane].view_subimg(offset_tr[1:], shape_tr[1:]) self.fig.canvas.draw_idle() def refresh_images(self, plot_ed=None, update_atlas_eds=False): """Refresh images in a plot editor, such as after editing one editor and updating the displayed image in the other editors. Args: plot_ed (:obj:`magmap.plot_editor.PlotEditor`): Editor that does not need updating, typically the editor that originally changed. Defaults to None. update_atlas_eds (bool): True to update other ``AtlasEditor``s; defaults to False. """ for key in self.plot_eds: ed = self.plot_eds[key] if ed != plot_ed: ed.refresh_img3d_labels() if ed.edited: # display save button as enabled if any editor has been edited enable_btn(self.save_btn) if update_atlas_eds and self.fn_refresh_atlas_eds is not None: # callback to synchronize other Atlas Editors self.fn_refresh_atlas_eds(self) def scroll_overview(self, event): """Scroll images and crosshairs in all plot editors Args: event: Scroll event. """ for key in self.plot_eds: self.plot_eds[key].scroll_overview(event) def alpha_update(self, event): """Update the alpha transparency in all plot editors. Args: event: Slider event. """ for key in self.plot_eds: self.plot_eds[key].alpha_updater(event) def alpha_reset(self, event): """Reset the alpha transparency in all plot editors. Args: event: Button event, currently ignored. """ self.alpha_slider.reset() def axes_exit(self, event): """Trigger axes exit for all plot editors. Args: event: Axes exit event. """ for key in self.plot_eds: self.plot_eds[key].on_axes_exit(event) def interpolate(self, event): """Interpolate planes using :attr:`interp_planes`. Args: event: Button event, currently ignored. """ try: self.interp_planes.interpolate(self.labels_img) # flag Plot Editors as edited so labels can be saved for ed in self.plot_eds.values(): ed.edited = True self.refresh_images(None, True) except ValueError as e: print(e) def save_atlas(self, event): """Save atlas labels using the registered image suffix given by :attr:`config.reg_suffixes[config.RegSuffixes.ANNOTATION]`. Args: event: Button event, currently not used. """ # only save if at least one editor has been edited if not any([ed.edited for ed in self.plot_eds.values()]): return # save to the labels reg suffix; use sitk Image if loaded and store # any Image loaded during saving reg_name = config.reg_suffixes[config.RegSuffixes.ANNOTATION] if self._labels_img_sitk is None: self._labels_img_sitk = config.labels_img_sitk self._labels_img_sitk = sitk_io.write_registered_image( self.labels_img, config.filename, reg_name, self._labels_img_sitk, overwrite=True) # reset edited flag in all editors and show save button as disabled for ed in self.plot_eds.values(): ed.edited = False enable_btn(self.save_btn, False) print("Saved labels image at {}".format(datetime.datetime.now())) def get_save_path(self): """Get figure save path based on filename, ROI, and overview plane shown. Returns: str: Figure save path. """ ext = config.savefig if config.savefig else config.DEFAULT_SAVEFIG return "{}.{}".format( naming.get_roi_path(os.path.basename(self.title), self.offset), ext) def toggle_edit_mode(self, event): """Toggle editing mode, determining the current state from the first :class:`magmap.plot_editor.PlotEditor` and switching to the opposite value for all plot editors. Args: event: Button event, currently not used. """ edit_mode = False for i, ed in enumerate(self.plot_eds.values()): if i == 0: # change edit mode based on current mode in first plot editor edit_mode = not ed.edit_mode toggle_btn(self.edit_btn, edit_mode, text=self._EDIT_BTN_LBLS) ed.edit_mode = edit_mode if not edit_mode: # reset the color picker text box when turning off editing self.color_picker_box.set_val("") def update_color_picker(self, val): """Update the color picker :class:`TextBox` with the given value. Args: val (str): Color value. If None, only :meth:`color_picker_changed` will be triggered. """ if val is None: # updated picked color directly self.color_picker_changed(val) else: # update text box, which triggers color_picker_changed self.color_picker_box.set_val(val) def color_picker_changed(self, text): """Respond to color picker :class:`TextBox` changes by updating the specified intensity value in all plot editors. Args: text (str): String of text box value. Converted to an int if non-empty. """ intensity = text if text: if not libmag.is_number(intensity): return intensity = int(intensity) print("updating specified color to", intensity) for i, ed in enumerate(self.plot_eds.values()): ed.intensity_spec = intensity
def update(val): amp = samp.val freq = sfreq.val l.set_ydata(amp*np.sin(2*np.pi*freq*t)) fig.canvas.draw_idle() sfreq.on_changed(update) samp.on_changed(update) resetax = plt.axes([0.8, 0.025, 0.1, 0.04]) button = Button(resetax, 'Reset', color=axcolor, hovercolor='0.975') def reset(event): sfreq.reset() samp.reset() button.on_clicked(reset) rax = plt.axes([0.025, 0.5, 0.15, 0.15], facecolor=axcolor) radio = RadioButtons(rax, ('red', 'blue', 'green'), active=0) def colorfunc(label): l.set_color(label) fig.canvas.draw_idle() radio.on_clicked(colorfunc) plt.show() print (input("Fin ej 017_16 \n continuar?"));
def update_mrt1(val): global mrt1_point s = mrt1_slice.val axes[1].clear() axes[1].set(title="MR_T1") axes[1].imshow(mrt1_array[s], cmap='gray') axes[1].axis("off") for point in mrt1_point: z, x, y = point if s == z: axes[1].scatter(x, y, marker="+", c='yellow') ct_slice.on_changed(update_ct) ct_slice.reset() ct_slice.set_val(0) mrt1_slice.on_changed(update_mrt1) mrt1_slice.reset() mrt1_slice.set_val(0) # 定义鼠标交互 def on_press(event): global ct_point, mrt1_point x_coord, y_coord = event.xdata, event.ydata if event.inaxes == axes[0]: z_coord = ct_slice.val ct_point.append([z_coord, x_coord, y_coord]) axes[0].scatter(x_coord, y_coord, marker="+", c='lime')
class Environment(): def __init__(self, xBoundary, yBoundary, obs): self.xb = xBoundary # of the form [ax, bx] self.yb = yBoundary # of the form [ay, by] self.obstacles = obs # of the form [[x0, y0,r0],[x1, y1, r1],[x2, y2, r2],...] print(self.obstacles) self.fig, self.ax = plt.subplots() plt.subplots_adjust(bottom=0.45, left=0.1) #setting the sliders self.axcolor = "lightgoldenrodyellow" # setting sliders for start pose self.axAngle1 = plt.axes( [0.2, 0.35, 0.2, 0.01], facecolor=self.axcolor ) #[distance from left, distance from bottom, length, width] self.axPos1x = plt.axes([0.2, 0.30, 0.2, 0.01], facecolor=self.axcolor) self.axPos1y = plt.axes([0.2, 0.25, 0.2, 0.01], facecolor=self.axcolor) # setting sliders for goal pose self.axAngle2 = plt.axes([0.6, 0.35, 0.2, 0.01], facecolor=self.axcolor) self.axPos2x = plt.axes([0.6, 0.30, 0.2, 0.01], facecolor=self.axcolor) self.axPos2y = plt.axes([0.6, 0.25, 0.2, 0.01], facecolor=self.axcolor) #setting the radius self.axRadius = plt.axes([0.2, 0.20, 0.2, 0.01], facecolor=self.axcolor) #creating sliders self.sAngle1 = Slider(self.axAngle1, 'Yaw 1 (deg)', 0, 360, valinit=0, valstep=5) self.sAngle2 = Slider(self.axAngle2, 'Yaw 2 (deg)', 0, 360, valinit=90, valstep=5) self.sRadius = Slider(self.axRadius, 'Radius (m)', 0, 2.33, valinit=2.33, valstep=0.1) self.sPos1x = Slider(self.axPos1x, 'pos1 x', -10, 10, valinit=0, valstep=0.1) self.sPos2x = Slider(self.axPos2x, 'pos2 x', -10, 10, valinit=5, valstep=0.1) self.sPos1y = Slider(self.axPos1y, 'pos1 y', -10, 10, valinit=0, valstep=0.1) self.sPos2y = Slider(self.axPos2y, 'pos2 y', -10, 10, valinit=5, valstep=0.1) #create a reset button self.resetax = plt.axes([0.8, 0.05, 0.1, 0.04]) self.resetButton = Button(self.resetax, 'Reset', color=self.axcolor, hovercolor='0.975') def plot_setup(self): self.ax.cla() self.ax.set_xlim(self.xb[0], self.xb[1]) self.ax.set_aspect('equal') self.ax.set_ylim(self.yb[0], self.yb[1]) self.plot_obstacles() def update(self, val): angle1 = self.sAngle1.val angle2 = self.sAngle2.val radius = self.sRadius.val pos1x = self.sPos1x.val pos2x = self.sPos2x.val pos1y = self.sPos1y.val pos2y = self.sPos2y.val self.plot_setup() self.ax.arrow(pos1x, pos1y, m.cos(wrapToPi(m.radians(angle1))), m.sin(wrapToPi(m.radians(angle1))), head_width=0.1, head_length=0.5) self.ax.arrow(pos2x, pos2y, m.cos(wrapToPi(m.radians(angle2))), m.sin(wrapToPi(m.radians(angle2))), head_width=0.1, head_length=0.5) # now we have got angles and we know start and end exactly start = [pos1x, pos1y, wrapToPi(m.radians(angle1))] goal = [pos2x, pos2y, wrapToPi(m.radians(angle2))] px, py = RSP_path(start, goal, radius) # now we need to plot it self.ax.plot(px, py, 'r') def reset_it(self, event): self.sAngle1.reset() self.sAngle2.reset() self.sRadius.reset() self.sPos1x.reset() self.sPos2x.reset() def set_sliders(self): # set the update loop self.sAngle1.on_changed(self.update) self.sAngle2.on_changed(self.update) self.sRadius.on_changed(self.update) self.sPos1x.on_changed(self.update) self.sPos2x.on_changed(self.update) self.sPos1y.on_changed(self.update) self.sPos2y.on_changed(self.update) self.resetButton.on_clicked(self.reset_it) def plot_obstacles(self): # source : https://stackoverflow.com/questions/9215658/plot-a-circle-with-pyplot for ob in self.obstacles: c = plt.Circle((ob[0], ob[1]), ob[2], color='k') self.ax.add_artist(c)
class PhasePlaneInteractive(object): """ An interactive phase-plane plot generated from a TVB model object. A TVB integrator object will be use for generating sample trajectories -- not the phase-plane. This is mainly interesting for visualising the effect of noise on a trajectory. """ def __init__(self, model, integrator): self.log = get_logger(self.__class__.__module__) self.model = model self.integrator = integrator #Make sure the model is fully configured... self.model.configure() self.model.update_derived_parameters() def get_required_memory_size(self, **kwargs): """ Return the required memory to run this algorithm. """ # Don't know how much memory is needed. return -1 def draw_phase_plane(self): """Generate the interactive phase-plane figure.""" self.log.debug("Plot started...") model_name = self.model.__class__.__name__ msg = "Generating an interactive phase-plane plot for %s" self.log.info(msg % model_name) self.svx = self.model.state_variables[0] # x-axis: 1st state variable self.svy = self.model.state_variables[1] # y-axis: 2nd state variable self.mode = 0 self._set_state_vector() #TODO: see how we can get the figure size from the UI to better 'fit' the encompassing div self.ipp_fig = pylab.figure(figsize=(10, 8)) pylab.clf() self.pp_ax = self.ipp_fig.add_axes([0.265, 0.2, 0.7, 0.75]) self.pp_splt = self.ipp_fig.add_subplot(212) self.ipp_fig.subplots_adjust(left=0.265, bottom=0.02, right=0.75, top=0.3, wspace=0.1, hspace=None) self.pp_splt.set_color_cycle(get_color(self.model.nvar)) self.pp_splt.plot(numpy.arange(TRAJ_STEPS + 1) * self.integrator.dt, numpy.zeros((TRAJ_STEPS + 1, self.model.nvar))) if hasattr(self.pp_splt, 'autoscale'): self.pp_splt.autoscale(enable=True, axis='y', tight=True) self.pp_splt.legend(self.model.state_variables) #Selectors self._add_state_variable_selector() self._add_mode_selector() #Sliders self._add_axes_range_sliders() self._add_state_variable_sliders() if isinstance(self.integrator, integrators_module.IntegratorStochastic): if self.integrator.noise.ntau > 0.0: self.integrator.noise.configure_coloured(self.integrator.dt, (1, self.model.nvar, 1, self.model.number_of_modes)) else: self.integrator.noise.configure_white(self.integrator.dt, (1, self.model.nvar, 1, self.model.number_of_modes)) self._add_noise_slider() self._add_reset_noise_button() self._add_reset_seed_button() #Reset buttons #self._add_reset_param_button() self._add_reset_sv_button() self._add_reset_axes_button() #Calculate the phase plane self._set_mesh_grid() self._calc_phase_plane() #Plot phase plane self._plot_phase_plane() # add mouse handler for trajectory clicking self.ipp_fig.canvas.mpl_connect('button_press_event', self._click_trajectory) self.ipp_fig.canvas.draw() return dict(serverIp=config.SERVER_IP, serverPort=config.MPLH5_SERVER_PORT, figureNumber=self.ipp_fig.number, showFullToolbar=False) def _add_state_variable_selector(self): """ Generate radio selector buttons to set which state variable is displayed on the x and y axis of the phase-plane plot. """ svx_ind = self.model.state_variables.index(self.svx) svy_ind = self.model.state_variables.index(self.svy) #State variable for the x axis pos_shp = [0.08, 0.07, 0.065, 0.12 + 0.006 * self.model.nvar] rax = self.ipp_fig.add_axes(pos_shp, axisbg=AXCOLOUR, title="x-axis") self.state_variable_x = RadioButtons(rax, tuple(self.model.state_variables), active=svx_ind) self.state_variable_x.on_clicked(self._update_svx) #State variable for the y axis pos_shp = [0.16, 0.07, 0.065, 0.12 + 0.006 * self.model.nvar] rax = self.ipp_fig.add_axes(pos_shp, axisbg=AXCOLOUR, title="y-axis") self.state_variable_y = RadioButtons(rax, tuple(self.model.state_variables), active=svy_ind) self.state_variable_y.on_clicked(self._update_svy) def _add_mode_selector(self): """ Add a radio button to the figure for selecting which mode of the model should be displayed. """ pos_shp = [0.02, 0.07, 0.04, 0.1 + 0.002 * self.model.number_of_modes] rax = self.ipp_fig.add_axes(pos_shp, axisbg=AXCOLOUR, title="Mode") mode_tuple = tuple(range(self.model.number_of_modes)) self.mode_selector = RadioButtons(rax, mode_tuple, active=0) self.mode_selector.on_clicked(self._update_mode) def _add_axes_range_sliders(self): """ Add sliders to the figure to allow the phase-planes axes to be set. """ self.axes_range_sliders = dict() default_range_x = (self.model.state_variable_range[self.svx][1] - self.model.state_variable_range[self.svx][0]) default_range_y = (self.model.state_variable_range[self.svy][1] - self.model.state_variable_range[self.svy][0]) min_val_x = self.model.state_variable_range[self.svx][0] - 4.0 * default_range_x max_val_x = self.model.state_variable_range[self.svx][1] + 4.0 * default_range_x min_val_y = self.model.state_variable_range[self.svy][0] - 4.0 * default_range_y max_val_y = self.model.state_variable_range[self.svy][1] + 4.0 * default_range_y sax = self.ipp_fig.add_axes([0.04, 0.835, 0.125, 0.025], axisbg=AXCOLOUR) sl_x_min = Slider(sax, "xlo", min_val_x, max_val_x, valinit=self.model.state_variable_range[self.svx][0]) sl_x_min.on_changed(self._update_range) sax = self.ipp_fig.add_axes([0.04, 0.8, 0.125, 0.025], axisbg=AXCOLOUR) sl_x_max = Slider(sax, "xhi", min_val_x, max_val_x, valinit=self.model.state_variable_range[self.svx][1]) sl_x_max.on_changed(self._update_range) sax = self.ipp_fig.add_axes([0.04, 0.765, 0.125, 0.025], axisbg=AXCOLOUR) sl_y_min = Slider(sax, "ylo", min_val_y, max_val_y, valinit=self.model.state_variable_range[self.svy][0]) sl_y_min.on_changed(self._update_range) sax = self.ipp_fig.add_axes([0.04, 0.73, 0.125, 0.025], axisbg=AXCOLOUR) sl_y_max = Slider(sax, "yhi", min_val_y, max_val_y, valinit=self.model.state_variable_range[self.svy][1]) sl_y_max.on_changed(self._update_range) self.axes_range_sliders["sl_x_min"] = sl_x_min self.axes_range_sliders["sl_x_max"] = sl_x_max self.axes_range_sliders["sl_y_min"] = sl_y_min self.axes_range_sliders["sl_y_max"] = sl_y_max def _add_state_variable_sliders(self): """ Add sliders to the figure to allow default values for the models state variable to be set. """ msv_range = self.model.state_variable_range offset = 0.0 self.sv_sliders = dict() for sv in range(self.model.nvar): offset += 0.035 pos_shp = [0.04, 0.6 - offset, 0.125, 0.025] sax = self.ipp_fig.add_axes(pos_shp, axisbg=AXCOLOUR) sv_str = self.model.state_variables[sv] self.sv_sliders[sv_str] = Slider(sax, sv_str, msv_range[sv_str][0], msv_range[sv_str][1], valinit=self.default_sv[sv, 0, 0]) self.sv_sliders[sv_str].on_changed(self._update_state_variables) def _add_noise_slider(self): """ Add a slider to the figure to allow the integrators noise strength to be set. """ pos_shp = [0.04, 0.365, 0.125, 0.025] sax = self.ipp_fig.add_axes(pos_shp, axisbg=AXCOLOUR) self.noise_slider = Slider(sax, "Noise", 0.0, 1.0, valinit=self.integrator.noise.nsig) self.noise_slider.on_changed(self._update_noise) def _add_reset_sv_button(self): """ Add a button to the figure for reseting the model state variables to their default values. """ bax = self.ipp_fig.add_axes([0.04, 0.60, 0.125, 0.04]) self.reset_sv_button = Button(bax, 'Reset state-variables', color=BUTTONCOLOUR, hovercolor=HOVERCOLOUR) def reset_state_variables(event): for svsl in self.sv_sliders.itervalues(): svsl.reset() self.reset_sv_button.on_clicked(reset_state_variables) def _add_reset_noise_button(self): """ Add a button to the figure for reseting the noise to its default value. """ bax = self.ipp_fig.add_axes([0.04, 0.4, 0.125, 0.04]) self.reset_noise_button = Button(bax, 'Reset noise strength', color=BUTTONCOLOUR, hovercolor=HOVERCOLOUR) def reset_noise(event): self.noise_slider.reset() self.reset_noise_button.on_clicked(reset_noise) def _add_reset_seed_button(self): """ Add a button to the figure for reseting the random number generator to its intial state. For reproducible noise... """ bax = self.ipp_fig.add_axes([0.04, 0.315, 0.125, 0.04]) self.reset_seed_button = Button(bax, 'Reset random stream', color=BUTTONCOLOUR, hovercolor=HOVERCOLOUR) def reset_seed(event): self.integrator.noise.trait["random_stream"].reset() self.reset_seed_button.on_clicked(reset_seed) def _add_reset_axes_button(self): """ Add a button to the figure for reseting the phase-plane axes to their default ranges. """ bax = self.ipp_fig.add_axes([0.04, 0.87, 0.125, 0.04]) self.reset_axes_button = Button(bax, 'Reset axes', color=BUTTONCOLOUR, hovercolor=HOVERCOLOUR) def reset_ranges(event): self.axes_range_sliders["sl_x_min"].reset() self.axes_range_sliders["sl_x_max"].reset() self.axes_range_sliders["sl_y_min"].reset() self.axes_range_sliders["sl_y_max"].reset() self.reset_axes_button.on_clicked(reset_ranges) ##------------------------------------------------------------------------## ##------------------- Functions for updating the figure ------------------## ##------------------------------------------------------------------------## #NOTE: All the ax.set_xlim, poly.xy, etc, garbage below is fragile. It works # at the moment, but there are currently bugs in Slider and the hackery # below takes these into account... If the bugs are fixed/changed then # this could break. As an example, the Slider doc says poly is a # Rectangle, but it's actually a Polygon. The Slider set_val method # assumes a Rectangle even though this is not the case, so the array # Slider.poly.xy is corrupted by that method. The corruption isn't # visible in the plot, which is probably why it hasn't been fixed... def update_xrange_sliders(self): """ """ default_range_x = (self.model.state_variable_range[self.svx][1] - self.model.state_variable_range[self.svx][0]) min_val_x = self.model.state_variable_range[self.svx][0] - 4.0 * default_range_x max_val_x = self.model.state_variable_range[self.svx][1] + 4.0 * default_range_x self.axes_range_sliders["sl_x_min"].valinit = self.model.state_variable_range[self.svx][0] self.axes_range_sliders["sl_x_min"].valmin = min_val_x self.axes_range_sliders["sl_x_min"].valmax = max_val_x self.axes_range_sliders["sl_x_min"].ax.set_xlim(min_val_x, max_val_x) self.axes_range_sliders["sl_x_min"].poly.axes.set_xlim(min_val_x, max_val_x) self.axes_range_sliders["sl_x_min"].poly.xy[[0, 1], 0] = min_val_x self.axes_range_sliders["sl_x_min"].vline.set_data( ([self.axes_range_sliders["sl_x_min"].valinit, self.axes_range_sliders["sl_x_min"].valinit], [0, 1])) self.axes_range_sliders["sl_x_max"].valinit = self.model.state_variable_range[self.svx][1] self.axes_range_sliders["sl_x_max"].valmin = min_val_x self.axes_range_sliders["sl_x_max"].valmax = max_val_x self.axes_range_sliders["sl_x_max"].ax.set_xlim(min_val_x, max_val_x) self.axes_range_sliders["sl_x_max"].poly.axes.set_xlim(min_val_x, max_val_x) self.axes_range_sliders["sl_x_max"].poly.xy[[0, 1], 0] = min_val_x self.axes_range_sliders["sl_x_max"].vline.set_data( ([self.axes_range_sliders["sl_x_max"].valinit, self.axes_range_sliders["sl_x_max"].valinit], [0, 1])) self.axes_range_sliders["sl_x_min"].reset() self.axes_range_sliders["sl_x_max"].reset() def update_yrange_sliders(self): """ """ default_range_y = (self.model.state_variable_range[self.svy][1] - self.model.state_variable_range[self.svy][0]) min_val_y = self.model.state_variable_range[self.svy][0] - 4.0 * default_range_y max_val_y = self.model.state_variable_range[self.svy][1] + 4.0 * default_range_y self.axes_range_sliders["sl_y_min"].valinit = self.model.state_variable_range[self.svy][0] self.axes_range_sliders["sl_y_min"].valmin = min_val_y self.axes_range_sliders["sl_y_min"].valmax = max_val_y self.axes_range_sliders["sl_y_min"].ax.set_xlim(min_val_y, max_val_y) self.axes_range_sliders["sl_y_min"].poly.axes.set_xlim(min_val_y, max_val_y) self.axes_range_sliders["sl_y_min"].poly.xy[[0, 1], 0] = min_val_y self.axes_range_sliders["sl_y_min"].vline.set_data( ([self.axes_range_sliders["sl_y_min"].valinit, self.axes_range_sliders["sl_y_min"].valinit], [0, 1])) self.axes_range_sliders["sl_y_max"].valinit = self.model.state_variable_range[self.svy][1] self.axes_range_sliders["sl_y_max"].valmin = min_val_y self.axes_range_sliders["sl_y_max"].valmax = max_val_y self.axes_range_sliders["sl_y_max"].ax.set_xlim(min_val_y, max_val_y) self.axes_range_sliders["sl_y_max"].poly.axes.set_xlim(min_val_y, max_val_y) self.axes_range_sliders["sl_y_max"].poly.xy[[0, 1], 0] = min_val_y self.axes_range_sliders["sl_y_max"].vline.set_data( ([self.axes_range_sliders["sl_y_max"].valinit, self.axes_range_sliders["sl_y_max"].valinit], [0, 1])) self.axes_range_sliders["sl_y_min"].reset() self.axes_range_sliders["sl_y_max"].reset() def _update_svx(self, label): """ Update state variable used for x-axis based on radio buttton selection. """ self.svx = label self.update_xrange_sliders() self._set_mesh_grid() self._calc_phase_plane() self._update_phase_plane() def _update_svy(self, label): """ Update state variable used for y-axis based on radio buttton selection. """ self.svy = label self.update_yrange_sliders() self._set_mesh_grid() self._calc_phase_plane() self._update_phase_plane() def _update_mode(self, label): """ Update the visualised mode based on radio button selection. """ self.mode = label self._update_phase_plane() def _update_noise(self, nsig): """ Update integrator noise based on the noise slider value. """ self.integrator.noise.nsig = numpy.array([nsig, ]) def _update_range(self, val): """ Update the axes ranges based on the current axes slider values. NOTE: Haven't figured out how to update independently, so just update everything. """ #TODO: Grab caller and use val directly, ie independent range update. self.axes_range_sliders["sl_x_min"].ax.set_axis_bgcolor(AXCOLOUR) self.axes_range_sliders["sl_x_max"].ax.set_axis_bgcolor(AXCOLOUR) self.axes_range_sliders["sl_y_min"].ax.set_axis_bgcolor(AXCOLOUR) self.axes_range_sliders["sl_y_max"].ax.set_axis_bgcolor(AXCOLOUR) if self.axes_range_sliders["sl_x_min"].val >= self.axes_range_sliders["sl_x_max"].val: self.log.error("X-axis min must be less than max...") self.axes_range_sliders["sl_x_min"].ax.set_axis_bgcolor("Red") self.axes_range_sliders["sl_x_max"].ax.set_axis_bgcolor("Red") return if self.axes_range_sliders["sl_y_min"].val >= self.axes_range_sliders["sl_y_max"].val: self.log.error("Y-axis min must be less than max...") self.axes_range_sliders["sl_y_min"].ax.set_axis_bgcolor("Red") self.axes_range_sliders["sl_y_max"].ax.set_axis_bgcolor("Red") return msv_range = self.model.state_variable_range msv_range[self.svx][0] = self.axes_range_sliders["sl_x_min"].val msv_range[self.svx][1] = self.axes_range_sliders["sl_x_max"].val msv_range[self.svy][0] = self.axes_range_sliders["sl_y_min"].val msv_range[self.svy][1] = self.axes_range_sliders["sl_y_max"].val self._set_mesh_grid() self._calc_phase_plane() self._update_phase_plane() def _update_phase_plane(self): """ Clear the axes and redraw the phase-plane. """ self.pp_ax.clear() self.pp_splt.clear() self.pp_splt.set_color_cycle(get_color(self.model.nvar)) self.pp_splt.plot(numpy.arange(TRAJ_STEPS + 1) * self.integrator.dt, numpy.zeros((TRAJ_STEPS + 1, self.model.nvar))) if hasattr(self.pp_splt, 'autoscale'): self.pp_splt.autoscale(enable=True, axis='y', tight=True) self.pp_splt.legend(self.model.state_variables) self._plot_phase_plane() def _update_state_variables(self, val): """ Update the default state-variable values, used for non-visualised state variables, based of the current slider values. """ for sv in self.sv_sliders: k = self.model.state_variables.index(sv) self.default_sv[k] = self.sv_sliders[sv].val self._calc_phase_plane() self._update_phase_plane() def _set_mesh_grid(self): """ Generate the phase-plane gridding based on currently selected statevariables and their range values. """ xlo = self.model.state_variable_range[self.svx][0] xhi = self.model.state_variable_range[self.svx][1] ylo = self.model.state_variable_range[self.svy][0] yhi = self.model.state_variable_range[self.svy][1] self.X = numpy.mgrid[xlo:xhi:(NUMBEROFGRIDPOINTS * 1j)] self.Y = numpy.mgrid[ylo:yhi:(NUMBEROFGRIDPOINTS * 1j)] def _set_state_vector(self): """ """ #import pdb; pdb.set_trace() svr = self.model.state_variable_range sv_mean = numpy.array([svr[key].mean() for key in self.model.state_variables]) sv_mean = sv_mean.reshape((self.model.nvar, 1, 1)) self.default_sv = sv_mean.repeat(self.model.number_of_modes, axis=2) self.no_coupling = numpy.zeros((self.model.nvar, 1, self.model.number_of_modes)) def _calc_phase_plane(self): """ Calculate the vector field. """ svx_ind = self.model.state_variables.index(self.svx) svy_ind = self.model.state_variables.index(self.svy) #Calculate the vector field discretely sampled at a grid of points grid_point = self.default_sv.copy() self.U = numpy.zeros((NUMBEROFGRIDPOINTS, NUMBEROFGRIDPOINTS, self.model.number_of_modes)) self.V = numpy.zeros((NUMBEROFGRIDPOINTS, NUMBEROFGRIDPOINTS, self.model.number_of_modes)) for ii in xrange(NUMBEROFGRIDPOINTS): grid_point[svy_ind] = self.Y[ii] for jj in xrange(NUMBEROFGRIDPOINTS): #import pdb; pdb.set_trace() grid_point[svx_ind] = self.X[jj] d = self.model.dfun(grid_point, self.no_coupling) for kk in range(self.model.number_of_modes): self.U[ii, jj, kk] = d[svx_ind, 0, kk] self.V[ii, jj, kk] = d[svy_ind, 0, kk] #self.UVmag = numpy.sqrt(self.U**2 + self.V**2) #import pdb; pdb.set_trace() if numpy.isnan(self.U).any() or numpy.isnan(self.V).any(): self.log.error("NaN") def _plot_phase_plane(self): """ Plot the vector field and its nullclines. """ # Set title and axis labels model_name = self.model.__class__.__name__ self.pp_ax.set(title=model_name + " mode " + str(self.mode)) self.pp_ax.set(xlabel="State Variable " + self.svx) self.pp_ax.set(ylabel="State Variable " + self.svy) #import pdb; pdb.set_trace() #Plot a discrete representation of the vector field if numpy.all(self.U[:, :, self.mode] + self.V[:, :, self.mode] == 0): self.pp_ax.set(title=model_name + " mode " + str(self.mode) + ": NO MOTION IN THIS PLANE") X, Y = numpy.meshgrid(self.X, self.Y) self.pp_quivers = self.pp_ax.scatter(X, Y, s=8, marker=".", c="k") else: self.pp_quivers = self.pp_ax.quiver(self.X, self.Y, self.U[:, :, self.mode], self.V[:, :, self.mode], #self.UVmag[:, :, self.mode], width=0.001, headwidth=8) #Plot the nullclines self.nullcline_x = self.pp_ax.contour(self.X, self.Y, self.U[:, :, self.mode], [0], colors="r") self.nullcline_y = self.pp_ax.contour(self.X, self.Y, self.V[:, :, self.mode], [0], colors="g") self.ipp_fig.canvas.draw() def _plot_trajectory(self, x, y): """ Plot a sample trajectory, starting at the position x,y in the phase-plane. """ svx_ind = self.model.state_variables.index(self.svx) svy_ind = self.model.state_variables.index(self.svy) #Calculate an example trajectory state = self.default_sv.copy() state[svx_ind] = x state[svy_ind] = y scheme = self.integrator.scheme traj = numpy.zeros((TRAJ_STEPS + 1, self.model.nvar, 1, self.model.number_of_modes)) traj[0, :] = state for step in range(TRAJ_STEPS): #import pdb; pdb.set_trace() state = scheme(state, self.model.dfun, self.no_coupling, 0.0, 0.0) traj[step + 1, :] = state self.pp_ax.scatter(x, y, s=42, c='g', marker='o', edgecolor=None) self.pp_ax.plot(traj[:, svx_ind, 0, self.mode], traj[:, svy_ind, 0, self.mode]) #Plot the selected state variable trajectories as a function of time self.pp_splt.plot(numpy.arange(TRAJ_STEPS + 1) * self.integrator.dt, traj[:, :, 0, self.mode]) pylab.draw() def _click_trajectory(self, event): """ """ if event.inaxes is self.pp_ax: x, y = event.xdata, event.ydata self.log.info('trajectory starting at (%f, %f)', x, y) self._plot_trajectory(x, y) def update_model_parameter(self, param_name, param_new_value): """ Update model parameters based on the current parameter slider values. NOTE: Haven't figured out how to update independantly, so just update everything. """ #TODO: Grab caller and use val directly, ie independent parameter update. setattr(self.model, param_name, numpy.array([param_new_value])) self.model.update_derived_parameters() self._calc_phase_plane() self._update_phase_plane() def update_all_model_parameters(self, model_instance): for key in model_instance.ui_configurable_parameters: attr = getattr(model_instance, key) if isinstance(attr, numpy.ndarray) and attr.size == 1: setattr(self.model, key, numpy.array([attr[0]])) self.model.update_derived_parameters() self._calc_phase_plane() self._update_phase_plane() def update_model_parameters_from_dict(self, parameters_dict): """ NOTE: I expect that the given parameters exists on the current model and also that they are numpy arrays. Sets the parameters from the given dict on the current model instance and also updates the phase-plane. """ for param_name in parameters_dict: setattr(self.model, param_name, numpy.array([parameters_dict[param_name]])) self.model.update_derived_parameters() self._calc_phase_plane() self._update_phase_plane()
class AppForm(QMainWindow): ''' Master GUI. To initialize: app = QApplication(sys.argv) form = AppForm() form.show() app.exec_() ''' def __init__(self, parent=None): QMainWindow.__init__(self, parent) # Creates GUI framework self.create_main_frame() # Plots initial image self.init_draw() def create_main_frame(self): self.main_frame = QWidget() # Figure parameters. # FIXME Probably change figure parameters given computer resolution self.fig = Figure((10.0, 10.0), dpi=100) self.canvas = FigureCanvas(self.fig) self.canvas.setParent(self.main_frame) self.canvas.setFocusPolicy(Qt.StrongFocus) self.canvas.setFocus() # Matplotlib move around # FIXME remove zoom in button # http://stackoverflow.com/questions/12695678/how-to-modify-the-navigation-toolbar-easily-in-a-matplotlib-figure-window self.mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame) # Add figures to GUI vbox = QVBoxLayout() vbox.addWidget(self.canvas) # the matplotlib canvas vbox.addWidget(self.mpl_toolbar) # Image selection dropdown box self.image_selection_menu = QComboBox() self.image_selection_menu.addItem('Galaxy Simulation 1') self.image_selection_menu.addItem('Galaxy Image 1') self.image_selection_menu.addItem('Galaxy Image 2') self.image_selection_menu.addItem('Jupiter Narrow Field Simulation') self.image_selection_menu.addItem('Jupiter Wide Field Simulation') self.image_selection_menu.addItem('Star Formation Simulation 1') self.image_selection_menu.addItem('Star Formation Simulation 2') self.image_selection_menu.addItem('Star Formation Simulation 3') self.image_selection_menu.addItem('Star Formation Image 1') self.image_selection_menu.addItem('Star Formation Image 2') self.image_selection_menu.activated[str].connect(self.image_selection) vbox.addWidget(self.image_selection_menu) # Initialize GUI self.main_frame.setLayout(vbox) self.setCentralWidget(self.main_frame) def init_draw(self): ''' Sets up all of the matplotlib widgets ''' self.fig.clear() # gs = gridspec.GridSpec(3,1, height_ratios=[30,1,1]) self.image_axes = self.fig.add_subplot(111) self.fig.subplots_adjust(bottom = .25) # Initial image # FIXME add null image self.current_pixscale = .05 im = misc.imread('galaxy_images/im1.jpg') self.obj = ImageObject(im, self.current_pixscale) self.image_object = self.obj.current_image # Initialize slider bars self.imshow = self.image_axes.imshow(self.image_object, interpolation='nearest') self.sample_axis = self.fig.add_axes([0.25, 0.1, 0.65, 0.03]) self.fov_axis = self.fig.add_axes([0.25, 0.15, 0.65, 0.03]) # self.sample_axis = self.fig.add_subplot(gs[1]) # self.fov_axis = self.fig.add_subplot(gs[2]) self.sample_slider = Slider(self.sample_axis, 'Sampling (arcsecs/pix)', self.current_pixscale, self.current_pixscale * 100., valinit = self.current_pixscale) self.fov_slider = Slider(self.fov_axis, 'Field of View (arsecs)', .05, 3., valinit = .05) def update(val): self.obj.update_sampling(self.sample_slider.val) self.imshow.set_data(self.obj.current_image) self.canvas.draw() self.sample_slider.on_changed(update) self.canvas.draw() def image_selection(self, image_name): ''' Hacked together image selection. Takes selection from the image_selection_menu widget ''' if image_name == 'Galaxy Image 1': im = misc.imread('galaxy_images/im1.jpg') pixscale = .05 self.obj = ImageObject(im, pixscale) self.image_update() if image_name == 'Galaxy Image 2': im = misc.imread('galaxy_images/im2.jpg') pixscale = .05 self.obj = ImageObject(im, pixscale) self.image_update() if image_name == 'Galaxy Simulation 1': im = misc.imread('galaxy_simulations/im1.jpg') pixscale = .1 self.obj = ImageObject(im, pixscale) self.image_update() if image_name == 'Jupiter Narrow Field Simulation': im = misc.imread('jupiter_simulation/jupiter_zoomin.png') pixscale = .1 self.obj = ImageObject(im, pixscale) self.image_update() if image_name == 'Jupiter Wide Field Simulation': im = misc.imread('jupiter_simulation/jupiter_zoomout.png') pixscale = .1 self.obj = ImageObject(im, pixscale) self.image_update() if image_name == 'Star Formation Simulation 1': im = misc.imread('star_formation_simulation/im1.gif') pixscale = .1 self.obj = ImageObject(im, pixscale) self.image_update() if image_name == 'Star Formation Simulation 2': im = misc.imread('star_formation_simulation/im2.gif') pixscale = .1 self.obj = ImageObject(im, pixscale) self.image_update() if image_name == 'Star Formation Simulation 3': im = misc.imread('star_formation_simulation/im3.gif') pixscale = .1 self.obj = ImageObject(im, pixscale) self.image_update() if image_name == 'Star Formation Image 1': im = misc.imread('star_formation_images/im1.jpg') pixscale = .1 self.obj = ImageObject(im, pixscale) self.image_update() if image_name == 'Star Formation Image 2': im = misc.imread('star_formation_images/im2.gif') pixscale = .1 self.obj = ImageObject(im, pixscale) self.image_update() def image_update(self): ''' Helper function to image selection, resets image and sliders ''' self.imshow.set_data(self.obj.current_image) self.canvas.draw() if self.obj.master_sampling != self.current_pixscale: self.current_pixscale = self.obj.master_sampling self.sample_axis.cla() self.sample_slider = Slider(self.sample_axis, 'Sampling (arcsecs/pix)', self.current_pixscale, self.current_pixscale * 20., valinit = self.current_pixscale) def update(val): self.obj.update_sampling(self.sample_slider.val) self.imshow.set_data(self.obj.current_image) self.canvas.draw() self.sample_slider.on_changed(update) else: self.sample_slider.reset()
class PlanetarySurveyor(object): """ The PlanetarySurveyor creates a Matplotlib "widget" letting the user navigate map data loaded from an image file. """ def __init__(self, filename="templates/nowwhat.png"): """ Initialized with filename of image file containing the equirectangular map data. """ self.filename = filename self.load_image() # Setup display: self.fig = plt.figure(1) self.ax = plt.subplot(111) plt.clf() plt.subplots_adjust(left=0.1, bottom=0.20) self.meridian = -90 self.parallel = 22.5 self.projection = "orthographic" self.parallels = 16 self.meridians = 16 self.setup_display() # Setup mouse interaction: self.click = self.hemisphere_axes.figure.canvas.mpl_connect( 'button_press_event', self.mouseclick) self.cursor = Cursor(self.hemisphere_axes, useblit=True, color='red', linewidth=1) # Setup axes: self.axes_step = plt.axes([0.13, 0.15, 0.60, 0.03]) self.axes_meridians = plt.axes([0.13, 0.10, 0.60, 0.03]) self.axes_parallels = plt.axes([0.13, 0.05, 0.60, 0.03]) self.update_axes = plt.axes([0.79, 0.095, 0.08, 0.04]) self.reset_axes = plt.axes([0.79, 0.05, 0.08, 0.04]) self.radio_axes = plt.axes([0.88, 0.05, 0.11, 0.15]) # Setup sliders: self.step = 22.5 self.slider_step = Slider(self.axes_step, 'Step', 0, 90, valinit=self.step, valfmt='%2.1f') self.slider_meridians = Slider(self.axes_meridians, 'Meridians', 0, 64, valinit=self.parallels, valfmt='%2d') self.slider_parallels = Slider(self.axes_parallels, 'Parallels', 0, 64, valinit=self.parallels, valfmt='%2d') self.slider_step.on_changed(self.update) self.slider_meridians.on_changed(self.update) self.slider_parallels.on_changed(self.update) # Setup button(s): self.update_button = Button(self.update_axes, 'Update') self.update_button.on_clicked(self.update_display) self.button = Button(self.reset_axes, 'Reset') self.button.on_clicked(self.reset) # Setup radio buttons: self.radio = RadioButtons(self.radio_axes, ('ortho', 'eq.dist', 'rect'), active=0) self.radio.on_clicked(self.set_mode) self.projections = {"ortho": ("orthographic", "ortho"), "eq.dist": ("equidistant", "aeqd"), "rect": ("rectangular", "cyl")} # Almost done: self.update() plt.show() def load_image(self): """ Checks if the image file specified exists and is an image file. If this fails, the default map is loaded. """ try: map_image = plt.imread(self.filename) except IOError as e: print "Could not load file {0} ({1})".format( self.filename, e.strerror) print "Using default image..." self.filename = "templates/nowwhat.png" def setup_display(self): """ Setup parameters and map display. """ self.hemisphere_axes = plt.gca() self.R = 10000 * 360.0 / (2 * np.pi) self.width = 180 * 10000 self.height = 180 * 10000 if self.projection == 'orthographic': self.hemisphere = Basemap(projection="ortho", lon_0=self.meridian, lat_0=self.parallel, resolution='c', area_thresh=100000, ax=self.hemisphere_axes) elif self.projection == 'equidistant': self.hemisphere = Basemap(projection="aeqd", lon_0=self.meridian, lat_0=self.parallel, resolution='c', area_thresh=100000, rsphere=self.R, ax=self.hemisphere_axes, width=self.width, height=self.height) elif self.projection == 'rectangular': self.hemisphere = Basemap(projection="cyl", lon_0=0, lat_0=0, resolution='c', area_thresh=100000, ax=self.hemisphere_axes) self.hemisphere.warpimage(self.filename) self.hemisphere.drawmapboundary() self.draw_graticules() def update_display(self): """ Update map display. """ if self.projection == 'orthographic': self.hemisphere = Basemap(projection="ortho", lon_0=self.meridian, lat_0=self.parallel, resolution='c', area_thresh=100000, ax=self.hemisphere_axes) elif self.projection == 'equidistant': self.hemisphere = Basemap(projection="aeqd", lon_0=self.meridian, lat_0=self.parallel, resolution='c', area_thresh=100000, rsphere=self.R, ax=self.hemisphere_axes, width=self.width, height=self.height) elif self.projection == 'rectangular': self.hemisphere = Basemap(projection="cyl", lon_0=0, lat_0=0, resolution='c', area_thresh=100000, ax=self.hemisphere_axes) self.hemisphere_axes.cla() self.hemisphere.warpimage(self.filename) self.hemisphere.drawmapboundary() self.draw_graticules() self.update() def update(self, val=0): """ Update internal parameters from sliders, update coordiantes and draw. """ if self.step != self.slider_step.val: self.step = np.round(self.slider_step.val / 0.5) * 0.5 self.slider_step.set_val(self.step) if (self.meridians != self.slider_meridians.val or self.parallels != self.slider_parallels.val): self.meridians = np.round(self.slider_meridians.val ).astype(np.int) self.parallels = np.round(self.slider_parallels.val ).astype(np.int) self.fix_coordinates() plt.draw() def set_mode(self, val="ortho"): """ Set projection mode. """ self.projection = self.projections[val][0] self.update_display() def reset(self, event): """ Reset widget """ self.slider_step.reset() self.slider_meridians.reset() self.slider_parallels.reset() self.meridian = 90 self.parallel = 0 self.update() def mouseclick(self, event): """ Handle mouse navigation of map display for the different projections. """ if event.inaxes == self.hemisphere_axes: if event.button == 1: if self.projection == "rectangular": self.parallel = np.round(event.ydata / 0.5) * 0.5 self.meridian = np.round(event.xdata / 0.5) * 0.5 else: xlim = self.hemisphere_axes.get_xlim() x = np.round(3 * (event.xdata - 0.5 * (xlim[1] - xlim[0])) / (xlim[1] - xlim[0])) ylim = self.hemisphere_axes.get_ylim() y = np.round(3 * (event.ydata - 0.5 * (ylim[1] - ylim[0])) / (ylim[1] - ylim[0])) self.meridian += self.step * x self.parallel += self.step * y self.update_display() self.update() def fix_coordinates(self): """ Fix coordinates so they comply to standard representation for maps. """ if self.parallel > 90.0: self.parallel = 180.0 - self.parallel elif self.parallel < -90.0: self.parallel = -180.0 - self.parallel if self.meridian > 180.0: self.meridian = 360.0 - self.meridian elif self.meridian < -180.0: self.meridian = -360.0 - self.meridian self.hemisphere_axes.set_title("{0}: {1}".format(self.projection, self.get_coordinates())) def get_coordinates(self): """ Return string representation of coordinates in N-S/E-W standard. """ parallel = np.abs(self.parallel) meridian = np.abs(self.meridian) if self.parallel >= 0: NS = "N" else: NS = "S" if self.meridian >= 0: EW = "E" else: EW = "W" return "{0} {1}, {2} {3}".format(parallel, NS, meridian, EW) def get_graticule(self): """ Return resolution of the current graticule (distances between parallel and meridian lines). """ try: dLat = 180.0 / self.parallels except ZeroDivisionError: dLat = None try: dLon = 360.0 / self.meridians except ZeroDivisionError: dLon = 0 return dLat, dLon def draw_graticules(self): """ Draw parallel and meridian lines. """ parallel_step = 180.0 / self.parallels meridian_step = 360.0 / self.meridians if self.parallels > 0: min_parallel = -90 max_parallel = 90 - parallel_step self.hemisphere.drawparallels( np.arange(min_parallel, max_parallel + 1, parallel_step), latmax=90 - parallel_step) if self.meridians > 0: min_meridian = -180 max_meridian = 180 - meridian_step self.hemisphere.drawmeridians( np.arange(min_meridian, max_meridian + 1, meridian_step), latmax=90 - parallel_step)
class viewer: def __init__(self,fnames,selectX=False): self.fnames=fnames self.labels=make_short_labels(fnames) self.allchains=read_all_chains(self.fnames) #print('allchains:',self.allchains) self.fig, self.ax = plt.subplots() if selectX: leftlim=0.35 bottomlim=0.30 else: leftlim=0.25 bottomlim=0.25 plt.subplots_adjust(left=leftlim, bottom=bottomlim) cx0 = 1 cy0 = 0 s0 = 3 d0 = 2 x,y=get_xydata(self.allchains[0].data,cx0,cy0,10**d0,10**s0) try: cmapname='tab10' self.cmap = matplotlib.cm.get_cmap(cmapname) except ValueError: cmapname='Vega10' self.cmap = matplotlib.cm.get_cmap(cmapname) self.cmap_norm=10 self.scat = plt.scatter(x, y, s=1, c=x, cmap=cmapname,norm=colors.Normalize(0,self.cmap_norm)) #scat = plt.scatter([], [], s=1,cmap="tab10") axcolor = 'lightgoldenrodyellow' axstart = plt.axes([leftlim, 0.1, 0.9-leftlim, 0.03]) axdens = plt.axes([leftlim, 0.15, 0.9-leftlim, 0.03]) height=(len(allparnames)-1)*0.05 resetax = plt.axes([0.8, 0.025, 0.1, 0.04]) if not selectX: #rax = plt.axes([0.025, 0.5-height/2, 0.1, height], facecolor=axcolor) rYax = plt.axes([0.025, 0.5-height/2, 0.1, height]) else: rXax = plt.axes([0.025, 0.5-height/2, 0.1, height]) rXax.text(0.9, 0.95, "X", transform=rXax.transAxes, fontsize=11, verticalalignment='top',horizontalalignment='right') rYax = plt.axes([0.15, 0.5-height/2, 0.1, height]) rYax.text(0.9, 0.95, "Y", transform=rYax.transAxes, fontsize=11, verticalalignment='top',horizontalalignment='right') ilogS=(math.log10(Smax)) ilogSamps=int(math.log10(Nmax)) print("ilogSmax=",ilogS) #Start slider print('axstart',axstart) self.sstart = Slider(axstart, 'log-Start', 2, ilogS, valinit=s0) self.sstart.on_changed(self.update) #Density slider self.sdens = Slider(axdens, 'log-Density', 1, ilogSamps, valinit=d0) self.sdens.on_changed(self.update) #X/y-axis radio buttons if selectX: self.radioX = RadioButtons(rXax, allparnames, active=cx0) self.radioY = RadioButtons(rYax, allparnames, active=cy0) parnameswidth=max([len(x) for x in allparnames]) fontsize=self.radioX.labels[0].get_fontsize()/max([1,parnameswidth/5.]) #print("fontsize=",fontsize) for label in self.radioX.labels: label.set_fontsize(fontsize) for label in self.radioY.labels: label.set_fontsize(fontsize) for circle in self.radioX.circles: # adjust radius here. The default is 0.05 circle.set_radius(0.03) self.radioX.on_clicked(self.update) self.haveX=True #print('set radio') else: self.radioY = RadioButtons(rYax, allparnames, active=0) parnameswidth=max([len(x) for x in allparnames]) fontsize=self.radioY.labels[0].get_fontsize()/max([1,parnameswidth/5.]) #print("fontsize=",fontsize) for label in self.radioY.labels: label.set_fontsize(fontsize) self.haveX=False for circle in self.radioY.circles: # adjust radius here. The default is 0.05 circle.set_radius(0.03) self.radioY.on_clicked(self.update) #Reset button self.button = Button(resetax, 'Reset', color=axcolor, hovercolor='0.975') self.button.on_clicked(self.reset) #print('calling update') self.update() #print('save fig') #plt.savefig('junk.png') #print('calling show') plt.show() #print('finished init') def update(self,val=0): #argument is not used #c0=1+allparnames[1:].index(radio.value_selected) #print("index->",c0) start = int(10**self.sstart.val) samps = int(10**self.sdens.val) xmin=1e100;xmax=-1e100 ymin=1e100;ymax=-1e100 xy=np.array([]) cc=np.array([]) ic0=0.5; ind=0 plotlabels=[] for chain in self.allchains: includeChain=True if self.haveX: if(self.radioX.value_selected in chain.names): cx=chain.names.index(self.radioX.value_selected) else: includeChain=False else: cx=0 if(self.radioY.value_selected in chain.names): cy=chain.names.index(self.radioY.value_selected) else: includeChain=False if includeChain: x,y=get_xydata(chain.data,cx,cy,samps,start) n=len(x) #xy=np.array([xyi for xyi in xy if np.all(np.isfinite(xyi))]) colorval=ic0+ind if(cc.size>0): cc = np.concatenate((cc,[colorval]*n)) xy = np.vstack((xy,np.vstack((x, y)).T)) else: cc=np.array([colorval]*n) xy = np.vstack((x, y)).T if(n==0): ind+=1 continue lim=x.min() if(xmin>lim):xmin=lim lim=x.max() if(xmax<lim):xmax=lim lim=y.min() if(ymin>lim):ymin=lim lim=y.max() if(ymax<lim):ymax=lim plotlabels.append(mpatches.Patch(color=self.cmap(colorval/self.cmap_norm), label=self.labels[ind],hatch='.')) ind=ind+1 self.scat.set_offsets(xy) self.scat.set_array(cc) self.ax.set_xlim(xmin-0.1*(xmax-xmin),xmax+0.1*(xmax-xmin)) self.ax.set_ylim(ymin-0.1*(ymax-ymin),ymax+0.1*(ymax-ymin)) self.ax.legend(handles=plotlabels,fontsize=8) for tick in self.ax.get_xticklabels(): tick.set_rotation(20) self.fig.canvas.draw_idle() def reset(self,event): #fixme self.allchains=read_all_chains(self.fnames) self.sstart.reset() self.sdens.reset()
class guiMenu: fig = None gauss_params = [33, 7] logTextLabels = [] logText = [] axMisc = None axAlgorithm = None axSaveOptions = None axGauss = None axLog = None axRadio = None axLogLabels = None line_gaussian = None ax_window_size = None slider_window_size = None ax_sigma = None slider_sigma = None originalStdOut = None #------------------------------------------------------------------------------ # Class initialization # def __init__(self): self.strTitle = 'Gesture Analysis Configuration - ' + settings.appVersion self.fig = plt.figure() self.fig.canvas.set_window_title(self.strTitle) self.fig.set_size_inches((settings.screen_cx * 0.49) / self.fig.dpi, (settings.screen_cy * 0.465) / self.fig.dpi) self.fig.canvas.mpl_connect('resize_event', self.onresize) self.fig.canvas.mpl_connect('close_event', self.onclose) self.fig.edgecolor = 'blue' self.fig.set_facecolor('0.90') left = 0.03 # the left side of the subplots of the figure right = 0.97 # the right side of the subplots of the figure bottom = 0.04 # the bottom of the subplots of the figure top = 0.92 # the top of the subplots of the figure wspace = 0.3 # the amount of width reserved for blank space between subplots hspace = 0.7 # the amount of height reserved for white space between subplots plt.subplots_adjust(left=left, top=top, right=right, bottom=bottom, wspace=wspace, hspace=hspace) self.axMisc = plt.subplot2grid((6, 4), (0, 0), rowspan=1, colspan=1, aspect='auto', anchor='NW') self.axAlgorithm = plt.subplot2grid((6, 4), (1, 0), rowspan=2, colspan=1, aspect='auto', anchor='NW') self.axSaveOptions = plt.subplot2grid((6, 4), (3, 0), rowspan=3, colspan=1, aspect='equal', anchor='NW') self.axGauss = plt.subplot2grid((6, 4), (0, 1), rowspan=4, colspan=3) self.axLog = plt.subplot2grid((6, 4), (5, 1), rowspan=1, colspan=3, aspect='auto', anchor='NW') # create the various groups of UI controls self.createUIMiscellaneous() self.createUILog() self.createUIAlgorithm() self.createUIGaussianFilterControls() self.createUIMiscellaneousControls() # set settings.tkGuiCanvas for use for modal dialogs try: if (self.fig is not None) and (self.fig.canvas is not None) and ( self.fig.canvas._tkcanvas is not None): settings.tkGuiCanvas = self.fig.canvas._tkcanvas except Exception as e: pass #------------------------------------------------------------------------------ # def get_aspect(self, ax): # Total figure size figW, figH = ax.get_figure().get_size_inches() # Axis size on figure _, _, w, h = ax.get_position().bounds # Ratio of display units disp_ratio = (figH * h) / (figW * w) # Ratio of data units # Negative over negative because of the order of subtraction data_ratio = sub(*ax.get_ylim()) / sub(*ax.get_xlim()) return disp_ratio / data_ratio #------------------------------------------------------------------------------ # def createUIAlgorithm(self): algorithm = settings.application.algorithm.lower() defaultAlgoritmIdx = 0 if (algorithm == 'total'): defaultAlgoritmIdx = 0 elif (algorithm == 'parallel'): defaultAlgoritmIdx = 1 elif (algorithm == 'naive'): defaultAlgoritmIdx = 2 self.axAlgorithm.set_title('Algorithm', x=0, horizontalalignment='left') # create an axis to host to radio buttons. make its aspect ratio # equal so the radiobuttons stay round aspect = self.get_aspect(self.axAlgorithm) rect = [0, 0, 1.0 * aspect, 1.0] ip = InsetPosition(self.axAlgorithm, rect) self.axRadio = plt.axes(rect) self.axRadio.set_axes_locator(ip) self.axRadio.axis('off') self.radioAlgorithm = RadioButtons( self.axRadio, ('Total Energy', 'Parallel Energy', 'Naive (no filter)'), active=defaultAlgoritmIdx) self.radioAlgorithm.on_clicked(self.onClickAlgorithm) #------------------------------------------------------------------------------ # def createUIGaussianFilterControls(self): axcolor = 'lightgoldenrodyellow' rect = [0.82, -0.158, 0.14, 0.07] ax_btnapply = plt.axes(rect) ip = InsetPosition(self.axGauss, rect) #posx, posy, width, height ax_btnapply.set_axes_locator(ip) self.btnApply = Button(ax_btnapply, 'Apply') self.btnApply.on_clicked(self.onclickApply) rect = [0.82, -0.245, 0.14, 0.07] ax_btnreset = plt.axes(rect) ip = InsetPosition(self.axGauss, rect) #posx, posy, width, height ax_btnreset.set_axes_locator(ip) self.btnReset = Button(ax_btnreset, 'Reset', color='0.950', hovercolor='0.975') self.btnReset.on_clicked(self.onclickReset) rect = [0.1, -0.155, 0.55, 0.04] self.ax_window_size = plt.axes(rect, facecolor=axcolor) ip = InsetPosition(self.axGauss, rect) #posx, posy, width, height self.ax_window_size.set_axes_locator(ip) self.slider_window_size = Slider(self.ax_window_size, 'Window Size', 1, (self.gauss_params[0] + 1) * 2 + 1, valinit=self.gauss_params[0], valstep=2) self.slider_window_size.on_changed(self.updateGaussianFilter) rect = [0.1, -0.235, 0.55, 0.04] self.ax_sigma = plt.axes(rect, facecolor=axcolor) ip = InsetPosition(self.axGauss, rect) #posx, posy, width, height self.ax_sigma.set_axes_locator(ip) self.slider_sigma = Slider(self.ax_sigma, 'Sigma', 1, (self.gauss_params[1] + 1) * 2, valinit=self.gauss_params[1], valstep=1) self.slider_sigma.on_changed(self.updateGaussianFilter) self.updateGaussianFilter() #------------------------------------------------------------------------------ # def createUIMiscellaneous(self): self.axMisc.set_title('', x=0, horizontalalignment='left') # removing top and right borders self.axMisc.xaxis.set_visible(False) self.axMisc.yaxis.set_visible(False) # remove ticks self.axSaveOptions.set_xticks([]) self.axSaveOptions.set_yticks([]) # remove ticks self.axAlgorithm.set_xticks([]) self.axAlgorithm.set_yticks([]) bbox = self.axMisc.get_window_extent() self.axMisc.set_xlim(0, bbox.width) self.axMisc.set_ylim(0, bbox.height) #------------------------------------------------------------------------------ # def createUILog(self): self.axLog.set_title('Console Log', x=0, horizontalalignment='left') # removing top and right borders self.axLog.xaxis.set_visible(False) self.axLog.yaxis.set_visible(False) self.resetLogLabels() # redirect console messages to gui's log self.originalStdOut = sys.stdout sys.stdout = CaptureOutput() # ----------------------------------------------------------------------------- # def resetLogLabels(self): cnt = len(self.logTextLabels) for i in range(0, cnt): self.logTextLabels[i].remove() self.logTextLabels = [] bbox = self.axLog.get_window_extent() self.axLog.set_xlim(0, bbox.width) self.axLog.set_ylim(0, bbox.height) aspect = self.get_aspect(self.axLog) rect = [0, 0, 1.0 * aspect, 1.0] ip = InsetPosition(self.axLog, rect) if (self.axLogLabels is None): self.axLogLabels = plt.axes(rect) else: self.axLogLabels.set_position(rect) self.axLogLabels.set_axes_locator(ip) self.axLogLabels.axis('off') aspectLog = 1.0 / self.get_aspect(self.axLog) strText = 'Tyg' tmp, self.logTextHeight = settings.getTextExtent(self.axLog, strText) self.logTextHeight = self.logTextHeight * aspectLog # * self.fig.dpi # pre-create empty log label placeholders self.logTextLabels = [] y = (self.logTextHeight / 4.0) cy = bbox.height idx = len(self.logText) - 1 while (y < cy): str = self.logText[idx] if (idx >= 0) else '' idx = idx - 1 lbl = self.axLogLabels.text( 8.0, y, str, horizontalalignment='left', verticalalignment='bottom', color='dimgray', clip_on=True, transform=self.axLog.transData ) #, bbox={'facecolor':'lightgray', 'alpha':0.7, 'pad':0.0}) self.logTextLabels.append(lbl) y += self.logTextHeight # ----------------------------------------------------------------------------- # def createUIMiscellaneousControls(self): rect = [0.06, 0.30, 0.70, 0.40] ip = InsetPosition(self.axMisc, rect) #posx, posy, width, height ax_btnbrowse = plt.axes(rect) ax_btnbrowse.set_axes_locator(ip) self.btnBrowse = Button(ax_btnbrowse, 'Input File') self.btnBrowse.on_clicked(self.onclickBrowse) self.axSaveOptions.set_title('Output Files', x=0, horizontalalignment='left') x = 0.06 dx = 0.70 # 0.80 dy = 0.10 # 0.17 cy = 0.14 # 0.24 y = 0.80 rect = [x, y, dx, dy] ip = InsetPosition(self.axSaveOptions, rect) #posx, posy, width, height ax_btn = plt.axes(rect) ax_btn.set_axes_locator(ip) self.btnSaveJSON = Button(ax_btn, 'JSON') self.btnSaveJSON.on_clicked(self.onclickSaveJSON) rect = [x, y - 1 * cy, dx, dy] ip = InsetPosition(self.axSaveOptions, rect) #posx, posy, width, height ax_btn = plt.axes(rect) ax_btn.set_axes_locator(ip) self.btnSaveTXT = Button(ax_btn, 'Text') self.btnSaveTXT.on_clicked(self.onclickSaveTXT) rect = [x, y - 2 * cy, dx, dy] ip = InsetPosition(self.axSaveOptions, rect) #posx, posy, width, height ax_btn = plt.axes(rect) ax_btn.set_axes_locator(ip) self.btnSaveFilterView = Button(ax_btn, 'Filter Graph') self.btnSaveFilterView.on_clicked(self.onclickSaveFilterView) rect = [x, y - 3 * cy, dx, dy] ip = InsetPosition(self.axSaveOptions, rect) #posx, posy, width, height ax_btn = plt.axes(rect) ax_btn.set_axes_locator(ip) self.btnSaveSkeletonView = Button(ax_btn, '3D Joint Data') self.btnSaveSkeletonView.on_clicked(self.onclickSaveSkeletonView) rect = [x, y - 4 * cy, dx, dy] ip = InsetPosition(self.axSaveOptions, rect) #posx, posy, width, height ax_btn = plt.axes(rect) ax_btn.set_axes_locator(ip) self.btnSaveScoreView = Button(ax_btn, 'Score View') self.btnSaveScoreView.on_clicked(self.onclickSaveScoreView) rect = [x, y - 5 * cy, dx, dy] ip = InsetPosition(self.axSaveOptions, rect) #posx, posy, width, height ax_btn = plt.axes(rect) ax_btn.set_axes_locator(ip) self.btnSavePNG = Button(ax_btn, 'Full Score') self.btnSavePNG.on_clicked(self.onclickSaveImage) #------------------------------------------------------------------------------ # canvas resize event # def onresize(self, event): # plt.tight_layout() # keep tha radio buttons round... if (self.axRadio is not None) and (self.axAlgorithm is not None): aspect = self.get_aspect(self.axAlgorithm) rect = [0, 0, 1.0 * aspect, 1.0] ip = InsetPosition(self.axAlgorithm, rect) self.axRadio.set_axes_locator(ip) self.axRadio.set_position(rect) self.resetLogLabels() # ----------------------------------------------------------------------------- # canvas close event # def onclose(self, event): self.fig = None # if user closes this figure, let the main application know and to exit settings.application.close() # ----------------------------------------------------------------------------- # def updateUIControls(self, algorithm): algorithm = algorithm.lower() fEnable = False if (algorithm == 'naive') else True alpha = 0.2 if (algorithm == 'naive') else 1.0 self.btnApply.set_active(fEnable) self.btnReset.set_active(fEnable) self.btnApply.label.set_alpha(alpha) self.btnReset.label.set_alpha(alpha) fUpdateGaussianPlot = False if (self.gauss_params[0] != self.slider_window_size.val): self.ax_window_size.clear() self.slider_window_size.__init__( self.ax_window_size, 'Window Size', valmin=1, valmax=(self.gauss_params[0] + 1) * 2 + 1, valinit=self.gauss_params[0], valstep=2) self.slider_window_size.on_changed(self.updateGaussianFilter) fUpdateGaussianPlot = True if (self.gauss_params[1] != self.slider_sigma.val): self.ax_sigma.clear() self.slider_sigma.__init__(self.ax_sigma, 'Sigma', valmin=1, valmax=(self.gauss_params[1] + 1) * 2, valinit=self.gauss_params[1], valstep=1) self.slider_sigma.on_changed(self.updateGaussianFilter) fUpdateGaussianPlot = True if (fUpdateGaussianPlot): self.updateGaussianFilter() self.line_gaussian.set_alpha(alpha) self.ax_window_size.patch.set_alpha(alpha) if (self.slider_window_size.poly): self.slider_window_size.poly.set_alpha(alpha) self.slider_window_size.set_active(fEnable) for r in self.slider_window_size.ax.texts: r.set_alpha(alpha) self.ax_sigma.patch.set_alpha(alpha) if (self.slider_sigma.poly): self.slider_sigma.poly.set_alpha(alpha) self.slider_sigma.set_active(fEnable) for r in self.slider_sigma.ax.texts: r.set_alpha(alpha) self.fig.canvas.draw_idle() # ----------------------------------------------------------------------------- # def updateInputName(self): self.fig.canvas.set_window_title( self.strTitle + ' - [' + settings.application.strBeautifiedInputFile + ']') # ----------------------------------------------------------------------------- # def getAlgorithmSelection(self): if (self.radioAlgorithm.value_selected == 'Total Energy'): return 'Total' elif (self.radioAlgorithm.value_selected == 'Parallel Energy'): return 'Parallel' return 'Naive' # ----------------------------------------------------------------------------- # def onClickAlgorithm(self, label): algorithm = self.getAlgorithmSelection() if (settings.application.labanotation is not None): self.gauss_params = settings.application.labanotation.getGaussianParameters( algorithm) self.updateUIControls(algorithm) settings.application.applyAlgoritm(algorithm) #------------------------------------------------------------------------------ # updateGaussianFilter() has an unused parameter, though needs it because the # sliders use this function as their update callback... def updateGaussianFilter(self, val=0): # remove current gaussian lines if (self.line_gaussian is not None): self.line_gaussian.remove() del self.line_gaussian self.line_gaussian = None gauss_params = (int(self.slider_window_size.val), int(self.slider_sigma.val)) self._t = np.arange(-gauss_params[0] / 2.0 + 0.5, gauss_params[0] / 2.0 + 0.5, 1.0) s = wf.gaussFilter(gauss_params[0], gauss_params[1]) self.line_gaussian, = self.axGauss.plot(self._t, s, marker="o", linestyle='-', color='red', lw=1) # for i, txt in enumerate(s): # self.axGauss.annotate("{:0.2f}".format(txt), (self._t[i], s[i])) wnd = int(gauss_params[0] / 2) + 1 self.axGauss.set_xlim(-wnd, wnd) self.axGauss.set_ylim(0, 0.42) # np.max(s)) self.fig.canvas.draw_idle() #------------------------------------------------------------------------------ # def onclickApply(self, event): algorithm = self.getAlgorithmSelection() self.gauss_params = (int(self.slider_window_size.val), int(self.slider_sigma.val)) if (settings.application.labanotation is not None): settings.application.labanotation.setGaussianParameters( algorithm, self.gauss_params) settings.application.applyAlgoritm(algorithm) #------------------------------------------------------------------------------ # def onclickSaveJSON(self, event): settings.application.saveJSON() #------------------------------------------------------------------------------ # def onclickSaveTXT(self, event): settings.application.saveTXT() #------------------------------------------------------------------------------ # def onclickSaveImage(self, event): settings.application.saveImage() #------------------------------------------------------------------------------ # def onclickSaveFilterView(self, event): settings.application.saveFilterView() #------------------------------------------------------------------------------ # def onclickSaveSkeletonView(self, event): settings.application.saveSkeletonView() #------------------------------------------------------------------------------ # def onclickSaveScoreView(self, event): settings.application.saveScoreView() #------------------------------------------------------------------------------ # def onclickReset(self, event): self.slider_window_size.reset() self.slider_sigma.reset() #------------------------------------------------------------------------------ # def onclickBrowse(self, event): file = self.selectInputFile() if (file is None): return settings.application.openAndProcessInputfile(file) #------------------------------------------------------------------------------ # def selectInputFile(self): fTyp = [("Kinect Joint Data File", "*.csv")] splitInput = os.path.split( os.path.abspath(settings.application.inputFilePath)) options = {} options['filetypes'] = fTyp options['initialdir'] = splitInput[0].replace('/', os.sep) if (settings.tkGuiCanvas is not None): options['parent'] = settings.tkGuiCanvas file = tkFileDialog.askopenfilename(**options) if not file: return None return file #------------------------------------------------------------------------------ # def logMessage(self, str, ioRedirect=False): # also write message to console if (self.originalStdOut is not None): extra = "\r\n" if (ioRedirect is False) else "" self.originalStdOut.write(str + extra) self.logText.append(str) cnt = len(self.logTextLabels) if (cnt > 0): for i in range(cnt - 1, 0, -1): self.logTextLabels[i].set_text( self.logTextLabels[i - 1].get_text()) self.logTextLabels[0].set_text(str) self.fig.canvas.draw_idle()
class PlotFrame(wx.Frame): """ PlotFrame is a custom wxPython frame to hold the panel with a Figure and WxAgg backend canvas for matplotlib plots or other figures. In this frame: self is an instance of a wxFrame; axes is an instance of MPL Axes; fig is an instance of MPL Figure; panel is an instance of wxPanel, used for the main panel, to hold canvas, an instance of MPL FigureCanvasWxAgg. """ # Main function to set everything up when the frame is created def __init__(self, title, pos, size): """ This will be executed when an instance of PlotFrame is created. It is the place to define any globals as "self.<name>". """ wx.Frame.__init__(self, None, wx.ID_ANY, title, pos, size) if len(sys.argv) < 2: self.filename = "" else: self.filename = sys.argv[1] # set some Boolean flags self.STOP = False self.data_loaded = False self.reverse_play = False self.step = 1 # Make the main Matplotlib panel for plots self.create_main_panel() # creates canvas and contents # Then add wxPython widgets below the MPL canvas # Layout with box sizers self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.EXPAND) self.sizer.AddSpacer(10) self.sizer.Add(self.toolbar, 0, wx.EXPAND) self.sizer.AddSpacer(10) # Make the control panel with a row of buttons self.create_button_bar() self.sizer.Add(self.button_bar_sizer, 0, flag = wx.ALIGN_CENTER | wx.TOP) # Make a Status Bar self.statusbar = self.CreateStatusBar() self.sizer.Add(self.statusbar, 0, wx.EXPAND) self.SetStatusText("Frame created ...") # ------------------------------------------------------- # set up the Menu Bar # ------------------------------------------------------- menuBar = wx.MenuBar() menuFile = wx.Menu() # File menu menuFile.Append(1, "&Open", "Filename(s) or wildcard list to plot") menuFile.Append(3, "Save", "Save plot as a PNG image") menuFile.AppendSeparator() menuFile.Append(10, "E&xit") menuBar.Append(menuFile, "&File") menuHelp = wx.Menu() # Help menu menuHelp.Append(11, "&About Netview") menuHelp.Append(12, "&Usage and Help") menuHelp.Append(13, "Program &Info") menuBar.Append(menuHelp, "&Help") self.SetMenuBar(menuBar) self.panel.SetSizer(self.sizer) self.sizer.Fit(self) # ------------------------------------------------------- # Bind the menu items to functions # ------------------------------------------------------- self.Bind(wx.EVT_MENU, self.OnOpen, id=1) self.Bind(wx.EVT_MENU, self.OnSave, id=3) self.Bind(wx.EVT_MENU, self.OnQuit, id=10) self.Bind(wx.EVT_MENU, self.OnAbout, id=11) self.Bind(wx.EVT_MENU, self.OnUsage, id=12) self.Bind(wx.EVT_MENU, self.OnInfo, id=13) # methods defined below to get and plot the data # Normally do the plot on request, and not here # self.get_data_params() # self.init_plot() # self.get_xyt_data() # plot_data() # ---------- end of __init__ ---------------------------- # ------------------------------------------------------- # Function to make the main Matplotlib panel for plots # ------------------------------------------------------- def create_main_panel(self): """ create_main_panel creates the main mpl panel with instances of: * mpl Canvas * mpl Figure * mpl Figure * mpl Axes with subplot * mpl Widget class Sliders and Button * mpl navigation toolbar self.axes is the instance of MPL Axes, and is where it all happens """ self.panel = wx.Panel(self) # Create the mpl Figure and FigCanvas objects. # 3.5 x 5 inches, 100 dots-per-inch # self.dpi = 100 self.fig = Figure((3.5, 5.0), dpi=self.dpi) self.canvas = FigCanvas(self.panel, wx.ID_ANY, self.fig) # Since we have only one plot, we could use add_axes # instead of add_subplot, but then the subplot # configuration tool in the navigation toolbar wouldn't work. self.axes = self.fig.add_subplot(111) # (111) == (1,1,1) --> row 1, col 1, Figure 1) # self.axes.set_title("View from: "+self.filename) # Now create some sliders below the plot after making room self.fig.subplots_adjust(left=0.1, bottom=0.20) self.axtmin = self.fig.add_axes([0.2, 0.10, 0.5, 0.03]) self.axtmax = self.fig.add_axes([0.2, 0.05, 0.5, 0.03]) self.stmin = Slider(self.axtmin, 't_min:', 0.0, 1.0, valinit = 0.0) self.stmax = Slider(self.axtmax, 't_max:', 0.0, 1.0, valinit = 1.0) self.stmin.on_changed(self.update_trange) self.stmax.on_changed(self.update_trange) self.axbutton = self.fig.add_axes([0.8, 0.07, 0.1, 0.07]) self.reset_button = Button(self.axbutton, 'Reset') self.reset_button.color = 'skyblue' self.reset_button.hovercolor = 'lightblue' self.reset_button.on_clicked(self.reset_trange) # Create the navigation toolbar, tied to the canvas self.toolbar = NavigationToolbar(self.canvas) def update_trange(self, event): self.t_min = self.stmin.val self.t_max = self.stmax.val # print(self.t_min, self.t_max) def reset_trange(self, event): self.stmin.reset() self.stmax.reset() def create_button_bar(self): """ create_button_bar makes a control panel bar with buttons and toggles for New Data - Play - STOP - Single Step - Forward/Back - Normal/Fast It does not create a Panel container, but simply creates Button objects with bindings, and adds them to a horizontal BoxSizer self.button_bar_sizer. This is added to the PlotFrame vertical BoxSizer, after the MPL canvas, during initialization of the frame. """ rewind_button = wx.Button(self.panel, -1, "New Data") self.Bind(wx.EVT_BUTTON, self.OnRewind, rewind_button) replot_button = wx.Button(self.panel, -1, "Play") self.Bind(wx.EVT_BUTTON, self.OnReplot, replot_button) sstep_button = wx.Button(self.panel, -1, "Single Step") self.Bind(wx.EVT_BUTTON, self.OnSstep, sstep_button) stop_button = wx.Button(self.panel, -1, "STOP") self.Bind(wx.EVT_BUTTON, self.OnStop, stop_button) # The toggle buttons need to be globally accessible self.forward_toggle = wx.ToggleButton(self.panel, -1, "Forward") self.forward_toggle.SetValue(True) self.forward_toggle.SetLabel("Forward") self.Bind(wx.EVT_TOGGLEBUTTON, self.OnForward, self.forward_toggle) self.fast_toggle = wx.ToggleButton(self.panel, -1, " Normal ") self.fast_toggle.SetValue(True) self.fast_toggle.SetLabel(" Normal ") self.Bind(wx.EVT_TOGGLEBUTTON, self.OnFast, self.fast_toggle) # Set button colors to some simple colors that are likely # to be independent on X11 color definitions. Some nice # bit maps (from a media player skin?) should be used # or the buttons and toggle state colors in OnFast() below rewind_button.SetBackgroundColour('skyblue') replot_button.SetBackgroundColour('skyblue') sstep_button.SetBackgroundColour('skyblue') stop_button.SetBackgroundColour('skyblue') self.forward_toggle.SetForegroundColour('black') self.forward_toggle.SetBackgroundColour('yellow') self.fast_toggle.SetForegroundColour('black') self.fast_toggle.SetBackgroundColour('yellow') self.button_bar_sizer = wx.BoxSizer(wx.HORIZONTAL) flags = wx.ALIGN_CENTER | wx.ALL self.button_bar_sizer.Add(rewind_button, 0, border=3, flag=flags) self.button_bar_sizer.Add(replot_button, 0, border=3, flag=flags) self.button_bar_sizer.Add(sstep_button, 0, border=3, flag=flags) self.button_bar_sizer.Add(stop_button, 0, border=3, flag=flags) self.button_bar_sizer.Add(self.forward_toggle, 0, border=3, flag=flags) self.button_bar_sizer.Add(self.fast_toggle, 0, border=3, flag=flags) # ------------------------------------------------------- # Functions to generate or read (x,y) data and plot it # ------------------------------------------------------- def get_data_params(self): # These parameters would normally be provided in a file header, # past as arguments in a function, or from other file information # Next version will bring up a dialog for dt NX NY if no file header # Here check to see if a filename should be entered from File/Open # self.filename = 'Ex_net_Vm_0001.txt' if len(self.filename) == 0: # fake a button press of File/Open self.OnOpen(wx.EVT_BUTTON) # should check here if file exists as specified [path]/filename # assume it is a bzip2 compressed file try: fp = bz2.BZ2File(self.filename) line = fp.readline() except IOError: # then assume plain text fp = open(self.filename) line = fp.readline() fp.close() # check if first line is a header line starting with '#' header = line.split() if header[0][0] == "#": self.Ntimes = int(header[1]) self.t_min = float(header[2]) self.dt = float(header[3]) self.NX = int(header[4]) self.NY = int(header[5]) else: pdentry = self.ParamEntryDialog() if pdentry.ShowModal() == wx.ID_OK: self.Ntimes = int(pdentry.Ntimes_dialog.entry.GetValue()) self.t_min = float(pdentry.tmin_dialog.entry.GetValue()) self.dt = float(pdentry.dt_dialog.entry.GetValue()) self.NX = int(pdentry.NX_dialog.entry.GetValue()) self.NY = int(pdentry.NY_dialog.entry.GetValue()) print 'Ntimes = ', self.Ntimes, ' t_min = ', self.t_min print 'NX = ', self.NX, ' NY = ', self.NY pdentry.Destroy() self.t_max = (self.Ntimes - 1)*self.dt # reset slider max and min self.stmin.valmax = self.t_max self.stmin.valinit = self.t_min self.stmax.valmax = self.t_max self.stmax.valinit = self.t_max self.stmax.set_val(self.t_max) self.stmin.reset() self.stmax.reset() fp.close() def init_plot(self): ''' init_plot creates the initial plot display. A normal MPL plot would be created here with a command "self.axes.plot(x, y)" in order to create a plot of points in the x and y arrays on the Axes subplot. Here, we create an AxesImage instance with imshow(), instead. The initial image is a blank one of the proper dimensions, filled with zeroes. ''' self.t_max = (self.Ntimes - 1)*self.dt self.axes.set_title("View of "+self.filename) # Note that NumPy array (row, col) = image (y, x) data0 = np.zeros((self.NY,self.NX)) # Define a 'cold' to 'hot' color scale based in GENESIS 2 'hot' hotcolors = ['#000032', '#00003c', '#000046', '#000050', '#00005a', '#000064', '#00006e', '#000078', '#000082', '#00008c', '#000096', '#0000a0', '#0000aa', '#0000b4', '#0000be', '#0000c8', '#0000d2', '#0000dc', '#0000e6', '#0000f0', '#0000fa', '#0000ff', '#000af6', '#0014ec', '#001ee2', '#0028d8', '#0032ce', '#003cc4', '#0046ba', '#0050b0', '#005aa6', '#00649c', '#006e92', '#007888', '#00827e', '#008c74', '#00966a', '#00a060', '#00aa56', '#00b44c', '#00be42', '#00c838', '#00d22e', '#00dc24', '#00e61a', '#00f010', '#00fa06', '#00ff00', '#0af600', '#14ec00', '#1ee200', '#28d800', '#32ce00', '#3cc400', '#46ba00', '#50b000', '#5aa600', '#649c00', '#6e9200', '#788800', '#827e00', '#8c7400', '#966a00', '#a06000', '#aa5600', '#b44c00', '#be4200', '#c83800', '#d22e00', '#dc2400', '#e61a00', '#f01000', '#fa0600', '#ff0000', '#ff0a00', '#ff1400', '#ff1e00', '#ff2800', '#ff3200', '#ff3c00', '#ff4600', '#ff5000', '#ff5a00', '#ff6400', '#ff6e00', '#ff7800', '#ff8200', '#ff8c00', '#ff9600', '#ffa000', '#ffaa00', '#ffb400', '#ffbe00', '#ffc800', '#ffd200', '#ffdc00', '#ffe600', '#fff000', '#fffa00', '#ffff00', '#ffff0a', '#ffff14', '#ffff1e', '#ffff28', '#ffff32', '#ffff3c', '#ffff46', '#ffff50', '#ffff5a', '#ffff64', '#ffff6e', '#ffff78', '#ffff82', '#ffff8c', '#ffff96', '#ffffa0', '#ffffaa', '#ffffb4', '#ffffbe', '#ffffc8', '#ffffd2', '#ffffdc', '#ffffe6', '#fffff0'] cmap = matplotlib.colors.ListedColormap(hotcolors) self.im = self.axes.imshow(data0, cmap=cmap, origin='lower') # http://matplotlib.sourceforge.net/examples/pylab_examples/show_colormaps.html # shows examples to use as a 'cold' to 'hot' mapping of value to color # cm.jet, cm.gnuplot and cm.afmhot are good choices, but are unlike G2 'hot' self.im.cmap=cmap # Not sure how to properly add a colorbar # self.cb = self.fig.colorbar(self.im, orientation='vertical') # refresh the canvas self.canvas.draw() def get_xyt_data(self): # Create scaled (0-1) luminance(x,y) array from ascii G-2 disk_out file # get the data to plot from the specified filename # Note that NumPy loadtxt transparently deals with bz2 compression self.SetStatusText('Data loading - please wait ....') rawdata = np.loadtxt(self.filename) # Note the difference between NumPy [row, col] order and network # x-y grid (x, y) = (col, row). We want a NumPy NY x NX, not # NX x NY, array to be used by the AxesImage object. xydata = np.resize(rawdata, (self.Ntimes, self.NY, self.NX)) # imshow expects the data to be scaled to range 0-1. Vmin = xydata.min() Vmax = xydata.max() self.ldata = (xydata - Vmin)/(Vmax - Vmin) self.data_loaded = True self.SetStatusText('Data has been loaded - click Play') def plot_data(self): ''' plot_data() shows successive frames of the data that was loaded into the ldata array. Creating a new self.im AxesImage instance for each frame is extremely slow, so the set_data method of AxesImage is used to load new data into the existing self.im for each frame. Normally 'self.canvas.draw()' would be used to display a frame, but redrawing the entire canvas, redraws the axes, labels, sliders, buttons, or anything else on the canvas. This uses a method taken from an example in Ch 7, p. 192 Matplotlib for Python developers, with draw_artist() and blit() redraw only the part that was changed. ''' if self.data_loaded == False: # bring up a warning dialog msg = """ Data for plotting has not been loaded! Please enter the file to plot with File/Open, unless it was already specified, and then click on 'New Data' to load the data to play back, before clicking 'Play'. """ wx.MessageBox(msg, "Plot Warning", wx.OK | wx.ICON_ERROR,self) return # set color limits self.im.set_clim(0.0, 1.0) self.im.set_interpolation('nearest') # 'None' is is slightly faster, but not implemented for MPL ver < 1.1 # self.im.set_interpolation('None') # do an initial draw, then save the empty figure axes self.canvas.draw() # self.bg = self.canvas.copy_from_bbox(self.axes.bbox) # However the save and restore is only needed if I change # axes legends, etc. The draw_artist(artist), and blit # are much faster than canvas.draw() and are sufficient. print 'system time (seconds) = ', time.time() # round frame_min down and frame_max up for the time window frame_min = int(self.t_min/self.dt) frame_max = min(int(self.t_max/self.dt) + 1, self.Ntimes) frame_step = self.step # Displaying simulation time to the status bar is much faster # than updating a slider progress bar, but location isn't optimum. # The check for the STOP button doesn't work because the button # click is not registered until this function exits. # check to see if self.reverse_play == True # then interchange frame_min, frame_max, and use negative step if self.reverse_play == True: frame_min = min(int(self.t_max/self.dt) + 1, self.Ntimes) - 1 frame_max = int(self.t_min/self.dt) - 1 frame_step = -self.step for frame_num in range(frame_min, frame_max, frame_step): self.SetStatusText('time: '+str(frame_num*self.dt)) if self.STOP == True: self.t_min = frame_num*self.dt # set t_min slider ? self.STOP = False break self.im.set_data(self.ldata[frame_num]) self.axes.draw_artist(self.im) self.canvas.blit(self.axes.bbox) print 'system time (seconds) = ', time.time() # ------------------------------------------------------------------ # Define the classes and functions for getting parameter values # -------------------------------------------------------------- class ParamEntryDialog(wx.Dialog): def __init__(self): wx.Dialog.__init__(self, None, wx.ID_ANY) self.SetSize((250, 200)) self.SetTitle('Enter Data File Parameters') vbox = wx.BoxSizer(wx.VERTICAL) self.Ntimes_dialog = XDialog(self) self.Ntimes_dialog.entry_label.SetLabel('Number of entries') self.Ntimes_dialog.entry.ChangeValue(str(2501)) self.tmin_dialog = XDialog(self) self.tmin_dialog.entry_label.SetLabel('Start time (sec)') self.tmin_dialog.entry.ChangeValue(str(0.0)) self.dt_dialog = XDialog(self) self.dt_dialog.entry_label.SetLabel('Output time step (sec)') self.dt_dialog.entry.ChangeValue(str(0.0002)) self.NX_dialog = XDialog(self) self.NX_dialog.entry_label.SetLabel('Number of cells on x-axis') self.NX_dialog.entry.ChangeValue(str(32)) self.NY_dialog = XDialog(self) self.NY_dialog.entry_label.SetLabel('Number of cells on y-axis') self.NY_dialog.entry.ChangeValue(str(32)) vbox.Add(self.Ntimes_dialog, 0, wx.EXPAND|wx.ALL, border=5) vbox.Add(self.tmin_dialog, 0, wx.EXPAND|wx.ALL, border=5) vbox.Add(self.dt_dialog, 0, wx.EXPAND|wx.ALL, border=5) vbox.Add(self.NX_dialog, 0, wx.EXPAND|wx.ALL, border=5) vbox.Add(self.NY_dialog, 0, wx.EXPAND|wx.ALL, border=5) okButton = wx.Button(self, wx.ID_OK,'Ok') # vbox.Add(okButton,flag=wx.ALIGN_CENTER|wx.TOP|wx.BOTTOM, border=10) vbox.Add(okButton,flag=wx.ALIGN_CENTER, border=10) self.SetSizer(vbox) self.SetSizerAndFit(vbox) # ------------------------------------------------------------------ # Define the functions executed on menu choices # --------------------------------------------------------------- def OnQuit(self, event): self.Close() def OnSave(self, event): file_choices = "PNG (*.png)|*.png" dlg = wx.FileDialog( self, message="Save plot as...", defaultDir=os.getcwd(), defaultFile="plot.png", wildcard=file_choices, style=wx.SAVE) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() self.canvas.print_figure(path, dpi=self.dpi) # self.flash_status_message("Saved to %s" % path) def OnAbout(self, event): msg = """ G-3 Netview ver. 1.7 Netview is a stand-alone Python application for viewing the output of GENESIS 2 and 3 network simulations. It is intended to replace GENESIS 2 SLI scripts that use the XODUS 'xview' widget. The design and operation is based on the G3Plot application for creating 2D plots of y(t) or y(x) from data files. Unlike G3Plot, the image created with Netview is an animated representation of a rectangular network with colored squares used to indicate the value of some variable at that position and time. Typically, this would be the membrane potenial of a cell soma, or a synaptic current in a dendrite segment. Help/Usage gives HTML help for using Netview. This is the main Help page. Help/Program Info provides some information about the objects and functions, and the wxPython and matplotlib classes used here. Dave Beeman, August 2012 """ dlg = wx.MessageDialog(self, msg, "About G-3 Netview", wx.OK | wx.ICON_QUESTION) dlg.ShowModal() dlg.Destroy() def OnOpen(self, event): dlg = wx.TextEntryDialog(self, "File with x,y data to plot", "File Open", self.filename, style=wx.OK|wx.CANCEL) if dlg.ShowModal() == wx.ID_OK: self.filename = dlg.GetValue() # A new filename has been entered, but the data has not been read self.data_loaded = False # print "You entered: %s" % self.filename dlg.Destroy() # This starts with the long string of HTML to display class UsageFrame(wx.Frame): text = """ <HTML> <HEAD></HEAD> <BODY BGCOLOR="#D6E7F7"> <CENTER><H1>Using G-3 Netview</H1></CENTER> <H2>Introduction and Quick Start</H2> <p>Netview is a stand-alone Python application for viewing the output of GENESIS 2 and 3 network simulations. It is intended to replace GENESIS 2 SLI scripts that use the XODUS 'xview' widget.</p> <p>The design and operation is based on the G3Plot application for creating 2D plots of y(t) or y(x) from data files. As with G3Plot, the main class PlotFrame uses a basic wxPython frame to embed a matplotlib figure for plotting. It defines some basic menu items and a control panel of buttons and toggles, each with bindings to a function to execute on a mouse click.</p> <p>Unlike G3Plot, the image created with Netview is an animated representation of a rectangular network with colored squares used to indicate the value of some variable at that position and time. Typically, this would be the membrane potenial of a cell soma, or a synaptic current in a dendrite segment.</p> <h2>Usage</h2> <p>The Menu Bar has <em>File/Open</em>, <em>File/Save</em>, and <em>File/Exit</em> choices. The Help Menu choices <em>About</em> and <em>Usage</em> give further information. The <em>Program Info</em> selection shows code documentation that is contained in some of the main function <em>docstrings</em>.</p> <p>After starting the <em>netview</em> program, enter a data file name in the dialog for File/Open, unless the filename was given as a command line argument. Then click on <strong>New Data</strong> to load the new data and initialize the plot. When the plot is cleared to black, press <strong>Play</strong>.</p> <p>The file types recognized are plain text or text files compressed with bzip2. The expected data format is one line for each output time step, with each line having the membrane potential value of each cell in the net. No time value should be given on the line. In order to properly display the data, netview needs some additional information about the network and the data. This can optionally be contained in a header line that precedes the data. If a header is not detected, a dialog will appear asking for the needed parameters.</p> <p>It is assumed that the cells are arranged on a NX x NY grid, numbered from 0 (bottom left corner) to NX*NY - 1 (upper right corner). In order to provide this information to netview, the data file should begin with a header line of the form:</p> <pre> #optional_RUNID_string Ntimes start_time dt NX NY SEP_X SEP_Y x0 y0 z0 </pre> <p>The line must start with "#" and can optionally be followed immediately by any string. Typically this is some identification string generated by the simulation run. The following parameters, separated by blanks or any whitespace, are:</p> <ul> <li>Ntimes - the number of lines in the file, exclusive of the header</li> <li>start_time - the simulation time for the first data line (default 0.0)</li> <li>dt - the time step used for output</li> <li>NX, NY - the integer dimensions of the network</li> <li>SEP_X, SEP_Y - the x,y distances between cells (optional)</li> <li>x0, y0, z0 - the location of the compartment (data source) relative to the cell origin</li> </ul> <p>The RUNID string and the last five parameters are not read or used by netview. These are available for other data analysis tools that need a RUNID and the location of each source.</p> <p>The slider bars can be used to set a time window for display, and the <strong>Reset</strong> button can set t_min and t_max back to the defaults. Use the <strong>Forward/Back</strong> toggle to reverse direction of <strong>Play</strong>, and the <strong>Normal/Fast</strong> toggle to show every tenth frame.</p> <p>The <strong>Single Step</strong> button can be used to advance a single step at a time (or 10, if in 'Fast' mode).</p> <p>The <strong>STOP</strong> button is currently not implemented</p> <p>To plot different data, enter a new filename with <strong>File/Open</strong> and repeat with <strong>New Data</strong> and <strong>Play</strong>.</p> <HR> </BODY> </HTML> """ def __init__(self, parent): wx.Frame.__init__(self, parent, -1, "Usage and Help", size=(640,600), pos=(400,100)) html = wx.html.HtmlWindow(self) html.SetPage(self.text) panel = wx.Panel(self, -1) button = wx.Button(panel, wx.ID_OK, "Close") self.Bind(wx.EVT_BUTTON, self.OnCloseMe, button) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(html, 1, wx.EXPAND|wx.ALL, 5) sizer.Add(panel, 0, wx.ALIGN_CENTER|wx.ALL, 5) self.SetSizer(sizer) self.Layout() def OnCloseMe(self, event): self.Close(True) # ----------- end of class UsageFrame --------------- def OnUsage(self,event): usagewin = self.UsageFrame(self) usagewin.Show(True) def OnInfo(self,event): msg = "Program information for PlotFrame obtained from docstrings:" msg += "\n" + self.__doc__ + "\n" + self.create_main_panel.__doc__ msg += self.create_button_bar.__doc__ msg += self.init_plot.__doc__ msg += self.plot_data.__doc__ dlg = wx.lib.dialogs.ScrolledMessageDialog(self, msg, "PlotFrame Documentation") dlg.ShowModal() # --------------------------------------------------------------- # Define the functions executed on control button click # --------------------------------------------------------------- def OnRewind(self,event): self.get_data_params() self.init_plot() self.get_xyt_data() def OnReplot(self,event): self.plot_data() self.canvas.draw() def OnSstep(self,event): if self.data_loaded == False: # bring up a warning dialog msg = """ Data for plotting has not been loaded! Please enter the file to plot with File/Open, unless it was already specified, and then click on 'New Data' to load the data to play back, before clicking 'Play'. """ wx.MessageBox(msg, "Plot Warning", wx.OK | wx.ICON_ERROR,self) return self.t_max = min(self.t_max + self.dt, (self.Ntimes - 1)*self.dt) self.stmax.set_val(self.t_max) frame_num = int(self.t_max/self.dt) self.SetStatusText('time: '+str(frame_num*self.dt)) self.im.set_data(self.ldata[frame_num]) self.axes.draw_artist(self.im) self.canvas.blit(self.axes.bbox) def OnStop(self,event): self.STOP = 'True' def OnForward(self,event): state = self.forward_toggle.GetValue() if state: self.reverse_play = False self.forward_toggle.SetLabel("Forward ") self.forward_toggle.SetForegroundColour('black') self.forward_toggle.SetBackgroundColour('yellow') else: self.reverse_play = True self.forward_toggle.SetLabel(" Back ") self.forward_toggle.SetForegroundColour('red') self.forward_toggle.SetBackgroundColour('green') def OnFast(self,event): state = self.fast_toggle.GetValue() if state: # print state self.fast_toggle.SetLabel(" Normal ") self.fast_toggle.SetForegroundColour('black') self.fast_toggle.SetBackgroundColour('yellow') self.step = 1 else: # print state self.fast_toggle.SetLabel(" Fast ") self.fast_toggle.SetForegroundColour('red') self.fast_toggle.SetBackgroundColour('green') self.step = 10
class RotatableAxes: def __init__(self, fig: mpl.figure.Figure, axes: mpl.axes.Axes, rect_angle: list, rect_reset: list): self.fig = fig # Suppose that there exists an image in the axes self.axes = axes self.renderer = self.axes.figure.canvas.get_renderer() self.axes_img_instance = self.axes.get_images()[0] self.original_axes_img = self.axes_img_instance.make_image( self.renderer, unsampled=True)[0] self.axes_for_angle_slider = self.fig.add_axes(rect_angle) self.axes_for_reset_button = self.fig.add_axes(rect_reset) self.angle_slider = Slider(self.axes_for_angle_slider, 'Angle(Degree)', 0.0, 359.0, valinit=0.0, valstep=0.1) self.angle_slider.on_changed(self.update_img) self.reset_button = Button(self.axes_for_reset_button, 'Reset') self.reset_button.on_clicked(self.reset) def connect(self) -> None: # connect to all the events we need self.fig.canvas.mpl_connect('button_press_event', self.onclick) def disconnect(self) -> None: # disconnect all the stored connection ids self.fig.canvas.mpl_disconnect(self.onclick) def update_la_img(self): self.axes_img_instance = self.axes.get_images()[0] self.original_axes_img = self.axes_img_instance.make_image( self.renderer, unsampled=True)[0] self.angle_slider.reset() def onclick(self, event: mpl.backend_bases.Event) -> None: if self.axes == event.inaxes: cur_img = self.axes_img_instance.make_image(self.renderer, unsampled=True)[0] if event.button == mpl.backend_bases.MouseButton.LEFT and event.inaxes is not None: rotated_image = ndimage.rotate(cur_img, 90.0, reshape=False) self.axes_img_instance.set_data(rotated_image) elif event.button == mpl.backend_bases.MouseButton.RIGHT and event.inaxes is not None: flipped_img = cur_img[:, ::-1] self.axes_img_instance.set_data(flipped_img) self.axes.figure.canvas.draw() self.axes.figure.canvas.flush_events() def update_img(self, new_angle: float) -> None: axes_images_list = self.axes.get_images() rotated_img = ndimage.rotate(self.original_axes_img, new_angle, reshape=False) axes_images_list[0].set_data(rotated_img) self.axes.figure.canvas.update() self.axes.figure.canvas.flush_events() def reset(self, event: mpl.backend_bases.Event): self.angle_slider.reset()
class RotatableAxes: def __init__(self, fig: mpl.figure.Figure, axes: mpl.axes.Axes, rect_angle: list, rect_reset: list): self.fig = fig # Suppose that there exists an image in the axes self.axes = axes self.renderer = self.axes.figure.canvas.get_renderer() self.axes_img = self.axes.get_images()[0] self.original_axes_img = self.axes_img self.original_img_list = [[ np.rot90(img, i) for i in range(4) ] for img in [self.axes_img._A, self.axes_img._A[::-1, :]]] self.rot_idx = 0 self.flip_idx = 0 self.axes_for_angle_slider = self.fig.add_axes(rect_angle) self.axes_for_reset_button = self.fig.add_axes(rect_reset) self.angle_slider = Slider(self.axes_for_angle_slider, 'Angle(Degree)', 0.0, 359.9, valinit=0.0, valstep=0.1) self.angle_slider.on_changed(self.update_img) self.reset_button = Button(self.axes_for_reset_button, 'Reset') self.reset_button.on_clicked(self.reset) def connect(self) -> None: # connect to all the events we need self.fig.canvas.mpl_connect('button_press_event', self.onclick) def disconnect(self) -> None: # disconnect all the stored connection ids self.fig.canvas.mpl_disconnect(self.onclick) def update_la_img(self) -> None: self.axes_img = self.axes.get_images()[0] self.original_axes_img = self.axes_img self.original_img_list = [[ np.rot90(img, i) for i in range(4) ] for img in [self.axes_img._A, self.axes_img._A[::-1, :]]] self.rot_idx = 0 self.flip_idx = 0 self.angle_slider.reset() def update_after_rot90(self) -> None: self.rot_idx = (self.rot_idx + 1) % 4 left, right, bottom, top = self.original_axes_img.get_extent() self.axes_img.set_extent([top, bottom, right, left]) def update_after_flip(self) -> None: self.flip_idx = (self.flip_idx + 1) % 2 def onclick(self, event: mpl.backend_bases.Event) -> None: if self.axes == event.inaxes: if event.button == mpl.backend_bases.MouseButton.LEFT: self.update_after_rot90() elif event.button == mpl.backend_bases.MouseButton.RIGHT: self.update_after_flip() self.angle_slider.set_val(self.angle_slider.val) self.axes.figure.canvas.draw() self.axes.figure.canvas.flush_events() def update_img(self, new_angle: float) -> None: rotated_img = rotate_img( self.original_img_list[self.flip_idx][self.rot_idx], new_angle) self.axes_img.set_data(rotated_img) self.axes.figure.canvas.update() self.axes.figure.canvas.flush_events() def reset(self, event: mpl.backend_bases.Event) -> None: self.angle_slider.reset()
class UHIDisplay: def __init__(self, sample_dir): self.sample_dir = sample_dir self.sample_idx = 0 self.uhi = None self.h, self.w, self.d = 0, 0, 0 self.px_min, self.px_max, self.refl_min, self.refl_max = 0, 0, 0, 0 self.has_refl = False self.show_refl = False self.autoscale = True # List sample files print(f'Reading sample directory... ({self.sample_dir})') self.sample_files = [ fname for fname in os.listdir(self.sample_dir) if fname.endswith('.h5') ] if not self.sample_files: print('No samples found in given directory, exiting...') exit() self.sample_files = sorted(self.sample_files) # Initialize first sample self.update_sample() # Create figure self.fig = plt.figure(figsize=(12, 4)) plt.tight_layout() gridspec.GridSpec(1, 2) self.ax_uhi = plt.subplot2grid((3, 1), (0, 0), colspan=1, rowspan=3) self.image = self.ax_uhi.imshow(self.uhi.px[:, :, self.d // 2], origin='lower') # Wavelength slider axfreq = plt.axes([0.1, 0.1, 0.8, 0.05], facecolor='lightgoldenrodyellow') self.sband = Slider(axfreq, 'Band [nm]', 0, self.d - 1, valinit=self.d // 2) self.sband.on_changed(self.update_band) # Previous button self.btn_prev_ax = plt.axes([0.04, 0.8, 0.1, 0.075]) self.btn_prev = Button(self.btn_prev_ax, 'Prev') self.btn_prev.on_clicked(self.click_prev) # Next button self.btn_next_ax = plt.axes([0.15, 0.8, 0.1, 0.075]) self.btn_next = Button(self.btn_next_ax, 'Next') self.btn_next.on_clicked(self.click_next) # Raw data / reflectance button self.btn_toggle_ax = plt.axes([0.26, 0.8, 0.1, 0.075]) self.btn_toggle = Button(self.btn_toggle_ax, 'Reflectance') self.btn_toggle.on_clicked(self.click_toggle) # Autoscaling (per-band) / uniform scaling button self.btn_autoscale_ax = plt.axes([0.37, 0.8, 0.1, 0.075]) self.btn_autoscale = Button(self.btn_autoscale_ax, 'Autoscale off') self.btn_autoscale.on_clicked(self.click_autoscale) self.update_title() self.fig.tight_layout() plt.tight_layout() plt.show() def update_sample(self): self.uhi = UHIData() self.uhi.read_hdf5( os.path.join(self.sample_dir, self.sample_files[self.sample_idx])) (self.w, self.h, self.d) = self.uhi.px.shape # Calculate reflectance self.uhi.calc_refl() self.refl_min, self.refl_max = np.min( self.uhi.refl[:, :, 50:-50]), np.max(self.uhi.refl[:, :, 50:-50]) self.px_min, self.px_max = np.min(self.uhi.px[:, :, 50:-50]), np.max( self.uhi.px[:, :, 50:-50]) self.has_refl = self.uhi.refl is not None def update_band(self, val=None): if val is None: val = self.sband.val band = np.floor(self.sband.val).astype(np.int) px = self.uhi.refl[:, :, band] if self.show_refl else self.uhi.px[:, :, band] self.image.set_data(px) if self.autoscale: self.image.autoscale() else: self.image.set_clim( vmin=self.refl_min if self.show_refl else self.px_min, vmax=self.refl_max if self.show_refl else self.px_max) self.sband.valtext.set_text(f'{self.uhi.wl[int(np.floor(val))]:.2f}') self.fig.canvas.draw_idle() def update_title(self): self.fig.suptitle( f'Sample {os.path.splitext(self.sample_files[self.sample_idx])[0]}' ) def click_prev(self, event): self.sample_idx -= 1 self.sample_idx = self.sample_idx if self.sample_idx > 0 else len( self.sample_files) - 1 self.update_sample() self.update_band() self.update_title() def click_next(self, event): self.sample_idx += 1 self.sample_idx = self.sample_idx % len(self.sample_files) self.update_sample() self.update_band() self.update_title() def click_toggle(self, event): if not self.has_refl: print( 'Sample does not have calibration data embedded. Cannot show reflectance' ) self.show_refl = False else: self.show_refl = not self.show_refl self.btn_toggle.label.set_text( 'Reflectance' if not self.show_refl else 'Raw data') print('Displaying reflectance' if self. show_refl else 'Displaying raw data') self.update_band() def click_autoscale(self, event): self.autoscale = not self.autoscale self.btn_autoscale.label.set_text( 'Autoscale off' if self.autoscale else 'Autoscale on') print('Autoscale on' if self.autoscale else 'Autoscale off') self.update_band() def reset(self, event): self.sband.reset()
class vlm_slicer_interactive: def __init__(self, seis_vlm, pred_vlm, flag_slice): axis_color = 'lightgoldenrodyellow' idx_max = np.shape(seis_vlm)[2] self.seis_vlm = seis_vlm self.pred_vlm = pred_vlm self.cmap_bg = plt.cm.gray_r self.flag_slice = flag_slice fig = plt.figure() fig.subplots_adjust(left=0.25, bottom=0.25) self.ax = fig.add_subplot(111) self.idx_slider_ax = fig.add_axes([0.4, 0.1, 0.35, 0.03], facecolor=axis_color) self.idx_slider = Slider(self.idx_slider_ax, 'Z', 0, idx_max, valinit=0, valfmt='%d') self.idx_slider.on_changed(self.sliders_on_changed) self.reset_button_ax = fig.add_axes([0.8, 0.025, 0.1, 0.04]) self.reset_button = Button(self.reset_button_ax, 'Reset', color=axis_color, hovercolor='0.975') self.reset_button.on_clicked(self.reset_button_on_clicked) self.plot_slice(idx=0) self.fig = fig self.imshow_alpha() plt.show() def plot_slice(self, idx): if self.flag_slice == 0: self.seis_slice = self.seis_vlm[:, :, idx] self.pred_slice = self.pred_vlm[:, :, idx] elif self.flag_slice == 1: self.seis_slice = self.seis_vlm[:, idx, :] self.pred_slice = self.pred_vlm[:, idx, :] elif self.flag_slice == 2: self.seis_slice = self.seis_vlm[idx, :, :] self.pred_slice = self.pred_vlm[idx, :, :] def create_img_alpha(self, img_input): img_alpha = np.zeros( [np.shape(img_input)[0], np.shape(img_input)[1], 4]) threshold = 0.1 img_input[img_input < threshold] = 0 # Yellow: (1,1,0), Red: (1,0,0) img_alpha[:, :, 0] = 1 img_alpha[:, :, 1] = 0 img_alpha[:, :, 2] = 0 img_alpha[..., -1] = img_input return img_alpha def imshow_alpha(self, idx=0): self.plot_slice(idx) img_alpha = self.create_img_alpha(self.pred_slice.T) self.ax.imshow(self.seis_slice.T, self.cmap_bg) self.ax.imshow(img_alpha, alpha=0.5) def sliders_on_changed(self, val): self.imshow_alpha(int(val)) self.fig.canvas.draw_idle() def reset_button_on_clicked(self, mouse_event): self.idx_slider.reset()
class Visualisation: def __init__(self, probability, big_dates, small_dates): self.probability = probability self.big_dates = big_dates self.small_dates = small_dates self.days = int(input("Number of days to visualize: ")) self.x_data = np.arange(0.0, self.days, 1) self.initial_work_rate = int(input("Initial work rate: ")) self.init_price_big = int(input("Initial price for a recovery try of full backups: ")) self.init_price_small = int(input("Initial price for a recovery try of incremental backups: ")) self.ax_color = 'lightgoldenrodyellow' self.s_work_rate = Slider self.s_price_big = Slider self.s_price_small = Slider def y_data(self, price_big, price_small, work_r): fail_big = 0 fail_small = 0 counter = 0 prices = self.x_data.copy() for time_iterator in self.x_data: for date_iterator in self.big_dates: if time_iterator == date_iterator: fail_big += 1 for date_iterator in self.small_dates: if time_iterator == date_iterator: fail_small += 1 prices[counter] = self.x_data[counter] * work_r + price_big * fail_big + price_small * fail_small counter += 1 return prices def slider_setup(self): ax_work_rate = plt.axes([0.25, 0.15, 0.65, 0.03], facecolor=self.ax_color) ax_price_big = plt.axes([0.25, 0.10, 0.65, 0.03], facecolor=self.ax_color) ax_price_small = plt.axes([0.25, 0.05, 0.65, 0.03], facecolor=self.ax_color) self.s_work_rate = Slider(ax_work_rate, 'Work Rate', 0.1, 300.0, valinit=self.initial_work_rate) self.s_price_big = Slider(ax_price_big, 'Big backup price', 0.1, 250.0, valinit=self.init_price_big) self.s_price_small = Slider(ax_price_small, 'Small backup price', 0.1, 250.0, valinit=self.init_price_small) def button_setup(self): reset_ax = plt.axes([0.8, 0.01, 0.1, 0.04]) button = Button(reset_ax, 'Reset', color=self.ax_color, hovercolor='0.975') return button def defining_plots(self): fig, ax = plt.subplots() plt.subplots_adjust(left=0.25, bottom=0.25) l, = plt.plot(self.x_data, self.y_data(self.init_price_big, self.init_price_small, self.initial_work_rate), lw=1.2) ax.margins(x=0) return [fig, l] def actual_plot(self): self.defining_plots() self.s_work_rate.on_changed(self.update) self.s_price_big.on_changed(self.update) self.s_price_small.on_changed(self.update) self.button_setup() button = self.button_setup() button.on_clicked(self.reset) plt.show() def reset(self, event): self.s_work_rate.reset() self.s_price_big.reset() self.s_price_small.reset() self.button_setup.on_clicked(self.reset) def update(self, val): plots = self.defining_plots() work_rate = self.s_work_rate.val price_big = self.s_price_big.val price_small = self.s_price_small.val plots[0].canvas.draw_idle() plots[1].set_ydata(self.y_data(price_big, price_small, work_rate))
class Graphics(object): def __init__(self, wl, r1, r2): # Initialize graphics using Matplotlib global mask self.wli = wl self.ri1 = r1 self.ri2 = r2 self.wl_msk = np.array([]) self.dwl_msk = np.array([]) self.fig1 = plt.figure(figsize=(15, 6)) self.ax1 = self.fig1.add_subplot(1, 1, 1) plt.subplots_adjust(bottom=0.35) self.ax1.set_xlabel('Wavelength, Angstroms') self.ax1.set_ylabel('Residual intensity') if mask == "": # Widgets # Button "Select line" axis_line = plt.axes([0.04, 0.025, 0.1, 0.04]) self.button_line = Button(axis_line, 'Select line', color='grey', hovercolor='0.975') self.button_line.on_clicked(self.lineselect) # Button "Measure line" axis_measure = plt.axes([0.15, 0.025, 0.1, 0.04]) self.button_measure = Button(axis_measure, 'Measure line', color='grey', hovercolor='0.975') self.button_measure.on_clicked(self.measure_line) # Button "Write result" axis_writeout = plt.axes([0.26, 0.025, 0.1, 0.04]) self.button_writeout = Button(axis_writeout, 'Write results', color='green', hovercolor='0.975') self.button_writeout.on_clicked(self.write_line) # Button "Dump line" axis_dumpline = plt.axes([0.37, 0.025, 0.1, 0.04]) self.button_dumpline = Button(axis_dumpline, 'Dump line', color='grey', hovercolor='0.975') self.button_dumpline.on_clicked(self.dump_line) # Button "Save mask" axis_savemask = plt.axes([0.48, 0.025, 0.1, 0.04]) if mask == "": name = 'Save mask' else: name = 'Measure by mask' self.button_savemask = Button(axis_savemask, name, color='grey', hovercolor='0.975') if args.usemask == "": self.button_savemask.on_clicked(self.save_mask) else: self.button_savemask.on_clicked(self.measure_mask) # Button "Analyse" axis_analyse = plt.axes([0.59, 0.025, 0.1, 0.04]) self.button_analyse = Button(axis_analyse, 'Analyse results', color='blue', hovercolor='0.975') self.button_analyse.on_clicked(self.analyse) # Button "Reset plot" axis_reset = plt.axes([0.74, 0.025, 0.1, 0.04]) self.button_reset = Button(axis_reset, 'Reset plot', color='orange', hovercolor='0.975') self.button_reset.on_clicked(self.reset) # Button "Exit" axis_exit = plt.axes([0.85, 0.025, 0.1, 0.04]) self.button_exit = Button(axis_exit, 'Exit app.', color='red', hovercolor='0.975') self.button_exit.on_clicked(self.exit) # draw initial plot self.ax1.plot(self.wli, self.ri1, linestyle='-', lw=1, marker='.', ms=1.1, color='red') self.ax1.plot(self.wli, self.ri2, linestyle='-', lw=1, marker='.', ms=1.1, color='blue') self.ax1.set_xlim([self.wli[0] - 1., self.wli[-1] + 1.]) if mask != "": self.readin_mask(mask) cursor = Cursor(self.ax1, useblit=True, color='red', linewidth=0.5) # Controls if mask != "": # Slider "Shift mask" axis_shiftmask = plt.axes([0.15, 0.10, 0.65, 0.03]) self.slider_shiftmask = Slider(axis_shiftmask, 'Shift mask [km/s]', -150, 150, valinit=0) self.slider_shiftmask.on_changed(self.shiftmask) else: # Slider "line width" axis_width = plt.axes([0.15, 0.1, 0.65, 0.03]) self.slider_width = Slider(axis_width, 'Selection Width', 0.5, 22.0, valinit=1.4) self.slider_width.on_changed(self.change_range) # Slider "line center" axis_shift = plt.axes([0.15, 0.20, 0.65, 0.03]) self.slider_shift = Slider(axis_shift, 'Selection shift', -6., 6., valinit=0.) self.slider_shift.on_changed(self.change_range) plt.show() def lineselect(self, event): print("Mark center of measured line") self.cid1 = self.fig1.canvas.mpl_connect('button_press_event', self.selected) def selected(self, event): if (event.button == 1): yc = self.ax1.get_ylim() self.lc = event.xdata self.fig1.canvas.mpl_disconnect(self.cid1) width = self.slider_width.val shift = self.slider_shift.val center = (self.lc + shift) self.band, = self.ax1.bar(center, width=width, height=max(self.ri1), color='blue', alpha=0.3, align='center') self.ax1.set_ylim(yc[0], yc[1]) plt.draw() self.line = ZLine() self.line.change_range(center - width / 2., width) def change_range(self, event): width = self.slider_width.val shift = self.slider_shift.val center = self.lc + self.slider_shift.val self.band.set_width(width) self.band.set_x(center - width / 2.) plt.draw() self.line.change_range(center - width / 2., width) def measure_line(self, event): global mask self.line.measure_line() if hasattr(self.line, 'func1') and hasattr(self.line, 'func2'): self.ax1.plot(self.line.fit_wl, self.line.func1, 'g-', lw=1) self.ax1.plot(self.line.fit_wl, self.line.func2, 'k-', lw=1) mingfit = min(min(self.line.func1), min(self.line.func2)) self.ax1.plot([self.line.gcent1, self.line.gcent1], [mingfit - 0.03, mingfit - 0.01], 'g-', lw=0.7) self.ax1.plot([self.line.gcent2, self.line.gcent2], [mingfit - 0.03, mingfit - 0.01], 'k-', lw=0.7) # self.ax1.plot(self.line.nwl1, self.line.cont1, 'r-') # draw semi-continuum # self.ax1.plot(self.line.nwl2, self.line.cont2, 'b-') # the same plt.draw() if mask == "": self.slider_shift.reset() def analyse(self, event): global report_fh ZSpec().analyse() def measure_mask(self, event): for ln in range(len(self.wl_msk)): self.line = ZLine() self.line.change_range(self.wl_msk[ln] - self.dwl_msk[ln], 2 * self.dwl_msk[ln]) self.measure_line(self) if hasattr(self.line, 'func1') and hasattr(self.line, 'func2'): self.write_line(self) print("Measuring using the mask has completed.") def readin_mask(self, file_mask): self.wl_msk, self.dwl_msk = np.loadtxt(file_mask, unpack=True, usecols=(0, 1), delimiter=';', comments='#') self.wl0_msk = self.wl_msk self.band_msk = self.ax1.bar(self.wl_msk, width=self.dwl_msk * 2., height=max(self.ri1), color='orange', alpha=0.5, align='center') plt.draw() def shiftmask(self, event): yc = self.ax1.get_ylim() self.wl_msk = self.wl0_msk * np.sqrt( (1. + self.slider_shiftmask.val / c) / (1. - self.slider_shiftmask.val / c)) for i in range(len(self.wl_msk)): self.band_msk[i].set_x(self.wl_msk[i] - self.dwl_msk[i]) plt.draw() self.ax1.set_ylim(yc[0], yc[1]) def reset(self, event): global mask self.ax1.clear() self.ax1.plot(self.wli, self.ri1, 'r-', lw=0.7) self.ax1.plot(self.wli, self.ri2, 'b-', lw=0.7) self.ax1.set_xlim([self.wli[0] - 1., self.wli[-1] + 1.]) if mask == "": self.slider_width.reset() self.slider_shift.reset() else: self.slider_shiftmask.reset() def write_line(self, event): global fh if len(self.line.res) > 1: np.savetxt(fh, self.line.res.transpose(), fmt='%10.4f') self.line.close() print("...saved") self.ax1.text( (self.line.gcent1 + self.line.gcent2) / 2, min(min(self.line.func1), min(self.line.func2)) - 0.04, 'S') self.wl_msk = np.append(self.wl_msk, np.mean(self.line.wl)) self.dwl_msk = np.append(self.dwl_msk, np.mean(self.line.wl) - self.line.wl[0]) else: print("...skipped") def save_mask(self, event): global mask_fh output = np.zeros(self.wl_msk.size, dtype=[('wave', float), ('width', float), ('id', 'U32'), ('lande', float)]) output['wave'] = self.wl_msk output['width'] = self.dwl_msk output['id'] = np.repeat('NoID', len(self.wl_msk)) output['lande'] = 1.23 * np.ones(len(self.wl_msk)) try: np.savetxt(mask_fh, output, header='Wl0 ; dWl ; ID ; g_lande', fmt="%.4f; %.4f; %s; %.2f") finally: print(f"Mask {mask_fh} saved.") def dump_line(self, event): # Make text dump of lines outname = str(int(self.line.cent1)) outarr1 = self.line.wl outarr2 = self.line.wl np.savetxt(outname + '_1.line', np.vstack((outarr1, self.line.r1)).transpose(), fmt='%10.4f', delimiter='\t') np.savetxt(outname + '_2.line', np.vstack((outarr2, self.line.r2)).transpose(), fmt='%10.4f', delimiter='\t') def exit(self, event): self.ax1.set_xlim([self.wli[0] - 1., self.wli[-1] + 1.]) self.ax1.set_ylim([0, 1.1]) self.fig1.savefig(report_fh + ".visual.pdf", dpi=350) exit(0)
class Vorwaertsproblem(): def __init__(self, l_e=10, l_r=3, h_m=30, h_b=90, phi_0=135, delta_phi=45, psi=90, show_legend=True): self.l_e = l_e self.l_r = l_r self.h_m = h_m self.h_b = h_b self.phi = phi_0 self.delta_phi = delta_phi self.psi = psi self.show_legend = show_legend def initUI(self): self.fig, self.ax = plt.subplots() self.fig.canvas.set_window_title('Numerik DGL 2 - Schattenprojektion') self.fig.suptitle('Vorwaertsproblem') plt.subplots_adjust(bottom=0.3) plt.axis([0, 200, -100, 100]) plt.axis('equal') axColor = 'lightgoldenrodyellow' # Slider - Phi axPhi = plt.axes([0.18, 0.2, 0.65, 0.03], axisbg=axColor) self.sliderPhi = Slider(axPhi, 'Phi', 0, 360, valinit=self.phi, valfmt='%1d') self.sliderPhi.on_changed(self.onUpdate) # Slider - Delta Phi axDeltaPhi = plt.axes([0.18, 0.15, 0.65, 0.03], axisbg=axColor) self.sliderDeltaPhi = Slider(axDeltaPhi, 'Delta Phi', 5, 360, valinit=self.delta_phi, valfmt='%1d') self.sliderDeltaPhi.on_changed(self.onUpdate) # Slider - Psi axPsi = plt.axes([0.18, 0.1, 0.65, 0.03], axisbg=axColor) self.sliderPsi = Slider(axPsi, 'Psi', 0, 180, valinit=self.psi, valfmt='%1d') self.sliderPsi.on_changed(self.onUpdate) # Button - Previous axPrev = plt.axes([0.18, 0.03, 0.1, 0.05]) self.buttonPrev = Button(axPrev, 'Previous') self.buttonPrev.on_clicked(self.onPrevious) # Button - Next axNext = plt.axes([0.29, 0.03, 0.1, 0.05]) self.buttonNext = Button(axNext, 'Next') self.buttonNext.on_clicked(self.onNext) # Button - Reset axReset = plt.axes([0.73, 0.03, 0.1, 0.05]) self.buttonReset = Button(axReset, 'Reset') self.buttonReset.on_clicked(self.onReset) self.onDraw() def onPrevious(self, event): self.phi -= self.delta_phi self.phi = self.phi % 360 self.onDraw() def onNext(self, event): self.phi += self.delta_phi self.phi = self.phi % 360 self.onDraw() def onReset(self, event): self.sliderPhi.reset() self.sliderDeltaPhi.reset() self.sliderPsi.reset() self.onDraw() def onUpdate(self, val): self.phi = int(self.sliderPhi.val) self.delta_phi = int(self.sliderDeltaPhi.val) self.psi = int(self.sliderPsi.val) self.onDraw() self.fig.canvas.draw_idle() def onDraw(self): self.ax.cla() # clear the axes self.ax.margins(x=.1, y=.1) # add margins self.ax.autoscale(enable=False) psi = np.radians(self.psi) phi = np.radians(self.phi) # Werte berechnen h_r = vw.get_h_r(self.l_e, self.h_m, phi) alpha = vw.get_alpha(self.l_e, phi, h_r) beta = vw.get_beta(alpha, psi) h = vw.get_h(psi, self.h_b, beta) gamma = vw.get_gamma(self.l_r, h_r) b_bottom = vw.get_b_bottom(h, beta, gamma) b_top = vw.get_b_top(h, beta, gamma) b = vw.get_b(h, beta, gamma) # Abstand bis Drehteller vom Ursprung point_phi_x, point_phi_y = self.plot_line(0, 0, np.radians(0), self.h_m, name="hm", color='k-') self.ax.plot(self.h_m, 0, 'kx') self.ax.text(self.h_m, -0.3, 'h_m') # Untere Bodenlinie point_psi_x, point_psi_y = self.plot_line(0, 0, np.radians(0), self.h_b, name="hb", color='k-') self.ax.plot(self.h_b, 0, 'kx') self.ax.text(self.h_b, -0.3, 'h_b') # Drehteller circlele = plt.Circle((point_phi_x, point_phi_y), self.l_e, color='k', linestyle='dashed', fill=False) self.ax.add_artist(circlele) # Winkelhalbierende point_b_x, point_b_y = self.plot_line(0,0, alpha, h, name="h", color='g-') # Winkelhalbierende bis Kreismittelpunkt point_r_x, point_r_y = self.plot_line(0, 0, alpha, h_r, name="hr", color = 'b-') # Abstand Mitte Drehteller, Mitte Zylinder self.ax.plot((self.h_m, point_r_x), (0, point_r_y), 'y-', label='l_e') self.ax.plot(point_r_x, point_r_y, 'kx') self.ax.text(point_r_x, point_r_y-0.3, 'M') # Zylinder circler = plt.Circle((point_r_x,point_r_y), self.l_r, color='k', fill=False) self.ax.add_artist(circler) # x,y Koordinate der Punkt b_top und b_bottom bestimmen b_top_x, b_top_y = self.plot_line(point_b_x, point_b_y, np.pi-psi, b_top, plot=False) b_bottom_x, b_bottom_y = self.plot_line(point_b_x, point_b_y, 2*np.pi-psi, b_bottom, plot=False) # Wand if b_bottom_y > point_psi_y and b_top_y > point_psi_y: # Schatten oberhalb der Mittellinie kathete_top_a = np.abs(b_bottom_x-point_psi_x) kathete_top_b = np.abs(b_bottom_y-point_psi_y) len_top = 2*np.sqrt(kathete_top_a**2+kathete_top_b**2)+b len_bottom = 1 elif b_bottom_y < point_psi_y and b_top_y < point_psi_y: # Schatten unterhalb der Mittellinie kathete_bottom_a = np.abs(b_top_x-point_psi_x) kathete_bottom_b = np.abs(b_top_y-point_psi_y) len_bottom = 2*np.sqrt(kathete_bottom_a**2+kathete_bottom_b**2)+b len_top = 1 else: # Schatten ober- und unterhalb der Mittellinie kathete_top_a = np.abs(b_top_x-point_psi_x) kathete_top_b = np.abs(b_top_y-point_psi_y) len_top = np.sqrt(kathete_top_a**2+kathete_top_b**2) + 5 kathete_bottom_a = np.abs(b_bottom_x-point_psi_x) kathete_bottom_b = np.abs(b_bottom_y-point_psi_y) len_bottom = np.sqrt(kathete_bottom_a**2+kathete_bottom_b**2) + 5 self.plot_line(point_psi_x, point_psi_y, np.pi-psi, len_top, color="k-") # obere Haelfte self.plot_line(point_psi_x, point_psi_y, 2*np.pi-psi, len_bottom, color="k-") # untere Haelfte # b an Wand self.plot_line(b_top_x, b_top_y, 2*np.pi-psi, b, name="b", color='r-') # Unterer Scheitel self.ax.plot((0, b_bottom_x), (0, b_bottom_y), 'c-.') self.ax.plot(b_bottom_x, b_bottom_y, 'kx') # Oberer Scheitel self.ax.plot((0, b_top_x), (0, b_top_y), 'c-.') self.ax.plot(b_top_x, b_top_y, 'kx') self.ax.axis('equal') if self.show_legend: self.ax.legend() def plot_line(self, pointx, pointy, angle, distance, plot=True, name=None, color='-'): x = np.cos(angle)*distance+pointx y = np.sin(angle)*distance+pointy if plot: self.ax.plot((pointx,x),(pointy,y),color, label=name) return x,y def plot(self): self.initUI() plt.show()
class PlanetarySurveyor(object): """ The PlanetarySurveyor creates a Matplotlib "widget" letting the user navigate map data loaded from an image file. """ def __init__(self, filename): """ Initialized with filename of image file containing the equirectangular map data. """ self.filename = filename self.load_image() # Setup display: self.fig = plt.figure(1) self.ax = plt.subplot(111) plt.clf() plt.subplots_adjust(left=0.1, bottom=0.25) self.meridian = 90 self.parallel = 90 self.parallels = 16 self.meridians = 16 self.mode = "azimuthal" self.projection = "orthographic" self.setup_display() # Setup mouse interaction: self.click = self.display.figure.canvas.mpl_connect( 'button_press_event', self.mouseclick) self.cursor = Cursor(self.display.axes, useblit=True, color='red', linewidth=1) # Setup axes: self.axes_step = plt.axes([0.13, 0.15, 0.60, 0.03]) self.axes_meridians = plt.axes([0.13, 0.10, 0.60, 0.03]) self.axes_parallels = plt.axes([0.13, 0.05, 0.60, 0.03]) self.update_axes = plt.axes([0.79, 0.095, 0.08, 0.04]) self.reset_axes = plt.axes([0.79, 0.05, 0.08, 0.04]) self.radio_axes = plt.axes([0.88, 0.05, 0.11, 0.15]) # Setup sliders: self.step = 22.5 self.slider_step = Slider(self.axes_step, 'Step', 0, 90, valinit=self.step, valfmt='%2.1f') self.slider_meridians = Slider(self.axes_meridians, 'Meridians', 0, 64, valinit=self.parallels, valfmt='%2d') self.slider_parallels = Slider(self.axes_parallels, 'Parallels', 0, 64, valinit=self.parallels, valfmt='%2d') self.slider_step.on_changed(self.update) self.slider_meridians.on_changed(self.update) self.slider_parallels.on_changed(self.update) # Setup button(s): self.update_button = Button(self.update_axes, 'Update') self.update_button.on_clicked(self.update_display) self.reset_button = Button(self.reset_axes, 'Reset') self.reset_button.on_clicked(self.reset) # Setup radio buttons: self.radio = RadioButtons( self.radio_axes, ('ortho', 'eq.area', 'eq.dist', 'stereo', 'rect'), active=0) self.radio.on_clicked(self.set_mode) self.projections = { "ortho": ("orthographic", "azimuthal"), "eq.area": ("lambert", "azimuthal"), "eq.dist": ("equidistant", "azimuthal"), "stereo": ("stereographic", "azimuthal"), "rect": ("rectangular", "rectangular") } # Almost ready: self.update() plt.show() def load_image(self): """ Load and flatten specified image file. If this fails, the default map is loaded. """ try: map_image = plt.imread(self.filename) except IOError as e: print "Could not load file {0} ({1})".format( self.filename, e.strerror) print "Using default image..." self.filename = "templates/nowwhat.png" map_image = plt.imread(self.filename) while len(map_image.shape) > 2: map_image = map_image.mean(-1) self.map_image = map_image def setup_display(self): """ Setup parameters and map display. """ self.R = 180 self.padding = self.R / 10 if self.mode == 'azimuthal': self.hemisphere = p.get_azimuthal_hemisphere( self.map_image, self.meridian, 90, self.R, self.projection, 0, self.padding) self.display = plt.imshow(self.hemisphere, cmap=plt.cm.gray, extent=[-1.5, 1.5, -1.5, 1.5]) plt.axis([-1.5, 1.5, -1.5, 1.5]) plt.axis('off') elif self.mode == 'rectangular': plt.axis([-180, 180, -90, 90]) pass if self.meridians > 0 or self.parallels > 0: self.draw_graticules() def update_display(self, val=0): """ Update map display. """ if self.mode == 'azimuthal': self.hemisphere = p.get_azimuthal_hemisphere( self.map_image, self.meridian, 90, self.R, self.projection, 0, self.padding) ax = self.display.axes self.display.axes.cla() self.display = ax.imshow(self.hemisphere, cmap=plt.cm.gray, extent=[-1.5, 1.5, -1.5, 1.5]) plt.axis([-1.5, 1.5, -1.5, 1.5]) plt.axis('off') elif self.mode == 'rectangular': self.hemisphere = p.get_rectangular_hemisphere( self.map_image, self.meridian, self.parallel, False) ax = self.display.axes self.display.axes.cla() self.display = ax.imshow(self.hemisphere, cmap=plt.cm.gray, extent=[ self.meridian - 90, self.meridian + 90, self.parallel - 90, self.parallel + 90 ]) plt.axis([ self.meridian - 90, self.meridian + 90, self.parallel - 90, self.parallel + 90 ]) self.fix_coordinates() if self.meridians > 0 or self.parallels > 0: self.draw_graticules() self.update() def update(self, val=0): """ Update internal parameters from sliders, update coordiantes and draw. """ if self.step != self.slider_step.val: self.step = np.round(self.slider_step.val / 0.5) * 0.5 self.slider_step.set_val(self.step) if (self.meridians != self.slider_meridians.val or self.parallels != self.slider_parallels.val): self.meridians = np.round(self.slider_meridians.val).astype(np.int) self.parallels = np.round(self.slider_parallels.val).astype(np.int) self.fix_coordinates() plt.draw() def set_mode(self, val="ortho"): """ Set projection and mode. """ self.projection = self.projections[val][0] self.mode = self.projections[val][1] if self.mode == "azimuthal": self.parallel = 90 self.update_display() def reset(self, event): """ Reset widget """ self.slider_step.reset() self.slider_meridians.reset() self.slider_parallels.reset() self.meridian = 90 self.parallel = 90 self.update() self.set_mode() def mouseclick(self, event): """ Handle mouse navigation of map display for the different projections. """ if event.inaxes == self.display.axes: if event.button == 1: if self.mode == "azimuthal": self.meridian += self.step * np.round(event.xdata) elif self.mode == "rectangular": self.parallel = 180 - np.round(event.ydata / 0.5) * 0.5 self.meridian = np.round(event.xdata / 0.5) * 0.5 self.update() self.update_display() def fix_coordinates(self): """ Fix coordinates so they comply to standard representation for maps. """ self.parallel %= 180 self.meridian %= 360 self.display.axes.set_title("{0}: {1}".format(self.projection, self.get_coordinates())) def get_coordinates(self): """ Return string representation of coordinates in N-S/E-W standard. """ parallel = self.parallel meridian = self.meridian - 180 if parallel > 90.0: parallel = 180.0 - parallel elif parallel < -90.0: parallel = -180.0 - parallel if meridian > 180.0: meridian = 360.0 - meridian elif meridian < -180.0: meridian = -360.0 - meridian if parallel >= 0: NS = "N" else: NS = "S" if meridian >= 0: EW = "E" else: EW = "W" return "{0} {1}, {2} {3}".format(np.abs(parallel), NS, np.abs(meridian), EW) def get_graticule(self): """ Return resolution of the current graticule (distances between parallel and meridian lines). """ try: dLat = 180.0 / self.parallels except ZeroDivisionError: dLat = None try: dLon = 360.0 / self.meridians except ZeroDivisionError: dLon = 0 return dLat, dLon def draw_graticules(self): """ Draw parallel and meridian lines using testgrids-module. """ dLat, dLon = self.get_graticule() ax = self.display.axes if self.meridians > 0: if self.mode == "azimuthal": x_mer, z_mer = grids.get_meridians(self.meridian, dLon, 1, 1.5 / 1.1, self.projection) ax.plot(x_mer, z_mer, ':k', label="meridians") ax.axis('off') elif self.mode == "rectangular": mer_min = np.ceil((self.meridian - 90) / dLon) * dLon mer_max = np.floor((self.meridian + 90) / dLon) * dLon ax.set_xticks(np.arange(mer_min, mer_max + 1, dLon)) ax.grid(True) if self.parallels > 0: if self.mode == "azimuthal": x_par, z_par = grids.get_parallels(self.parallel, dLat, 1, 1.5 / 1.1, self.projection) ax.plot(x_par, z_par, ':k', label="parallels") ax.axis('off') elif self.mode == "rectangular": par_min = np.ceil((self.parallel - 90) / dLat) * dLat par_max = np.floor((self.parallel + 90) / dLat) * dLat ax.set_yticks(np.arange(par_min, par_max + 1, dLat)) ax.grid(True)
class slider_factory(object): """ Accepts: my overloaded subplot from adials_gui returns: a slider for a relational interval """ def __init__(self, ax, a=.1, b=10.): self.ax = ax self.fig = self.ax.figure self.plt = plt t = np.arange(0.0, 1.0, 0.001) self.t = t a0 = 5 f0 = 3 self.a0 = a0 self.f0 = f0 s = a0 * np.sin(2 * np.pi * f0 * t) self.l, = plt.plot(t, s, lw=2, color='red') plt.axis([0, 1, -10, 10]) self.axcolor = 'lightgoldenrodyellow' axcolor = self.axcolor self.axfreq = plt.axes([0.25, 0.1, 0.65, 0.03], axisbg=axcolor) self.axamp = plt.axes([0.25, 0.15, 0.65, 0.03], axisbg=axcolor) self.sfreq = Slider(self.axfreq, 'Freq', 0.1, 30.0, valinit=f0) self.samp = Slider(self.axamp, 'Amp', a, b, valinit=a0) self.resetax = self.plt.axes([0.8, 0.025, 0.1, 0.04]) self.button = Button(self.resetax, 'Reset', color=self.axcolor, hovercolor='0.975') self.rax = plt.axes([0.025, 0.5, 0.15, 0.15], axisbg=axcolor) self.radio = RadioButtons(self.rax, ('red', 'blue', 'green'), active=0) self.radio.on_clicked(self.colorfunc) self.update() return def update_(self, val): t = self.t amp = self.samp.val freq = self.sfreq.val self.l.set_ydata(amp * np.sin(2 * np.pi * freq * t)) self.fig.canvas.draw_idle() return def update_freq(self, values): """ TODO: implement """ a = values[0] b = values[1] self.sfreq = Slider(self.axfreq, 'Freq', a, b, valinit=self.f0) self.update() self.fig.canvas.draw_idle() return def update_amp(self, values): a = values[0] b = values[1] self.fig.clear() self = slider_factory(ax, a, b) return def update(self): self.sfreq.on_changed(self.update_) self.samp.on_changed(self.update_) return def reset(self, event): self.sfreq.reset() self.samp.reset() def colorfunc(self, label): self.l.set_color(label) self.fig.canvas.draw_idle() return
ax.set_yticklabels([r'$\mathcal{P}_{B}$', r'$\Omega$', r'$\mathcal{P}_{A}$']) ax.set_xlabel('timesteps', labelpad=3) ax.set_ylabel('excitation energy', labelpad=5) initial = excitation_histogram(axhist, full, Ua, Ub, N) def update_plot(du): sim, simc, full, Ub, Ua = calc_timeseries(N, du, tmax, phi, avg_steps=per_timestep) ln_const.set_ydata(simc[:ixs-brk]) ln_fluc.set_ydata(sim[ixs+brk:]) ax.set_yticks([N*Ub, N, N*Ua]) axhist.cla() excitation_histogram(axhist, full, Ua, Ub, N, fit=initial) fig.canvas.draw_idle() duslider = Slider(ax_duslider, r'$\Delta$', 0.1, 1.9, valinit=du, dragging=False) duslider.on_changed(update_plot) button = Button(axreset, 'Reset') button.on_clicked(lambda e : duslider.reset()) ttl = str(N) + " absorbers" + " " ttl = ttl + str(per_timestep) + " events/timestep" + " " ttl = ttl + r"$\phi =$ " + str(phi) plt.suptitle(ttl, fontsize=14) fig.show() plt.show()
class Handler: def __init__(self): # plt.ion() self.url = "https://seasweb.azurewebsites.net/data.json" self.filter_const = 25 self.by1 = None self.by2 = None self.py1 = None self.py2 = None self.unfiltered_series = None self.filtered_series = None self.data_to_plot = None self.subplot_axes = None self.radio = None self.slider = None self.func = None self.df = None # Downloading data and creating dataset def create_dataset(self): # Loading dataset from given url rawData = json.loads(requests.get(self.url).text) self.df = pd.DataFrame(rawData) # Creating numpy arrays for further processing self.by1 = self.df['BY1'].astype('float').to_numpy() self.by2 = self.df['BY2'].astype('float').to_numpy() self.py1 = self.df['PY1'].astype('float').to_numpy() self.py2 = self.df['PY2'].astype('float').to_numpy() # Creating lists of series self.unfiltered_series = [self.by1, self.by2, self.py1, self.py2] self.filtered_series = [ self.__filter(self.by1), self.__filter(self.by2), self.__filter(self.py1), self.__filter(self.py2) ] # Plotting all series together on one figure def plot_all(self): # Testing if dataset was created if self.df is None: raise ValueError("Dataset is not created") # Plotting and setting up graph ax1 = self.df.plot(x='category', figsize=(10, 9)) ax1.title.set_text( 'European Energy Exchange (EEX) data for years 2021 and 2022') ax1.set_ylabel('Price[€]', fontsize='large', fontweight='bold') ax1.set_xlabel('Date', fontsize='large', fontweight='bold') ax1.legend([ "BY1 BaseLoad 2021 in €/MWh", "BY2 BaseLoad 2022 in €/MWh", "PY1 PeakLoad 2021 in €/MWh", "PY2 PeakLoad 2022 in €/MWh", "CO2 - Price of emission allowances in €/tonne" ]) plt.draw() # Plotting all series separately on subplots def plot_by_one(self): # Testing if dataset was created if self.df is None: raise ValueError("Dataset is not created") # Plotting and setting up graph fig2, self.subplot_axes = plt.subplots(2, 2, figsize=(10, 9)) fig2.subplots_adjust(left=0.3, wspace=0.2, hspace=0.3) fig2.suptitle('All series separately') fig2.text(0.25, 0.5, 'Price[€/MWh]', rotation='vertical', verticalalignment='center', fontsize='large', fontweight='bold') fig2.text(0.6, 0.03, 'Date', fontsize='large', horizontalalignment='center', fontweight='bold') fig2.text( 0.05, 0.1, 'Use slider only when filtered series is selected\nSlider for changing filter constant (filtering rate)', rotation='vertical', fontsize='large', fontweight='bold') # Reshaping list of axes for usage in for loop self.subplot_axes = np.reshape(self.subplot_axes, 4, 'F') # Updating which data will be plotted self.data_to_plot = self.unfiltered_series # Updating subplots by class function self.__subplot_update() # Creating radio button for changing which series to plot rax = plt.axes([0.05, 0.7, 0.15, 0.15]) self.radio = RadioButtons(rax, ('Unfiltered series', 'Filtered series')) self.func = { 'Unfiltered series': self.unfiltered_series, 'Filtered series': self.filtered_series } # Creating slider for changing filter constant axSlider = plt.axes([0.1, 0.1, 0.05, 0.5]) self.slider = Slider(axSlider, 'Slider', valmin=1, valmax=125, valinit=25, orientation='vertical', valfmt='%d') # Assign a function handler to a button and slider self.radio.on_clicked(self.__radioButton_update) self.slider.on_changed(self.__slider_update) plt.draw() # Printing max values def print_max_values(self): # Printing 5 highest values to console for every series print("--------------------------------------------------") print("Highest values of series [BY1, BY2, PY1, PY2] :\n") # Iterating throught all series for s in self.unfiltered_series: # Indirect partition ind = np.argpartition(-s, 5)[:5] a = s[ind] # Swapping order a = -np.sort(-a) print(a) print("--------------------------------------------------") # Regression analysis def nonlinear_regression(self): # Prepocessing data for reggresion fig3 = plt.figure(3, figsize=(10, 9)) X = [i for i in range(len(self.unfiltered_series[0]))] X = np.asfarray(X).reshape(-1, 1) y = self.unfiltered_series[0] # Fit regression model svr_rbf = SVR(kernel='rbf', C=100, gamma=0.1, epsilon=.1) # Plot graph of reggresion plt.plot(X, svr_rbf.fit(X, y).predict(X), color='m', lw=2, label='{} model'.format('RBF')) # Plot points plt.scatter(X, y, s=10) # Displaying information a = svr_rbf.score(X, y) fig3.suptitle('RBF regression') fig3.text(0.5, 0.9, 'Coefficient of determination R^2 is %s' % (a), horizontalalignment='center', fontsize='large', fontweight='bold') plt.ylabel('Price[€]', fontsize='large', fontweight='bold') plt.xlabel('Days', fontsize='large', fontweight='bold') plt.draw() # The function which handle subplots updating every time data to plot or slider value was changed def __subplot_update(self): self.__plot_on_axis() # Positioning x label elements for a in self.subplot_axes: plt.setp(a.get_xticklabels(), rotation=30, ha='right') # Naming each subplot self.subplot_axes[0].title.set_text('BY1') self.subplot_axes[1].title.set_text('BY2') self.subplot_axes[2].title.set_text('PY1') self.subplot_axes[3].title.set_text('PY2') plt.draw() # Handler for radio button def __radioButton_update(self, label): # Updating which data will be plotted self.data_to_plot = self.func[label] # Updating subplots by class function self.__subplot_update() # Reseting slider self.slider.reset() # Handler for slider def __slider_update(self, val): # Slider is working only in filtered series state if self.radio.value_selected == 'Filtered series': # Updating filter constant self.filter_const = int(self.slider.val) # Updating list of filtered series self.filtered_series = [ self.__filter(self.by1), self.__filter(self.by2), self.__filter(self.py1), self.__filter(self.py2) ] # Updating which data to plot self.data_to_plot = self.filtered_series # Updating subplots by class function self.__subplot_update() # The function for plotting columns of dataset to separated subplots def __plot_on_axis(self): # Each axis, one graph if len(self.data_to_plot) != len(self.subplot_axes): raise ValueError( 'This function plot one column of dataset stored in array on one axis. Data array length is not the same as axes array length.' ) i = 0 for a in self.subplot_axes: a.clear() a.plot(pd.to_datetime(self.df['category']), self.data_to_plot[i]) i += 1 # The filter, it uses Furier transformation # ???!Malokedy vyuzijem v praxi nieco co som sa naucil v skole, ale toto je jedna z tych veci ktore som pochopil a pouzil!??? def __filter(self, input): furrier_transform = np.fft.fft(input) shifted_furrier_transform = np.fft.fftshift(furrier_transform) HP_filter = np.zeros(len(shifted_furrier_transform), dtype=int) n = int(len(HP_filter)) HP_filter[int(n / 2) - self.filter_const:int(n / 2) + self.filter_const] = 1 output = shifted_furrier_transform * HP_filter output = abs(np.fft.ifft(output)) return output
class TCG(): # @profile def __init__(self): self.dim_x = 1280 # * Horizonal pixel dimension self.dim_y = 720 # * Vertical pixel dimension self.limits = [-5, 15] # * Curve View axis limits extent = self.limits * 2 aspect_ratio = self.dim_x / self.dim_y bg_path = "./bg_images/" self.bg_list = [bg_path + s for s in os.listdir(bg_path)] axis_color = "#ede5c0" slider_color = "#bf616a" self.fig = plt.figure("TCG", (14, 8)) self.fig.suptitle("Trash Cluster Generator", fontsize=14, y=0.95) self.fig.patch.set_facecolor("#D8DEE9") self.ax_bez = self.fig.add_subplot(121) self.ax_img = self.fig.add_subplot(122) self.fig.subplots_adjust(left=0.12, bottom=0.45, top=0.99, right=0.82) # ? Slider init values self.rad = 0.5 # * Radius self.edgy = 0.5 # * Edginess self.seeder = 50 # * Random Seed self.c = [-1, 1] # * Translation co-ords self.scale = 10 # * Scale self.points = 4 # * Number of control points self.cluster_limit = (5, 10) # * Cluster Limit # ? Images self.bg_index = 0 # * Background image pointer self.cluster_image = None # * Generated Cluster image self.cluster_mask = None # * Segmentation Mask (RGB) self.cluster_pil = None # * Ground Truth Segmentation Mask self.cache = None # * Reference params # ? Random Bezier Control Points self.a = ( get_random_points(self.seeder, n=self.points, scale=self.scale) + self.c) # ? Bezier Curve coordinates and centre self.x, self.y, self.s = get_bezier_curve(self.a, rad=self.rad, edgy=self.edgy) self.centre = np.array([ (np.max(self.x) + np.min(self.x)) / 2, (np.max(self.y) + np.min(self.y)) / 2, ]) self.a_new = np.append(self.a, [self.centre], axis=0) self.ax_bez.set_xlim(self.limits) self.ax_bez.set_ylim(self.limits) # ? Curve View Image handler self.bezier_handler = self.ax_bez.imshow(plt.imread( self.bg_list[self.bg_index]), extent=extent, interpolation="none") self.ax_bez.set_aspect(1 / (aspect_ratio)) self.ax_img.set_aspect(1 / (aspect_ratio)) # ? Curve View Plot and Scatter handler (self.bezier_curve, ) = self.ax_bez.plot(self.x, self.y, linewidth=1, color="w", zorder=1) self.scatter_points = self.ax_bez.scatter( self.a_new[:, 0], self.a_new[:, 1], color="orangered", marker=".", alpha=1, zorder=2, ) # ? Generator View Image handler self.cluster_handler = self.ax_img.imshow( np.flipud(np.array(plt.imread(self.bg_list[0]))), origin="lower", interpolation="none", ) # ? State Indicator Text handler self.text_handler = plt.figtext(0.88, 0.70, " Ready ", fontsize=14, backgroundcolor="#a3be8c") # ? Class distribution and its indicator text handlers self.class_dict = { "G:": (0.86, "#bdae93"), "M:": (0.901, "#81a1c1"), "P:": (0.942, "#b48ead"), } self.class_handlers = [] self.class_count = Counter() for (cname, textarg) in self.class_dict.items(): self.class_handlers.append( plt.figtext( textarg[0], 0.80, cname + "0".rjust(3), fontsize=10, backgroundcolor=textarg[1], )) # ? Saved image count and its indicator text handler self.count = len( [f for f in os.listdir(".") if f.startswith("label_")]) self.count_handler = plt.figtext( 0.86, 0.76, f"Generated images: {self.count}", fontsize=10, backgroundcolor="#cf9f91", ) undo_asset = plt.imread("./assets/undo.png") # ? Sliders rad_slider_ax = self.fig.add_axes([0.12, 0.42, 0.65, 0.03], facecolor=axis_color) self.rad_slider = Slider(rad_slider_ax, "Radius", 0.0, 1.0, valinit=self.rad, color=slider_color) edgy_slider_ax = self.fig.add_axes([0.12, 0.37, 0.65, 0.03], facecolor=axis_color) self.edgy_slider = Slider(edgy_slider_ax, "Edginess", 0.0, 5.0, valinit=self.edgy, color=slider_color) c0_slider_ax = self.fig.add_axes([0.12, 0.32, 0.65, 0.03], facecolor=axis_color) self.c0_slider = Slider(c0_slider_ax, "Move X", -7.0, 16.0, valinit=self.c[0], color=slider_color) c1_slider_ax = self.fig.add_axes([0.12, 0.27, 0.65, 0.03], facecolor=axis_color) self.c1_slider = Slider(c1_slider_ax, "Move Y", -7.0, 16.0, valinit=self.c[1], color=slider_color) scale_slider_ax = self.fig.add_axes([0.12, 0.22, 0.65, 0.03], facecolor=axis_color) self.scale_slider = Slider(scale_slider_ax, "Scale", 1.0, 20.0, valinit=self.scale, color=slider_color) points_slider_ax = self.fig.add_axes([0.12, 0.17, 0.65, 0.03], facecolor=axis_color) self.points_slider = Slider( points_slider_ax, "Points", 3, 10, valinit=self.points, valfmt="%d", color=slider_color, ) seeder_slider_ax = self.fig.add_axes([0.12, 0.12, 0.65, 0.03], facecolor=axis_color) self.seeder_slider = Slider( seeder_slider_ax, "Seed", 1, 100, valinit=self.seeder, valfmt="%d", color=slider_color, ) cluster_limit_slider_ax = self.fig.add_axes([0.12, 0.07, 0.65, 0.03], facecolor=axis_color) self.cluster_limit_slider = RangeSlider( cluster_limit_slider_ax, "Cluster Count", 1, 20, valinit=self.cluster_limit, valfmt="%d", color=slider_color, ) # ? Buttons save_button_ax = self.fig.add_axes([0.85, 0.05, 0.1, 0.06]) self.save_button = Button(save_button_ax, "Save", color="#aee3f2", hovercolor="#85cade") reset_button_ax = self.fig.add_axes([0.85, 0.12, 0.1, 0.06]) self.reset_button = Button(reset_button_ax, "Reset", color="#aee3f2", hovercolor="#85cade") background_button_ax = self.fig.add_axes([0.85, 0.19, 0.1, 0.06]) self.background_button = Button(background_button_ax, "Background", color="#aee3f2", hovercolor="#85cade") generate_button_ax = self.fig.add_axes([0.85, 0.26, 0.1, 0.06]) self.generate_button = Button(generate_button_ax, "Generate", color="#aee3f2", hovercolor="#85cade") add_new_button_ax = self.fig.add_axes([0.85, 0.33, 0.1, 0.06]) self.add_new_button = Button(add_new_button_ax, "Add Cluster", color="#aee3f2", hovercolor="#85cade") update_button_ax = self.fig.add_axes([0.85, 0.40, 0.1, 0.06]) self.update_button = Button(update_button_ax, "Update", color="#aee3f2", hovercolor="#85cade") undo_button_ax = self.fig.add_axes([0.875, 0.50, 0.05, 0.06]) self.undo_button = Button(undo_button_ax, "", image=undo_asset, color="#aee3f2", hovercolor="#85cade") # ? Slider event triggers self.rad_slider.on_changed(self.curveplot) self.edgy_slider.on_changed(self.curveplot) self.c0_slider.on_changed(self.curveplot) self.c1_slider.on_changed(self.curveplot) self.scale_slider.on_changed(self.curveplot) self.points_slider.on_changed(self.curveplot) self.seeder_slider.on_changed(self.curveplot) self.cluster_limit_slider.on_changed(self.curveplot) # ? Button event triggers self.save_button.on_clicked(self.save) self.save_button.on_clicked(self.curveplot) self.reset_button.on_clicked(self.reset) self.reset_button.on_clicked(self.curveplot) self.background_button.on_clicked(self.curveplot) self.background_button.on_clicked(self.background) self.generate_button.on_clicked(self.curveplot) self.generate_button.on_clicked(self.generate) self.add_new_button.on_clicked(self.curveplot) self.add_new_button.on_clicked(self.add_new) self.update_button.on_clicked(self.curveplot) self.update_button.on_clicked(self.update) self.undo_button.on_clicked(self.curveplot) self.undo_button.on_clicked(self.undo) plt.show() # @profile def curveplot(self, _): self.cluster_limit = ( int(self.cluster_limit_slider.val[0]), int(self.cluster_limit_slider.val[1]), ) self.c = [self.c0_slider.val, self.c1_slider.val] self.scale = self.scale_slider.val self.a = (get_random_points( int(self.seeder_slider.val), n=int(self.points_slider.val), scale=self.scale, ) + self.c) self.x, self.y, _ = get_bezier_curve(self.a, rad=self.rad_slider.val, edgy=self.edgy_slider.val) self.centre = np.array([ (np.max(self.x) + np.min(self.x)) / 2, (np.max(self.y) + np.min(self.y)) / 2, ]) self.a_new = np.append(self.a, [self.centre], axis=0) self.bezier_curve.set_data(self.x, self.y) self.scatter_points.set_offsets(self.a_new) self.fig.canvas.draw_idle() # @profile def save(self, _): try: if self.cluster_image is None: raise ClusterNotGeneratedError save_generate(self.cluster_image, self.cluster_mask, self.cluster_pil) self.cluster_image = None self.cluster_mask = None self.cluster_pil = None self.cache = None except ClusterNotGeneratedError: logger.warning("Generate cluster before saving.") self.text_handler.set_text("Generate new") self.text_handler.set_position((0.87, 0.70)) self.text_handler.set_backgroundcolor("#ede5c0") except Exception: logger.error(traceback.print_exc()) self.text_handler.set_text("Error. See logs") self.text_handler.set_position((0.87, 0.70)) self.text_handler.set_backgroundcolor("#bf616a") else: logger.debug("Saved successfully.") self.text_handler.set_text("Saved") self.text_handler.set_position((0.89, 0.70)) self.text_handler.set_backgroundcolor("#a3be8c") self.count += 1 self.count_handler.set_text(f"Generated images: {self.count}") # @profile def reset(self, _): try: self.rad_slider.reset() self.edgy_slider.reset() self.c0_slider.reset() self.c1_slider.reset() self.scale_slider.reset() self.points_slider.reset() self.seeder_slider.reset() self.cluster_limit_slider.set_val((3, 7)) self.bg_index = 0 self.cluster_image = None self.cluster_mask = None self.cluster_pil = None self.cluster_handler.set_data( np.flipud(np.array(plt.imread(self.bg_list[0])))) self.bezier_handler.set_data( plt.imread(self.bg_list[self.bg_index])) except Exception: logger.error(traceback.print_exc()) self.text_handler.set_text("Error. See logs") self.text_handler.set_position((0.87, 0.70)) self.text_handler.set_backgroundcolor("#bf616a") else: logger.info("Reset state.") self.text_handler.set_text("Reset") self.text_handler.set_position((0.89, 0.70)) self.text_handler.set_backgroundcolor("#a3be8c") for ind, cname in enumerate(self.class_dict): self.class_handlers[ind].set_text(cname + "0".rjust(3)) # @profile def background(self, _): try: self.bg_index = (self.bg_index + 1) % len(self.bg_list) self.bezier_handler.set_data( plt.imread((self.bg_list[self.bg_index]))) except Exception: logger.error(traceback.print_exc()) self.text_handler.set_text("Error. See logs") self.text_handler.set_position((0.87, 0.70)) self.text_handler.set_backgroundcolor("#bf616a") else: logger.info("Changed background.") self.text_handler.set_text("Changed") self.text_handler.set_position((0.88, 0.70)) self.text_handler.set_backgroundcolor("#a3be8c") # @profile def generate(self, _): try: bg_image = np.array(plt.imread(self.bg_list[self.bg_index])) bg_mask = np.array( plt.imread(self.bg_list[self.bg_index].replace( "images", "labels").replace("jpeg", "png"))) params = list(zip(self.x, self.y)) params.append(tuple(self.centre)) ( self.cluster_image, self.cluster_mask, self.cluster_pil, self.cache, ) = generate_cluster( bg_image, bg_mask, params, self.cluster_limit, self.limits, (self.dim_x, self.dim_y), ) if not self.cluster_image: raise OutOfBoundsClusterError self.cluster_handler.set_data(np.flipud(self.cluster_image)) except OutOfBoundsClusterError: logger.warning("Out of Bounds. Retry") self.text_handler.set_text("Out of Bounds") self.text_handler.set_position((0.87, 0.70)) self.text_handler.set_backgroundcolor("#ede5c0") except Exception: logger.error(traceback.print_exc()) self.text_handler.set_text("Error. See logs") self.text_handler.set_position((0.87, 0.70)) self.text_handler.set_backgroundcolor("#bf616a") else: logger.info("Generated new cluster.") self.text_handler.set_text("Generated") self.text_handler.set_position((0.88, 0.70)) self.text_handler.set_backgroundcolor("#a3be8c") self.class_count = Counter(self.cache[2]) for ind, cname in enumerate(self.class_dict): self.class_handlers[ind].set_text( cname + str(self.class_count[ind + 3]).rjust(3)) # @profile def add_new(self, _): try: params = list(zip(self.x, self.y)) params.append(tuple(self.centre)) if self.cluster_image is None: raise ClusterNotGeneratedError ( self.cluster_image, self.cluster_mask, self.cluster_pil, self.cache, ) = generate_cluster( np.array(self.cluster_image), self.cluster_mask, params, self.cluster_limit, self.limits, (self.dim_x, self.dim_y), new_cluster=False, ) if np.array_equal(self.cluster_image, self.cache[0]): raise OutOfBoundsClusterError self.cluster_handler.set_data(np.flipud(self.cluster_image)) except ClusterNotGeneratedError: logger.warning("Generate cluster before adding a new one.") self.text_handler.set_text("Generate new") self.text_handler.set_position((0.87, 0.70)) self.text_handler.set_backgroundcolor("#ede5c0") except OutOfBoundsClusterError: logger.warning("Out of Bounds. Retry") self.text_handler.set_text("Out of Bounds") self.text_handler.set_position((0.87, 0.70)) self.text_handler.set_backgroundcolor("#ede5c0") except Exception: logger.error(traceback.print_exc()) self.text_handler.set_text("Error. See logs.") self.text_handler.set_position((0.87, 0.70)) self.text_handler.set_backgroundcolor("#bf616a") else: logger.info("Added cluster.") self.text_handler.set_text("Added") self.text_handler.set_position((0.89, 0.70)) self.text_handler.set_backgroundcolor("#a3be8c") self.class_count += Counter(self.cache[2]) for ind, cname in enumerate(self.class_dict): self.class_handlers[ind].set_text( cname + str(self.class_count[ind + 3]).rjust(3)) # @profile def update(self, _): try: params = list(zip(self.x, self.y)) params.append(tuple(self.centre)) if self.cluster_image is None: raise ClusterNotGeneratedError bg_mask = np.array( plt.imread(self.bg_list[self.bg_index].replace( "images", "labels").replace("jpeg", "png"))) if np.array_equal(bg_mask, self.cache[1]): new_cluster = True else: new_cluster = False # old_class_list = cache[2][:] ( self.cluster_image, self.cluster_mask, self.cluster_pil, self.cache, ) = update_cluster(*self.cache, params, self.limits, (self.dim_x, self.dim_y), new_cluster) if np.array_equal(self.cluster_image, self.cache[0]): raise OutOfBoundsClusterError self.cluster_handler.set_data(np.flipud(self.cluster_image)) except ClusterNotGeneratedError: logger.warning("Generate cluster before updating.") self.text_handler.set_text("Generate new") self.text_handler.set_position((0.87, 0.70)) self.text_handler.set_backgroundcolor("#ede5c0") except OutOfBoundsClusterError: logger.warning("Out of Bounds. Retry") self.text_handler.set_text("Out of Bounds") self.text_handler.set_position((0.87, 0.70)) self.text_handler.set_backgroundcolor("#ede5c0") except Exception: logger.error(traceback.print_exc()) self.text_handler.set_text("Error. See logs") self.text_handler.set_position((0.87, 0.70)) self.text_handler.set_backgroundcolor("#bf616a") else: logger.info("Updated cluster.") self.text_handler.set_text("Updated") self.text_handler.set_position((0.88, 0.70)) self.text_handler.set_backgroundcolor("#a3be8c") # @profile def undo(self, _): try: if self.cluster_image is None: raise UndoError ( self.cluster_image, self.cluster_mask, self.cluster_pil, self.cache, ) = undo_func() if self.cache is None: raise UndoError self.cluster_handler.set_data(np.flipud(self.cluster_image)) except UndoError: logger.warning("Cannot undo as there is no previous state.") self.text_handler.set_text("Cannot undo") self.text_handler.set_position((0.87, 0.70)) self.text_handler.set_backgroundcolor("#ede5c0") except Exception: logger.error(traceback.print_exc()) self.text_handler.set_text("Error. See logs") self.text_handler.set_position((0.87, 0.70)) self.text_handler.set_backgroundcolor("#bf616a") else: logger.info("Cluster undone.") self.text_handler.set_text("Undone") self.text_handler.set_position((0.88, 0.70)) self.text_handler.set_backgroundcolor("#a3be8c") self.class_count -= Counter(self.cache[2]) for ind, cname in enumerate(self.class_dict): self.class_handlers[ind].set_text( cname + str(self.class_count[ind + 3]).rjust(3))
class my_Slider: def __init__(self, img, threshold=30, kernel=5, std=5): self.img = img self.threshold = threshold self.smooth = 'Gaussian smooth' self.k = kernel self.s = std self.fig = plt.figure() self.p = self.draw_plots(self.img, self.threshold, self.smooth, self.s) #set up sliders - location axcolor = 'lightgoldenrodyellow' ax_threshold = self.fig.add_axes([0.25, 0.01, 0.65, 0.02], facecolor=axcolor) ax_kernel = self.fig.add_axes([0.25, 0.03, 0.65, 0.02], facecolor=axcolor) ax_std = self.fig.add_axes([0.25, 0.05, 0.65, 0.02], facecolor=axcolor) #set up sliders - content, length, width self.s_threshold = Slider(ax_threshold, 'Threshold', 0.0, 255.0, valinit=30.0, valstep=10.0) self.s_kenel = Slider(ax_kernel, 'Kernel', 3.0, 21.0, valinit=5.0, valstep=2.0) self.s_std = Slider(ax_std, 'Std', 1.0, 15.0, valinit=5.0, valstep=2.0) #set up buttons resetax = self.fig.add_axes([0.01, 0.025, 0.1, 0.04]) self.button = Button(resetax, 'Reset', color=axcolor, hovercolor='0.975') rax = self.fig.add_axes([0.01, 0.5, 0.25, 0.25], facecolor=axcolor) self.radio = RadioButtons(rax, ('Gaussian smooth', 'median smooth'), active=0) self.s_threshold.on_changed(self.update) self.s_kenel.on_changed(self.update) self.s_std.on_changed(self.update) self.button.on_clicked(self.reset) self.radio.on_clicked(self.buttonfunc) self.p.show() def draw_plots(self, img, threshold_value, smooth, kernel=11, std=1, C=2, maxVal=255, onplot=None): threshold_value = int(threshold_value) kernel = int(kernel) img = cv2.imread(img, 0) if smooth == 'median smooth': img = cv2.medianBlur(img, kernel) elif smooth == 'Gaussian smooth': img = cv2.GaussianBlur(img, (kernel, kernel), std) #global ret, thresh1 = cv2.threshold(img, threshold_value, maxVal, cv2.THRESH_BINARY) #otsu ret2, thresh2 = cv2.threshold(img, 0, maxVal, cv2.THRESH_BINARY + cv2.THRESH_OTSU) #adaptive thresh3 = cv2.adaptiveThreshold(img, maxVal, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, kernel, C) thresh4 = cv2.adaptiveThreshold(img, maxVal, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, kernel, C) titles = [ 'Binary', 'Otsu', 'Adaptive-mean', 'Adaptive-gaussian', 'histogram' ] images = [thresh1, thresh2, thresh3, thresh4] nrow = 2 ncol = 2 for i in range(4): self.fig.add_subplot(2, 2, i + 1) plt.imshow(images[i], 'gray') plt.title(titles[i], fontsize=8) plt.xticks([]), plt.yticks([]) plt.tight_layout() plt.subplots_adjust(left=0.25, bottom=0.1, top=0.9, right=0.95, hspace=0.1, wspace=0) return plt def update(self, val): self.threshold = int(self.s_threshold.val) self.k = int(self.s_kenel.val) self.s = int(self.s_std.val) p = self.draw_plots(self.img, self.threshold, self.smooth, kernel=self.k, std=self.s) p.show() self.fig.canvas.draw_idle() def reset(self, event): self.s_threshold.reset() self.s_kenel.reset() self.s_std.reset() def buttonfunc(self, label): self.smooth = label p2 = self.draw_plots(self.img, self.threshold, self.smooth, kernel=self.k, std=self.s) p2.show() self.fig.canvas.draw_idle()
class AnimatedScatter(object): def __init__(self, bodies, axis_range, timescale): self.bodies = bodies self.axis_range = axis_range self.timescale = timescale self.stream = self.data_stream() fig = plt.figure() ax = fig.add_subplot(111, projection='3d') self.fig = fig self.ax = ax self.force_norm_factor = None self.ani = animation.FuncAnimation(self.fig, self.update, interval=INTERVAL, init_func=self.setup_plot, blit=False) self.x_ = [] self.y_ = [] self.z_ = [] def setup_plot(self): xi, yi, zi, ui, vi, wi, x_, y_, z_ = next(self.stream) c = [np.random.rand(3, ) for i in range(len(xi))] self.ax.set_proj_type('ortho') self.scatter = self.ax.scatter(xi, yi, zi, c=c, s=10) self.quiver = self.ax.quiver(xi, yi, zi, ui, vi, wi, length=1) self.lines, = self.ax.plot([], [], [], ".", markersize=0.5) self.axtime = plt.axes([0.25, 0.1, 0.65, 0.03]) self.stime = Slider(self.axtime, 'Time', 0.0, 10.0, valinit=0.0) def update(val): if val == 0: return print("Jumping e^{}={} frames".format(int(val), int(math.e**val))) for v in range(int(math.e**val)): x_i, y_i, z_i, u_i, v_i, w_i, x_, y_, z_ = next(self.stream) self.stime.reset() self.stime.on_changed(update) self.resetax = plt.axes([0.8, 0.025, 0.1, 0.04]) self.button = Button(self.resetax, 'Reset', hovercolor='0.975') def reset(event): self.stime.reset() self.x_ = [] self.y_ = [] self.z_ = [] self.button.on_clicked(reset) FLOOR = self.axis_range[0] CEILING = self.axis_range[1] self.ax.set_xlim3d(FLOOR, CEILING) self.ax.set_ylim3d(FLOOR, CEILING) self.ax.set_zlim3d(FLOOR, CEILING) self.ax.set_xlabel('X') self.ax.set_ylabel('Y') self.ax.set_zlabel('Z') return self.scatter, self.quiver def quiver_force_norm_factor(self): axis_length = np.abs(self.axis_range[1]) + np.abs(self.axis_range[0]) return np.amax(np.array([b.f for b in self.bodies])) / (axis_length / 10) def data_stream(self): while True: move(self.bodies, self.timescale) if not self.force_norm_factor: self.force_norm_factor = self.quiver_force_norm_factor() # print('factor ', self.force_norm_factor) x, y, z = points_for_bodies(self.bodies) u, v, w = norm_forces_for_bodies(self.bodies, self.force_norm_factor) # rad = random.randint(0, TRACK_NUM-1) # x_.append(x[rad]) # y_.append(y[rad]) # z_.append(z[rad]) self.x_.append(x[-1]) self.y_.append(y[-1]) self.z_.append(z[-1]) yield x, y, z, u, v, w, self.x_, self.y_, self.z_ def update(self, i): x_i, y_i, z_i, u_i, v_i, w_i, x_, y_, z_ = next(self.stream) self.scatter._offsets3d = (x_i, y_i, z_i) segments = np.array([(b.p, b.p + b.f / self.force_norm_factor) for b in self.bodies]) self.quiver.set_segments(segments) self.lines.set_data(np.array(x_), np.array(y_)) self.lines.set_3d_properties(np.array(z_)) plt.draw() return self.scatter, self.quiver, self.lines def show(self): plt.show()
def plot_wid( self, X=[], Y=[], # X-Y points in the graph. labels=[], # Labels for tittle, axis and so on. legend=[], # Legend for the curves plotted nf=1, # New figure na=0, # New axis. To plot in a new axis # Basic parameters that we can usually find in a plot color=None, # Color lw=2, # Line width alpha=1.0, # Alpha fontsize=20, # The font for the labels in the title fontsizeL=10, # The font for the labels in the legeng fontsizeA=15, # The font for the labels in the axis loc=1, scrolling=-1, # Size of the window to visualize ### Super Special Shit !! fill=0 # 0 = No fill, 1 = Fill and line, 2 = Only fill ): ## Preprocess the data given so that it meets the right format self.preprocess_data(X, Y) X = self.X Y = self.Y NpX, NcX = X.shape NpY, NcY = Y.shape # Management of the figure self.figure_management(nf, na, labels, fontsize) plt.subplots_adjust(left=0.05, bottom=0.1) ################################################################## ############### CALL PLOTTING FUNCTION ########################### ################################################################## ## TODO. Second case where NcY = NcX !! ## This function is the encharged of the plotting itself !! ## We must have an "array" with the different plot scenarios that we make ax = self.axes fig = self.fig wsize = scrolling val = NpX - wsize for i in range(NcY): # We plot once for every line to plot self.zorder = self.zorder + 1 colorFinal = self.get_color(color) if (i >= len(legend)): ln, = plt.plot(X[val:val + wsize], Y[val:val + wsize, i], lw=lw, alpha=alpha, color=colorFinal, zorder=self.zorder) else: # print X.shape # print Y[:,i].shape ln, = plt.plot(X[val:val + wsize], Y[val:val + wsize:, i], lw=lw, alpha=alpha, color=colorFinal, label=legend[i], zorder=self.zorder) if (fill == 1): ## Fill this shit !! self.filler(X[val:val + wsize], Y[val:val + wsize:, i], colorFinal, alpha) axcolor = 'lightgoldenrodyellow' # The canvas is small in the inferior part SmarginX = 0.05 SmarginY = 0.05 Sheight = 0.03 axpos = plt.axes([SmarginX, SmarginY, 1.0 - 2 * SmarginX, Sheight], axisbg=axcolor) sliderBar = Slider(axpos, 'Pos', 0, NpX - wsize, valinit=NpX - wsize) ## Init, graph ln.set_ydata(Y[val:val + wsize]) ln.set_xdata(X[val:val + wsize]) def slide(val): # print "Pene" val = int(val) # Init index of the time series. # We change the Y data shown ln.set_ydata(Y[val:val + wsize]) ln.set_xdata(X[val:val + wsize]) # ln.set_color("red") # ax.set_title(frame) # Set the new limits of Y axes ax.relim() ax.autoscale_view() # # Draw the new signal # plt.draw() fig.canvas.draw_idle() sliderBar.on_changed(slide) sliderBar.reset() self.slider = sliderBar self.update_legend(legend, NcY, loc=loc) self.format_axis(nf, fontsize=fontsizeA) if (na == 1 or nf == 1): self.format_plot() return 0
class PhasePlaneInteractive(object): """ An interactive phase-plane plot generated from a TVB model object. A TVB integrator object will be use for generating sample trajectories -- not the phase-plane. This is mainly interesting for visualising the effect of noise on a trajectory. """ def __init__(self, model, integrator): self.log = get_logger(self.__class__.__module__) self.model = model self.integrator = integrator #Make sure the model is fully configured... self.model.configure() self.model.update_derived_parameters() def get_required_memory_size(self, **kwargs): """ Return the required memory to run this algorithm. """ # Don't know how much memory is needed. return -1 def draw_phase_plane(self): """Generate the interactive phase-plane figure.""" self.log.debug("Plot started...") model_name = self.model.__class__.__name__ msg = "Generating an interactive phase-plane plot for %s" self.log.info(msg % model_name) self.svx = self.model.state_variables[0] # x-axis: 1st state variable self.svy = self.model.state_variables[1] # y-axis: 2nd state variable self.mode = 0 self._set_state_vector() #TODO: see how we can get the figure size from the UI to better 'fit' the encompassing div self.ipp_fig = pylab.figure(figsize=(10, 8)) pylab.clf() self.pp_ax = self.ipp_fig.add_axes([0.265, 0.2, 0.7, 0.75]) self.pp_splt = self.ipp_fig.add_subplot(212) self.ipp_fig.subplots_adjust(left=0.265, bottom=0.02, right=0.75, top=0.3, wspace=0.1, hspace=None) self.pp_splt.set_color_cycle(get_color(self.model.nvar)) self.pp_splt.plot( numpy.arange(TRAJ_STEPS + 1) * self.integrator.dt, numpy.zeros((TRAJ_STEPS + 1, self.model.nvar))) if hasattr(self.pp_splt, 'autoscale'): self.pp_splt.autoscale(enable=True, axis='y', tight=True) self.pp_splt.legend(self.model.state_variables) #Selectors self._add_state_variable_selector() self._add_mode_selector() #Sliders self._add_axes_range_sliders() self._add_state_variable_sliders() if isinstance(self.integrator, integrators_module.IntegratorStochastic): if self.integrator.noise.ntau > 0.0: self.integrator.noise.configure_coloured( self.integrator.dt, (1, self.model.nvar, 1, self.model.number_of_modes)) else: self.integrator.noise.configure_white( self.integrator.dt, (1, self.model.nvar, 1, self.model.number_of_modes)) self._add_noise_slider() self._add_reset_noise_button() self._add_reset_seed_button() #Reset buttons #self._add_reset_param_button() self._add_reset_sv_button() self._add_reset_axes_button() #Calculate the phase plane self._set_mesh_grid() self._calc_phase_plane() #Plot phase plane self._plot_phase_plane() # add mouse handler for trajectory clicking self.ipp_fig.canvas.mpl_connect('button_press_event', self._click_trajectory) self.ipp_fig.canvas.draw() return dict(serverIp=config.SERVER_IP, serverPort=config.MPLH5_SERVER_PORT, figureNumber=self.ipp_fig.number, showFullToolbar=False) def _add_state_variable_selector(self): """ Generate radio selector buttons to set which state variable is displayed on the x and y axis of the phase-plane plot. """ svx_ind = self.model.state_variables.index(self.svx) svy_ind = self.model.state_variables.index(self.svy) #State variable for the x axis pos_shp = [0.08, 0.07, 0.065, 0.12 + 0.006 * self.model.nvar] rax = self.ipp_fig.add_axes(pos_shp, axisbg=AXCOLOUR, title="x-axis") self.state_variable_x = RadioButtons(rax, tuple(self.model.state_variables), active=svx_ind) self.state_variable_x.on_clicked(self._update_svx) #State variable for the y axis pos_shp = [0.16, 0.07, 0.065, 0.12 + 0.006 * self.model.nvar] rax = self.ipp_fig.add_axes(pos_shp, axisbg=AXCOLOUR, title="y-axis") self.state_variable_y = RadioButtons(rax, tuple(self.model.state_variables), active=svy_ind) self.state_variable_y.on_clicked(self._update_svy) def _add_mode_selector(self): """ Add a radio button to the figure for selecting which mode of the model should be displayed. """ pos_shp = [0.02, 0.07, 0.04, 0.1 + 0.002 * self.model.number_of_modes] rax = self.ipp_fig.add_axes(pos_shp, axisbg=AXCOLOUR, title="Mode") mode_tuple = tuple(range(self.model.number_of_modes)) self.mode_selector = RadioButtons(rax, mode_tuple, active=0) self.mode_selector.on_clicked(self._update_mode) def _add_axes_range_sliders(self): """ Add sliders to the figure to allow the phase-planes axes to be set. """ self.axes_range_sliders = dict() default_range_x = (self.model.state_variable_range[self.svx][1] - self.model.state_variable_range[self.svx][0]) default_range_y = (self.model.state_variable_range[self.svy][1] - self.model.state_variable_range[self.svy][0]) min_val_x = self.model.state_variable_range[ self.svx][0] - 4.0 * default_range_x max_val_x = self.model.state_variable_range[ self.svx][1] + 4.0 * default_range_x min_val_y = self.model.state_variable_range[ self.svy][0] - 4.0 * default_range_y max_val_y = self.model.state_variable_range[ self.svy][1] + 4.0 * default_range_y sax = self.ipp_fig.add_axes([0.04, 0.835, 0.125, 0.025], axisbg=AXCOLOUR) sl_x_min = Slider(sax, "xlo", min_val_x, max_val_x, valinit=self.model.state_variable_range[self.svx][0]) sl_x_min.on_changed(self._update_range) sax = self.ipp_fig.add_axes([0.04, 0.8, 0.125, 0.025], axisbg=AXCOLOUR) sl_x_max = Slider(sax, "xhi", min_val_x, max_val_x, valinit=self.model.state_variable_range[self.svx][1]) sl_x_max.on_changed(self._update_range) sax = self.ipp_fig.add_axes([0.04, 0.765, 0.125, 0.025], axisbg=AXCOLOUR) sl_y_min = Slider(sax, "ylo", min_val_y, max_val_y, valinit=self.model.state_variable_range[self.svy][0]) sl_y_min.on_changed(self._update_range) sax = self.ipp_fig.add_axes([0.04, 0.73, 0.125, 0.025], axisbg=AXCOLOUR) sl_y_max = Slider(sax, "yhi", min_val_y, max_val_y, valinit=self.model.state_variable_range[self.svy][1]) sl_y_max.on_changed(self._update_range) self.axes_range_sliders["sl_x_min"] = sl_x_min self.axes_range_sliders["sl_x_max"] = sl_x_max self.axes_range_sliders["sl_y_min"] = sl_y_min self.axes_range_sliders["sl_y_max"] = sl_y_max def _add_state_variable_sliders(self): """ Add sliders to the figure to allow default values for the models state variable to be set. """ msv_range = self.model.state_variable_range offset = 0.0 self.sv_sliders = dict() for sv in range(self.model.nvar): offset += 0.035 pos_shp = [0.04, 0.6 - offset, 0.125, 0.025] sax = self.ipp_fig.add_axes(pos_shp, axisbg=AXCOLOUR) sv_str = self.model.state_variables[sv] self.sv_sliders[sv_str] = Slider(sax, sv_str, msv_range[sv_str][0], msv_range[sv_str][1], valinit=self.default_sv[sv, 0, 0]) self.sv_sliders[sv_str].on_changed(self._update_state_variables) def _add_noise_slider(self): """ Add a slider to the figure to allow the integrators noise strength to be set. """ pos_shp = [0.04, 0.365, 0.125, 0.025] sax = self.ipp_fig.add_axes(pos_shp, axisbg=AXCOLOUR) self.noise_slider = Slider(sax, "Noise", 0.0, 1.0, valinit=self.integrator.noise.nsig) self.noise_slider.on_changed(self._update_noise) def _add_reset_sv_button(self): """ Add a button to the figure for reseting the model state variables to their default values. """ bax = self.ipp_fig.add_axes([0.04, 0.60, 0.125, 0.04]) self.reset_sv_button = Button(bax, 'Reset state-variables', color=BUTTONCOLOUR, hovercolor=HOVERCOLOUR) def reset_state_variables(event): for svsl in self.sv_sliders.itervalues(): svsl.reset() self.reset_sv_button.on_clicked(reset_state_variables) def _add_reset_noise_button(self): """ Add a button to the figure for reseting the noise to its default value. """ bax = self.ipp_fig.add_axes([0.04, 0.4, 0.125, 0.04]) self.reset_noise_button = Button(bax, 'Reset noise strength', color=BUTTONCOLOUR, hovercolor=HOVERCOLOUR) def reset_noise(event): self.noise_slider.reset() self.reset_noise_button.on_clicked(reset_noise) def _add_reset_seed_button(self): """ Add a button to the figure for reseting the random number generator to its intial state. For reproducible noise... """ bax = self.ipp_fig.add_axes([0.04, 0.315, 0.125, 0.04]) self.reset_seed_button = Button(bax, 'Reset random stream', color=BUTTONCOLOUR, hovercolor=HOVERCOLOUR) def reset_seed(event): self.integrator.noise.trait["random_stream"].reset() self.reset_seed_button.on_clicked(reset_seed) def _add_reset_axes_button(self): """ Add a button to the figure for reseting the phase-plane axes to their default ranges. """ bax = self.ipp_fig.add_axes([0.04, 0.87, 0.125, 0.04]) self.reset_axes_button = Button(bax, 'Reset axes', color=BUTTONCOLOUR, hovercolor=HOVERCOLOUR) def reset_ranges(event): self.axes_range_sliders["sl_x_min"].reset() self.axes_range_sliders["sl_x_max"].reset() self.axes_range_sliders["sl_y_min"].reset() self.axes_range_sliders["sl_y_max"].reset() self.reset_axes_button.on_clicked(reset_ranges) ##------------------------------------------------------------------------## ##------------------- Functions for updating the figure ------------------## ##------------------------------------------------------------------------## #NOTE: All the ax.set_xlim, poly.xy, etc, garbage below is fragile. It works # at the moment, but there are currently bugs in Slider and the hackery # below takes these into account... If the bugs are fixed/changed then # this could break. As an example, the Slider doc says poly is a # Rectangle, but it's actually a Polygon. The Slider set_val method # assumes a Rectangle even though this is not the case, so the array # Slider.poly.xy is corrupted by that method. The corruption isn't # visible in the plot, which is probably why it hasn't been fixed... def update_xrange_sliders(self): """ """ default_range_x = (self.model.state_variable_range[self.svx][1] - self.model.state_variable_range[self.svx][0]) min_val_x = self.model.state_variable_range[ self.svx][0] - 4.0 * default_range_x max_val_x = self.model.state_variable_range[ self.svx][1] + 4.0 * default_range_x self.axes_range_sliders[ "sl_x_min"].valinit = self.model.state_variable_range[self.svx][0] self.axes_range_sliders["sl_x_min"].valmin = min_val_x self.axes_range_sliders["sl_x_min"].valmax = max_val_x self.axes_range_sliders["sl_x_min"].ax.set_xlim(min_val_x, max_val_x) self.axes_range_sliders["sl_x_min"].poly.axes.set_xlim( min_val_x, max_val_x) self.axes_range_sliders["sl_x_min"].poly.xy[[0, 1], 0] = min_val_x self.axes_range_sliders["sl_x_min"].vline.set_data(([ self.axes_range_sliders["sl_x_min"].valinit, self.axes_range_sliders["sl_x_min"].valinit ], [0, 1])) self.axes_range_sliders[ "sl_x_max"].valinit = self.model.state_variable_range[self.svx][1] self.axes_range_sliders["sl_x_max"].valmin = min_val_x self.axes_range_sliders["sl_x_max"].valmax = max_val_x self.axes_range_sliders["sl_x_max"].ax.set_xlim(min_val_x, max_val_x) self.axes_range_sliders["sl_x_max"].poly.axes.set_xlim( min_val_x, max_val_x) self.axes_range_sliders["sl_x_max"].poly.xy[[0, 1], 0] = min_val_x self.axes_range_sliders["sl_x_max"].vline.set_data(([ self.axes_range_sliders["sl_x_max"].valinit, self.axes_range_sliders["sl_x_max"].valinit ], [0, 1])) self.axes_range_sliders["sl_x_min"].reset() self.axes_range_sliders["sl_x_max"].reset() def update_yrange_sliders(self): """ """ default_range_y = (self.model.state_variable_range[self.svy][1] - self.model.state_variable_range[self.svy][0]) min_val_y = self.model.state_variable_range[ self.svy][0] - 4.0 * default_range_y max_val_y = self.model.state_variable_range[ self.svy][1] + 4.0 * default_range_y self.axes_range_sliders[ "sl_y_min"].valinit = self.model.state_variable_range[self.svy][0] self.axes_range_sliders["sl_y_min"].valmin = min_val_y self.axes_range_sliders["sl_y_min"].valmax = max_val_y self.axes_range_sliders["sl_y_min"].ax.set_xlim(min_val_y, max_val_y) self.axes_range_sliders["sl_y_min"].poly.axes.set_xlim( min_val_y, max_val_y) self.axes_range_sliders["sl_y_min"].poly.xy[[0, 1], 0] = min_val_y self.axes_range_sliders["sl_y_min"].vline.set_data(([ self.axes_range_sliders["sl_y_min"].valinit, self.axes_range_sliders["sl_y_min"].valinit ], [0, 1])) self.axes_range_sliders[ "sl_y_max"].valinit = self.model.state_variable_range[self.svy][1] self.axes_range_sliders["sl_y_max"].valmin = min_val_y self.axes_range_sliders["sl_y_max"].valmax = max_val_y self.axes_range_sliders["sl_y_max"].ax.set_xlim(min_val_y, max_val_y) self.axes_range_sliders["sl_y_max"].poly.axes.set_xlim( min_val_y, max_val_y) self.axes_range_sliders["sl_y_max"].poly.xy[[0, 1], 0] = min_val_y self.axes_range_sliders["sl_y_max"].vline.set_data(([ self.axes_range_sliders["sl_y_max"].valinit, self.axes_range_sliders["sl_y_max"].valinit ], [0, 1])) self.axes_range_sliders["sl_y_min"].reset() self.axes_range_sliders["sl_y_max"].reset() def _update_svx(self, label): """ Update state variable used for x-axis based on radio buttton selection. """ self.svx = label self.update_xrange_sliders() self._set_mesh_grid() self._calc_phase_plane() self._update_phase_plane() def _update_svy(self, label): """ Update state variable used for y-axis based on radio buttton selection. """ self.svy = label self.update_yrange_sliders() self._set_mesh_grid() self._calc_phase_plane() self._update_phase_plane() def _update_mode(self, label): """ Update the visualised mode based on radio button selection. """ self.mode = label self._update_phase_plane() def _update_noise(self, nsig): """ Update integrator noise based on the noise slider value. """ self.integrator.noise.nsig = numpy.array([ nsig, ]) def _update_range(self, val): """ Update the axes ranges based on the current axes slider values. NOTE: Haven't figured out how to update independently, so just update everything. """ #TODO: Grab caller and use val directly, ie independent range update. self.axes_range_sliders["sl_x_min"].ax.set_axis_bgcolor(AXCOLOUR) self.axes_range_sliders["sl_x_max"].ax.set_axis_bgcolor(AXCOLOUR) self.axes_range_sliders["sl_y_min"].ax.set_axis_bgcolor(AXCOLOUR) self.axes_range_sliders["sl_y_max"].ax.set_axis_bgcolor(AXCOLOUR) if self.axes_range_sliders["sl_x_min"].val >= self.axes_range_sliders[ "sl_x_max"].val: self.log.error("X-axis min must be less than max...") self.axes_range_sliders["sl_x_min"].ax.set_axis_bgcolor("Red") self.axes_range_sliders["sl_x_max"].ax.set_axis_bgcolor("Red") return if self.axes_range_sliders["sl_y_min"].val >= self.axes_range_sliders[ "sl_y_max"].val: self.log.error("Y-axis min must be less than max...") self.axes_range_sliders["sl_y_min"].ax.set_axis_bgcolor("Red") self.axes_range_sliders["sl_y_max"].ax.set_axis_bgcolor("Red") return msv_range = self.model.state_variable_range msv_range[self.svx][0] = self.axes_range_sliders["sl_x_min"].val msv_range[self.svx][1] = self.axes_range_sliders["sl_x_max"].val msv_range[self.svy][0] = self.axes_range_sliders["sl_y_min"].val msv_range[self.svy][1] = self.axes_range_sliders["sl_y_max"].val self._set_mesh_grid() self._calc_phase_plane() self._update_phase_plane() def _update_phase_plane(self): """ Clear the axes and redraw the phase-plane. """ self.pp_ax.clear() self.pp_splt.clear() self.pp_splt.set_color_cycle(get_color(self.model.nvar)) self.pp_splt.plot( numpy.arange(TRAJ_STEPS + 1) * self.integrator.dt, numpy.zeros((TRAJ_STEPS + 1, self.model.nvar))) if hasattr(self.pp_splt, 'autoscale'): self.pp_splt.autoscale(enable=True, axis='y', tight=True) self.pp_splt.legend(self.model.state_variables) self._plot_phase_plane() def _update_state_variables(self, val): """ Update the default state-variable values, used for non-visualised state variables, based of the current slider values. """ for sv in self.sv_sliders: k = self.model.state_variables.index(sv) self.default_sv[k] = self.sv_sliders[sv].val self._calc_phase_plane() self._update_phase_plane() def _set_mesh_grid(self): """ Generate the phase-plane gridding based on currently selected statevariables and their range values. """ xlo = self.model.state_variable_range[self.svx][0] xhi = self.model.state_variable_range[self.svx][1] ylo = self.model.state_variable_range[self.svy][0] yhi = self.model.state_variable_range[self.svy][1] self.X = numpy.mgrid[xlo:xhi:(NUMBEROFGRIDPOINTS * 1j)] self.Y = numpy.mgrid[ylo:yhi:(NUMBEROFGRIDPOINTS * 1j)] def _set_state_vector(self): """ """ #import pdb; pdb.set_trace() svr = self.model.state_variable_range sv_mean = numpy.array( [svr[key].mean() for key in self.model.state_variables]) sv_mean = sv_mean.reshape((self.model.nvar, 1, 1)) self.default_sv = sv_mean.repeat(self.model.number_of_modes, axis=2) self.no_coupling = numpy.zeros( (self.model.nvar, 1, self.model.number_of_modes)) def _calc_phase_plane(self): """ Calculate the vector field. """ svx_ind = self.model.state_variables.index(self.svx) svy_ind = self.model.state_variables.index(self.svy) #Calculate the vector field discretely sampled at a grid of points grid_point = self.default_sv.copy() self.U = numpy.zeros((NUMBEROFGRIDPOINTS, NUMBEROFGRIDPOINTS, self.model.number_of_modes)) self.V = numpy.zeros((NUMBEROFGRIDPOINTS, NUMBEROFGRIDPOINTS, self.model.number_of_modes)) for ii in xrange(NUMBEROFGRIDPOINTS): grid_point[svy_ind] = self.Y[ii] for jj in xrange(NUMBEROFGRIDPOINTS): #import pdb; pdb.set_trace() grid_point[svx_ind] = self.X[jj] d = self.model.dfun(grid_point, self.no_coupling) for kk in range(self.model.number_of_modes): self.U[ii, jj, kk] = d[svx_ind, 0, kk] self.V[ii, jj, kk] = d[svy_ind, 0, kk] #self.UVmag = numpy.sqrt(self.U**2 + self.V**2) #import pdb; pdb.set_trace() if numpy.isnan(self.U).any() or numpy.isnan(self.V).any(): self.log.error("NaN") def _plot_phase_plane(self): """ Plot the vector field and its nullclines. """ # Set title and axis labels model_name = self.model.__class__.__name__ self.pp_ax.set(title=model_name + " mode " + str(self.mode)) self.pp_ax.set(xlabel="State Variable " + self.svx) self.pp_ax.set(ylabel="State Variable " + self.svy) #import pdb; pdb.set_trace() #Plot a discrete representation of the vector field if numpy.all(self.U[:, :, self.mode] + self.V[:, :, self.mode] == 0): self.pp_ax.set(title=model_name + " mode " + str(self.mode) + ": NO MOTION IN THIS PLANE") X, Y = numpy.meshgrid(self.X, self.Y) self.pp_quivers = self.pp_ax.scatter(X, Y, s=8, marker=".", c="k") else: self.pp_quivers = self.pp_ax.quiver( self.X, self.Y, self.U[:, :, self.mode], self.V[:, :, self.mode], #self.UVmag[:, :, self.mode], width=0.001, headwidth=8) #Plot the nullclines self.nullcline_x = self.pp_ax.contour(self.X, self.Y, self.U[:, :, self.mode], [0], colors="r") self.nullcline_y = self.pp_ax.contour(self.X, self.Y, self.V[:, :, self.mode], [0], colors="g") self.ipp_fig.canvas.draw() def _plot_trajectory(self, x, y): """ Plot a sample trajectory, starting at the position x,y in the phase-plane. """ svx_ind = self.model.state_variables.index(self.svx) svy_ind = self.model.state_variables.index(self.svy) #Calculate an example trajectory state = self.default_sv.copy() state[svx_ind] = x state[svy_ind] = y scheme = self.integrator.scheme traj = numpy.zeros( (TRAJ_STEPS + 1, self.model.nvar, 1, self.model.number_of_modes)) traj[0, :] = state for step in range(TRAJ_STEPS): #import pdb; pdb.set_trace() state = scheme(state, self.model.dfun, self.no_coupling, 0.0, 0.0) traj[step + 1, :] = state self.pp_ax.scatter(x, y, s=42, c='g', marker='o', edgecolor=None) self.pp_ax.plot(traj[:, svx_ind, 0, self.mode], traj[:, svy_ind, 0, self.mode]) #Plot the selected state variable trajectories as a function of time self.pp_splt.plot( numpy.arange(TRAJ_STEPS + 1) * self.integrator.dt, traj[:, :, 0, self.mode]) pylab.draw() def _click_trajectory(self, event): """ """ if event.inaxes is self.pp_ax: x, y = event.xdata, event.ydata self.log.info('trajectory starting at (%f, %f)', x, y) self._plot_trajectory(x, y) def update_model_parameter(self, param_name, param_new_value): """ Update model parameters based on the current parameter slider values. NOTE: Haven't figured out how to update independantly, so just update everything. """ #TODO: Grab caller and use val directly, ie independent parameter update. setattr(self.model, param_name, numpy.array([param_new_value])) self.model.update_derived_parameters() self._calc_phase_plane() self._update_phase_plane() def update_all_model_parameters(self, model_instance): for key in model_instance.ui_configurable_parameters: attr = getattr(model_instance, key) if isinstance(attr, numpy.ndarray) and attr.size == 1: setattr(self.model, key, numpy.array([attr[0]])) self.model.update_derived_parameters() self._calc_phase_plane() self._update_phase_plane() def update_model_parameters_from_dict(self, parameters_dict): """ NOTE: I expect that the given parameters exists on the current model and also that they are numpy arrays. Sets the parameters from the given dict on the current model instance and also updates the phase-plane. """ for param_name in parameters_dict: setattr(self.model, param_name, numpy.array([parameters_dict[param_name]])) self.model.update_derived_parameters() self._calc_phase_plane() self._update_phase_plane()
def add_slider(self, plots_affected=[], name="slidy", func="timeSlide", args={}): ## This function adds a slider related to one of the plots ## Indicated by the index # plot_i = Indexes of the plot associated to the slider. # func = Set of functions that we want the slider to do. # Since we need to referenced inner things, we migh as well define the # updating functions inside this funciton. ## Shirnk the main axes. TODO, move this to another general func # plt.subplots_adjust(left = 0.2, bottom=0.2) ## Limits of value of the slider. ## If nothig specified, they are the index of the selected plot if (len(plots_affected) == 0): plots_affected = range(len(self.plots_list)) if (func == "timeSlide"): wsize = args["wsize"] NpX, NcY = (self.Data_list[plots_affected[0]][0]).shape valMin = 0 valMax = NpX - wsize valInit = NpX - wsize # Create the Slider canvas axcolor = 'lightgoldenrodyellow' SmarginX = 0.05 SmarginY = 0.05 Sheight = 0.03 Swidth = 0.8 - 2 * SmarginX axpos = plt.axes([SmarginX, SmarginY, Swidth, Sheight], axisbg=axcolor) sliderBar = Slider(axpos, name, valMin, valMax, valinit=valInit) def slideTime(val): ## Function to slide the time signal through time val = int(val) # Init index of the time series. fig = self.fig # print "FRGR" ## This will clear the axis !! # plt.cla() # Now we iterate over all the necesary plots # print "In bitch" for plot_i in plots_affected: lns = self.plots_list[plot_i] # The reference to the plot # We might have more than one signal plotter though # We change the Y data shown # print "In bitch 2" # print self.plots_type[plot_i] for i in range(len(lns)): # print "In bitch 3" # Type of plot will change the way to treat it ln_type = self.plots_type[plot_i][i] if (ln_type == "plot"): ln = lns[i] ln.set_ydata(self.Data_list[plot_i][1][val:val + wsize, i]) ln.set_xdata(self.Data_list[plot_i][0][val:val + wsize]) elif (ln_type == "fill"): ## We will remove and redraw !! ln = lns[i] # print ln # print type(ln) ln.remove() # x = self.Data_list[plot_i][0][val:val + wsize] # y1 = self.Data_list[plot_i][1][val:val + wsize] # y2 = self.Data_list[plot_i][2] x, y1, y2, where, ax, alpha, color, args, kwargs = self.Data_list[ plot_i] # ln.set_xdata (self.Data_list[plot_i][0][val:val + wsize]) # TODO me estas puto diciendo que solo port seleccionar esto me jodes ? x = x[val:val + wsize] y1 = y1[val:val + wsize] if where is None: pass else: where = where[val:val + wsize] # print len(x), len(y1), y2 # print type(x), type(y1) # print kwargs # We also need to resize "where" vector if needed. # if "where" in kwargs ln = ax.fill_between(x=x, y1=y1, y2=y2, where=where, color=color, alpha=0.3, *args, **kwargs) self.plots_list[plot_i][i] = ln # print XX # ln.set_ydata(self.Data_list[plot_i][1][val:val + wsize,i]) # ln.set_xdata (self.Data_list[plot_i][0][val:val + wsize]) elif (ln_type == "bar"): ln = lns[i] j = 0 for rect in ln: rect.align = "center" # print self.Data_list[plot_i][i] rect.set_height(self.Data_list[plot_i][1][val + j - 1]) rect.set_x(self.Data_list[plot_i][0][val + j - 1]) rect.set_y(self.Data_list[plot_i][2][val + j - 1]) # rect.align = "center" # print plt.getp(rect, "width") j += 1 elif (ln_type == "candlestick"): lines = self.plots_list[plot_i][0][0] rects = self.plots_list[plot_i][0][1] axes_candlestick = self.Data_list[plot_i][1] data = self.Data_list[plot_i][0] for line in lines: line.remove() for rects in rects: rects.remove() plotting = candlestick_ohlc(axes_candlestick, data[val:val + wsize, :], width=0.7) self.plots_list[plot_i][0] = plotting # print "d2" # ln.set_color("red") # ax.set_title(frame) # Set the new limits of Y axes self.format_axis(val=val, wsize=wsize) for ax in self.axes_list: ax.relim() ax.autoscale_view() # # Draw the new signal # plt.draw() fig.canvas.draw_idle() ## Set the slider if (func == "timeSlide"): sliderBar.on_changed(slideTime) sliderBar.reset() slideTime(valInit) self.widget_list.append(sliderBar) ######################################################## ###### Buttons for sliding as well ##################### ########################################################## Bheight = Sheight Bwidth = 0.03 BmarginXleft = SmarginX - Bwidth - 0.001 BmarginXright = SmarginX + Swidth + 0.001 BmarginY = SmarginY BleftAx = plt.axes([BmarginXleft, BmarginY, Bwidth, Bheight]) BrightAx = plt.axes([BmarginXright, BmarginY, Bwidth, Bheight]) # Set the bottom into the axes, with some properties Bleft = Button2(BleftAx, '<', color=axcolor, hovercolor='0.975') Bright = Button2(BrightAx, '>', color=axcolor, hovercolor='0.975') # Create the function of the object def bleft_func(event, caca): # print caca sliderBar.set_val( sliderBar.val - caca) # Calls the on_changed func with the init value def bright_func(event, caca): sliderBar.set_val( sliderBar.val + caca) # Calls the on_changed func with the init value Bleft.on_clicked(bleft_func) Bright.on_clicked(bright_func) self.widget_list.append(Bleft) self.widget_list.append(Bright)