Search code examples
pythonuser-interfacetkinterscale

Any way to scale up points (x, y) in Python tkinter gui?


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:

enter image description here

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?


Solution

  • 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:

    enter image description here

    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!)