From 7583f640ac89c36996dd9d92c318678de7790053 Mon Sep 17 00:00:00 2001 From: ckski Date: Mon, 16 Nov 2020 16:14:49 -0700 Subject: [PATCH 1/2] Implement print function can work in draw method The print output for each frame is accumulated and drawn only once per frame overriding the output from the previous frame. If the output is identical to the previous frame then no update happens (this prevents flickering). --- spark/core.py | 54 ++++++++- test/PrintTest.ipynb | 268 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 316 insertions(+), 6 deletions(-) create mode 100644 test/PrintTest.ipynb diff --git a/spark/core.py b/spark/core.py index ee07ad1..b6d9dee 100644 --- a/spark/core.py +++ b/spark/core.py @@ -41,12 +41,19 @@ def __init__(self, globals_dict): self._globals_dict = globals_dict self._methods = {} + # Supports the print function. + self.current_step = 'presetup' + self.print_outputs = { 'setup': '', 'draw': '' } + self.draw_output_tracker = '' + self.draw_output_frame = 0 + + self.frame_count = 0 + self.stop_button = Button(description="Stop") self.stop_button.on_click(self.on_stop_button_clicked) self._globals_dict["canvas"] = Canvas() self.kb_mon = Event(source=self.canvas, watched_events=['keydown', 'keyup'], wait=1000 // FRAME_RATE, prevent_default_actions=True) - self.output_text = "" self.color_strings = { "default": "#888888" } @@ -83,6 +90,16 @@ def __init__(self, globals_dict): def canvas(self) -> Canvas: return self._globals_dict["canvas"] + @property + @ignite_global + def frame_count(self): + return self._globals_dict["frame_count"] + + @frame_count.setter + def frame_count(self, val): + self._globals_dict["frame_count"] = val + + @property @ignite_global def mouse_x(self): @@ -158,7 +175,10 @@ def start(self, methods): display(self.canvas) - self.output_text_code = display(Code(self.output_text), display_id=True) + self.print_output_display = { + 'handle': display(Code(''), display_id=True), + 'value': '' + } self.canvas.on_mouse_down(self.on_mouse_down) self.canvas.on_mouse_up(self.on_mouse_up) @@ -203,12 +223,16 @@ def loop(self): setup = self._methods.get("setup", None) if setup: + self.current_step = 'setup' try: setup() except Exception as e: + self.update_print_output_display() self.stop("Error in setup() function: " + str(e)) return + self.update_print_output_display() + while _sparkplug_running: if _sparkplug_active_thread_id != current_thread_id \ or time.time() - _sparkplug_last_activity > NO_ACTIVITY_THRESHOLD: @@ -219,12 +243,16 @@ def loop(self): self.stop("Done drawing.") return + self.current_step = 'draw' with hold_canvas(self.canvas): try: draw() + self.frame_count += 1 except Exception as e: + self.update_print_output_display() self.stop("Error in draw() function: " + str(e)) return + self.update_print_output_display() time.sleep(1 / FRAME_RATE) @@ -236,11 +264,25 @@ def print_status(self, msg): # Can't use @validate_args decorator for functions actually accepting variable arguments @ignite_global def print(self, *args, sep=' ', end='\n', flush=True): - global _sparkplug_running - self.output_text += sep.join([str(arg) for arg in args]) + end + if self.current_step == 'presetup': + print(*args) # Use built-in print outside of setup and draw methods. + return - if _sparkplug_running and flush: - self.output_text_code.update(Code(self.output_text)) + if self.current_step == 'draw': + # If printing from the draw method, clear values from the previous frame. + if self.draw_output_frame != self.frame_count: + self.draw_output_frame = self.frame_count + self.print_outputs['draw'] = '' + + msg = sep.join([str(arg) for arg in args]) + end + self.print_outputs[self.current_step] += msg + + def update_print_output_display(self): + vals = [self.print_outputs['setup'], self.print_outputs['draw']] + new_text = ''.join(filter(None, vals)) # Filter out empty values. + if self.print_output_display['value'] != new_text: + self.print_output_display['value'] = new_text + self.print_output_display['handle'].update(Code(new_text)) # Update mouse_x, mouse_y, and call mouse_down handler def on_mouse_down(self, x, y): diff --git a/test/PrintTest.ipynb b/test/PrintTest.ipynb new file mode 100644 index 0000000..08b06b0 --- /dev/null +++ b/test/PrintTest.ipynb @@ -0,0 +1,268 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "import spark\n", + "%reload_ext spark" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Stopped\n",
+       "
\n" + ], + "text/latex": [ + "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n", + "\\PY{err}{S}\\PY{err}{t}\\PY{err}{o}\\PY{err}{p}\\PY{err}{p}\\PY{err}{e}\\PY{err}{d}\n", + "\\end{Verbatim}\n" + ], + "text/plain": [ + "Stopped" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "f9a52c6545e246b7b8493123105274cf", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Button(description='Stop', style=ButtonStyle())" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "c8b723c4b0a64b80b878deadf30bc728", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Canvas(height=100, width=100)" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
0\n",
+       "80 71 15\n",
+       "
\n" + ], + "text/latex": [ + "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n", + "\\PY{err}{0}\n", + "\\PY{err}{8}\\PY{err}{0}\\PY{err}{ }\\PY{err}{7}\\PY{err}{1}\\PY{err}{ }\\PY{err}{1}\\PY{err}{5}\n", + "\\end{Verbatim}\n" + ], + "text/plain": [ + "0\n", + "80 71 15" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%ignite\n", + "\n", + "x = 0\n", + "\n", + "def setup():\n", + " print(x)\n", + "\n", + "def draw():\n", + " global x\n", + " x += 1\n", + " print(x, mouse_x, mouse_y)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.6" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} From b447c07edd9444abf7e1182710854e92a83c7da8 Mon Sep 17 00:00:00 2001 From: R Lee Date: Tue, 24 Nov 2020 00:16:24 -0700 Subject: [PATCH 2/2] Added unit tests for frame_count --- test/KeyEventsUnits.ipynb | 2 +- test/PrintTest.ipynb | 245 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 239 insertions(+), 8 deletions(-) diff --git a/test/KeyEventsUnits.ipynb b/test/KeyEventsUnits.ipynb index bce14d1..4bf0aa5 100644 --- a/test/KeyEventsUnits.ipynb +++ b/test/KeyEventsUnits.ipynb @@ -1598,7 +1598,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.8.6" } }, "nbformat": 4, diff --git a/test/PrintTest.ipynb b/test/PrintTest.ipynb index 08b06b0..a2911a8 100644 --- a/test/PrintTest.ipynb +++ b/test/PrintTest.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 6, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -12,7 +12,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 2, "metadata": {}, "outputs": [ { @@ -109,7 +109,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "f9a52c6545e246b7b8493123105274cf", + "model_id": "acd511e6d1664663a5f33819b319c666", "version_major": 2, "version_minor": 0 }, @@ -123,7 +123,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "c8b723c4b0a64b80b878deadf30bc728", + "model_id": "ce52e55f431d4b02ba6c27edb7ead3c2", "version_major": 2, "version_minor": 0 }, @@ -211,18 +211,18 @@ ".output_html .vi { color: #19177C } /* Name.Variable.Instance */\n", ".output_html .vm { color: #19177C } /* Name.Variable.Magic */\n", ".output_html .il { color: #666666 } /* Literal.Number.Integer.Long */
0\n",
-       "80 71 15\n",
+       "21 65 1\n",
        "
\n" ], "text/latex": [ "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n", "\\PY{err}{0}\n", - "\\PY{err}{8}\\PY{err}{0}\\PY{err}{ }\\PY{err}{7}\\PY{err}{1}\\PY{err}{ }\\PY{err}{1}\\PY{err}{5}\n", + "\\PY{err}{2}\\PY{err}{1}\\PY{err}{ }\\PY{err}{6}\\PY{err}{5}\\PY{err}{ }\\PY{err}{1}\n", "\\end{Verbatim}\n" ], "text/plain": [ "0\n", - "80 71 15" + "21 65 1" ] }, "metadata": {}, @@ -232,6 +232,8 @@ "source": [ "%%ignite\n", "\n", + "# Prints out a variable x that is constantly incrementing and mouse_x and mouse_y on-the-spot inside draw()\n", + "\n", "x = 0\n", "\n", "def setup():\n", @@ -242,6 +244,235 @@ " x += 1\n", " print(x, mouse_x, mouse_y)" ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Stopped\n",
+       "
\n" + ], + "text/latex": [ + "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n", + "\\PY{err}{S}\\PY{err}{t}\\PY{err}{o}\\PY{err}{p}\\PY{err}{p}\\PY{err}{e}\\PY{err}{d}\n", + "\\end{Verbatim}\n" + ], + "text/plain": [ + "Stopped" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "4e749ac0b6b649c89c9db61e37491e3c", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Button(description='Stop', style=ButtonStyle())" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "cb6f158f70a84fdf93857ba85ac1e63a", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Canvas(height=100, width=100)" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
23\n",
+       "
\n" + ], + "text/latex": [ + "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n", + "\\PY{err}{2}\\PY{err}{3}\n", + "\\end{Verbatim}\n" + ], + "text/plain": [ + "23" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%ignite\n", + "\n", + "# Print out the variable frame_count\n", + "\n", + "def setup():\n", + " size(100, 100)\n", + " background(\"aqua\")\n", + " \n", + "def draw():\n", + " print(frame_count)" + ] } ], "metadata": {