Newer
Older
RespDoppler / gdx / gdx_vpython.py
import logging
  
# from gdx_modules.gdx import gdx_class
# gdx = gdx_class()
#import gdx_modules.gdx


#Are these variable required outside the class? 
# woutput = wtext(text='')
# collectbutton = None
# closebutton = None

class ver_vpython:


    closed = False
    collect_button_state = False
    period = 100   # period in ms
    time = 0
    plot_1 = None    # vpython gcurve for the graph canvas
    plot_2 = None
    plot_3 = None
    plot_4 = None
    plot_5 = None
    graph_canvas = None
    meter_canvas = None
    button_canvas = None
    meter_text = None
    slider_text = None
    cb = None    # collect button
    clsb = None    # close button
    sl = None    # slider

    def __init__(self):  
        """
        """

    def setup_canvas(self, vp_button=False, slider_control=False):

        # Can we install the vpython library, with godirect?
        #from vpython import canvas, button, box, wtext, checkbox, rate
        from vpython import button, scene, slider, wtext, canvas, color
        #global collectbutton, closebutton
        # if they are using vpython, then create the canvas and collect/stop/close buttons
        
    
        ver_button_scene = canvas()
        ver_vpython.button_canvas = ver_button_scene
        ver_button_scene.width = 0
        ver_button_scene.height = 10

        ver_button_scene.append_to_title('\n')
        if vp_button:
            collectbutton = button(text='<b style="color:green; font-size:26px"> COLLECT </b>', 
                                pos=ver_button_scene.title_anchor, bind=vp_collect_stop)
            ver_vpython.cb = collectbutton
            ver_button_scene.append_to_title('  ')
            closebutton = button(text='<b style="color:red; font-size:26px">   CLOSE   </b>', 
                                pos=ver_button_scene.title_anchor, bind=vp_closed)
            ver_vpython.clsb = closebutton
        
        if slider_control:
            ver_button_scene.append_to_title('  ')
            slider_control = slider(pos=ver_button_scene.title_anchor, min=1, max=100, value=10, step=1, length=200, bind=vp_slider)
            ver_vpython.sl = slider_control
            #scene.append_to_caption('\n\n') 
            #scene.append_to_title('\n')
            slider_text = wtext(pos=ver_button_scene.title_anchor, text='10 samples/second')
            ver_vpython.period = 100
            ver_vpython.slider_text = slider_text


        ver_button_scene.append_to_title('\n')

    def create_default_canvas(self):
        """ Add a small canvas below the button canvas and the meter canvas. This should allow
        the user to create vpython objects without having to create a scene. If they do create
        a scene it should simply overwrite this canvas.        
        """

        from vpython import canvas, scene, color

        scene = canvas(width=800, height=150)
        scene.background = color.black
    
    def button_delete(self):
        ver_vpython.cb.delete()
        ver_vpython.clsb.delete()

    def slider_delete(self):
        from vpython import canvas
        
        canvas.delete(ver_vpython.slider_text)
        ver_vpython.sl.delete()

    def canvas_delete(self):
        from vpython import canvas, scene

        # this also seems to work for deleting the button object
        #canvas.delete(ver_vpython.cb)
        # ver_vpython.cb.delete()
        # ver_vpython.clsb.delete()
        ver_vpython.button_canvas.delete()
        
        scene.delete()
        current = canvas.get_selected()
        if current:
            current.delete()

    def slider_set(self, sample_rate):
        ver_vpython.sl.value = sample_rate
        ver_vpython.period = (1/sample_rate) * 1000
        ver_vpython.slider_text.text = f'{sample_rate} samples/second'

    def slider_get(self):
        period = ver_vpython.period
        return period
    
    def chart_init(self, column_headers):
        from vpython import graph, gcurve, color, vector
        
        if column_headers == None:
            column_headers = 'Data'
        gd = graph(xtitle='Time', ytitle=column_headers, scroll=True,
        width=500, height=300, xmin=0, xmax=5, fast=False)
        ver_vpython.graph_canvas = gd
        plot_1 = gcurve(color=vector(0.37, 0.57, 0.74))
        ver_vpython.plot_1 = plot_1
        ver_vpython.plot_1.plot(0,0)
        plot_2 = gcurve(color=vector(0.75, 0.75, 0.3))
        ver_vpython.plot_2 = plot_2
        ver_vpython.plot_2.plot(0,0)
        plot_3 = gcurve(color=vector(0, 0, 0.57))
        ver_vpython.plot_3 = plot_3
        ver_vpython.plot_3.plot(0,0)
        plot_4 = gcurve(color=vector(0.8, 0.38, 0.44))
        ver_vpython.plot_4 = plot_4
        ver_vpython.plot_4.plot(0,0)
        plot_5 = gcurve(color=vector(0.35, 0.2, 0.49))
        ver_vpython.plot_5 = plot_5
        ver_vpython.plot_5.plot(0,0)

    def chart_plot(self, data):
        if data == None:
            return
        else:
            if not isinstance(data, list):
                # measurements needs to be a list, if it is not, change it to a list
                data = [data]
            len_data = len(data)
            if len_data == 1:
                ver_vpython.plot_1.plot(ver_vpython.time, data[0])
            elif len_data == 2:
                ver_vpython.plot_1.plot(ver_vpython.time, data[0])
                ver_vpython.plot_2.plot(ver_vpython.time, data[1])
            elif len_data == 3:
                ver_vpython.plot_1.plot(ver_vpython.time, data[0])
                ver_vpython.plot_2.plot(ver_vpython.time, data[1])
                ver_vpython.plot_3.plot(ver_vpython.time, data[2])
            elif len_data == 4:
                ver_vpython.plot_1.plot(ver_vpython.time, data[0])
                ver_vpython.plot_2.plot(ver_vpython.time, data[1])
                ver_vpython.plot_3.plot(ver_vpython.time, data[2])
                ver_vpython.plot_4.plot(ver_vpython.time, data[3])
            else:
                ver_vpython.plot_1.plot(ver_vpython.time, data[0])
                ver_vpython.plot_2.plot(ver_vpython.time, data[1])
                ver_vpython.plot_3.plot(ver_vpython.time, data[2])
                ver_vpython.plot_4.plot(ver_vpython.time, data[3])
                ver_vpython.plot_5.plot(ver_vpython.time, data[4])

        ver_vpython.time = ver_vpython.time + (ver_vpython.period/1000)
        

    def chart_clear(self, column_headers):
        if column_headers == None:
            column_headers = 'Data'
        ver_vpython.plot_1.delete()
        ver_vpython.plot_2.delete()
        ver_vpython.plot_3.delete()
        ver_vpython.plot_4.delete()
        ver_vpython.plot_5.delete()
        ver_vpython.graph_canvas.ytitle = column_headers
        ver_vpython.graph_canvas.xmin = 0
        ver_vpython.graph_canvas.xmax = 5
        
    def chart_delete(self):
        ver_vpython.graph_canvas.delete()

    def meter_init(self):
        from vpython import canvas, wtext, scene, color
        
        ver_meter_canvas = canvas(width=0, height=20)
        ver_vpython.meter_canvas = ver_meter_canvas
        ver_meter_canvas.append_to_title('\n')
        woutput = wtext(text='', pos=ver_meter_canvas.title_anchor)
        ver_vpython.meter_text = woutput
        #<b>mass <i>M</i></b>
        #woutput.text = "<b>{ch_string}</b>\n".format(ch_string)
        
        woutput.text = f""  

    def meter_data(self, column_headers, data):
        if data == None:
            meter_string = 'No data'
        else:
            if not isinstance(data, list):
                # data needs to be a list, if it is not, change it to a list
                data = [data]
            if not isinstance(column_headers, list):
                # column_headers needs to be a list, if it is not, change it to a list
                column_headers = [column_headers]

            meter_string = ' '
            for (ch, d) in zip(column_headers, data):
                round_data = str(round(d, 2))
                meter_string = meter_string + ch + ": " + round_data + '    '
        
        ver_vpython.meter_text.text = f"{meter_string}"

    def meter_delete(self):
        from vpython import canvas
        
        canvas.delete(ver_vpython.meter_text)
        ver_meter_canvas = ver_vpython.meter_canvas
        # this worked
        ver_meter_canvas.delete()
        # this worked too
        #canvas.delete(ver_meter_canvas)
    
    # def slider_init(self):
    #     from vpython import canvas, slider, wtext, scene
        
    #     sc = canvas(width=0, height=20)
    #     ver_vpython.slider_canvas = sc
    #     # when the slider is changed, the function vp_slider is called
    #     sl = slider(align='right', min=1, max=100, value=10, step=1, length=200, bind=vp_slider, left=20)
    #     #scene.append_to_caption('\n\n') 
    #     #scene.append_to_title('\n')
    #     slider_text = wtext(text='')
    #     ver_vpython.slider_text = slider_text

    # def print_to_canvas(self):
    #     """ Feedback to the user on the vpython screen 
	# 	"""  
    #     from vpython import canvas

    #     canvas.get_selected().append_to_caption('Must specify device sensors.')
    #     canvas.get_selected().caption = 'test caption'
    #     raise AttributeError('Must specify device sensors.')     

    def collect_button(self):
        """ Return value = True if the button is in the Collect state. Return
        value = False if it is in the Stop state.
        """
        from vpython import rate, color

        if ver_vpython.collect_button_state:
            return True
            
        else:
            # assumption is that rate() is only needed when data collection is not occurring
            # When it is, the computer will automatically be slowed because of the time
            # required to talk to the hardware.
            rate(50)
            return False

    def closed_button(self):
        if ver_vpython.closed:
            return True
        else:
            return False

    

    
def vp_collect_stop(f):
    """ This function gets called only when the button has been pressed. Return
    value = True if the button is in the Collect state.
    """
    
    if f.text == '<b style="color:green; font-size:26px"> COLLECT </b>':
        f.text = '<b style="color:black; font-size:26px">    STOP     </b>'
        #
        # "Change the class variable’s value using the class name only."
        ver_vpython.collect_button_state = True

    else:
        f.text = '<b style="color:green; font-size:26px"> COLLECT </b>'
        ver_vpython.collect_button_state = False

def vp_closed():

    ver_vpython.closed = True
    ver_vpython.collect_button_state = False

def vp_slider(s):
    ver_vpython.period = (1/s.value) * 1000
    ver_vpython.slider_text.text = f'{s.value} samples/second'