-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwebsock.py
137 lines (105 loc) · 4 KB
/
websock.py
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import asyncio
from contextlib import contextmanager
import json
import threading
import numpy as np
import matplotlib.pyplot as plt
import websockets
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
class WebSocketServer:
def __init__(self, host='localhost', port=8765):
self.host = host
self.port = port
self.data_storage = {}
self.callbacks = {}
self.websocket_server = None
async def handle_client(self, websocket, path):
self.websocket_server = websocket
while True:
async for message in websocket:
try:
msg = json.loads(message)
except json.JSONDecodeError:
print("Received a non-JSON message")
ev_name = msg.get('event', None)
ev = msg.get('ev', {})
if ev_name == 'data':
data_name = ev["name"]
data_key = ev["key"]
data_value = ev["data"]
if not data_name or not data_value:
continue
if data_name not in self.data_storage:
self.data_storage[data_name] = {}
d = self.data_storage[data_name]
d[data_key] = data_value
else:
cbs = self.callbacks.get(ev_name, [])
for cb in cbs:
cb(**ev)
def get_data(self, name, key=None):
return self.data_storage.get(name, {}).get(key or name, None)
def on(self, event_name, func=None):
if func:
if event_name not in self.callbacks:
self.callbacks[event_name] = []
cbs = self.callbacks[event_name]
cbs.append(func)
else:
def wrapper(func):
return self.on(event_name, func=func)
return wrapper
async def start_server(self):
async with websockets.serve(self.handle_client, self.host, self.port):
await asyncio.Future()
class MatplotlibPlotter(QMainWindow):
def __init__(self):
super().__init__()
self.central_widget = QWidget(self)
self.setCentralWidget(self.central_widget)
self.layout = QVBoxLayout(self.central_widget)
self.figure = plt.Figure()
self.canvas = FigureCanvas(self.figure)
self.layout.addWidget(self.canvas)
class MatplotlibServer:
def __init__(self):
self.server = WebSocketServer()
self.app = QApplication([])
self.event_loop = asyncio.get_event_loop()
self.plotter = MatplotlibPlotter()
self.ax = self.plotter.figure.subplots()
def on(self, event_name, func=None):
return self.server.on(event_name, func=func)
def get_data(self, name, key=None):
return self.server.get_data(name, key=key)
@contextmanager
def make_plot(self):
self.ax.clear()
yield self.ax
self.plotter.canvas.draw()
def run(self):
websocket_thread = threading.Thread(target=lambda: asyncio.run(self.server.start_server()))
websocket_thread.daemon = True
websocket_thread.start()
self.plotter.show()
self.app.exec()
if __name__ == "__main__":
server = MatplotlibServer()
@server.on("feature")
def on_feature(fname=None, isVolume=None):
print(f"selected feature {fname}")
# Get the data.
colors = server.get_data('regionColors', fname)
values = server.get_data('regionValues', fname)
if values is None:
return
# Make a plot.
values = {d['idx']: d['normalized'] for d in values.values()}
arr = list(values.values())
with server.make_plot() as ax:
ax.hist(arr, bins=50, alpha=0.75)
ax.set_xlabel('Values')
ax.set_ylabel('Frequency')
ax.set_title('Histogram')
server.run()