commit-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Commit-gnuradio] r8733 - gnuradio/branches/developers/jblum/gr-wxglgui/


From: jblum
Subject: [Commit-gnuradio] r8733 - gnuradio/branches/developers/jblum/gr-wxglgui/src/python
Date: Thu, 26 Jun 2008 18:20:22 -0600 (MDT)

Author: jblum
Date: 2008-06-26 18:20:21 -0600 (Thu, 26 Jun 2008)
New Revision: 8733

Modified:
   gnuradio/branches/developers/jblum/gr-wxglgui/src/python/fftsink.py
   gnuradio/branches/developers/jblum/gr-wxglgui/src/python/plotter.py
Log:
almost functioning fft plot in ogl

Modified: gnuradio/branches/developers/jblum/gr-wxglgui/src/python/fftsink.py
===================================================================
--- gnuradio/branches/developers/jblum/gr-wxglgui/src/python/fftsink.py 
2008-06-26 23:14:37 UTC (rev 8732)
+++ gnuradio/branches/developers/jblum/gr-wxglgui/src/python/fftsink.py 
2008-06-27 00:20:21 UTC (rev 8733)
@@ -18,3 +18,397 @@
 # the Free Software Foundation, Inc., 51 Franklin Street,
 # Boston, MA 02110-1301, USA.
 # 
+
+##################################################
+# Imports
+##################################################
+from gnuradio import gr, window
+import plotter
+import wx
+import math
+import threading
+import numpy
+
+##################################################
+# Constants
+##################################################
+DEFAULT_FFT_RATE = gr.prefs().get_long('wxgui', 'fft_rate', 15)
+DIV_LEVELS = (1, 2, 5, 10, 20)
+
+##################################################
+# FFT window control panel
+##################################################
+class control_panel(wx.Panel):
+       """!
+       A control panel with wx widgits to control the plotter and fft block 
chain.
+       """
+       
+       class LabelText(wx.StaticText): 
+               def __init__(self, window, label):
+                       wx.StaticText.__init__(self, window, -1, label)
+                       font = self.GetFont()
+                       font.SetWeight(wx.FONTWEIGHT_BOLD)
+                       font.SetUnderlined(True)
+                       self.SetFont(font)
+       
+       def __init__(self, parent):
+               """!
+               Create a new control panel.
+               @param parent the wx parent window
+               """
+               self.parent = parent
+               wx.Panel.__init__(self, parent, -1, style=wx.SIMPLE_BORDER)     
+               control_box = wx.BoxSizer(wx.VERTICAL)
+               
+               #checkboxes for average and peak hold
+               control_box.AddStretchSpacer()
+               control_box.Add(self.LabelText(self, 'Options'), 0, 
wx.ALIGN_CENTER)
+               self.average_check_box = wx.CheckBox(parent=self, 
style=wx.CHK_2STATE, label="Average")
+               self.average_check_box.Bind(wx.EVT_CHECKBOX, parent.on_average)
+               control_box.Add(self.average_check_box, 0, wx.EXPAND)
+               self.peak_hold_check_box = wx.CheckBox(parent=self, 
style=wx.CHK_2STATE, label="Peak Hold")
+               self.peak_hold_check_box.Bind(wx.EVT_CHECKBOX, 
parent.on_peak_hold) 
+               control_box.Add(self.peak_hold_check_box, 0, wx.EXPAND)
+          
+               #radio buttons for div size
+               control_box.AddStretchSpacer()
+               control_box.Add(self.LabelText(self, 'Set dB/div'), 0, 
wx.ALIGN_CENTER)
+               radio_box = wx.BoxSizer(wx.VERTICAL)
+               self.radio_buttons = list()
+               for y_per_div in DIV_LEVELS:
+                       radio_button = wx.RadioButton(self, -1, "%d 
dB/div"%y_per_div)
+                       radio_button.Bind(wx.EVT_RADIOBUTTON, 
self.on_radio_button_change)
+                       self.radio_buttons.append(radio_button)
+                       radio_box.Add(radio_button, 0, wx.ALIGN_LEFT)
+               control_box.Add(radio_box, 0, wx.EXPAND)
+               
+               #ref lvl buttons
+               control_box.AddStretchSpacer()
+               control_box.Add(self.LabelText(self, 'Adj Ref Lvl'), 0, 
wx.ALIGN_CENTER)
+               control_box.AddSpacer(2)
+               button_box = wx.BoxSizer(wx.HORIZONTAL)         
+               self.ref_plus_button = wx.Button(self, -1, '+', 
style=wx.BU_EXACTFIT)
+               self.ref_plus_button.Bind(wx.EVT_BUTTON, 
parent.on_incr_ref_level)
+               button_box.Add(self.ref_plus_button, 0, wx.ALIGN_CENTER)
+               self.ref_minus_button = wx.Button(self, -1, ' - ', 
style=wx.BU_EXACTFIT)
+               self.ref_minus_button.Bind(wx.EVT_BUTTON, 
parent.on_decr_ref_level)
+               button_box.Add(self.ref_minus_button, 0, wx.ALIGN_CENTER)
+               control_box.Add(button_box, 0, wx.ALIGN_CENTER)
+               control_box.AddStretchSpacer()
+               #set sizer
+               self.SetSizerAndFit(control_box)
+               #update
+               self.update()
+               
+       def update(self):
+               """!
+               Read the state of the fft plot settings and update the control 
panel.
+               """
+               #update checkboxes
+               self.average_check_box.SetValue(self.parent.average)
+               self.peak_hold_check_box.SetValue(self.parent.peak_hold)
+               #update radio buttons   
+               try:
+                       index = list(DIV_LEVELS).index(self.parent.y_per_div)
+                       self.radio_buttons[index].SetValue(True)
+               except: pass
+       
+       def on_radio_button_change(self, event):
+               selected_radio_button = filter(lambda rb: rb.GetValue(), 
self.radio_buttons)[0] 
+               index = self.radio_buttons.index(selected_radio_button)
+               self.parent.set_y_per_div(DIV_LEVELS[index])
+
+##################################################
+# FFT window with plotter and control panel
+##################################################
+class fft_window(wx.Panel):
+       def __init__(
+               self, 
+               parent, 
+               title,
+               y_per_div,
+               y_divs,
+               ref_level,
+               average,
+               peak_hold,
+               set_average,
+       ):              
+               #ensure y_per_div
+               if y_per_div not in DIV_LEVELS: y_per_div = DIV_LEVELS[0]
+               #setup
+               self.y_per_div = y_per_div
+               self.y_divs = y_divs
+               self.ref_level = ref_level
+               self.average = average
+               self.peak_hold = peak_hold
+               self.set_average = set_average
+               #init panel and plot 
+               wx.Panel.__init__(self, parent, -1)                             
  
+               self.plotter = plotter.grid_plotter(self, title, 
'Frequency(Hz)', 'Amplitude(dB)', 35, 10, 40, 60)   
+               #setup the box with plot and controls
+               self.control_panel = control_panel(self)
+               main_box = wx.BoxSizer(wx.HORIZONTAL)
+               main_box.Add(self.plotter, 1, wx.EXPAND)
+               main_box.Add(self.control_panel, 0, wx.EXPAND)
+               self.SetSizerAndFit(main_box)
+               #update
+               self.update()
+               
+       def plot(self, samples):
+               self.plotter.set_waveform(
+                       channel=1, 
+                       samples=samples, 
+                       offset=0.0, 
+                       color_spec=(0, 1, 0),
+               )
+               #update the plotter
+               self.plotter.update()
+       
+       def update(self):
+               #update average
+               self.set_average(self.average)
+               #update peak hold
+               #TODO
+               #update y grid
+               
self.plotter.set_y_grid(self.ref_level-self.y_per_div*self.y_divs, 
self.ref_level, self.y_per_div)
+               #update control panel if non-gui changes occured
+               self.control_panel.update()
+               #update the plotter
+               self.plotter.update()
+       
+       def on_average(self, event):
+               self.average = event.IsChecked()
+               self.update()           
+               
+       def on_peak_hold(self, event):
+               self.peak_hold = event.IsChecked()
+               self.update()
+               
+       def on_incr_ref_level(self, event):
+               self.ref_level = self.ref_level + self.y_per_div
+               self.update()
+               
+       def on_decr_ref_level(self, event):
+               self.ref_level = self.ref_level - self.y_per_div
+               self.update()
+               
+       def set_y_per_div(self, y_per_div):
+               self.y_per_div = y_per_div
+               self.update()
+
+##################################################
+# FFT blocks chain: input -> message sink
+##################################################     
+class fft_block(gr.hier_block2):
+       """!
+       Create an fft block chain, with real/complex input.
+       """
+       
+       def __init__(self, item_size, sample_rate, fft_size, fft_rate, 
ref_scale, avg_alpha):
+               """!
+               Create an fft block.
+               Write the samples to a message sink.
+               Provide access to the msg queue and setting the filter.
+               @param item_size the input size complex or float
+               @param sample_rate, fft_size, fft_rate, ref_scale, avg_alpha 
the fft parameters
+               """
+               self._avg_alpha = avg_alpha
+               #init
+               gr.hier_block2.__init__(
+                       self, 
+                       "fft_block",
+                       gr.io_signature(1, 1, item_size),
+                       gr.io_signature(0, 0, 0),
+               )
+               #create blocks
+               s2p = gr.stream_to_vector(item_size, fft_size)          
+               one_in_n = gr.keep_one_in_n(item_size * fft_size, max(1, 
int(sample_rate/fft_size/fft_rate)))           
+               #create fft
+               fft_window = window.blackmanharris(fft_size)
+               fft = {
+                       gr.sizeof_float: gr.fft_vfc, 
+                       gr.sizeof_gr_complex: gr.fft_vcc
+               }[item_size](fft_size, True, fft_window)
+               power = sum(map(lambda x: x*x, fft_window))                     
+               #filter fft, convert to dB
+               c2mag = gr.complex_to_mag(fft_size)
+               self._avg = gr.single_pole_iir_filter_ff(1.0, fft_size)
+               log = gr.nlog10_ff(
+                       20, 
+                       fft_size,
+                       -10*math.log10(fft_size) # Adjust for number of bins
+                       -10*math.log10(power/fft_size) # Adjust for windowing 
loss
+                       -20*math.log10(ref_scale/2) # Adjust for reference scale
+               )
+               #message sink                                                   
                   
+               self.msgq = gr.msg_queue(2)
+               sink = gr.message_sink(gr.sizeof_float*fft_size, self.msgq, 
True)
+               #connect
+               self.connect(self, s2p, one_in_n, fft, c2mag, self._avg, log, 
sink)             
+
+       def set_average(self, average):
+               """!
+               Set the averaging filter on/off.
+               @param average true to set averaging on
+               """
+               if average: self._avg.set_taps(self._avg_alpha)
+               else: self._avg.set_taps(1.0)
+
+##################################################
+# Input watcher for msg queue
+##################################################
+class input_watcher(threading.Thread):
+       def __init__ (self, msgq, handle_samples):
+               threading.Thread.__init__(self)
+               self.setDaemon(1)
+               self.msgq = msgq
+               self.handle_samples = handle_samples
+               self.keep_running = True
+               self.start()
+
+       def run(self):
+               while self.keep_running:
+                       msg = self.msgq.delete_head() #blocking read of message 
queue
+                       itemsize = int(msg.arg1())
+                       nitems = int(msg.arg2())
+
+                       s = msg.to_string() #get the body of the msg as a string
+
+                       # There may be more than one frame in the message.
+                       # If so, we take only the last one
+                       if nitems > 1:
+                               start = itemsize * (nitems - 1)
+                               s = s[start:start+itemsize]
+
+                       samples = numpy.fromstring(s, numpy.float32)
+                       self.handle_samples(samples)
+
+##################################################
+# FFT sink base block for real and complex types
+##################################################     
+class _fft_sink_base(gr.hier_block2):
+       """!
+       An fft block with real/complex inputs.
+       The fft stream is written to a message sink.
+       This block provides a callback to set the average on/off.
+       """
+       
+       def __init__(
+               self, 
+               parent,
+               baseband_freq=0, 
+               ref_scale=2.0, 
+               y_per_div=10,
+               y_divs=8, 
+               ref_level=50,
+               sample_rate=1, 
+               fft_size=512,
+               fft_rate=DEFAULT_FFT_RATE,
+               average=False, 
+               avg_alpha=None, 
+               title='', 
+               peak_hold=False,
+       ): 
+               #ensure avg alpha
+               if avg_alpha is None: avg_alpha = 2.0/fft_rate
+               #init
+               gr.hier_block2.__init__(
+                       self, 
+                       "fft_sink",
+                       gr.io_signature(1, 1, self.item_size),
+                       gr.io_signature(0, 0, 0),
+               )
+               copy = gr.kludge_copy(self.item_size)
+               #fft block
+               fft = fft_block(
+                       item_size=self.item_size,
+                       sample_rate=sample_rate, 
+                       fft_size=fft_size, 
+                       fft_rate=fft_rate, 
+                       ref_scale=ref_scale, 
+                       avg_alpha=avg_alpha,
+               )
+               #connect
+               self.connect(self, copy, fft)
+               #create window
+               self.win = fft_window(
+                       parent=parent, 
+                       title=title,                    
+                       y_per_div=y_per_div,
+                       y_divs=y_divs,
+                       ref_level=ref_level,                    
+                       average=average,
+                       peak_hold=peak_hold,
+                       set_average=fft.set_average,    
+               )
+               #setup x grid and setup the input watcher
+               if self.item_size == gr.sizeof_float:
+                       self.win.plotter.set_x_grid(baseband_freq, 
baseband_freq + sample_rate/2.0, int(sample_rate/16))
+                       input_watcher(fft.msgq, self.win.plot)
+               else:
+                       self.win.plotter.set_x_grid(baseband_freq - 
sample_rate/2.0, baseband_freq + sample_rate/2.0, int(sample_rate/8))
+                       input_watcher(fft.msgq, self._handle_complex_samples)   
        
+               
+       def _handle_complex_samples(self, samples):
+               """!
+               Reorder the complex fft samples so the negative bins come first
+               @param samples an array of fft samples
+               """
+               num_samples = len(samples)
+               samples = numpy.concatenate((samples[num_samples/2+1:], 
samples[:num_samples/2]))
+               self.win.plot(samples)                  
+
+class fft_sink_f(_fft_sink_base): item_size = gr.sizeof_float
+class fft_sink_c(_fft_sink_base): item_size = gr.sizeof_gr_complex
+
+# ----------------------------------------------------------------
+# Standalone test app
+# ----------------------------------------------------------------
+
+class test_app_block (gr.top_block):
+       def __init__(self, frame, vbox):
+               gr.top_block.__init__(self)
+               fft_size = 256
+
+               # build our flow graph
+               input_rate = 20.48e3
+
+               # Generate a complex sinusoid
+               src1 = gr.sig_source_c (input_rate, gr.GR_SIN_WAVE, 2e3, 1)
+               #src1 = gr.sig_source_c (input_rate, gr.GR_CONST_WAVE, 5.75e3, 
1)
+
+               # We add these throttle blocks so that this demo doesn't
+               # suck down all the CPU available.  Normally you wouldn't use 
these.
+               thr1 = gr.throttle(gr.sizeof_gr_complex, input_rate)
+
+               sink1 = fft_sink_c (frame, title="Complex Data", 
fft_size=fft_size,
+                                                       sample_rate=input_rate, 
baseband_freq=100e3,
+                                                       ref_level=0, 
y_per_div=20, y_divs=10)
+               vbox.Add (sink1.win, 1, wx.EXPAND)
+
+               self.connect(src1, thr1, sink1)
+
+               src2 = gr.sig_source_f (input_rate, gr.GR_SIN_WAVE, 2e3, 1)
+               #src2 = gr.sig_source_f (input_rate, gr.GR_CONST_WAVE, 5.75e3, 
1)
+               thr2 = gr.throttle(gr.sizeof_float, input_rate)
+               sink2 = fft_sink_f (frame, title="Real Data", 
fft_size=fft_size*2,
+                                                       sample_rate=input_rate, 
baseband_freq=100e3,
+                                                       ref_level=0, 
y_per_div=20, y_divs=10)
+               vbox.Add (sink2.win, 1, wx.EXPAND)
+
+               self.connect(src2, thr2, sink2)
+               self.start()
+
+def main ():
+       app = wx.PySimpleApp()
+       frame = wx.Frame(None, -1, 'Demo', wx.DefaultPosition)
+       vbox = wx.BoxSizer(wx.VERTICAL)
+       test_app_block(frame, vbox)
+       frame.SetSizerAndFit(vbox)
+       frame.SetSize(wx.Size(700, 300))
+       frame.Show()
+       app.MainLoop()
+
+if __name__ == '__main__':
+       main ()
+

Modified: gnuradio/branches/developers/jblum/gr-wxglgui/src/python/plotter.py
===================================================================
--- gnuradio/branches/developers/jblum/gr-wxglgui/src/python/plotter.py 
2008-06-26 23:14:37 UTC (rev 8732)
+++ gnuradio/branches/developers/jblum/gr-wxglgui/src/python/plotter.py 
2008-06-27 00:20:21 UTC (rev 8733)
@@ -29,6 +29,7 @@
 import gltext
 import sys
 import math
+import numpy
 
 BACKGROUND_COLOR_SPEC = (1, 0.976, 1, 1) #creamy white
 GRID_LINE_COLOR_SPEC = (0, 0, 0) #black
@@ -95,25 +96,26 @@
 
 class grid_plotter(_plotter_base):
        
-       def __init__(self, parent, title, units_x, units_y, padding_top, 
padding_right, padding_bottom, padding_left):
-               
-               self.channels = dict()
-               
+       def __init__(self, parent, title, x_units, y_units, padding_top, 
padding_right, padding_bottom, padding_left):
+               """!
+               Create a new grid plotter.
+               """             
+               self.channels = dict()  
+               #store title and unit strings   
                self.title = title
-               self.units_x = units_x
-               self.units_y = units_y
-               
+               self.x_units = x_units
+               self.y_units = y_units  
+               #store padding  
                self.padding_top = padding_top
                self.padding_right = padding_right
                self.padding_bottom = padding_bottom
-               self.padding_left = padding_left
-               
-               self.set_grid_x(-1, 1, 1)               
-               self.set_grid_y(-1, 1, 1)
-               
+               self.padding_left = padding_left        
+               #init the grid to some value    
+               self.set_x_grid(-1, 1, 1)               
+               self.set_y_grid(-1, 1, 1)               
                _plotter_base.__init__(self, parent)
 
-       def set_grid_x(self, x_min, x_max, x_step):
+       def set_x_grid(self, x_min, x_max, x_step):
                """!
                Set the x grid parameters.
                @param x_min the left-most value
@@ -125,7 +127,7 @@
                self.x_step = float(x_step)
                self._changed = True
                
-       def set_grid_y(self, y_min, y_max, y_step):
+       def set_y_grid(self, y_min, y_max, y_step):
                """!
                Set the y grid parameters.
                @param y_min the bottom-most value
@@ -148,6 +150,17 @@
                        self._draw_grid()
                        glEndList()
                        self._changed = False
+               self._draw_waveforms()
+               #draw the grid
+               glCallList(GRID_COMPILED_LIST_ID)
+               glFlush()
+               self.SwapBuffers()
+       
+       def _draw_waveforms(self):
+               """!
+               Draw the waveforms for each channel.
+               Scale the waveform data to the grid using numpy (saves CPU).
+               """
                ##################################################
                # Draw Waveforms
                ##################################################
@@ -155,15 +168,14 @@
                        glColor3f(*color_spec)
                        glBegin(GL_LINE_STRIP)
                        num_samps = len(samples)
-                       for i, samp in enumerate(samples):      
-                               x = 
(self.width-self.padding_left-self.padding_right)*i/float(num_samps-1) + 
self.padding_left
-                               y = 
(self.height-self.padding_top-self.padding_bottom)*(1 - (samp + offset - 
self.y_min)/(self.y_max-self.y_min)) + self.padding_top
-                               glVertex3f(x, y, 0)
+                       #use numpy to scale the waveform
+                       x_scalar = 
(self.width-self.padding_left-self.padding_right)
+                       x_arr = x_scalar*numpy.arange(0, 
num_samps)/float(num_samps-1) + self.padding_left
+                       y_scalar = 
(self.height-self.padding_top-self.padding_bottom)
+                       y_arr = y_scalar*(1 - (numpy.array(samples) + offset - 
self.y_min)/(self.y_max-self.y_min)) + self.padding_top
+                       #draw the lines
+                       for x, y in zip(x_arr, y_arr): glVertex3f(x, y, 0)
                        glEnd()
-               #draw the grid
-               glCallList(GRID_COMPILED_LIST_ID)
-               glFlush()
-               self.SwapBuffers()
        
        def _draw_grid(self):
                """!
@@ -233,10 +245,10 @@
                font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
                font.SetWeight(wx.FONTWEIGHT_BOLD)      
                #draw x units
-               txt = gltext.Text(self.units_x, font=font, 
font_size=UNITS_TEXT_FONT_SIZE, centered=True)
+               txt = gltext.Text(self.x_units, font=font, 
font_size=UNITS_TEXT_FONT_SIZE, centered=True)
                txt.draw_text(wx.Point(self.width/2.0, 
self.height-.25*self.padding_bottom))
                #draw y units
-               txt = gltext.Text(self.units_y, font=font, 
font_size=UNITS_TEXT_FONT_SIZE, centered=True)
+               txt = gltext.Text(self.y_units, font=font, 
font_size=UNITS_TEXT_FONT_SIZE, centered=True)
                txt.draw_text(wx.Point(.25*self.padding_left, self.height/2.0), 
rotation=90)
                
        def _draw_tick_label(self, tick, coor):
@@ -309,67 +321,22 @@
                """
                self.channels[channel] = samples, offset, color_spec
 
-from gnuradio import gr, window
-class test_block(gr.top_block):
-       def __init__(self):
-               gr.top_block.__init__(self)
-
-               fft_size = 256
-
-               input_rate = 55.48e3
-
-               src = gr.sig_source_c (input_rate, gr.GR_SIN_WAVE, 2.32e3, 1)
-               gr_noise_source_x = gr.noise_source_c(gr.GR_GAUSSIAN, 1, 42)
-               
-               gr_add_vxx = gr.add_vcc(1)
-               
-               thr = gr.throttle(gr.sizeof_gr_complex, input_rate)
-                                                       
-               gr_stream_to_vector = 
gr.stream_to_vector(gr.sizeof_gr_complex*1, fft_size)
-               gr_fft_vxx = gr.fft_vcc(fft_size, True, 
(window.blackmanharris(fft_size)))
-               gr_complex_to_mag_fft = gr.complex_to_mag(fft_size)
-               
-               self.msgq = gr.msg_queue(1)
-               sink = gr.message_sink(gr.sizeof_float * fft_size, self.msgq, 
True)             
-               
-               self.connect(src, gr_add_vxx, thr, gr_stream_to_vector, 
gr_fft_vxx, gr_complex_to_mag_fft, sink)
-               self.connect(gr_noise_source_x, (gr_add_vxx, 1))
-
-import threading
-import numpy
-class animate(threading.Thread):
-       def __init__(self, plotter):
-               self.plotter = plotter
-               self.tb = test_block()
-               threading.Thread.__init__(self)
-               self.start()
-
-       def run(self):
-               self.plotter.set_grid_x(-1, 1, .2)              
-               self.plotter.set_grid_y(-30, 75, 30)
-               self.tb.start()
-               while 1:
-                       msg = self.tb.msgq.delete_head()  # blocking read of 
message queue
-                       itemsize = int(msg.arg1())
-                       nitems = int(msg.arg2())
-                       s = msg.to_string()
-                       if nitems > 1:
-                               start = itemsize * (nitems - 1)
-                               s = s[start:start+itemsize]
-
-
-                       arr = numpy.fromstring(s, numpy.float32)
-                       self.plotter.set_waveform(1, arr, -10, (0, 1, 0))
-                       self.plotter.set_waveform(2, arr, -20, (0, 0, 1))
-                       self.plotter.update()
-def main():
+if __name__ == '__main__':
        app = wx.PySimpleApp()
-       frame = wx.Frame(None, -1, 'Demo', wx.DefaultPosition, wx.Size(700, 
300))
-       plotter = grid_plotter(frame, 'Demo Grid', 'Frequency(Hz)', 
'Amplitude(dB)', 35, 10, 40, 60)
-       plotter.set_grid_x(-1, 1, .2)           
-       plotter.set_grid_y(-1, 1, .4)
-       animate(plotter)
+       frame = wx.Frame(None, -1, 'Demo', wx.DefaultPosition)
+       vbox = wx.BoxSizer(wx.VERTICAL)
+       
+       plotter = grid_plotter(frame, 'Demo Grid1', 'Frequency(Hz)', 
'Amplitude(dB)', 35, 10, 40, 60)
+       plotter.set_x_grid(-1, 1, .2)           
+       plotter.set_y_grid(-1, 1, .4)
+       vbox.Add(plotter, 1, wx.EXPAND)
+       
+       plotter = grid_plotter(frame, 'Demo Grid2', 'Frequency(Hz)', 
'Amplitude(dB)', 35, 10, 40, 60)
+       plotter.set_x_grid(-1, 1, .2)           
+       plotter.set_y_grid(-1, 1, .4)
+       vbox.Add(plotter, 1, wx.EXPAND)
+       
+       frame.SetSizerAndFit(vbox)
+       frame.SetSize(wx.Size(800, 600))
        frame.Show()
        app.MainLoop()
-
-if __name__ == '__main__': main()





reply via email to

[Prev in Thread] Current Thread [Next in Thread]