How to draw an arc on a tkinter canvas?

0 votes
asked Sep 10, 2017 by abhera

I'm studying automata theory and I was requested to program the graph (tree) of an automaton that looks more or less like:

this

So far I got this (I'm using tkinter and canvas to draw):

from tkinter import Tk, Canvas, mainloop

def circle(canvas, x, y, r, width):
   id = canvas.create_oval (x-r, y-r, x+r, y+r, width = width)
   return id

def line (canvas, x1, y1, x2, y2, width):
    canvas.create_line (x1, y1, x2, y2, width = width)

def text (canvas, x, y, text):
    canvas.create_text (x, y, text = text, font = ("bold", 20))

w = Canvas(Tk (), width=1000, height=600, bg = "white")

circle (w , 150, 300, 70, 3)
circle (w , 150, 300, 50, 3)
circle (w , 370, 300, 70, 3)
circle (w , 640, 300, 70, 3)
circle (w , 910, 300, 70, 3)

line (w, 10, 300, 80, 300, 3)
circle (w, 73, 300, 5, 6)
line (w, 220, 300, 300, 300, 3)
circle (w, 293, 300, 5, 6)
line (w, 440, 300, 570, 300, 3)
circle (w, 567, 300, 5, 6)
line (w, 710, 300, 840, 300, 3)
circle (w, 837, 300, 5, 6)

text (w, 150, 300, "q0")
text (w, 370, 300, "q1")
text (w, 640, 300, "q2")
text (w, 910, 300, "q3")

w.pack()
mainloop()

Which displays this:

screenshot of image created by current code

I don't need the arrows, because I will use dots instead. The problem is that I need to draw a line from circle q3 to circle q0, and from circle q0 to circle q0, too (a "buckle"). I tried the canvas.create_arc() method, but I can't get the handle of it. Is there an alternative? Any ideas on how to draw the "buckle"?

1 Answer

0 votes
answered Sep 12, 2017 by martineau

Here's some utility functions that provide an alternative way draw arcs on a tkinter.Canvas. Instead of the usual specification of two-points, (x0, y0) and (x1, y1) to define an enclosing rectangle, the arc functions accept a starting and stopping angle in the open range of [0..360) degrees.

It also illustrates how to have arrowheads drawn at the ends of straight lines (but not arcs) since you asked about that, too.

from tkinter import Canvas, mainloop, Tk

def circle(canvas, x, y, r, width):
    return canvas.create_oval(x+r, y+r, x-r, y-r, width=width)

def circular_arc(canvas, x, y, r, t0, t1, width):
    return canvas.create_arc(x-r, y-r, x+r, y+r, start=t0, extent=t1-t0,
                             style='arc', width=width)

def ellipse(canvas, x, y, r1, r2, width):
    return canvas.create_oval(x+r1, y+r2, x-r1, y-r2, width=width)

def elliptical_arc(canvas, x, y, r1, r2, t0, t1, width):
    return canvas.create_arc(x-r1, y-r2, x+r1, y+r2, start=t0, extent=t1-t0,
                             style='arc', width=width)

def line(canvas, x1, y1, x2, y2, width, start_arrow=0, end_arrow=0):
    arrow_opts = start_arrow << 1 | end_arrow
    arrows = {0b10: 'first', 0b01: 'last', 0b11: 'both'}.get(arrow_opts, None)
    return canvas.create_line(x1, y1, x2, y2, width=width, arrow=arrows)

def text(canvas, x, y, text):
    return canvas.create_text(x, y, text=text, font=('bold', 20))


w = Canvas(Tk(), width=1000, height=600, bg='white')

circle(w, 150, 300, 70, 3)  # q0 outer edge
circle(w, 150, 300, 50, 3)  # q0 inner edge
circle(w, 370, 300, 70, 3)  # q1
circle(w, 640, 300, 70, 3)  # q2
circle(w, 910, 300, 70, 3)  # q3

# Draw arc from circle q3 to q0.
midx, midy = (150+910) / 2, 300
r1, r2 = 910-midx, 70+70
elliptical_arc(w, midx, midy, r1, r2, 30, 180-30, 3)

line(w,  10, 300,  80, 300, 3, end_arrow=1)
line(w, 220, 300, 300, 300, 3, end_arrow=1)
line(w, 440, 300, 570, 300, 3, end_arrow=1)
line(w, 710, 300, 840, 300, 3, end_arrow=1)

text(w, 150, 300, 'q0')
text(w, 370, 300, 'q1')
text(w, 640, 300, 'q2')
text(w, 910, 300, 'q3')

w.pack()
mainloop()

This is what it draws:

screenshot showing output

It doesn't draw a "buckle" like you want partly because drawing "a line from circle q3 to circle q0, and from circle q0 to circle q0" isn't like the illustration at the beginning of your question which is one drawn between two circles (if I understand correctly what you meant by the term).

However, it does provide another way for you to draw arcs on a canvas.

Welcome to Q&A, where you can ask questions and receive answers from other members of the community.
Website Online Counter

...