GUI.py 17.6 KB
Newer Older
1 2 3 4
from ipywidgets import interactive, interact, interact_manual
from IPython.display import display
from IPython.display import HTML
import ipywidgets as widgets
Nick Sauerwein's avatar
Nick Sauerwein committed
5

6 7
import numpy as np
import matplotlib.pyplot as plt
Nick Sauerwein's avatar
Nick Sauerwein committed
8

9
import DataManager as dm
Nick Sauerwein's avatar
Nick Sauerwein committed
10 11


12 13 14 15 16 17 18 19
class interaction_tool:
    
    def __init__ (self, variable_name, value, device, config):
        self.variable_name = variable_name
        self.value = value
        self.device = device
        self.config = config
        layout_bt = widgets.Layout(width = '20px')
20
        layout_text = widgets.Layout(width = '180px')
21 22 23 24 25 26
        if type(value) == bool:
            self.cb =  widgets.Checkbox(value=value,
                                        description=variable_name, layout = layout_text)
            self.cb.observe(self.change_bool, names = 'value')
            
            self.widget =self.cb
Hermann Benedikt's avatar
Hermann Benedikt committed
27
        elif type(value) == str:
28 29 30
            self.text = widgets.Text(value = value, describtion = variable_name)
            self.text.on_submit(self.change_str)
            self.widget = self.text 
31
        elif np.dtype(type(value)) == np.dtype('float64'):
32
            self.flt = widgets.Text(value=str(np.round(value,4)),description=variable_name, layout = layout_text)
33 34 35 36 37
            self.step = widgets.FloatText(value=0.1,description='step', layout = layout_text)
            self.bp = widgets.Button(description='+', layout = layout_bt)
            self.bm = widgets.Button(description='-', layout = layout_bt)


38 39 40
            self.flt.on_submit(self.change_by_enter_float)
            self.bp.on_click(self.change_p_float)
            self.bm.on_click(self.change_m_float)
41 42

            self.widget = widgets.HBox([self.flt, self.step, self.bm, self.bp])
43 44 45 46 47 48 49 50 51 52 53 54
        elif np.dtype(type(value)) == np.dtype('int64') or np.dtype(type(value)) == np.dtype('int32'):
            self.flt = widgets.Text(value=str(np.round(value,4)),description=variable_name, layout = layout_text)
            self.bp = widgets.Button(description='+1', layout = layout_bt)
            self.bm = widgets.Button(description='-1', layout = layout_bt)


            self.flt.on_submit(self.change_by_enter_int)
            self.bp.on_click(self.change_p_int)
            self.bm.on_click(self.change_m_int)

            self.widget = widgets.HBox([self.flt, self.bm, self.bp])
           
55
        else:
56
            self.widget = widgets.HTML('Type '+str(np.dtype(type(value)))+' not changeable')
57 58 59 60
    def change_str(self,text):
        self.config[self.variable_name] = self.text.value
        self.device.set_config(self.config)
    def change_bool(self, new):
Hermann Benedikt's avatar
Hermann Benedikt committed
61
        self.config[self.variable_name] = new['new']
62
        self.device.set_config(self.config)
63 64
    
    def change_by_enter_float(self, text):
65 66
        self.config[self.variable_name] = float(self.flt.value)
        self.device.set_config(self.config)
67 68 69 70 71

    def change_by_enter_int(self, text):
        self.config[self.variable_name] = int(self.flt.value)
        self.device.set_config(self.config)        
    
72
        
73
    def change_p_float(self, bt):
74
        self.config[self.variable_name] = float(self.flt.value) + self.step.value
75
        self.flt.value = str(np.round(float(self.flt.value) + self.step.value,4))
76 77
        self.device.set_config(self.config)
        
78 79 80 81 82 83 84 85 86 87 88
    def change_p_int(self, bt):
        self.config[self.variable_name] = int(self.flt.value) + 1
        self.flt.value = str(int(self.flt.value) + 1)
        self.device.set_config(self.config)
        
    def change_m_int(self, bt):
        self.config[self.variable_name] = int(self.flt.value) - 1
        self.flt.value = str(int(self.flt.value) - 1)
        self.device.set_config(self.config)
        
    def change_m_float(self, bt):
89
        self.config[self.variable_name] = float(self.flt.value) - self.step.value
90
        self.flt.value = str(np.round(float(self.flt.value) - self.step.value,4))
91
        self.device.set_config(self.config)
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
        

class plot_config_tool:
    
    def __init__ (self, variable_name, value, plot_config):
        self.variable_name = variable_name
        self.value = value
        self.plot_config = plot_config
        layout_bt = widgets.Layout(width = '20px')
        layout_text = widgets.Layout(width = 'auto')
        if np.dtype(type(value)) == np.dtype('float64') or np.dtype(type(value)) == np.dtype('int64') or np.dtype(type(value)) == np.dtype('int32'):
            plot_config[variable_name] = False 
            self.cb =  widgets.Checkbox(description=variable_name, layout = layout_text)
            self.cb.observe(self.change_bool, names = 'value')

            self.widget = self.cb

        else:
            self.widget = widgets.HTML('Type '+str(np.dtype(type(value)))+' not history plottalbe')
    def change_bool(self, new):
        self.plot_config[self.variable_name] = new['new']
113

114 115 116 117 118
class wrapper:
    def __init__(self, devices, i, io):
        self.device = devices[i]#
        self.devices = devices
        self.io = io
Sauerwein Nick Jacob's avatar
Sauerwein Nick Jacob committed
119
        self.measure_check = False
Nick Sauerwein's avatar
Nick Sauerwein committed
120
        
Sauerwein Nick Jacob's avatar
Sauerwein Nick Jacob committed
121 122
    def measure(self, check):
        self.measure_check = check['new']
Nick Sauerwein's avatar
Nick Sauerwein committed
123
        
124
def main(devices, io, parallel = False):
125
    
Sauerwein Nick Jacob's avatar
Sauerwein Nick Jacob committed
126
    config = dm.get_config(devices)
127 128
    config['comment'] = 'start of GUI'
    #io.save(config, comment = 'start of GUI')
129 130 131 132 133 134 135
    #main
    display(widgets.HTML('<h1>LWFA GUI</h1>'))
    display(widgets.HTML('<b>Save and Restore configurations</b>'))
    bt_save = widgets.Button(description= 'Save config')
    def save(bt):
        comment = text_comment.value
        if comment == '':
136
            ht_save.value = '<b>Enter comment to save config!</b>'
137
            return
Sauerwein Nick Jacob's avatar
Sauerwein Nick Jacob committed
138 139
        config = dm.get_config(devices)
        io.save(config, comment = comment, elog = check_elog.value)
140
        text_comment.value = ''
141
        ht_save.value = '<b>Config saved!</b>'
142
        select_restore.options = get_all()
Sauerwein Nick Jacob's avatar
Sauerwein Nick Jacob committed
143
        
144
    bt_save.on_click(save)
145
    ht_save = widgets.HTML('')
146
    def restore(bt):
147
        restore = select_restore.value
148 149 150
        config = io.load(restore)
        dm.set_config(devices,config)
        refresh('')
151
        ht_restore.value = '<b>restored config: '+config['comment']+'</b>'
152
        select_restore.options = get_all()
153 154 155
    
    def restore_view(inst):
        restore = inst.new
156 157 158 159 160
        try:
            config = io.load(restore)
        except:
            ht_restore.value = '<b>Error: This config doesnot exist</b>'
            return
161
        ht_restore.value = '<b>selected config: '+config['comment']+'</b>'
162
    
163 164 165 166 167 168 169 170
    def get_all():
        configs = io.search(output = False)
        c = {}
        for i in range(len(configs)):
            c[configs[i]['comment']] = i
        return c
    
    select_restore = widgets.Select(description='restore:', options = get_all())
Sauerwein Nick Jacob's avatar
Sauerwein Nick Jacob committed
171 172
    
    
173 174
    bt_restore = widgets.Button(description='restore now!')
    bt_restore.on_click(restore)
Sauerwein Nick Jacob's avatar
Sauerwein Nick Jacob committed
175
    
176 177
    ht_restore = widgets.HTML('<b>selected config: '+config['comment']+'</b>')
    
178
    display(widgets.HBox([select_restore,bt_restore, ht_restore]))
179
    
180 181 182 183 184 185 186 187 188 189
    #browse configs
    
    def find_config(bt):
        config = io.load(gui = True)
        dm.set_config(devices,config)
        refresh('')
        print ('restored config: '+config['comment'])
    
    bt_browse = widgets.Button(description='Browse configs')
    bt_browse.on_click(find_config)
190
    #display(bt_browse)
191
    
192
    text_comment = widgets.Text(description= 'Comment:')
193 194
    check_elog = widgets.Checkbox(value=False,
                                  description='elog')
195
    display(widgets.HBox([bt_save,text_comment,check_elog,ht_save] ))
196 197 198 199 200 201
    
    def make_controller():
        #devices
        vbs = []
        names = {}
        wps = []
Sauerwein Nick Jacob's avatar
Sauerwein Nick Jacob committed
202
        meas_check = {}
203 204
        for i in range(len(devices)):
            config = devices[i].get_config()
Nick Sauerwein's avatar
Nick Sauerwein committed
205

206
            wps += [wrapper(devices, i, io)]
207 208
            wgs = [] 
            for item in sorted(config.items()):
Sauerwein Nick Jacob's avatar
Sauerwein Nick Jacob committed
209 210 211 212
                wgs += [interaction_tool(item[0],
                                         item[1], 
                                         devices[i], 
                                         config).widget]
213 214 215
            
            if hasattr(devices[i], 'measure'): 
                
Sauerwein Nick Jacob's avatar
Sauerwein Nick Jacob committed
216
                meas_check[i] = widgets.Checkbox(description='measure')
217
                
Sauerwein Nick Jacob's avatar
Sauerwein Nick Jacob committed
218 219
                meas_check[i].observe(wps[i].measure, names = 'value')
                wgs += [meas_check[i]]
220 221

            vbs += [widgets.VBox(wgs)]
222 223
            names[i] = [type(devices[i]).__name__]
        tab = widgets.Tab(children = vbs, _titles= names)
Sauerwein Nick Jacob's avatar
Sauerwein Nick Jacob committed
224
        return tab, wps
Nick Sauerwein's avatar
Nick Sauerwein committed
225
    
226 227
    display(widgets.HTML('<b><br>Interact with devices</b>'))
    bt_refresh = widgets.Button(description='Refresh configs')
228 229
    
    
230
    global tab
231
    global wps
Sauerwein Nick Jacob's avatar
Sauerwein Nick Jacob committed
232
    tab, wps = make_controller()
233 234 235 236
    
    vb_config = widgets.VBox([bt_refresh, tab])
    display(vb_config)
    
237 238
    def refresh(bt):
        global tab
239
        global wps
240
        tab.close()
241 242
        tab, wps = make_controller()
        vb_config.children = [bt_refresh, tab]
243
    bt_refresh.on_click(refresh)
Sauerwein Nick Jacob's avatar
Sauerwein Nick Jacob committed
244
    
245 246
    display(widgets.HTML('<b><br>Plot measure configuration</b>'))
    bt_plot_config_init = widgets.Button(description='Measure to initialize')
247 248
    global plot_config
    plot_config = {}
249 250 251 252 253 254 255 256 257
    def plot_configurator(bt):
        #devices
        vbs = []
        names = {}
        wps = []
        
        plot_meas_check = {}
        
        devices2measure = find_devices2measure()
258 259
        
        print (devices2measure)
260 261 262 263
        measurement = dm.measure(devices2measure)
        global plot_config
        plot_config = {}
        for i in range(len(devices2measure)):
264
            device_name = type(devices2measure[i]).__name__
265 266 267 268 269 270 271 272
            plot_config[device_name] = {}

            wgs = [] 
            for item in sorted(measurement['measure'][device_name].items()):
                wgs += [plot_config_tool(item[0],
                                         item[1],
                                         plot_config[device_name]).widget]
            
273
            if hasattr(devices2measure[i], 'plot_measure'): 
274 275 276 277 278 279
                
                wgs += [plot_config_tool('plot_measure',
                                         0,
                                         plot_config[device_name]).widget]

            vbs += [widgets.VBox(wgs)]
280
            names[i] = [type(devices2measure[i]).__name__]
281 282 283
        measure_tab = widgets.Tab(children = vbs, _titles= names)
        vb_plot_config.children = [bt_plot_config_init, measure_tab] 
        
284
    
285 286 287 288 289 290 291
    
    bt_plot_config_init.on_click(plot_configurator)
    
    vb_plot_config = widgets.VBox([bt_plot_config_init])
    
    display(vb_plot_config)
    
Sauerwein Nick Jacob's avatar
Sauerwein Nick Jacob committed
292
    display(widgets.HTML('<b><br>Make measurements</b>'))
293

294
    loop_inttext = widgets.IntText(value = 10, description = 'loop')
Sauerwein Nick Jacob's avatar
Sauerwein Nick Jacob committed
295 296 297 298
    output_check = widgets.Checkbox(description = 'output')
    
    save_check = widgets.Checkbox(description = 'save')
    
299
    display(widgets.HBox([loop_inttext, output_check, save_check]))
300
    rate_text = widgets.FloatText(value = 5, description = 'rate')
301
    display(rate_text)
Sauerwein Nick Jacob's avatar
Sauerwein Nick Jacob committed
302
    meas_bt = widgets.Button(description = 'measure')
303 304 305
    clear_hist_bt = widgets.Button(description = 'clear history')
    display(widgets.HBox([meas_bt, clear_hist_bt]))
    def find_devices2measure():
Sauerwein Nick Jacob's avatar
Sauerwein Nick Jacob committed
306 307 308 309 310
        #load_devices to measure
        devices2measure = []
        for i in range(len(devices)):
            if wps[i].measure_check:
                devices2measure += [devices[i]]
311
        return devices2measure
312
    def measure(bt, comment = '', name = None):
313
        devices2measure = find_devices2measure()
314 315 316 317 318 319 320 321 322 323 324
        
        #initialize parallelization
        if parallel:
            from multiprocessing import Process, Pipe
            class DataStreamProcess(Process):
                def __init__(self, connec, *args, **kwargs):
                    self.connec = connec
                    Process.__init__(self, *args, **kwargs)

                def run(self):
                    loop_measure(parallel = True, connec = self.connec)
Sauerwein Nick Jacob's avatar
Sauerwein Nick Jacob committed
325
        #loop measure
326 327 328
        def loop_measure(parallel = False, connec = None):
            
            for i in range(loop_inttext.value):
329
                
330 331 332
                import IPython
                IPython.display.clear_output(wait = True)
                
333 334 335 336 337 338 339 340 341 342 343 344 345
                import time
                t = time.time()
                
                measurement = dm.measure(devices2measure)
                if save_check.value:
                    if name == None:
                        io.save(measurement, 
                                kind = 'measure', comment = comment)
                    else:
                        io.save(measurement, 
                                kind = 'measure', comment = comment, name = name+'_'+str(i))
                if parallel:
                    connec.send(measurement)
346 347 348 349
                elif output_check.value:
                    dm.plot_measure(measurement, devices2measure,plot_config, 0.01)
                    plt.pause(0.001)
                    plt.draw_all(force = True)
350 351 352 353 354
                print ('maximal possible rate: ',np.round(1/(time.time() -t),1))
                if (1/rate_text.value - (time.time() -t) < 0):
                    print ('set rate cannot be reached.')
                else:
                    time.sleep(1/rate_text.value - (time.time() -t))
355
            
356

357
        
358
      
359 360
        
        
361
        if output_check.value and parallel:
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
            global plot_config
            
            
            conn1, conn2  = Pipe()
            data_stream = DataStreamProcess(conn1)
            data_stream.start()
            
            while True:
                if not(conn2.poll(0.1)):
                    if not(data_stream.is_alive()):
                        break
                    else:
                        continue
                measurement = conn2.recv()

                dm.plot_measure(measurement, devices2measure,plot_config, 0.01)
                plt.pause(0.001)
                plt.draw_all(force = True)
        else:
            loop_measure()
        
        
        

386
            
387 388 389 390
    
    def clear_hist(bt):
        import Globals
        Globals.plot_hist = {}
Sauerwein Nick Jacob's avatar
Sauerwein Nick Jacob committed
391 392
    
    meas_bt.on_click(measure)
393
    clear_hist_bt.on_click(clear_hist)
394 395 396 397 398 399 400 401 402 403 404
    display(widgets.HTML('<b>Scanning Tool</b>'))
    bt_scan = widgets.Button(description = 'start Scanning Tool')
    display(bt_scan)
    scanning_tool_box = widgets.VBox([])
    display(scanning_tool_box)
    
    def scanning_tool(bt):
        def choose_device(bt):
            device = select_device.value
            def choose_parameter(bt):
                par_to_scan = select_scannable.value
405
                config = dm.get_config(devices)
406 407 408 409 410 411 412 413 414 415 416
                current_value = config[type(device).__name__][par_to_scan]
                def scan(bt):
                    comment = 'scan of '+par_to_scan+' over '+str((minv.value, maxv.value, nsteps.value))
                    
                    
                    if save_check.value:
                        import os
                        import datetime
                        folder_name = 'scan_'+par_to_scan+'_'+str(minv.value)+'-'+str(maxv.value)+'_'+str(nsteps.value)+'_'+str(datetime.datetime.now()).replace(':','-').replace(' ','_')
                        os.mkdir(io.path + folder_name)
                        conifg = dm.get_config(devices)
417
                        io.save(config, name = folder_name+'/config_at_start',comment = 'before '+comment)
418 419 420 421 422 423 424 425 426 427 428
                    else:
                        folder_name = ''
                    
                    scan_values = np.linspace(minv.value, maxv.value, nsteps.value)

                    for scan_value in scan_values:
                    
                        config[type(device).__name__][par_to_scan] = scan_value
                        dm.set_config(devices, config)
                        measure('', comment = comment+', current value: '+str(scan_value), name = folder_name+'/'+par_to_scan+'='+str(scan_value))

429 430 431
                minv = widgets.FloatText(description='minv:',value = current_value)
                maxv = widgets.FloatText(description='maxv:',value = current_value) 
                nsteps = widgets.IntText(description='nsteps:', value = 1) 
432 433 434
                bt = widgets.Button(description='Run scan')
                bt.on_click(scan)

435
                menue = widgets.VBox([widgets.HTML('current value: '+str(current_value)), minv, maxv, nsteps,  bt])
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
                            
                scanning_tool_box.children = list(scanning_tool_box.children) + [menue]
                
            scannable = []

            for item in config[type(device).__name__].items():
                if np.dtype(type(item[1])) == np.dtype('float64') or np.dtype(type(item[1])) == np.dtype(int):
                    scannable += [item[0]]
            
            select_scannable = widgets.Select(description = 'parameter to scan: ',options = scannable)
            bt_scannable = widgets.Button(description = 'choose parameter')
            bt_scannable.on_click(choose_parameter)
            hb_scannable = widgets.HBox([select_scannable,bt_scannable])
            scanning_tool_box.children = list(scanning_tool_box.children)[:1] + [hb_scannable]
                
        scanning_tool_box.children = []
        device_dict = {}
        for device in devices:
            device_dict[type(device).__name__] = device
        select_device = widgets.Select(description = 'device to scan: ',options = device_dict)
        bt_device = widgets.Button(description = 'choose device')
        bt_device.on_click(choose_device)
        hb_device = widgets.HBox([select_device,bt_device])
        scanning_tool_box.children = [hb_device]     

    
    bt_scan.on_click(scanning_tool)
    

Sauerwein Nick Jacob's avatar
Sauerwein Nick Jacob committed
465 466
    
    
Nick Sauerwein's avatar
Nick Sauerwein committed
467
    
468 469 470 471 472 473 474 475 476 477 478
def get_path():
    import tkinter as tk
    from tkinter import filedialog

    root = tk.Tk()
    root.withdraw()
    return filedialog.askopenfilename()

    

    
479
    
Nick Sauerwein's avatar
Nick Sauerwein committed
480