PlottingServers.py 6.24 KB
Newer Older
Nick Sauerwein's avatar
Nick Sauerwein committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
import numpy as np

from bokeh.client import push_session
from bokeh.plotting import figure
from bokeh.document import Document

from multiprocessing import Process, Pipe
from bokeh.driving import count

from NotebookTools import open_window
class DataStreamProcess_1D(Process):
    def __init__(self,server, connecx, connecy, config, *args, **kwargs):
        self.connecx = connecx
        self.connecy = connecy
        self.config = config
        Process.__init__(self, *args, **kwargs)
    def run(self):
        plot_server_1d(connecx = self.connecx, connecy = self.connecy, config = self.config)
def plot_server_1d( connecx = None, connecy = None, config = {'xlabel' : '','ylabel' : '', 'title': ''}):
    doc = Document()
    doc.title = config['title']
    x = np.linspace(0,1,2)
    y = np.linspace(0,1,2)
    
    p = figure(title = config['title'],tools = 
Nick Sauerwein's avatar
Nick Sauerwein committed
26
'pan,box_zoom,wheel_zoom,save,crosshair,resize,reset,hover')
Nick Sauerwein's avatar
Nick Sauerwein committed
27
    
Nick Sauerwein's avatar
Nick Sauerwein committed
28
    p.plot_height = 300
Nick Sauerwein's avatar
Nick Sauerwein committed
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
    p.plot_width = 500

    
    r1 = p.square(x, y, fill_color=None, line_color="green")
    r2 = p.line(x, y,  line_color="green")
    
    p.xaxis.axis_label = config['xlabel']
    p.yaxis.axis_label = config['ylabel']

    
    # open a session to keep our local document in sync with server
    session = push_session(doc)


    def update():
        # updating a single column of the the *same length* is OK
        if connecx.poll(0.1):
Nick Sauerwein's avatar
Nick Sauerwein committed
46
            print (p.plot_height)
Nick Sauerwein's avatar
Nick Sauerwein committed
47 48 49 50 51
            r1.data_source.data["x"] = connecx.recv()
            r2.data_source.data["x"] = r1.data_source.data["x"]
            r1.data_source.data["y"] = connecy.recv()
            r2.data_source.data["y"] = r1.data_source.data["y"]

Nick Sauerwein's avatar
Nick Sauerwein committed
52 53 54
            p.plot_height = int(np.round(r1.data_source.data["y"][0]*1000))
            
            
Nick Sauerwein's avatar
Nick Sauerwein committed
55 56
    doc.add_periodic_callback(update, 50)

Nick Sauerwein's avatar
Nick Sauerwein committed
57
    doc.add_root(p)
Nick Sauerwein's avatar
Nick Sauerwein committed
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96

    open_window('http://localhost:5006/?bokeh-session-id='+str(session.id))
    
    session.loop_until_closed() # run forever
    
    
class Plot1DServer:
    def __init__(self, config = {'xlabel' : '','ylabel' : '', 'title': ''}):
        self.connecx_ch, self.connecx_par  = Pipe()
        self.connecy_ch, self.connecy_par  = Pipe()

        self.data_stream = DataStreamProcess_1D(self, self.connecx_par, self.connecy_par, config)
        self.data_stream.start()
        
    def update(self, x,y):
        self.connecx_ch.send(x)
        self.connecy_ch.send(y)
        
    def close():
        self.data_stream.close()
        
        
class DataStreamProcess_2D(Process):
    def __init__(self,connecim,connecext, config, *args, **kwargs):
        self.connecim = connecim
        self.connecext = connecext
        self.config = config
        Process.__init__(self, *args, **kwargs)

    def run(self):
        plot_server_2d( connecim = self.connecim,connecext = self.connecext, config = self.config)
        
def plot_server_2d(connecim = None,connecext = None, config = {'xlabel' : '','ylabel' : '', 'title': ''}):
    doc = Document()
    doc.title = config['title']
    img = np.array([[0,0],[0,0]])
    
    p = figure(title = config['title'], 
               x_range=[0, img.shape[0]], y_range=[0, img.shape[1]],
Nick Sauerwein's avatar
Nick Sauerwein committed
97 98 99 100 101
               tools = 'pan,wheel_zoom,save,crosshair,resize,reset')
    from bokeh.models.tools import BoxZoomTool
    p.add_tools(BoxZoomTool(match_aspect = True))
    p.plot_height = 400
    p.plot_width = 400
Nick Sauerwein's avatar
Nick Sauerwein committed
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
    from bokeh.palettes import Viridis256
    r1 = p.image(image=[np.flipud(img)], x=[0], y=[0],
           dw=[img.shape[0]], dh=[img.shape[1]],palette = Viridis256)
    
    p.xaxis.axis_label = config['xlabel']
    p.yaxis.axis_label = config['ylabel']

    
    # open a session to keep our local document in sync with server
    session = push_session(doc)

    def update():
        # updating a single column of the the *same length* is OK
        if connecim.poll(0.1):
            r1.data_source.data["image"] = [connecim.recv()]
            extent = connecext.recv()
            

            r1.data_source.data["x"] = [extent[0]]
            r1.data_source.data["dw"] = [extent[1] - extent[0]]
            r1.data_source.data["y"] = [extent[2]]
            r1.data_source.data["dh"] = [extent[3] - extent[2]]
Nick Sauerwein's avatar
Nick Sauerwein committed
124 125 126 127 128
            
            x = [extent[0],extent[1], extent[0], extent[1]]
            y = [extent[2],extent[2], extent[3], extent[3]]
            
            set_aspect(p, x, y, aspect=1)
Nick Sauerwein's avatar
Nick Sauerwein committed
129 130 131

    doc.add_periodic_callback(update, 50)

Nick Sauerwein's avatar
Nick Sauerwein committed
132
    doc.add_root(p)
Nick Sauerwein's avatar
Nick Sauerwein committed
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152

    open_window('http://localhost:5006/?bokeh-session-id='+str(session.id), width = 500)
    
    session.loop_until_closed() # run forever

class Plot2DServer:
    def __init__(self, config = {'xlabel' : '','ylabel' : '', 'title': ''}):
        self.connecext_ch, self.connecext_par  = Pipe()
        self.connecim_ch, self.connecim_par  = Pipe()

        self.data_stream = DataStreamProcess_2D(self.connecim_par,self.connecext_par, config)
        self.data_stream.start()
        
    def update(self,image ,extent):
        self.connecext_ch.send(extent)

        self.connecim_ch.send(image)
        
        
    def close(self):
Nick Sauerwein's avatar
Nick Sauerwein committed
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
        self.data_stream.join()
        
from bokeh.models import Range1d

def set_aspect(fig, x, y, aspect=1, margin=0.0):
    """Set the plot ranges to achieve a given aspect ratio.

    Args:
      fig (bokeh Figure): The figure object to modify.
      x (iterable): The x-coordinates of the displayed data.
      y (iterable): The y-coordinates of the displayed data.
      aspect (float, optional): The desired aspect ratio. Defaults to 1.
        Values larger than 1 mean the plot is squeezed horizontally.
      margin (float, optional): The margin to add for glyphs (as a fraction
        of the total plot range). Defaults to 0.1
    """
    xmin = min(xi for xi in x)
    xmax = max(xi for xi in x)
    ymin = min(yi for yi in y)
    ymax = max(yi for yi in y)
    width = (xmax - xmin)*(1+2*margin)
    if width <= 0:
        width = 1.0
    height = (ymax - ymin)*(1+2*margin)
    if height <= 0:
        height = 1.0
    xcenter = 0.5*(xmax + xmin)
    ycenter = 0.5*(ymax + ymin)
    r = aspect*(fig.plot_width/fig.plot_height)
    if width < r*height:
        width = r*height
    else:
        height = width/r
    fig.x_range.start = xcenter-0.5*width
    fig.x_range.end = xcenter+0.5*width
    fig.y_range.start = ycenter-0.5*height
    fig.y_range.end = ycenter+0.5*height