main.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. import matplotlib
  2. matplotlib.use("TkAgg")
  3. from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
  4. from matplotlib.figure import Figure
  5. from Tkinter import *
  6. import tkSimpleDialog
  7. import urllib
  8. import urllib2
  9. import json
  10. import time
  11. JUMP = 40
  12. MAX_WIDTH = 20 * JUMP
  13. MAX_HEIGHT = 20 * JUMP
  14. address = "http://127.0.0.1:8001"
  15. username = "test"
  16. root = Tk()
  17. canvas = Canvas(root, width=MAX_WIDTH, height=MAX_HEIGHT, bg="white")
  18. name = 0
  19. class FakeLayer():
  20. def __init__(self, address):
  21. self.types = {}
  22. self.sources = {}
  23. self.targets = {}
  24. self.attrs = {}
  25. def read_available_attributes(self, name):
  26. if self.types[name] == "const":
  27. return ["value"]
  28. else:
  29. return []
  30. def read_attribute(self, name, attr):
  31. return self.attr.get(name, {}).get(attr, None)
  32. def set_attribute(self, name, attr, value):
  33. self.attrs[name][attr] = value
  34. def instantiate_block(self, name, block_type):
  35. self.types[name] = block_type
  36. def instantiate_link(self, name, link_type, source, target):
  37. self.types[name] = link_type
  38. self.sources[name] = source
  39. self.targets[name] = target
  40. self.attrs[name] = {}
  41. def simulate(self):
  42. pass
  43. def step(self):
  44. pass
  45. def pause(self):
  46. pass
  47. attribute = []
  48. available_attrs = []
  49. simulation = []
  50. def poll(address):
  51. working_available_attrs = []
  52. working_simulation = None
  53. while 1:
  54. returnvalue = json.loads(urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "get_output", "username": username}))).read())
  55. print("Process " + str(returnvalue))
  56. if (returnvalue.startswith("AVAILABLE_ATTR_VALUE")):
  57. working_available_attrs.append([json.loads(returnvalue.split(" ", 1)[1]), None])
  58. elif (returnvalue.startswith("AVAILABLE_ATTR_TYPE")):
  59. working_available_attrs[-1][1] = json.loads(returnvalue.split(" ", 1)[1])
  60. elif (returnvalue.startswith("AVAILABLE_ATTR_END")):
  61. available_attrs.append(working_available_attrs)
  62. working_available_attrs = []
  63. elif (returnvalue.startswith("ATTR_VALUE")):
  64. v = returnvalue.split(" ", 1)[1]
  65. if v == "None":
  66. v = None
  67. else:
  68. v = json.loads(v)
  69. attribute.append(v)
  70. elif (returnvalue.startswith("SIM_TIME")):
  71. working_simulation = (json.loads(returnvalue.split(" ", 1)[1]), {})
  72. elif (returnvalue.startswith("SIM_PROBE")):
  73. blockname, blockvalue = returnvalue.split(" ", 1)[1].rsplit(" ", 1)
  74. working_simulation[1][json.loads(blockname)] = json.loads(blockvalue)
  75. elif (returnvalue.startswith("SIM_END")):
  76. simulation.append(working_simulation)
  77. working_simulation = None
  78. elif (returnvalue.startswith("CONFORMANCE_OK")):
  79. root.configure(background="grey")
  80. elif (returnvalue.startswith("CONFORMANCE_FAIL")):
  81. root.configure(background="red")
  82. elif (returnvalue.startswith("ALGEBRAIC_LOOP")):
  83. root.configure(background="blue")
  84. else:
  85. print("Error: got unknown result: " + returnvalue)
  86. class MvLayer():
  87. def __init__(self, address):
  88. import threading
  89. self.address = address
  90. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % username, "username": "user_manager"}))).read()
  91. thrd = threading.Thread(target=poll, args=[address])
  92. thrd.daemon = True
  93. thrd.start()
  94. def read_available_attributes(self, name):
  95. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"read_available_attributes"', "username": username}))).read()
  96. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % name, "username": username}))).read()
  97. while not available_attrs:
  98. time.sleep(0.1)
  99. return available_attrs.pop(0)
  100. def read_attribute(self, name, attr):
  101. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"read_attribute"', "username": username}))).read()
  102. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % name, "username": username}))).read()
  103. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % attr, "username": username}))).read()
  104. while not attribute:
  105. time.sleep(0.1)
  106. return attribute.pop(0)
  107. def set_attribute(self, name, attr, value):
  108. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"set_attribute"', "username": username}))).read()
  109. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % name, "username": username}))).read()
  110. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % attr, "username": username}))).read()
  111. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": json.dumps(value), "username": username}))).read()
  112. def instantiate_block(self, name, block_type):
  113. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"instantiate_node"', "username": username}))).read()
  114. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % (block_type), "username": username}))).read()
  115. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % (name), "username": username}))).read()
  116. def instantiate_link(self, name, link_type, source, target):
  117. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"instantiate_association"', "username": username}))).read()
  118. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % (link_type), "username": username}))).read()
  119. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % (name), "username": username}))).read()
  120. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % (source), "username": username}))).read()
  121. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % (target), "username": username}))).read()
  122. def simulate(self):
  123. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"simulate"', "username": username}))).read()
  124. def step(self):
  125. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"step"', "username": username}))).read()
  126. def pause(self):
  127. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"pause"', "username": username}))).read()
  128. def delete(self, block):
  129. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"delete_element"', "username": username}))).read()
  130. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"%s"' % (block), "username": username}))).read()
  131. def lower(value):
  132. return value / JUMP * JUMP
  133. def upper(value):
  134. return (value / JUMP + 1) * JUMP
  135. def avg(a, b):
  136. return float(a + b) / 2
  137. class InterfaceCore():
  138. mode = ""
  139. drawn = set()
  140. refs = dict()
  141. mv = MvLayer(address)
  142. #mv = FakeLayer(address)
  143. def set_mode(self, mode):
  144. self.mode = mode
  145. def delete(self, x, y):
  146. lname = self.find((x, y))
  147. self.mv.delete(lname)
  148. for i in self.refs[lname]:
  149. canvas.delete(i)
  150. del self.refs[lname]
  151. self.drawn = set([e for e in self.drawn if e[4] != lname])
  152. def clicked(self, event):
  153. if self.find((event.x, event.y)):
  154. # Something already there, so don't add, but modify
  155. lname = self.find((event.x, event.y))
  156. attrs = self.mv.read_available_attributes(lname)
  157. print("Managing " + str(attrs))
  158. if not attrs:
  159. print("No attrs to manage!")
  160. for attr, t in attrs:
  161. print("Reading data from " + str(attr))
  162. old_value = self.mv.read_attribute(lname, attr)
  163. if old_value == "None":
  164. old_value = None
  165. new_value = tkSimpleDialog.askstring("Attribute modification", attr, initialvalue=old_value)
  166. if t == "Float":
  167. new_value = float(new_value)
  168. elif t == "String":
  169. new_value = str(new_value)
  170. else:
  171. print("Got unknown type: " + str(t))
  172. self.mv.set_attribute(lname, attr, new_value)
  173. elif self.mode not in ["AdditionBlock", "NegatorBlock", "ConstantBlock", "MultiplyBlock", "ConstantBlock", "InverseBlock", "DelayBlock", "IntegratorBlock", "DerivatorBlock", "ProbeBlock"]:
  174. print("Cannot create something not guaranteed to be block type!")
  175. else:
  176. global name
  177. x = event.x
  178. y = event.y
  179. self.mv.instantiate_block(str(name), self.mode)
  180. r = canvas.create_rectangle(lower(x), lower(y), upper(x), upper(y), fill="white")
  181. t = canvas.create_text(avg(lower(x), upper(x)), avg(lower(y), upper(y)), text=self.mode, fill="black")
  182. b = (lower(x), lower(y), upper(x), upper(y), str(name))
  183. self.drawn.add(b)
  184. self.refs[str(name)] = [r, t]
  185. name += 1
  186. def find(self, location):
  187. x, y = location
  188. for e in self.drawn:
  189. if (e[0] <= x and
  190. e[1] <= y and
  191. e[2] >= x and
  192. e[3] >= y):
  193. return e[4]
  194. print("Found nothing at that location!")
  195. return []
  196. def draw(self, start, end):
  197. source = self.find(start)
  198. target = self.find(end)
  199. print("Connect from %s to %s" % (source, target))
  200. if source and target:
  201. if self.mode not in ["Link", "InitialCondition"]:
  202. print("Cannot create something not guaranteed to be link type!")
  203. elif source == target:
  204. print("Cannot create link to self")
  205. else:
  206. global name
  207. self.mv.instantiate_link(str(name), self.mode, source, target)
  208. self.refs[str(name)] = [canvas.create_line(start[0], start[1], end[0], end[1], fill="black", arrow=LAST)]
  209. name += 1
  210. core = InterfaceCore()
  211. def clicked(event):
  212. core.clicked(event)
  213. def draw(event):
  214. global start_location
  215. start_location = (event.x, event.y)
  216. def release(event):
  217. core.draw(start_location, (event.x, event.y))
  218. def simulate():
  219. core.mv.simulate()
  220. def step():
  221. core.mv.step()
  222. def pause():
  223. core.mv.pause()
  224. def addition():
  225. core.set_mode("AdditionBlock")
  226. def negation():
  227. core.set_mode("NegatorBlock")
  228. def link():
  229. core.set_mode("Link")
  230. def multiply():
  231. core.set_mode("MultiplyBlock")
  232. def constant():
  233. core.set_mode("ConstantBlock")
  234. def inverse():
  235. core.set_mode("InverseBlock")
  236. def ic():
  237. core.set_mode("InitialCondition")
  238. def delay():
  239. core.set_mode("DelayBlock")
  240. def derivator():
  241. core.set_mode("DerivatorBlock")
  242. def integrator():
  243. core.set_mode("IntegratorBlock")
  244. def delete(event):
  245. core.delete(event.x, event.y)
  246. def make_probe():
  247. core.set_mode("ProbeBlock")
  248. buttons = [
  249. Button(root, text="+", command=addition, bg="red"),
  250. Button(root, text="-x", command=negation, bg="red"),
  251. Button(root, text="*", command=multiply, bg="red"),
  252. Button(root, text="1/x", command=inverse, bg="red"),
  253. Button(root, text="Constant", command=constant, bg="red"),
  254. Button(root, text="Delay", command=delay, bg="red"),
  255. Button(root, text="d/dx", command=derivator, bg="red"),
  256. Button(root, text="integrator", command=integrator, bg="red"),
  257. Button(root, text="Probe", command=make_probe, bg="red"),
  258. Button(root, text="Link", command=link, bg="blue"),
  259. Button(root, text="InitialCondition", command=ic, bg="blue"),
  260. Button(root, text="SIM", command=simulate, bg="green"),
  261. Button(root, text="STEP", command=step, bg="green"),
  262. Button(root, text="PAUSE", command=pause, bg="green"),
  263. ]
  264. for i, b in enumerate(buttons):
  265. b.grid(row=0, column=i)
  266. canvas.grid(row=1,column=0,columnspan=len(buttons))
  267. core.canvas = canvas
  268. for i in range(JUMP, MAX_HEIGHT, JUMP):
  269. canvas.create_line(0, i, MAX_HEIGHT, i, fill="grey")
  270. for i in range(JUMP, MAX_WIDTH, JUMP):
  271. canvas.create_line(i, 0, i, MAX_WIDTH, fill="grey")
  272. canvas.bind("<Button-1>", clicked)
  273. canvas.bind("<Button-2>", delete)
  274. canvas.bind("<Button-3>", draw)
  275. canvas.bind("<ButtonRelease-3>", release)
  276. visual = Toplevel(root)
  277. probes = {}
  278. values = {}
  279. # Example:
  280. # simulation = [(1, {"a": 1, "b": 2}), (2, {"a": 3}), (3, {"a": 4, "b": 6})]
  281. # Class from StackOverflow
  282. class VerticalScrolledFrame(Frame):
  283. """A pure Tkinter scrollable frame that actually works!
  284. * Use the 'interior' attribute to place widgets inside the scrollable frame
  285. * Construct and pack/place/grid normally
  286. * This frame only allows vertical scrolling
  287. """
  288. def __init__(self, parent, *args, **kw):
  289. Frame.__init__(self, parent, *args, **kw)
  290. # create a canvas object and a vertical scrollbar for scrolling it
  291. vscrollbar = Scrollbar(self, orient=VERTICAL)
  292. vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
  293. canvas = Canvas(self, bd=0, highlightthickness=0,
  294. yscrollcommand=vscrollbar.set)
  295. canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
  296. vscrollbar.config(command=canvas.yview)
  297. # reset the view
  298. canvas.xview_moveto(0)
  299. canvas.yview_moveto(0)
  300. # create a frame inside the canvas which will be scrolled with it
  301. self.interior = interior = Frame(canvas)
  302. interior_id = canvas.create_window(0, 0, window=interior,
  303. anchor=NW)
  304. # track changes to the canvas and frame width and sync them,
  305. # also updating the scrollbar
  306. def _configure_interior(event):
  307. # update the scrollbars to match the size of the inner frame
  308. size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
  309. canvas.config(scrollregion="0 0 %s %s" % size)
  310. if interior.winfo_reqwidth() != canvas.winfo_width():
  311. # update the canvas's width to fit the inner frame
  312. canvas.config(width=interior.winfo_reqwidth())
  313. interior.bind('<Configure>', _configure_interior)
  314. def _configure_canvas(event):
  315. if interior.winfo_reqwidth() != canvas.winfo_width():
  316. # update the inner frame's width to fill the canvas
  317. canvas.itemconfigure(interior_id, width=canvas.winfo_width())
  318. canvas.bind('<Configure>', _configure_canvas)
  319. frame = VerticalScrolledFrame(visual)
  320. frame.pack(fill=BOTH,expand=True)
  321. def update_graphs():
  322. while simulation:
  323. t, results = simulation.pop(0)
  324. for k, v in results.items():
  325. if k in probes:
  326. fcanvas, a = probes[k]
  327. else:
  328. f = Figure()
  329. a = f.add_subplot(111)
  330. a.plot([], [])
  331. print(k)
  332. f.suptitle(k)
  333. fcanvas = FigureCanvasTkAgg(f, frame.interior)
  334. fcanvas.show()
  335. fcanvas.get_tk_widget().pack()
  336. probes[k] = (fcanvas, a)
  337. values[k] = ([], [])
  338. values[k][0].append(t)
  339. values[k][1].append(v)
  340. a.clear()
  341. a.plot(values[k][0], values[k][1], linestyle="none", marker="o")
  342. fcanvas.draw()
  343. root.after(100, update_graphs)
  344. root.after(100, update_graphs)
  345. root.mainloop()