|
21 | 21 | "\n", |
22 | 22 | "from ipywidgets import VBox, IntSlider\n", |
23 | 23 | "\n", |
24 | | - "from ipycanvas import Canvas, hold_canvas" |
| 24 | + "from ipycanvas import MultiCanvas, hold_canvas" |
25 | 25 | ] |
26 | 26 | }, |
27 | 27 | { |
|
32 | 32 | "source": [ |
33 | 33 | "def init_2d_plot(x, y, color=None, scheme=branca.colormap.linear.RdBu_11, canvas=None, canvas_size=(800, 600), padding=0.1):\n", |
34 | 34 | " if canvas is None:\n", |
35 | | - " canvas = Canvas(size=canvas_size)\n", |
| 35 | + " canvas = MultiCanvas(3, size=canvas_size)\n", |
36 | 36 | " else:\n", |
37 | 37 | " canvas.size = canvas_size\n", |
38 | 38 | "\n", |
39 | 39 | " padding_x = padding * canvas_size[0]\n", |
40 | 40 | " padding_y = padding * canvas_size[1]\n", |
41 | 41 | "\n", |
| 42 | + " # TODO Fix drawarea max: It should be (canvas.size - padding)\n", |
42 | 43 | " drawarea = (drawarea_min_x, drawarea_min_y, drawarea_max_x, drawarea_max_y) = (padding_x, padding_y, canvas_size[0] - 2 * padding_x, canvas_size[1] - 2 * padding_y)\n", |
43 | 44 | "\n", |
44 | 45 | " min_x, min_y, max_x, max_y = np.min(x), np.min(y), np.max(x), np.max(y)\n", |
|
121 | 122 | "\n", |
122 | 123 | " with hold_canvas(canvas):\n", |
123 | 124 | " canvas.clear()\n", |
124 | | - " canvas.save()\n", |
| 125 | + " canvas[1].save()\n", |
125 | 126 | "\n", |
126 | | - " draw_background(canvas, drawarea, unscale_x, unscale_y)\n", |
| 127 | + " draw_background(canvas[0], drawarea, unscale_x, unscale_y)\n", |
127 | 128 | "\n", |
128 | 129 | " # Draw scatter\n", |
129 | 130 | " n_marks = min(x.shape[0], y.shape[0], size.shape[0], color.shape[0])\n", |
130 | 131 | "\n", |
131 | | - " canvas.stroke_style = stroke_color\n", |
| 132 | + " canvas[1].stroke_style = stroke_color\n", |
132 | 133 | "\n", |
133 | 134 | " for idx in range(n_marks):\n", |
134 | | - " canvas.fill_style = colormap(color[idx])\n", |
| 135 | + " canvas[1].fill_style = colormap(color[idx])\n", |
135 | 136 | " \n", |
136 | 137 | " mark_x = scale_x(x[idx])\n", |
137 | 138 | " mark_y = scale_y(y[idx])\n", |
138 | 139 | " mark_size = size[idx]\n", |
139 | 140 | "\n", |
140 | | - " canvas.fill_arc(mark_x, mark_y, mark_size, 0, 2 * pi)\n", |
141 | | - " canvas.stroke_arc(mark_x, mark_y, mark_size, 0, 2 * pi)\n", |
| 141 | + " canvas[1].fill_arc(mark_x, mark_y, mark_size, 0, 2 * pi)\n", |
| 142 | + " canvas[1].stroke_arc(mark_x, mark_y, mark_size, 0, 2 * pi)\n", |
142 | 143 | "\n", |
143 | | - " canvas.restore()\n", |
| 144 | + " canvas[1].restore()\n", |
| 145 | + "\n", |
| 146 | + " def click_handler(pixel_x, pixel_y):\n", |
| 147 | + " unscaled_x = unscale_x(pixel_x)\n", |
| 148 | + " unscaled_y = unscale_y(pixel_y)\n", |
| 149 | + "\n", |
| 150 | + " for idx in range(n_marks):\n", |
| 151 | + " mark_x = x[idx]\n", |
| 152 | + " mark_y = y[idx]\n", |
| 153 | + " mark_size = size[idx]\n", |
| 154 | + "\n", |
| 155 | + " if (pixel_x > scale_x(mark_x) - mark_size and pixel_x < scale_x(mark_x) + mark_size and\n", |
| 156 | + " pixel_y > scale_y(mark_y) - mark_size and pixel_y < scale_y(mark_y) + mark_size):\n", |
| 157 | + " canvas[2].fill_style = 'red'\n", |
| 158 | + " canvas[2].fill_arc(scale_x(mark_x), scale_y(mark_y), mark_size, 0, 2 * pi)\n", |
| 159 | + "\n", |
| 160 | + " canvas[2].on_click(click_handler)\n", |
144 | 161 | "\n", |
145 | 162 | " return canvas" |
146 | 163 | ] |
|
156 | 173 | "\n", |
157 | 174 | " with hold_canvas(canvas):\n", |
158 | 175 | " canvas.clear()\n", |
159 | | - " canvas.save()\n", |
| 176 | + " canvas[1].save()\n", |
160 | 177 | "\n", |
161 | | - " draw_background(canvas, drawarea, unscale_x, unscale_y)\n", |
| 178 | + " draw_background(canvas[0], drawarea, unscale_x, unscale_y)\n", |
162 | 179 | "\n", |
163 | 180 | " # Draw lines\n", |
164 | 181 | " n_points = min(x.shape[0], y.shape[0])\n", |
165 | 182 | "\n", |
166 | | - " canvas.begin_path()\n", |
167 | | - " canvas.stroke_style = line_color\n", |
168 | | - " canvas.line_width = line_width\n", |
169 | | - " canvas.line_join = 'bevel'\n", |
170 | | - " canvas.line_cap = 'round'\n", |
171 | | - " canvas.move_to(scale_x(x[0]), scale_y(y[0]))\n", |
| 183 | + " canvas[1].begin_path()\n", |
| 184 | + " canvas[1].stroke_style = line_color\n", |
| 185 | + " canvas[1].line_width = line_width\n", |
| 186 | + " canvas[1].line_join = 'bevel'\n", |
| 187 | + " canvas[1].line_cap = 'round'\n", |
| 188 | + " canvas[1].move_to(scale_x(x[0]), scale_y(y[0]))\n", |
172 | 189 | " for idx in range(1, n_points):\n", |
173 | | - " canvas.line_to(\n", |
| 190 | + " canvas[1].line_to(\n", |
174 | 191 | " scale_x(x[idx]), scale_y(y[idx])\n", |
175 | 192 | " )\n", |
176 | 193 | "\n", |
177 | | - " canvas.stroke()\n", |
178 | | - " canvas.close_path()\n", |
| 194 | + " canvas[1].stroke()\n", |
| 195 | + " canvas[1].close_path()\n", |
179 | 196 | " \n", |
180 | | - " canvas.restore()\n", |
| 197 | + " canvas[1].restore()\n", |
181 | 198 | "\n", |
182 | 199 | " return canvas" |
183 | 200 | ] |
|
196 | 213 | "\n", |
197 | 214 | " with hold_canvas(canvas):\n", |
198 | 215 | " canvas.clear()\n", |
199 | | - " canvas.save()\n", |
| 216 | + " canvas[1].save()\n", |
200 | 217 | "\n", |
201 | | - " draw_background(canvas, drawarea, unscale_x, unscale_y)\n", |
| 218 | + " draw_background(canvas[0], drawarea, unscale_x, unscale_y)\n", |
202 | 219 | "\n", |
203 | 220 | " # Draw heatmap\n", |
204 | 221 | " n_marks = min(x.shape[0], y.shape[0])\n", |
205 | 222 | "\n", |
206 | 223 | " for x_idx in range(1, color.shape[0] - 1):\n", |
207 | 224 | " for y_idx in range(1, color.shape[1] - 1):\n", |
208 | | - " canvas.fill_style = colormap(color[x_idx][y_idx])\n", |
| 225 | + " canvas[1].fill_style = colormap(color[x_idx][y_idx])\n", |
209 | 226 | "\n", |
210 | 227 | " rect_center = (scale_x(x[x_idx]), scale_y(y[y_idx]))\n", |
211 | 228 | " neighbours_x = (scale_x(x[x_idx - 1]), scale_x(x[x_idx + 1]))\n", |
|
217 | 234 | " width = rect_low_right_corner[0] - rect_top_left_corner[0]\n", |
218 | 235 | " height = rect_low_right_corner[1] - rect_top_left_corner[1]\n", |
219 | 236 | "\n", |
220 | | - " canvas.fill_rect(\n", |
| 237 | + " canvas[1].fill_rect(\n", |
221 | 238 | " rect_top_left_corner[0], rect_top_left_corner[1],\n", |
222 | 239 | " width, height\n", |
223 | 240 | " )\n", |
224 | 241 | "\n", |
225 | | - " canvas.restore()\n", |
| 242 | + " canvas[1].restore()\n", |
226 | 243 | "\n", |
227 | 244 | " return canvas" |
228 | 245 | ] |
|
243 | 260 | "n_points = 1_000" |
244 | 261 | ] |
245 | 262 | }, |
| 263 | + { |
| 264 | + "cell_type": "markdown", |
| 265 | + "metadata": {}, |
| 266 | + "source": [ |
| 267 | + "### Scatter marks are clickable! Try clicking on them" |
| 268 | + ] |
| 269 | + }, |
246 | 270 | { |
247 | 271 | "cell_type": "code", |
248 | 272 | "execution_count": null, |
|
271 | 295 | "metadata": {}, |
272 | 296 | "outputs": [], |
273 | 297 | "source": [ |
274 | | - "plot.stroke_style = 'red'\n", |
275 | | - "plot.line_width = 2\n", |
276 | | - "plot.stroke_rect(200, 300, 50, 100)" |
| 298 | + "plot[1].stroke_style = 'red'\n", |
| 299 | + "plot[1].line_width = 2\n", |
| 300 | + "plot[1].stroke_rect(200, 300, 50, 100)" |
277 | 301 | ] |
278 | 302 | }, |
279 | 303 | { |
|
0 commit comments