From 2b871855e70f157d86920a2eb4a7723bacf40e85 Mon Sep 17 00:00:00 2001 From: Eldar Khayrullin Date: Sun, 7 Jun 2020 20:25:43 +0300 Subject: [PATCH 1/3] Enable grid in plots --- SignalIntegrity/App/SParameterViewerWindow.py | 15 +++++++++++++-- SignalIntegrity/App/Simulator.py | 6 +++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/SignalIntegrity/App/SParameterViewerWindow.py b/SignalIntegrity/App/SParameterViewerWindow.py index 1c9f8f165..e5330925f 100644 --- a/SignalIntegrity/App/SParameterViewerWindow.py +++ b/SignalIntegrity/App/SParameterViewerWindow.py @@ -998,6 +998,8 @@ def PlotSParameter(self): self.topLeftPlot.set_ylabel('magnitude (dB)',fontsize=10) self.topLeftPlot.set_xlabel('frequency ('+self.freqLabel+')',fontsize=10) + self.topLeftPlot.grid(True, 'both') + TD = self.plotProperties['Delay'] frph=fr._DelayBy(-TD) @@ -1050,6 +1052,8 @@ def PlotSParameter(self): self.topRightPlot.set_ylabel('phase (degrees)',fontsize=10) self.topRightPlot.set_xlabel('frequency ('+self.freqLabel+')',fontsize=10) + self.topRightPlot.grid(True, 'both') + if ir is not None: if self.buttonLabels[self.toPort-1][self.fromPort-1][:2]=='i/' or self.buttonLabels[self.toPort-1][self.fromPort-1][:3]=='di/': print('Integrate') @@ -1105,6 +1109,8 @@ def PlotSParameter(self): self.bottomLeftPlot.set_ylabel('amplitude',fontsize=10) self.bottomLeftPlot.set_xlabel('time ('+timeLabel+')',fontsize=10) + self.bottomLeftPlot.grid(True) + firFilter=ir.FirFilter() stepWaveformTimeDescriptor=ir.td/firFilter.FilterDescriptor() stepWaveform=si.td.wf.StepWaveform(stepWaveformTimeDescriptor) @@ -1196,6 +1202,8 @@ def PlotSParameter(self): self.bottomRightPlot.set_ylim(bottom=self.bottomRightPlotProperties['MinY']*self.bottomRightPlotProperties['M']+self.bottomRightPlotProperties['B']) self.bottomRightPlot.set_ylim(top=self.bottomRightPlotProperties['MaxY']*self.bottomRightPlotProperties['M']+self.bottomRightPlotProperties['B']) + self.bottomRightPlot.grid(True) + self.topLeftCanvas.draw() self.topRightCanvas.draw() self.bottomLeftCanvas.draw() @@ -1292,6 +1300,9 @@ def onDelayEntered(self,event): self.topRightPlot.set_ylabel('phase (degrees)',fontsize=10) self.topRightPlot.set_xlabel('frequency ('+self.freqLabel+')',fontsize=10) + + self.topRightPlot.grid(True, 'both') + self.topRightCanvas.draw() self.topRightToolbar.update() @@ -1411,7 +1422,7 @@ def onMatplotlib2TikZ(self): def onHelp(self): if Doer.helpKeys is None: - messagebox.showerror('Help System','Cannot find or open this help element') + messagebox.showerror('Help System','Cannot find or open this help element') return Doer.helpKeys.Open('sec:S-parameter-Viewer') @@ -1432,7 +1443,7 @@ def onEnforceCausality(self): self.sp.EnforceCausality() self.UpdatePropertiesFromSParameters() self.PlotSParameter() - + def onEnforceBothPassivityAndCausality(self): self.sp.EnforceBothPassivityAndCausality(maxIterations=30,causalityThreshold=1e-5) self.UpdatePropertiesFromSParameters() diff --git a/SignalIntegrity/App/Simulator.py b/SignalIntegrity/App/Simulator.py index 81648c918..219c09a41 100644 --- a/SignalIntegrity/App/Simulator.py +++ b/SignalIntegrity/App/Simulator.py @@ -301,6 +301,8 @@ def PlotWaveformsFrequencyContent(self,density=False): if self.maxy != None: self.plt.set_ylim(top=self.maxy) + self.plt.grid(True) + self.ZoomsInitialized=True self.f.canvas.draw() @@ -460,6 +462,8 @@ def PlotWaveformsTimeDomain(self): if self.maxy != None: self.plt.set_ylim(top=self.maxy) + self.plt.grid(True) + self.ZoomsInitialized=True self.f.canvas.draw() @@ -517,7 +521,7 @@ def onMatplotlib2TikZ(self): messagebox.showerror('Export LaTeX','LaTeX could not be generated or written ') def onHelp(self): if Doer.helpKeys is None: - messagebox.showerror('Help System','Cannot find or open this help element') + messagebox.showerror('Help System','Cannot find or open this help element') return Doer.helpKeys.Open('sec:Simulator-Dialog') From 181ecb2bf5cf2ab7d3bd6a93b1e2d1730180f411 Mon Sep 17 00:00:00 2001 From: Eldar Khayrullin Date: Sun, 7 Jun 2020 22:04:38 +0300 Subject: [PATCH 2/3] Enable cursor in plots (uses mpldatacursor module) --- SignalIntegrity/App/SParameterViewerWindow.py | 58 +++++++++++-------- SignalIntegrity/App/Simulator.py | 16 +++-- 2 files changed, 44 insertions(+), 30 deletions(-) diff --git a/SignalIntegrity/App/SParameterViewerWindow.py b/SignalIntegrity/App/SParameterViewerWindow.py index e5330925f..d263ddb46 100644 --- a/SignalIntegrity/App/SParameterViewerWindow.py +++ b/SignalIntegrity/App/SParameterViewerWindow.py @@ -55,6 +55,8 @@ from matplotlib import rcParams rcParams.update({'figure.autolayout': True}) +from mpldatacursor import datacursor + class NavigationToolbar(NavigationToolbar2Tk): def __init__(self, canvas, window,homeCallback=None): NavigationToolbar2Tk.__init__(self,canvas,window) @@ -260,7 +262,6 @@ def __init__(self, parent,sp,filename=None,title=None,buttonLabels=None): self.topLeftToolbar = NavigationToolbar( self.topLeftCanvas, topLeftFrame ,self.onTopLeftHome) self.topLeftToolbar.update() self.topLeftCanvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1) - self.topLeftToolbar.pan() self.topRightFigure=Figure(figsize=(plotWidth,plotHeight), dpi=plotDPI) self.topRightPlot=self.topRightFigure.add_subplot(111) @@ -269,7 +270,6 @@ def __init__(self, parent,sp,filename=None,title=None,buttonLabels=None): self.topRightToolbar = NavigationToolbar( self.topRightCanvas, topRightFrame ,self.onTopRightHome) self.topRightToolbar.update() self.topRightCanvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1) - self.topRightToolbar.pan() self.topRightCanvasControlsFrame=tk.Frame(topRightFrame) self.topRightCanvasControlsFrame.pack(side=tk.TOP, fill=tk.X, expand=tk.NO) tk.Button(self.topRightCanvasControlsFrame,text='unwrap',command=self.onUnwrap).pack(side=tk.LEFT,expand=tk.NO,fill=tk.NONE) @@ -283,7 +283,6 @@ def __init__(self, parent,sp,filename=None,title=None,buttonLabels=None): self.bottomLeftToolbar = NavigationToolbar( self.bottomLeftCanvas, bottomLeftFrame ,self.onBottomLeftHome) self.bottomLeftToolbar.update() self.bottomLeftCanvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1) - self.bottomLeftToolbar.pan() self.bottomRightFigure=Figure(figsize=(plotWidth,plotHeight), dpi=plotDPI) self.bottomRightPlot=self.bottomRightFigure.add_subplot(111) @@ -292,7 +291,6 @@ def __init__(self, parent,sp,filename=None,title=None,buttonLabels=None): self.bottomRightToolbar = NavigationToolbar( self.bottomRightCanvas, bottomRightFrame , self.onBottomRightHome) self.bottomRightToolbar.update() self.bottomRightCanvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1) - self.bottomRightToolbar.pan() self.controlsFrame = tk.Frame(self.dialogFrame) self.controlsFrame.pack(side=tk.TOP,fill=tk.X,expand=tk.NO) @@ -458,16 +456,16 @@ def onLogScale(self): def ZoomJoinActivations(self): self.Zoom['Frequencies']['Join']['All'].Activate(self.Zoom['Frequencies']['JoinWithOthers'].Bool()) self.Zoom['Frequencies']['Join']['OffDiagonal'].Activate(self.Zoom['Frequencies']['JoinWithOthers'].Bool() and not self.Zoom['Frequencies']['Join']['All'].Bool() and self.Zoom['AreSParameterLike']) - self.Zoom['Frequencies']['Join']['Reciprocals'].Activate(self.Zoom['Frequencies']['JoinWithOthers'].Bool() and not self.Zoom['Frequencies']['Join']['All'].Bool() and not self.Zoom['Frequencies']['Join']['OffDiagonal'].Bool() and self.Zoom['AreSParameterLike']) + self.Zoom['Frequencies']['Join']['Reciprocals'].Activate(self.Zoom['Frequencies']['JoinWithOthers'].Bool() and not self.Zoom['Frequencies']['Join']['All'].Bool() and not self.Zoom['Frequencies']['Join']['OffDiagonal'].Bool() and self.Zoom['AreSParameterLike']) self.Zoom['Frequencies']['Join']['Reflects'].Activate(self.Zoom['Frequencies']['JoinWithOthers'].Bool() and not self.Zoom['Frequencies']['Join']['All'].Bool() and self.Zoom['AreSParameterLike']) self.Zoom['Times']['Join']['All'].Activate(self.Zoom['Times']['JoinWithOthers'].Bool()) self.Zoom['Times']['Join']['OffDiagonal'].Activate(self.Zoom['Times']['JoinWithOthers'].Bool() and not self.Zoom['Times']['Join']['All'].Bool() and self.Zoom['AreSParameterLike']) - self.Zoom['Times']['Join']['Reciprocals'].Activate(self.Zoom['Times']['JoinWithOthers'].Bool() and not self.Zoom['Times']['Join']['All'].Bool() and not self.Zoom['Times']['Join']['OffDiagonal'].Bool() and self.Zoom['AreSParameterLike']) + self.Zoom['Times']['Join']['Reciprocals'].Activate(self.Zoom['Times']['JoinWithOthers'].Bool() and not self.Zoom['Times']['Join']['All'].Bool() and not self.Zoom['Times']['Join']['OffDiagonal'].Bool() and self.Zoom['AreSParameterLike']) self.Zoom['Times']['Join']['Reflects'].Activate(self.Zoom['Times']['JoinWithOthers'].Bool() and not self.Zoom['Times']['Join']['All'].Bool() and self.Zoom['AreSParameterLike']) verticalsActive = self.Zoom['Vertical']['JoinMagnitudeWithOthers'].Bool() or self.Zoom['Vertical']['JoinPhaseWithOthers'].Bool() or self.Zoom['Vertical']['JoinImpulseWithOthers'].Bool() or self.Zoom['Vertical']['JoinStepImpedanceWithOthers'].Bool() self.Zoom['Vertical']['Join']['All'].Activate(verticalsActive) self.Zoom['Vertical']['Join']['OffDiagonal'].Activate(verticalsActive and not self.Zoom['Vertical']['Join']['All'].Bool() and self.Zoom['AreSParameterLike']) - self.Zoom['Vertical']['Join']['Reciprocals'].Activate(verticalsActive and not self.Zoom['Vertical']['Join']['All'].Bool() and not self.Zoom['Vertical']['Join']['OffDiagonal'].Bool() and self.Zoom['AreSParameterLike']) + self.Zoom['Vertical']['Join']['Reciprocals'].Activate(verticalsActive and not self.Zoom['Vertical']['Join']['All'].Bool() and not self.Zoom['Vertical']['Join']['OffDiagonal'].Bool() and self.Zoom['AreSParameterLike']) self.Zoom['Vertical']['Join']['Reflects'].Activate(verticalsActive and not self.Zoom['Vertical']['Join']['All'].Bool() and self.Zoom['AreSParameterLike']) SignalIntegrity.App.Preferences.SaveToFile() @@ -955,14 +953,16 @@ def PlotSParameter(self): else: for i in range(len(x)-1): if self.LogScaleDoer.Bool(): - self.topLeftPlot.semilogx(x[i:i+2],y[i:i+2],linewidth=lw[i],color='blue') + lines=self.topLeftPlot.semilogx(x[i:i+2],y[i:i+2],linewidth=lw[i],color='blue') else: - self.topLeftPlot.plot(x[i:i+2],y[i:i+2],linewidth=lw[i],color='blue') + lines=self.topLeftPlot.plot(x[i:i+2],y[i:i+2],linewidth=lw[i],color='blue') else: if self.LogScaleDoer.Bool(): - self.topLeftPlot.semilogx(x,y) + lines=self.topLeftPlot.semilogx(x,y) else: - self.topLeftPlot.plot(x,y) + lines=self.topLeftPlot.plot(x,y) + + datacursor(lines,formatter="f: {x:.3f}\nmag: {y:.2f}".format,display='multiple',draggable=True) if self.ShowPassivityViolationsDoer.Bool(): self.topLeftPlot.scatter( @@ -1016,14 +1016,16 @@ def PlotSParameter(self): else: for i in range(len(x)-1): if self.LogScaleDoer.Bool(): - self.topRightPlot.semilogx(x[i:i+2],y[i:i+2],linewidth=lw[i],color='blue') + lines=self.topRightPlot.semilogx(x[i:i+2],y[i:i+2],linewidth=lw[i],color='blue') else: - self.topRightPlot.plot(x[i:i+2],y[i:i+2],linewidth=lw[i],color='blue') + lines=self.topRightPlot.plot(x[i:i+2],y[i:i+2],linewidth=lw[i],color='blue') else: if self.LogScaleDoer.Bool(): - self.topRightPlot.semilogx(x,y) + lines=self.topRightPlot.semilogx(x,y) else: - self.topRightPlot.plot(x,y) + lines=self.topRightPlot.plot(x,y) + + datacursor(lines,formatter="f: {x:.3f}\nphi: {y:.1f}".format,display='multiple',draggable=True) self.topRightPlotProperties=self.plotProperties['Phase'] self.topRightLabel.config(text='Phase') @@ -1069,7 +1071,9 @@ def PlotSParameter(self): x=ir.Times(timeLabelDivisor) - self.bottomLeftPlot.plot(x,y) + lines=self.bottomLeftPlot.plot(x,y) + + datacursor(lines,formatter="t: {x:.3f}\namp: {y:.3f}".format,display='multiple',draggable=True) if self.ShowCausalityViolationsDoer.Bool(): minv=0.00001; maxv=0.1 @@ -1175,7 +1179,9 @@ def PlotSParameter(self): self.bottomRightPlotProperties['MaxY']=max(max(y)*1.05,0.1) self.bottomRightPlotProperties['YInitialized']=True - self.bottomRightPlot.plot(x,y) + lines=self.bottomRightPlot.plot(x,y) + + datacursor(lines,formatter="t: {x:.3f}\namp: {y:.3f}".format,display='multiple',draggable=True) if self.ShowCausalityViolationsDoer.Bool(): self.bottomRightPlot.scatter( @@ -1268,14 +1274,16 @@ def onDelayEntered(self,event): else: for i in range(len(x)-1): if self.LogScaleDoer.Bool(): - self.topRightPlot.semilogx(x[i:i+2],y[i:i+2],linewidth=lw[i],color='blue') + lines=self.topRightPlot.semilogx(x[i:i+2],y[i:i+2],linewidth=lw[i],color='blue') else: - self.topRightPlot.plot(x[i:i+2],y[i:i+2],linewidth=lw[i],color='blue') + lines=self.topRightPlot.plot(x[i:i+2],y[i:i+2],linewidth=lw[i],color='blue') else: if self.LogScaleDoer.Bool(): - self.topRightPlot.semilogx(x,y) + lines=self.topRightPlot.semilogx(x,y) else: - self.topRightPlot.plot(x,y) + lines=self.topRightPlot.plot(x,y) + + datacursor(lines,formatter="f: {x:.3f}\nphi: {y:.1f}".format,display='multiple',draggable=True) if not self.topRightPlotProperties['XInitialized']: self.topRightPlotProperties['MinX']=min(x) @@ -1376,7 +1384,7 @@ def onMatplotlib2TikZ(self): try: si.test.PlotTikZ(filename,self.topLeftFigure) except: - messagebox.showerror('Export LaTeX','LaTeX could not be generated or written ') + messagebox.showerror('Export LaTeX','LaTeX could not be generated or written ') fp=FileParts(filename.replace('_Magnitude.tex', '').replace('Magnitude.tex', '')) filename=fp.filename @@ -1390,7 +1398,7 @@ def onMatplotlib2TikZ(self): try: si.test.PlotTikZ(filename,self.topRightFigure) except: - messagebox.showerror('Export LaTeX','LaTeX could not be generated or written ') + messagebox.showerror('Export LaTeX','LaTeX could not be generated or written ') fp=FileParts(filename.replace('_Phase.tex', '').replace('Phase.tex', '')) filename=fp.filename @@ -1404,7 +1412,7 @@ def onMatplotlib2TikZ(self): try: si.test.PlotTikZ(filename,self.bottomLeftFigure) except: - messagebox.showerror('Export LaTeX','LaTeX could not be generated or written ') + messagebox.showerror('Export LaTeX','LaTeX could not be generated or written ') fp=FileParts(filename.replace('_ImpulseResponse.tex', '').replace('ImpulseResponse.tex', '')) filename=fp.filename @@ -1480,7 +1488,7 @@ def onSelection(self,x): filename=self.spList[x][1] title=self.spList[x][2] self.buttonLabels=self.spList[x][3] - + self.filename=self.spList[x][1] self.fileparts=FileParts(filename) if title is None: diff --git a/SignalIntegrity/App/Simulator.py b/SignalIntegrity/App/Simulator.py index 219c09a41..ad3ac6931 100644 --- a/SignalIntegrity/App/Simulator.py +++ b/SignalIntegrity/App/Simulator.py @@ -48,6 +48,8 @@ from matplotlib.figure import Figure +from mpldatacursor import datacursor + import math from numpy import mean,std @@ -159,7 +161,6 @@ def __init__(self, parent): toolbar = NavigationToolbar2Tk( self.canvas, self ) toolbar.update() - toolbar.pan() self.canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1) controlsFrame = tk.Frame(self) @@ -284,7 +285,9 @@ def PlotWaveformsFrequencyContent(self,density=False): fcName=str(self.waveformNamesList[wfi]) fcColor=self.waveformColorIndexList[wfi] - self.plt.plot(fcFrequencies,fcValues,label=fcName,c=fcColor) + lines=self.plt.plot(fcFrequencies,fcValues,label=fcName,c=fcColor) + + datacursor(lines,formatter="f: {x:.3f}\nmag: {y:.3f}".format,display='multiple',draggable=True) if minv != None or minvStd != None: minv = max(minv,minvStd) @@ -441,11 +444,14 @@ def PlotWaveformsTimeDomain(self): plotlog=False plotdB=False if plotlog: - self.plt.semilogy(wfTimes,wf.Values('abs'),label=wfName,c=wfColor) + lines=self.plt.semilogy(wfTimes,wf.Values('abs'),label=wfName,c=wfColor) + datacursor(lines,formatter="t: {x:.3f}\namp: {y:.3f}".format,display='multiple',draggable=True) elif plotdB: - self.plt.plot(wfTimes,[max(20.*math.log10(abs(a)),-200.) for a in wf.Values('abs')],label=wfName,c=wfColor) + lines=self.plt.plot(wfTimes,[max(20.*math.log10(abs(a)),-200.) for a in wf.Values('abs')],label=wfName,c=wfColor) + datacursor(lines,formatter="t: {x:.3f}\namp: {y:.2f}".format,display='multiple',draggable=True) else: - self.plt.plot(wfTimes,wfValues,label=wfName,c=wfColor) + lines=self.plt.plot(wfTimes,wfValues,label=wfName,c=wfColor) + datacursor(lines,formatter="t: {x:.3f}\namp: {y:.3f}".format,display='multiple',draggable=True) minv=min(wfValues) if minv is None else min(minv,min(wfValues)) maxv=max(wfValues) if maxv is None else max(maxv,max(wfValues)) From 9bb511325ffe523782b98e22d9ecf86b042fd2bb Mon Sep 17 00:00:00 2001 From: Eldar Khayrullin Date: Sun, 7 Jun 2020 22:09:07 +0300 Subject: [PATCH 3/3] Previous fix. Append install requires: mpldatacursor --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 01bb63c74..4e5d05217 100644 --- a/setup.py +++ b/setup.py @@ -33,7 +33,7 @@ dataValue=eval(token[1].strip().strip(os.linesep)) globals()['__'+keyValue+'__']=dataValue -install_requires=['setuptools>=24.2.0','pip>=9.0.0','numpy>=1.13.0','matplotlib>=2.2.3','urllib3>=1.22.0'] +install_requires=['setuptools>=24.2.0','pip>=9.0.0','numpy>=1.13.0','matplotlib>=2.2.3','urllib3>=1.22.0','mpldatacursor>='0.7.1'] pathToIcons='SignalIntegrity/App/icons/png' pathToMoreIcons=pathToIcons+'/16x16/actions'