<jupyter_start><jupyter_text>Interactive drawing exampleA simple drawing app:* Draw dots by clicking with LMB.* Toggle color by clicking RMB.<jupyter_code>import numpy as np
import jupyter_rfb
class Drawingapp(jupyter_rfb.RemoteFrameBuffer):
    
    def __init__(self):
        super().__init__()
        self.pixel_ratio = 1 / 8
        w, h = 600, 400
        self.css_width = f"{w}px"
        self.css_height = f"{h}px"
        self.resizable = False
        self.array = np.ones((int(h*self.pixel_ratio), int(w*self.pixel_ratio), 4), np.uint8) * 5
        self.pen_colors = [(1, 0.2, 0, 1), (0, 1, 0.2, 1), (0.2, 0, 1, 1)]
        self.pen_index = 0        
    
    def handle_event(self, event):
        event_type = event.get("event_type", None)
        if event_type == "pointer_down":
            if event["button"] == 1:
                # Draw
                x = int(event["x"] * self.pixel_ratio)
                y = int(event["y"] * self.pixel_ratio)
                self.array[y, x] = 255 * np.array(self.pen_colors[self.pen_index])
                self.request_draw()
            elif event["button"] == 2:
                # Toggle color
                self.pen_index = (self.pen_index + 1) % len(self.pen_colors)
    
    def get_frame(self):
        return self.array
        

app = Drawingapp()
app<jupyter_output><empty_output><jupyter_text>After some clicking ...<jupyter_code># We can also generate some clicks programatically :)
for x, y in [(503, 37), (27, 182), (182, 383), (396, 235), (477, 151), (328, 308), (281, 16)]:
    app.handle_event({"event_type": "pointer_down", "button": 1, "x": x, "y": y})
app.handle_event({"event_type": "pointer_down", "button": 2, "x": 0, "y": 0})
for x, y in [(226, 115), (135, 253), (351, 220), (57, 11), (345, 87), (67, 175), (559, 227)]:
    app.handle_event({"event_type": "pointer_down", "button": 1, "x": x, "y": y})
app.snapshot()
app.request_draw()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.16632443531827515, 'fraction_numerical': 0.059034907597535935, 'mean_word_length': 2.719465648854962, 'pattern_counts': {'":': 13, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '2', 'dir': 'jupyter-structured-clean-dedup', 'id': '552413', 'license': 'MIT', 'n_tokens_mistral': 795, 'n_tokens_neox': 689, 'n_words': 173, 'path': 'examples/interaction2.ipynb', 'repo_name': 'vispy/jupyter_rfb', 'size': '1948'}