views:

11581

answers:

8

So I'm looking for a pretty basic library in python where i can create a window, and then draw lines and basic shapes too it. Nothing too complex, just nice and simple. I figure theres lots of libraries out there that can do this, but I don't know any of them. Can anyone give me some recommendations?

Thanks

EDIT: Note that there are several answers describing different GUI toolkits with code snippets. Take a look at the various answers for a brief look into the various toolkits.

+15  A: 

Try the TK canvas that comes with TkInter. TkInter comes bundled as standard with the base Python system, so you don't have to go hunting down any third-party libraries. It's also pretty easy to learn and very portable as it runs on pretty much every platform supported by Python.

A little ferreting around on the web gives this code sample from Fredrick Lundh's web site.

from Tkinter import *

master = Tk()
w = Canvas(master, width=200, height=100)
w.pack()
w.create_line(0, 0, 200, 100)
w.create_line(0, 100, 200, 0, fill="red", dash=(4, 4))
w.create_rectangle(50, 25, 150, 75, fill="blue")

mainloop()
ConcernedOfTunbridgeWells
+1 for using standard module
Josip
+2  A: 

In the past I have used PyGTK, PyCairo (used PyGTK to create the window, but cairo to draw), PyGame and http://www.pyglet.org/. They are all worth a look. Personally, I'd probably use PyCairo with PyGTK, but it's a little effort compared to NXC's suggestion.

EDIT: Nowadays I'd probably use PyQt.

Dan
+8  A: 

wxPython is pretty easy to get up to speed with. The tutorial is fairly good, and it is cross-platform so your code will run on OSX, Linux and WinXP with little or no changes to it.

Here is a basic program to draw a circle in a window, from this site.

# draw lines, a rounded-rectangle and a circle on a wx.PaintDC() surface
# tested with Python24 and wxPython26     vegaseat      06mar2007
# Works with Python2.5 on OSX bcl 28Nov2008

import wx 

class MyFrame(wx.Frame): 
    """a frame with a panel"""
    def __init__(self, parent=None, id=-1, title=None): 
        wx.Frame.__init__(self, parent, id, title) 
        self.panel = wx.Panel(self, size=(350, 200)) 
        self.panel.Bind(wx.EVT_PAINT, self.on_paint) 
        self.Fit() 

    def on_paint(self, event):
        # establish the painting surface
        dc = wx.PaintDC(self.panel)
        dc.SetPen(wx.Pen('blue', 4))
        # draw a blue line (thickness = 4)
        dc.DrawLine(50, 20, 300, 20)
        dc.SetPen(wx.Pen('red', 1))
        # draw a red rounded-rectangle
        rect = wx.Rect(50, 50, 100, 100) 
        dc.DrawRoundedRectangleRect(rect, 8)
        # draw a red circle with yellow fill
        dc.SetBrush(wx.Brush('yellow'))
        x = 250
        y = 100
        r = 50
        dc.DrawCircle(x, y, r)


# test it ...
app = wx.PySimpleApp() 
frame1 = MyFrame(title='rounded-rectangle & circle') 
frame1.Center() 
frame1.Show() 
app.MainLoop()
Brian C. Lane
+1 Code samples showing off using the various systems is a ++good idea.
ConcernedOfTunbridgeWells
-1 for recommending a 20 Mb large framework just for doing some basic drawing, in a overcomplicated way. I agree wx is powerful and very useful in most cases. This is obviously not one of those cases.
Josip
Thanks for explaining the -1. Maybe you don't realize that wxPython is included by default on OSX and many Linux distributions.
Brian C. Lane
(Accepted) PyGame is not exactly small neither.
jetxee
+28  A: 

I'd definitely recommend pygame. Here is some code that does what you want:

import sys
#import and init pygame
import pygame
pygame.init() 

#create the screen
window = pygame.display.set_mode((640, 480)) 

#draw a line - see http://www.pygame.org/docs/ref/draw.html for more 
pygame.draw.line(window, (255, 255, 255), (0, 0), (30, 50))

#draw it to the screen
pygame.display.flip() 

#input handling (somewhat boilerplate code):
while True: 
   for event in pygame.event.get(): 
      if event.type == pygame.QUIT: 
          sys.exit(0) 
      else: 
          print event 
Claudiu
+1 for the code sample.
ConcernedOfTunbridgeWells
+1 for suggesting it simply because pygame is an awesome library with tons of easy to use examples and functions.
Manuel Ferreria
Thanks - I would have never thought of pygame for simple graphics - certainly simpler than opengl.
Martin Beckett
If you intend to publish your figures, you'll want to use library that supports anti-aliased drawing. In pygame, you can replace draw.line calls with draw.aaline to accomplish this. Another hack would be to draw figures on 4 X bigger canvas, and then scale it down on intended size.
Josip
Macports users beware, py-game has dependencies:[port-alldeps](http://code.activestate.com/recipes/576868) -> py-game* -> python24* libsdl* libsdl_mixer* libsdl_image* libsdl_ttf* smpeg* py-numeric* libsdl* -> xorg-libXext* xorg-libXrandr* xrender perl5* -> perl5.8* ...
Denis
+1. Also note that the event handling loop in SDL and pygame can be resource intensive if used the way it is in this code sample. To rectify this problem, add something like `pygame.time.wait(10)` to give up processor time to other processes.
avpx
Pygame is terrible. It's slow and limited.
Matthew Mitchell
I believe the line "if event.type == QUIT:" should read "if event.type == pygame.QUIT". Also there needs to be an "import sys" line in there somewhere before sys is used.
Bryce Thomas
@Bryce: fixed! Thanks for the heads up.
Claudiu
Pyglet >>>> Pygame. Though, it's easier to use. So, if you want to get something done really quickly, use pygame. If you are into a serious project, go for Pyglet, which is nicely designed and implemented.
Manuel
+5  A: 

A little digging and here's the scribble demo from the pygtk tutorial. Gtk started life on Unix/Linux but now has been ported to Windows and OSX. It has extensive support for theming - this theming support is baked into the system and is used to provide 'themes' that are actually wrappers for native widgets on the host O/S. Arguably GTK was the system that really popularised theming support in GUI toolkits.

This allows applications with a reasonably native look and feel on non-X11 systems.

This example is the scribble demo. It is perhaps a little long-winded, so add a comment pointing me to something a bit more terse and and I'll substitute that.

#!/usr/bin/env python

# example scribblesimple.py

 # GTK - The GIMP Toolkit
 # Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 # Copyright (C) 2001-2004 John Finlay
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Library General Public
 # License as published by the Free Software Foundation; either
 # version 2 of the License, or (at your option) any later version.
 #
 # This library is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 # Library General Public License for more details.
 #
 # You should have received a copy of the GNU Library General Public
 # License along with this library; if not, write to the
 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 # Boston, MA 02111-1307, USA.


import pygtk
pygtk.require('2.0')
import gtk

# Backing pixmap for drawing area
pixmap = None

# Create a new backing pixmap of the appropriate size
def configure_event(widget, event):
    global pixmap

    x, y, width, height = widget.get_allocation()
    pixmap = gtk.gdk.Pixmap(widget.window, width, height)
    pixmap.draw_rectangle(widget.get_style().white_gc,
                          True, 0, 0, width, height)

    return True

# Redraw the screen from the backing pixmap
def expose_event(widget, event):
    x , y, width, height = event.area
    widget.window.draw_drawable(widget.get_style().fg_gc[gtk.STATE_NORMAL],
                                pixmap, x, y, x, y, width, height)
    return False

# Draw a rectangle on the screen
def draw_brush(widget, x, y):
    rect = (int(x-5), int(y-5), 10, 10)
    pixmap.draw_rectangle(widget.get_style().black_gc, True,
                          rect[0], rect[1], rect[2], rect[3])
    widget.queue_draw_area(rect[0], rect[1], rect[2], rect[3])

def button_press_event(widget, event):
    if event.button == 1 and pixmap != None:
        draw_brush(widget, event.x, event.y)
    return True

def motion_notify_event(widget, event):
    if event.is_hint:
        x, y, state = event.window.get_pointer()
    else:
        x = event.x
        y = event.y
        state = event.state

    if state & gtk.gdk.BUTTON1_MASK and pixmap != None:
        draw_brush(widget, x, y)

    return True

def main():
    window = gtk.Window(gtk.WINDOW_TOPLEVEL)
    window.set_name ("Test Input")

    vbox = gtk.VBox(False, 0)
    window.add(vbox)
    vbox.show()

    window.connect("destroy", lambda w: gtk.main_quit())

    # Create the drawing area
    drawing_area = gtk.DrawingArea()
    drawing_area.set_size_request(200, 200)
    vbox.pack_start(drawing_area, True, True, 0)

    drawing_area.show()

    # Signals used to handle backing pixmap
    drawing_area.connect("expose_event", expose_event)
    drawing_area.connect("configure_event", configure_event)

    # Event signals
    drawing_area.connect("motion_notify_event", motion_notify_event)
    drawing_area.connect("button_press_event", button_press_event)

    drawing_area.set_events(gtk.gdk.EXPOSURE_MASK
                            | gtk.gdk.LEAVE_NOTIFY_MASK
                            | gtk.gdk.BUTTON_PRESS_MASK
                            | gtk.gdk.POINTER_MOTION_MASK
                            | gtk.gdk.POINTER_MOTION_HINT_MASK)

    # .. And a quit button
    button = gtk.Button("Quit")
    vbox.pack_start(button, False, False, 0)

    button.connect_object("clicked", lambda w: w.destroy(), window)
    button.show()

    window.show()

    gtk.main()

    return 0

if __name__ == "__main__":
    main()
ConcernedOfTunbridgeWells
+6  A: 

And here's a sample with PyQT taken from This tutorial at www.zetcode.com. QT is a cross-platform GUI toolkit with python bindings available from www.riverbankcomputing.com. It runs on Unix/Linux, Windows, OSX and there is also a version for smart phones.

#!/usr/bin/python

# colors.py

import sys, random
from PyQt4 import QtGui, QtCore


class Colors(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.setGeometry(300, 300, 350, 280)
        self.setWindowTitle('Colors')

    def paintEvent(self, event):
        paint = QtGui.QPainter()
        paint.begin(self)

        color = QtGui.QColor(0, 0, 0)
        color.setNamedColor('#d4d4d4')
        paint.setPen(color)

        paint.setBrush(QtGui.QColor(255, 0, 0, 80))
        paint.drawRect(10, 15, 90, 60)

        paint.setBrush(QtGui.QColor(255, 0, 0, 160))
        paint.drawRect(130, 15, 90, 60)

        paint.setBrush(QtGui.QColor(255, 0, 0, 255))
        paint.drawRect(250, 15, 90, 60)

        paint.setBrush(QtGui.QColor(10, 163, 2, 55))
        paint.drawRect(10, 105, 90, 60)

        paint.setBrush(QtGui.QColor(160, 100, 0, 255))
        paint.drawRect(130, 105, 90, 60)

        paint.setBrush(QtGui.QColor(60, 100, 60, 255))
        paint.drawRect(250, 105, 90, 60)

        paint.setBrush(QtGui.QColor(50, 50, 50, 255))
        paint.drawRect(10, 195, 90, 60)

        paint.setBrush(QtGui.QColor(50, 150, 50, 255))
        paint.drawRect(130, 195, 90, 60)

        paint.setBrush(QtGui.QColor(223, 135, 19, 255))
        paint.drawRect(250, 195, 90, 60)

        paint.end()

app = QtGui.QApplication(sys.argv)
dt = Colors()
dt.show()
app.exec_()
ConcernedOfTunbridgeWells
+19  A: 

Pyglet will do what you want and runs on OS X, Windows, and Linux. An example that draws a red line:

import pyglet

window = pyglet.window.Window(resizable=True)

@window.event
def on_draw():
    window.clear()
    pyglet.gl.glColor4f(1.0,0,0,1.0)
    pyglet.graphics.draw(2, pyglet.gl.GL_LINES,
        ('v2i', (10, 15, 30, 35))
    )

pyglet.app.run()

See more examples and documentation here.

Steve Johnson
pyglet rocks, it's so simple to get going with full 3D
Tony Arkles
+5  A: 

The "turtle" module from python's standard library provides turtle graphics similar to LOGO (but with python syntax of course) in an automagically generated TK window.

I certainly wouldn't say that this is the "best" way to draw graphics with python (too many inherent limitations), but it is extremely easy to get started with, and may be all you need if your task is simple enough.

from turtle import *

setup (width=200, height=200, startx=0, starty=0)

speed ("fastest") # important! turtle is intolerably slow otherwise
tracer (False)    # This too: rendering the 'turtle' wastes time

for i in range(200):
    forward(i)
    right(90.5)

done()


EDIT:

There is also a new and improved module for turtle grapics called xturtle.py. I haven't tried it yet but it may be worth a look.

nakedfanatic