"Create a rectangle with coordinates x1=15, y1=20, width=120, height=150"
Does it have to do something with the coordinates? Cause there's no 'height' option
from tkinter import *
window = Tk()
root.geometry("300x300")
canv = Canvas(window, width=200, height=250, bg="white")
canv.pack(pady=15)
coords = [15, 20, 0, 0]
rect = canvas.create_rectangle(coords, width=120)
window.mainloop()```
Yes, your coords define the positions of two opposite corners of the rectangle, [x1, y1, x2, y2]. You have the coordinates of the top left corner already, so you need to figure out the coordinates of the bottom right corner using the given height and width - you simply add these to the coordinates.
In this example you simply would change your coords from [15, 20, 0, 0] to [15, 20, 135, 170].
One thing to note is that the coordinate system in Tkinter is defined with (0,0) at the top left of the window, so a higher y coordinate means further down the window and higher x coordinate means further right.
The coordinates are how you define the height and width of the rectangle. No height definition is required.
This is from : https://pythonguides.com/python-tkinter-canvas/
Python Tkinter Canvas Rectangle
Python Tkinter Canvas has built-in features to create shapes.
To create a rectangle create_rectangle() method is used.
This method accepts 4 parameters x1, y1, x2, y2. Here x1 and y1 are the coordinates for the top left corner and x2 and y2 are the coordinates for the bottom right corner.
Related
I am working on the TSP problem and reading some points from a file (have to use the points I'm given) and want to plot the points on to a GUI. But the problem is that the points are all only 2 digit and when I plot them using the tkinter.Canvas(), they all look really smudged up and tiny, almost like they're overlapping on top of each other.
Like this:
I got the problem working but just want to use this GUI to show it working instead of outputting it all to the console but can't cause it just looks stupid even worse when the lines are being drawn. So is there some way I can scale up that canvas or modify the points some way to make them look better. Can I do really anything or am I just stuck throwing it all to the console?
Given nodes values centered at (0, 0) in any coordinate system, you need to manipulate the given coordinates to comply to what your screen and canvas needs to properly render the drawing
You can rescale your points by a scalar factor, then translate the origin to the center of the screen (or at any location for that matter), in order to visualize them more easily:
Maybe like this:
import tkinter as tk
WIDTH = 600
HEIGHT = 400
given_nodes = ((-1, -1), (-1, 1), (1, 1), (1, -1), (0, -1.5))
scale = 100
scaled_nodes = [(x * scale, y * scale) for x, y in given_nodes]
translated_to_center_nodes = [(x + WIDTH/2, y + HEIGHT/2) for x, y in scaled_nodes]
app = tk.Tk()
canvas = tk.Canvas(app, width=WIDTH, height=HEIGHT, bg='cyan')
canvas.pack()
# Draw connecting lines
line_nodes = translated_to_center_nodes + [translated_to_center_nodes[0]]
for idx, node in enumerate(line_nodes[:-1]):
x0, y0 = node
x1, y1 = line_nodes[idx+1]
canvas.create_line(x0, y0, x1, y1, fill='black')
# draw nodes
for node in translated_to_center_nodes:
x, y = node
dx, dy = 2, 2
canvas.create_oval(x-dx, y+dy, x+dx, y-dy, fill='white')
# draw origin & coordinate system at rescaled drawing scale
canvas.create_line(0, 0, 0 + scale, 0, width=9, fill='blue', arrow=tk.LAST)
canvas.create_line(0, 0, 0, scale, width=9, fill='blue', arrow=tk.LAST)
canvas.create_text(40, 40, text='SCALED\nCANVAS\nORIGIN')
# draw moved origin & coordinate system at rescaled drawing scale
canvas.create_line(0, HEIGHT/2, WIDTH, HEIGHT/2, fill='black', dash=(1, 3))
canvas.create_line(WIDTH/2, HEIGHT/2, WIDTH/2 + scale, HEIGHT/2, width=3, fill='black', arrow=tk.LAST)
canvas.create_line(WIDTH/2, 0, WIDTH/2, HEIGHT, fill='black', dash=(1, 3))
canvas.create_line(WIDTH/2, HEIGHT/2, WIDTH/2, HEIGHT/2 + scale, width=3, fill='black', arrow=tk.LAST)
canvas.create_text(WIDTH/2, HEIGHT/2, text='MOVED\nORIGIN')
if __name__ == '__main__':
app.mainloop()
This is commonly done with matrix multiplication and homogeneous coordinates (look it up), but the machinery needed to demonstrate a simple example is a little too heavy.
The process of using the coordinates of an object and drawing it at scale, at the proper place, maybe rotated of skewed is called instantiation (look it up too!)
from tkinter import *
window = Tk()
window.geometry('1000x1000')
window.configure(bg='black')
myCanvas = Canvas(window)
myCanvas.pack()
def create_circle(x, y, r, canvasName):
x0 = x - r
y0 = y - r
x1 = x + r
y1 = y + r
return canvasName.create_oval(x0, y0, x1, y1)
create_circle(100, 100, 50, myCanvas)
window.mainloop()
The output looks like this:
Why is there a white rectangle there? I am just trying to print a circle on a black canvas.
There are two bugs that are causing your problem:
1.Any default canvas's color are white.
2.The canvas also has a default highlight boarder which is also white.
To solve both of these problems you can change:
myCanvas = Canvas(window)
to
myCanvas = Canvas(window, bg='black',highlightthickness=0)
Then the white rectangle will disappear
if you want to keep the highlight boarder you can also change the color of the boarder using highlightbackground="black"
or any other desired color.
Finally, if you want to change the circle's color because the circle blends into the canvas color add: outline="white"
to when you make the oval
I have a simple ellipse (red) and I want to rotate the ellipse.
The following code only return flatten ellipse (blue) but it does not rotate:
import tkinter as tk
import numpy as np
import math
def rotate(points, angle):
new_points = list(points)
rad = angle * (math.pi/180)
cos_val = math.cos(rad)
sin_val = math.sin(rad)
for coords in new_points:
x_val = coords[0]
y_val = coords[1]
coords[0] = x_val * cos_val - y_val * sin_val
coords[1] = x_val * sin_val + y_val * cos_val
return new_points
window = tk.Tk()
window.geometry("500x300")
canvas = tk.Canvas(window, height=300, width=500)
canvas.grid(row=0, column=0, sticky='w')
# draw ellipse
size=80
x0,y0=100,100
width,height=0.25*size,0.5*size
x1,y1=x0+width,y0+height
xc=x0+width/2
yc=y0+height/2
ellipse = canvas.create_oval([x0, y0, x1,y1],fill='blue')
#draw rotated ellipse
coord1=canvas.coords(ellipse)
points=[[coord1[0],coord1[1]],[coord1[2],coord1[3]]]
point2=rotate(points,30)
coord2 = [item for sublist in point2 for item in sublist]
ellipse2 = canvas.create_oval(coord2,fill='red')
window.mainloop ()
Here is the result:
The red ellipse supposed to be rotated by 30 degree but instead of rotated, it just get flattened.
Question: How to rotate the ellipse in tkinter canvas?
Notes:
I am using python 3.6
I checked stackoverflow on similar question and it has no correct answer.
unlike polygon that we can simply rotate each vertices, ellipse has no vertex.
The oval item of tkinter canvas is not rotatable as an oval.
If you look at the docs, like effbot.org, you'll see that some items are created with a first position arg (a single point, like text), some with a bbox arg (two points, like rectangle and oval), and some with coords (variable, two or more points, like line and polygon).
You can rotate the coords items by (1) calculating new coords and (2) updating the item with the new coords, using the coords() method.
For the rest of the items, you're out of luck, except for text which supports an angle attribute which you can set with itemconfig(item, angle=new_angle)
But all hope is not lost. You can convert a rectangle or oval into a polygon (by creating a new polygon to replace your old bbox item, and then you'll be able to rotate the new item. With rectangle, it's easy-peasy. With oval, it's much trickier, as you have to simulate the oval using many, many polygon coordinates for it to look good.
There are 2 ways that I know of 1) plot every point on the edge of the ellipse. There are pages on the web that show how to calculate all of the points 2) save as an image and use tkinter's PIL library to rotate the image.
I've tried several ways to change the width of the blue rectangle in this example code. Nothing seems to work. In the code, "a" represents a float variable between 1.00, and 0.00. That value is used to calculate "b," which is the desired width of the blue rectangle in pixels. I have some fairly complicated code that generates that value, and at least that works. In order for the code to work, the width of the blue rectangle must rely on "b." I've tried "Canvas.itemconfig()," and it didn't work.
import tkinter
from tkinter import *
root = Tk()
root.maxsize(320,240) # Sets max size of window
root.minsize(320,240)
canvas_height = 23
canvas_width = 315
w = Canvas(root, width=canvas_width, height=canvas_height)
w.pack()
w.create_rectangle(5, canvas_height, canvas_width, 2, fill="yellow")
w.create_rectangle(5, canvas_height, canvas_width, 2, fill="blue")
a = 1.0 # More complicated code creates this float between 0.00 and 1.00. It is a percentage of the desired 'blue rectangle' width
b = int(a * canvas_width)
root.mainloop()
If anyone could help, I would greatly appreciate it!
P.s. I'm new to the Stackoverflow community, so please let me know if there's anything I can do to make my questions easier to answer.
The rectangle is defined by a couple of coordinates for opposite corners. Get the coordinates of the left edge, add the width to the x coordinate, and use that to set the coordinates of the right edge.
First, keep track of the object id so you can change it later:
blue = w.create_rectangle(5, canvas_height, canvas_width, 2, fill="blue")
To resize, get the coordinates...
x0, y0, x1, y1 = w.coords(blue)
Do some math...
x1 = x0 + b
And reset the coordinates
w.coords(blue, x0, y0, x1, y1)
I am using Tkinter to visualize my data points. My problem is that I cannot make the data points appear in the center of the canvas and meanwhile the canvas is big enough.
To make the canvas look good, I wish to fix it at around 800*600 (I think the unit is pixel). So I did the following:
class DisplayParticles(Canvas):
def __init__(self):
# Canvas
Canvas.__init__(self)
self.configure(width=800, height=600)
# Particles
self.particle_radius = 1
self.particle_color = 'red'
# User
self.user_radius = 4
self.user_color = 'blue'
self.ghost_color = None
However, my data to be plotted are in the unit of meter. Plus, they center around the origin (0, 0), which means that there are negative coordinates for both x and y.
Then when I plot them on the canvas I get something like this
Obviously, the data points were plotted in pixel!
I wish the canvas to be big enough on the screen and meanwhile the data are plotted in a proper scale centered at the canvas. (Place my origin (0, 0) at the canvas center)
How may I do that?
The visible center of the canvas can be changed by setting the scrollregion attribute. For example, if you set the scrollregion to (-400,-400, 400, 400) in a canvas that is 800 pixels wide, the coordinate 0,0 will appear in the center of the screen.
Here's an example that draws a square at 0,0, and which appears in the center of the screen:
import Tkinter as tk
class Example(tk.Frame):
def __init__(self,*args, **kwargs):
tk.Frame.__init__(self, *args, **kwargs)
self.canvas = tk.Canvas(width=800, height=800)
self.canvas.pack(side="top", fill="both", expand=True)
self.canvas.configure(scrollregion=(-400, -400, 400, 400))
self.canvas.create_rectangle(-10,-10,10,10, fill="red", outline="black")
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(side="top", fill="both", expand=True)
root.mainloop()
You can also use the xview_scroll and yview_scroll methods to move 0,0 into the center of the visible portion of the canvas. Instead of setting the scrollregion as in the above example, you can do this after creating your canvas:
self.canvas.xview_scroll(800, "units")
self.canvas.yview_scroll(800, "units")
This will programmatically scroll the canvas over and down 800 pixels, so that 0,0 is in the center of the screen.
Use the xview and yview methods to scroll the canvas view so the origin is in the center.
Scaling is not supported, so if you need that, you need to transform the source data, like Brionius suggests.
Your Canvas is not going to automatically scale to fit what you've drawn - you'll have to figure out what the proper size is and set it.
Also, Canvas coordinates will always start with (0, 0) in the upper left corner - no way to change that. That means you'll have to translate all the points you plot on the canvas. Luckily, that's easy:
width = ... # Determine the correct width
height = ... # Determine the correct height
self.configure(width=width, height=height)
coords = (-20, -30, 10, 60) # The coordinates of a shape you want to draw
# add width/2 and height/2 to x and y coordinates respectively so that the (0, 0) coordinate is shifted to the center of the canvas:
newCoords = (coords[0]+width/2, coords[1]+height/2, coords[2]+width/2, coords[3]+height/2)
self.create_oval(*newCoords) # Create the translated shape