<jupyter_start><jupyter_text>`ipycanvas`provides the [Web-Canvas-API](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API). However, there are some differences:* The Canvas widget exposes the [CanvasRenderingContext2D](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D) API directly* The entire API is written in `snake_case` instead of `camelCase`, so for example `canvas.fillStyle = 'red'` written in Python becomes `canvas.fill_style = 'red'` in JavaScript.  Installation```$ pipenv install ipycanvasInstalling ipycanvas……```  Creating canvas elementsBefore we can start creating canvas elements, first a note about the canvas grid. The origin of a grid is in the upper left corner at the coordinate `(0,0)`. All elements are placed relative to this origin.There are four methods of drawing rectangles:* `fill_rect(x, y, width, height=None)` draws a filled rectangle* `stroke_rect(x, y, width, height=None)` draws a rectangular outline* `fill_rects(x, y, width, height=None)` draws filled rectangles* `stroke_rects(x, y, width, height=None)` draws rectangular outlinesWith `height=None`, the same value is used as with `width`.For `*_rects`, `x`, `y`, `width` and `height` are integers, lists of integers or numpy arrays.<jupyter_code>from ipycanvas import Canvas

canvas = Canvas(size=(120, 100))
canvas.fill_style = 'lime'
canvas.stroke_style = 'green'

canvas.fill_rect(10, 20, 100, 50)
canvas.stroke_rect(10, 20, 100, 50)

canvas
from ipycanvas import MultiCanvas

# Create a multi-layer canvas with 2 layers
multi_canvas = MultiCanvas(2, size=(165, 115))
multi_canvas[0] #  Access first layer (background)
multi_canvas[0].fill_style = 'lime'
multi_canvas[0].stroke_style = 'green'
multi_canvas[0].fill_rect(10, 20, 100, 50)
multi_canvas[0].stroke_rect(10, 20, 100, 50)

multi_canvas[1] #  Access last layer
multi_canvas[1].fill_style = 'red'
multi_canvas[1].stroke_style = 'brown'
multi_canvas[1].fill_rect(55, 45, 100, 50)
multi_canvas[1].stroke_rect(55, 45, 100, 50)

multi_canvas
import numpy as np

from ipycanvas import Canvas

n_particles = 75_000

x = np.array(np.random.rayleigh(350, n_particles), dtype=np.int32)
y = np.array(np.random.rayleigh(150, n_particles), dtype=np.int32)
size = np.random.randint(1, 3, n_particles)

canvas = Canvas(size=(1000, 500))

canvas.fill_style = 'green'
canvas.fill_rects(x, y, size)

canvas<jupyter_output><empty_output><jupyter_text>Since `Canvas` is an [ipywidget](https://ipywidgets.readthedocs.io/en/stable/), it can* appear several times in a notebook* change the attributes* Link changed attributes to other widget attributes  Delete canvas<jupyter_code>from ipycanvas import Canvas

canvas = Canvas(size=(120, 100))
# Perform some drawings…
canvas.clear()
from ipycanvas import Canvas

canvas = Canvas(size=(165, 115))

canvas.fill_style = 'lime'
canvas.stroke_style = 'brown'

canvas.fill_rect(10, 20, 100, 50)
canvas.clear_rect(52, 42, 100, 50)
canvas.stroke_rect(55, 45, 100, 50)

canvas<jupyter_output><empty_output><jupyter_text>ShapesThe available drawing commands are:* `move_to(x, y)`: * `line_to(x, y)`: * `arc(x, y, radius, start_angle, end_angle, anticlockwise=False)`: * `arc_to(x1, y1, x2, y2, radius)`: * `quadratic_curve_to(cp1x, cp1y, x, y)`: * `bezier_curve_to(cp1x, cp1y, cp2x, cp2y, x, y)`: * `rect(x, y, width, height)`:   Draw circlesThere are four different ways to draw circles:* `fill_arc(x, y, radius, start_angle, end_angle, anticlockwise=False)`* `stroke_arc(x, y, radius, start_angle, end_angle, anticlockwise=False)`* `fill_arcs(x, y, radius, start_angle, end_angle, anticlockwise=False)`* `stroke_arcs(x, y, radius, start_angle, end_angle, anticlockwise=False)`With `*_arcs`, `x`, `y` and `radius` are NumPy arrays, lists or scalar values.<jupyter_code>from math import pi

from ipycanvas import Canvas

canvas = Canvas(size=(200, 200))

canvas.fill_style = 'red'
canvas.stroke_style = 'green'

canvas.fill_arc(60, 60, 50, 0, pi)
canvas.stroke_arc(60, 60, 40, 0, 2 * pi)

canvas<jupyter_output><empty_output><jupyter_text>Drawing pathsA path is a list of points connected by line segments that can be different shapes, straight or curved, closed or open, different widths and colors. The following functions are available:     begin_path ()      close_path () adds a straight line to the path leading to the beginning of the current path     stroke () draws the shape along the contour     fill (rule) draws the shape using a fill within the path     * `begin_path()` creates a new path* `close_path()` adds a straight line to the path leading to the beginning of the current path* `stroke()` draws the shape along the contour* `fill(rule)` draws the shape using a fill within the path<jupyter_code>from ipycanvas import Canvas

canvas = Canvas(size=(100, 100))

# Draw simple triangle shape
canvas.begin_path()
canvas.move_to(75, 50)
canvas.line_to(100, 75)
canvas.line_to(100, 25)
canvas.fill()

canvas<jupyter_output><empty_output><jupyter_text>Examples  `arc`<jupyter_code>from math import pi

from ipycanvas import Canvas

canvas = Canvas(size=(200, 200))

# Draw smiley face
canvas.begin_path()
canvas.arc(75, 75, 50, 0, pi * 2, True) # Outer circle
canvas.move_to(110, 75)
canvas.arc(75, 75, 35, 0, pi, False) # Mouth (clockwise)
canvas.move_to(65, 65)
canvas.arc(60, 65, 5, 0, pi * 2, True) # Left eye
canvas.move_to(95, 65)
canvas.arc(90, 65, 5, 0, pi * 2, True) # Right eye
canvas.stroke()

canvas<jupyter_output><empty_output><jupyter_text>`bezier_curve_to`<jupyter_code>from ipycanvas import Canvas

canvas = Canvas(size=(200, 200))

# Cubic curves example
canvas.begin_path()
canvas.move_to(75, 40)
canvas.bezier_curve_to(75, 37, 70, 25, 50, 25)
canvas.bezier_curve_to(20, 25, 20, 62.5, 20, 62.5)
canvas.bezier_curve_to(20, 80, 40, 102, 75, 120)
canvas.bezier_curve_to(110, 102, 130, 80, 130, 62.5)
canvas.bezier_curve_to(130, 62.5, 130, 25, 100, 25)
canvas.bezier_curve_to(85, 25, 75, 37, 75, 40)
canvas.fill()

canvas<jupyter_output><empty_output><jupyter_text>Styles and colors  Colors`Canvas`  has two color attributes, one for strokes and one for areas; the transparency can also be changed.* `stroke_style` expects a valid HTML color. The default is black.* `fill_style`  expects a valid HTML color. The default is black.* `global_alpha` indicates the transparency. The default is 1.0.  Lines  Line styleLines can be described by the following attributes:* `line_width`* `line_cap`* `line_join`* `miter_limit`* `get_line_dash()`* `set_line_dash(segments)`* `line_dash_offset`  Line width<jupyter_code>from ipycanvas import Canvas

canvas = Canvas(size=(400, 280))
canvas.scale(2)

for i in range(10):
    width = 1 + i
    x = 5 + i * 20
    canvas.line_width = width

    canvas.fill_text(str(width), x - 5, 15)

    canvas.begin_path()
    canvas.move_to(x, 20)
    canvas.line_to(x, 140)
    canvas.stroke()
canvas<jupyter_output><empty_output><jupyter_text>Line end<jupyter_code>from ipycanvas import Canvas

canvas = Canvas(size=(320, 360))

# Possible line_cap values
line_caps = ['butt', 'round', 'square']

canvas.scale(2)

# Draw guides
canvas.stroke_style = '#09f'
canvas.begin_path()
canvas.move_to(10, 30)
canvas.line_to(140, 30)
canvas.move_to(10, 140)
canvas.line_to(140, 140)
canvas.stroke()

# Draw lines
canvas.stroke_style = 'black'
canvas.font = '15px serif'

for i in range(len(line_caps)):
    line_cap = line_caps[i]
    x = 25 + i * 50

    canvas.fill_text(line_cap, x - 15, 15)
    canvas.line_width = 15
    canvas.line_cap = line_cap
    canvas.begin_path()
    canvas.move_to(x, 30)
    canvas.line_to(x, 140)
    canvas.stroke()

canvas<jupyter_output><empty_output><jupyter_text>Line connectiondefines the appearance of the corners where lines meet.<jupyter_code>from ipycanvas import Canvas

canvas = Canvas(size=(320, 360))

# Possible line_join values
line_joins = ['round', 'bevel', 'miter']

min_y = 40
max_y = 80
spacing = 45

canvas.line_width = 10
canvas.scale(2)
for i in range(len(line_joins)):
    line_join = line_joins[i]

    y1 = min_y + i * spacing
    y2 = max_y + i * spacing

    canvas.line_join = line_join

    canvas.fill_text(line_join, 60, y1 - 10)

    canvas.begin_path()
    canvas.move_to(-5, y1)
    canvas.line_to(35, y2)
    canvas.line_to(75, y1)
    canvas.line_to(115, y2)
    canvas.line_to(155, y1)
    canvas.stroke()

canvas<jupyter_output><empty_output><jupyter_text>Line pattern<jupyter_code>from ipycanvas import Canvas

canvas = Canvas(size=(400, 280))
canvas.scale(2)

line_dashes = [
    [5, 10],
    [10, 5],
    [5, 10, 20],
    [10, 20],
    [20, 10],
    [20, 20]
]

canvas.line_width = 2

for i in range(len(line_dashes)):
    x = 5 + i * 20

    canvas.set_line_dash(line_dashes[i])
    canvas.begin_path()
    canvas.move_to(x, 0)
    canvas.line_to(x, 140)
    canvas.stroke()
canvas<jupyter_output><empty_output><jupyter_text>textThere are two methods of designing text:* `fill_text(text, x, y, max_width=None)`* `stroke_text(text, x, y, max_width=None)`<jupyter_code>from ipycanvas import Canvas

canvas = Canvas(size=(400, 50))

canvas.font = '32px serif'
canvas.fill_text('Drawing from Python is cool!', 10, 32)
canvas
from ipycanvas import Canvas

canvas = Canvas(size=(400, 50))

canvas.font = '32px serif'
canvas.stroke_text('Hello There!', 10, 32)
canvas<jupyter_output><empty_output><jupyter_text>font indicates the current text style. The default value is "12px sans-serif".     text_align specifies the text alignment. Possible values are "start", "end", "left", "right" or "center".     text_baseline indicates the alignment with the baseline. Possible values are "top", "hanging", "middle", "alphabetic", "ideographic" and "bottom". The default value is "alphabetic".     direction indicates the text direction. Possible values are "ltr", "rtl", "inherit". The default value is "inherit".Of course, fill_style and stroke_style can also be used to color the text.* `font` indicates the current text style. The default value is `"12px sans-serif"`.* `text_align` specifies the text alignment. Possible values are `"start"`, `"end"`, `"left"`, `"right"` or `"center"` .* `text_baseline` indicates the alignment with the baseline. Possible values are `"top"`, `"hanging"`, `"middle"`, `"alphabetic"`, `"ideographic"` and `"bottom"`. The default value is `"alphabetic"`.* `direction` indicates the text direction. Possible values are `"ltr"`, `"rtl"`, `"inherit"`. The default value is `"inherit"`. Of course, `fill_style` and `stroke_style` can also be used to color the text.  Images  … from a Numpy arrayWith `put_image_data(image_data, dx, dy)` an image can be displayed, where `image_data` specifies a Numpy array and `dx` and `dy` the upper left corner of the image.<jupyter_code>import numpy as np

from ipycanvas import Canvas

x = np.linspace(-1, 1, 600)
y = np.linspace(-1, 1, 600)

x_grid, y_grid = np.meshgrid(x, y)

blue_channel = np.array(np.sin(x_grid**2 + y_grid**2) * 255, dtype=np.int32)
red_channel = np.zeros_like(blue_channel) + 200
green_channel = np.zeros_like(blue_channel) + 50

image_data = np.stack((red_channel, blue_channel, green_channel), axis=2)

canvas = Canvas(size=(image_data.shape[0], image_data.shape[1]))
canvas.put_image_data(image_data, 0, 0)

canvas<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1273551368645574, 'fraction_numerical': 0.04772484891574831, 'mean_word_length': 5.375637393767706, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 49, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '12', 'dir': 'jupyter-structured-clean-dedup', 'id': '574909', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 4420, 'n_tokens_neox': 3926, 'n_words': 1168, 'path': 'docs/workspace/jupyter/ipywidgets/libs/ipycanvas.ipynb', 'repo_name': 'hofmannedv/jupyter-tutorial', 'size': '11252'}