The Tkinter Canvas widget provides a drawable area for graphics and interactive objects. It can display text, lines, rectangles, ovals, arcs, polygons, bitmaps and images.
Canvas items can also be moved, resized, recolored, hidden, deleted and connected to mouse events. This makes Canvas useful for diagrams, dashboards, animations, drawing tools, games and other graphical interfaces.

(0, 0). The x-coordinate increases toward the right and the y-coordinate increases downward.import tkinter as tk
root=tk.Tk()
root.geometry('300x250')
canvas=tk.Canvas(root, width=200, height=200, bg='white')
canvas.pack(padx=20, pady=20)
root.mainloop()
width and height specify the requested Canvas size in pixels.

Most Canvas drawing methods use x and y coordinates.
(x, y)
For a normal Canvas:
(0, 0) is at the top-left,For example:
canvas.create_line(20, 50, 180, 50)
draws a horizontal line because both points use the same y-coordinate.
import tkinter as tk
root=tk.Tk()
canvas=tk.Canvas(root, width=350, height=150)
canvas.pack()
canvas.create_text(175, 40, text='Welcome to plus2net.com', fill='#606060', font=('Times', 22, 'bold'))
root.mainloop()

Coordinates normally identify the center of Canvas text. Use anchor when another reference point is required.
canvas.create_text(10, 10, text='Top Left', anchor='nw')
canvas.create_text(100, 100, text='Vertical', angle=90)
import tkinter as tk
root=tk.Tk()
canvas=tk.Canvas(root, width=200, height=120)
canvas.pack()
canvas.create_line(10, 60, 190, 60, fill='#ff00ff', width=5)
root.mainloop()

canvas.create_line(10, 50, 180, 50, arrow='last')
Common values are:
'first'
'last'
'both'
A line can contain several coordinate pairs.
canvas.create_line(10, 100, 60, 20, 110, 100, 160, 20)
A rectangle is defined by two opposite corners.
canvas.create_rectangle(30, 30, 150, 100, fill='#c0c0c0', outline='black')

The coordinates represent:
(x1, y1, x2, y2)
An oval is drawn inside a rectangular bounding box.
canvas.create_oval(25, 25, 140, 100, fill='#c0c0c0')

A circle is produced when the bounding box has equal width and height.
def create_circle(canvas, x, y, radius, **options):
return canvas.create_oval(x-radius, y-radius, x+radius, y+radius, **options)
circle=create_circle(canvas, 80, 80, 30, fill='lightblue')

An arc also uses a bounding box.
canvas.create_arc(10, 10, 140, 140, start=15, extent=220, fill='#c0c0c0')


start specifies the starting angle and extent specifies how many degrees the arc covers.
style=tk.PIESLICE
style=tk.ARC
style=tk.CHORD
Example:
canvas.create_arc(20, 20, 140, 140, start=0, extent=180, style=tk.ARC, width=4)
Pass a sequence of x-y coordinate pairs.
canvas.create_polygon(5, 40, 15, 120, 130, 70, 35, 5, fill='#c0c0c0')

import tkinter as tk
root=tk.Tk()
canvas=tk.Canvas(root, width=300, height=200)
canvas.pack()
photo=tk.PhotoImage(file='icon-dwn.png')
image_id=canvas.create_image(20, 20, image=photo, anchor='nw')
root.mainloop()
PhotoImage in a variable such as photo. If Python garbage-collects the image object, the Canvas image can disappear.import tkinter as tk
from PIL import Image, ImageTk
root=tk.Tk()
canvas=tk.Canvas(root, width=400, height=300)
canvas.pack()
image=Image.open('photo.jpg')
photo=ImageTk.PhotoImage(image)
canvas.create_image(0, 0, image=photo, anchor='nw')
root.mainloop()
import tkinter as tk
root=tk.Tk()
canvas=tk.Canvas(root, width=200, height=150)
canvas.pack()
canvas.create_bitmap(50, 50, bitmap='question')
root.mainloop()

A Canvas can embed another Tkinter widget by creating a window item.
button=tk.Button(root, text='Click Me')
window_id=canvas.create_window(100, 80, window=button)
This is different from placing a normal widget over the Canvas with grid(), pack() or place(). The embedded widget becomes a Canvas window item and participates in Canvas positioning.
Every create_*() method returns an item ID.
rectangle=canvas.create_rectangle(20, 20, 120, 80, fill='yellow')
print(rectangle)
The ID can later be used to modify, move or delete that specific Canvas item.
circle=canvas.create_oval(30, 30, 100, 100, fill='red', tags=('circle', 'shape'))
A tag can identify one item or a group of items.
canvas.itemconfig('shape', state='hidden')
This can affect all items carrying the shape tag.
canvas.itemconfig(rectangle, fill='lightblue', outline='navy')
print(canvas.coords(rectangle))
Sample Output
[20.0, 20.0, 120.0, 80.0]
Set new coordinates:
canvas.coords(rectangle, 50, 50, 180, 120)
canvas.move(rectangle, 20, 10)
This moves the item 20 pixels right and 10 pixels down.
print(canvas.bbox(rectangle))
canvas.delete(rectangle)
canvas.delete('all')
coords() to read or replace coordinates. Use move() when the item should shift relative to its current position.Available options depend on the type of Canvas item.
| Option | Purpose |
|---|---|
fill | Fill or text color, depending on the item type. |
outline | Outline color for shapes such as rectangles, ovals and polygons. |
width | Line or outline width. |
dash | Dash pattern for supported lines and outlines. |
stipple | Bitmap pattern used instead of a solid fill for supported items. |
state | Usually normal, disabled or hidden for Canvas items. |
tags | Assign one or more names used to manipulate groups of items. |
activefill | Fill used while the mouse pointer is over a supported item. |
activeoutline | Outline used while a supported item is active. |
activewidth | Width used while a supported item is active. |
activestipple | Stipple pattern used while supported item is active. |
disabledfill | Fill used when a supported item is disabled. |
disabledoutline | Outline used when a supported item is disabled. |
outline makes sense for shapes such as rectangles and ovals but not for ordinary text in the same way.The Canvas widget itself also has configuration options separate from the items drawn inside it.
| Option | Purpose |
|---|---|
width | Requested Canvas width. |
height | Requested Canvas height. |
background / bg | Canvas background color. |
borderwidth | Canvas border width. |
relief | Canvas widget border style such as flat, raised or sunken. |
cursor | Mouse cursor over the Canvas. |
scrollregion | Defines the scrollable Canvas coordinate area. |
xscrollcommand | Connects a horizontal Scrollbar. |
yscrollcommand | Connects a vertical Scrollbar. |
print(canvas.config().keys())
for option in canvas.config():
print(option, ':', canvas[option])
This rectangle uses one fill pattern normally and another while the mouse pointer is over it.
import tkinter as tk
root=tk.Tk()
canvas=tk.Canvas(root, width=400, height=400)
canvas.pack()
canvas.create_rectangle(20, 20, 380, 380, fill='#ff6347', stipple='gray50', activefill='#ffd700', activestipple='gray25')
text="fill='#ff6347'\nstipple='gray50'\nactivefill='#ffd700'\nactivestipple='gray25'"
canvas.create_text(200, 200, text=text, fill='darkblue', font=('Arial', 14, 'bold'))
root.mainloop()

import tkinter as tk
root=tk.Tk()
root.geometry('430x450')
canvas=tk.Canvas(root, width=400, height=400, bg='lightgreen')
canvas.grid(row=0, column=0, padx=5, pady=10)
canvas.create_text(290, 50, text='Welcome to plus2net', fill='#606060', font=('Times', 16, 'bold'))
rectangle=canvas.create_rectangle(60, 20, 180, 80)
canvas.create_oval(180, 90, 390, 200, fill='gray', dash=(25, 5, 1, 10), activedash=(50, 10), stipple='gray75', width=5, activestipple='gray25')
canvas.create_line(10, 10, 50, 50, arrow='last')
canvas.create_arc(50, 85, 180, 240, start=45, extent=135, fill='red')
canvas.create_polygon(35, 160, 70, 390, 180, 310, 260, 350, 200, 250, fill='yellow')
photo=tk.PhotoImage(file='top2.png')
canvas.create_image(315, 375, image=photo)
root.mainloop()
Create an image item at the top-left of the Canvas.
background=tk.PhotoImage(file='bg2.png')
canvas=tk.Canvas(root, width=1000, height=500)
canvas.grid(row=0, column=0)
background_id=canvas.create_image(0, 0, image=background, anchor='nw')
Other Canvas items created later appear above the background image.
canvas.tag_lower(background_id)
create_window(). A Canvas image alone does not turn Canvas into a Frame-style widget container.
import tkinter as tk
import tkinter.font as tkfont
def button_press(event):
event.widget.config(relief='sunken')
message_var.set('Hi and welcome to plus2net')
def button_release(event):
event.widget.config(relief='raised')
root=tk.Tk()
root.geometry('400x250')
font=tkfont.nametofont('TkDefaultFont')
text='plus2net '
height=font.measure(text)+10
width=font.metrics()['linespace']+10
canvas=tk.Canvas(root, height=height, width=width, background='SystemButtonFace', borderwidth=2, relief='raised')
canvas.create_text(4, 4, angle=90, anchor='ne', text=text, fill='SystemButtonText', font=font)
canvas.grid(row=0, column=0, padx=20, pady=20)
message_var=tk.StringVar(value='Welcome')
tk.Label(root, textvariable=message_var, font=('Times', 20)).grid(row=0, column=1, padx=5)
canvas.bind('<ButtonPress-1>', button_press)
canvas.bind('<ButtonRelease-1>', button_release)
root.mainloop()
import tkinter as tk
root=tk.Tk()
root.geometry('400x300')
root.rowconfigure(0, weight=1)
root.columnconfigure(0, weight=1)
canvas=tk.Canvas(root, bg='lightblue')
canvas.grid(row=0, column=0, sticky='nsew')
canvas.create_oval(50, 50, 150, 150, fill='yellow', outline='black')
root.mainloop()
sticky='nsew' allows the Canvas widget to expand with its grid cell.
The Canvas becoming larger does not automatically scale the coordinates or sizes of existing Canvas items. Resizing drawn objects requires separate code if that behaviour is needed.
More on responsive rows and columnsimport tkinter as tk
root=tk.Tk()
root.geometry('620x350')
c1=tk.Canvas(root, width=180, height=180, bg='lightyellow')
c2=tk.Canvas(root, width=180, height=180, bg='lightgreen')
c3=tk.Canvas(root, width=180, height=180, bg='lightblue')
c1.grid(row=0, column=0, padx=10, pady=10)
c2.grid(row=0, column=1, padx=10, pady=10)
c3.grid(row=0, column=2, padx=10, pady=10)
c1.create_rectangle(30, 30, 150, 100, fill='red')
c2.create_oval(30, 30, 150, 150, fill='blue')
c3.create_polygon(30, 150, 90, 30, 150, 150, fill='orange')
root.mainloop()
tag_bind() connects events to a Canvas item ID or tag.
import tkinter as tk
def change_background(event, color):
canvas.config(bg=color)
root=tk.Tk()
root.geometry('320x250')
canvas=tk.Canvas(root, width=300, height=200, bg='white')
canvas.pack()
red_circle=canvas.create_oval(30, 50, 100, 120, fill='red', outline='black')
green_circle=canvas.create_oval(115, 50, 185, 120, fill='green', outline='black')
blue_circle=canvas.create_oval(200, 50, 270, 120, fill='blue', outline='black')
canvas.tag_bind(red_circle, '<Button-1>', lambda event: change_background(event, 'red'))
canvas.tag_bind(green_circle, '<Button-1>', lambda event: change_background(event, 'green'))
canvas.tag_bind(blue_circle, '<Button-1>', lambda event: change_background(event, 'blue'))
root.mainloop()
The Canvas background changes to the color of the clicked circle.
canvas.create_rectangle(20, 20, 100, 80, fill='yellow', tags='clickable')
canvas.create_oval(120, 20, 200, 100, fill='lightblue', tags='clickable')
canvas.tag_bind('clickable', '<Button-1>', callback)
Both items now use the same event binding.
A Canvas can represent an area larger than its visible window.
import tkinter as tk
from tkinter import ttk
root=tk.Tk()
canvas=tk.Canvas(root, width=400, height=250, scrollregion=(0, 0, 1000, 800))
canvas.grid(row=0, column=0)
vs=ttk.Scrollbar(root, orient='vertical', command=canvas.yview)
hs=ttk.Scrollbar(root, orient='horizontal', command=canvas.xview)
canvas.config(yscrollcommand=vs.set, xscrollcommand=hs.set)
vs.grid(row=0, column=1, sticky='ns')
hs.grid(row=1, column=0, sticky='ew')
canvas.create_rectangle(700, 500, 900, 700, fill='lightblue')
root.mainloop()
After creating Canvas items:
canvas.config(scrollregion=canvas.bbox('all'))
This uses the bounding box of all Canvas items as the scrolling region.
After learning the Canvas basics, choose the next tutorial based on what you want to build.
Moving by:
canvas.move(item, 0, 10)
moves the item downward, not upward.
Keep the image object in a variable for as long as the Canvas image is needed.
Use tk.PhotoImage for supported image formats. Use Pillow when image loading or processing requires it, such as common JPEG workflows.
relief configures the Canvas widget itself:
canvas.config(relief='raised')
It is not a rectangle or oval item option.
Canvas item configuration depends on item type.
Store it when the item will later be updated or moved.
rectangle=canvas.create_rectangle(20, 20, 100, 80)
coords() reads or replaces coordinates. move() shifts an item by a relative amount.
If the Canvas widget expands with the window, existing shapes retain their Canvas coordinates unless your program changes them.
Use create_window() when a Tkinter widget should be embedded as a Canvas item.
Prefer project-relative paths:
photo=tk.PhotoImage(file='images/icon.png')
instead of a machine-specific path such as D:\....
(0, 0).create_text() adds text.create_line() creates straight or multi-segment lines.create_rectangle() draws a rectangle from two opposite corners.create_oval() draws an ellipse inside a bounding box.create_arc() draws part of an oval.create_polygon() creates a shape from several coordinate pairs.create_image() places an image on the Canvas.PhotoImage objects.create_bitmap() displays bitmap resources.create_window() embeds another Tkinter widget as a Canvas item.create_*() method returns an item ID.itemconfig() changes an existing item's options.coords() reads or replaces item coordinates.move() shifts an item relative to its current position.bbox() returns a visual bounding box.delete() removes Canvas items.tag_bind() connects mouse events to items or tags.scrollregion, xview and yview support scrolling through larger Canvas areas.Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.