title: How to draw 10000+ 2d graphical objects quickly?
body: <p>I need to draw tens of thousands, in the future probably hundreds of thousands of simple 2d objects (circles, rectangles, some filled, labeled...) to a widget.</p>
  
  <p>In the same program I need GUI widgets (buttons, text input, checkboxes).</p>
  
  <p>I tried Gtk, Qt and SDL with C++ and Python. First result was to be expected: C++ and Python show the same performance, as they call the same C or C++ routines in the backend.</p>
  
  <p>Second result is that none of the libraries made a big difference. In numbers: 22500 rectangles (150*150) needed approximately a second to update. As there will be constant upadating due to (a) new data, i.e. more rectangles, and (b) user interaction, i.e. zooming, panning etc., a second is way to long!</p>
  
  <p>What would be a faster way. Small examples are very much appreciated. Python and C++ is good. Other libraries should be easily accessible and installable on Linux.</p>
  
  <p>Maybe I am just doing it wrong.</p>
  
  <p>ps. I am not posting my test codes, because I don't want to bias answers. And I don't want my code to be corrected, I want to the fastest way to do it...</p>
  
  <p><strong>edit:</strong></p>
  
  <p>Alright, I will add my gtk test:</p>
  
  <pre><code>#!/bin/env python2
  
  import gtk
  import gobject
  import gtk.gdk
  
  class GraphWidget(gtk.DrawingArea):
      __gsignals__ = {
          'expose-event': 'override',
          'clicked' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, gtk.gdk.Event))
          }
  
      def __init__(self,window):
          gtk.DrawingArea.__init__(self)
          #self.win = window
          self.zoom_ratio = 1.0
          self.dx = 40
          self.dy = 40
  
      def do_expose_event(self, event):
          cr = self.window.cairo_create()
          cr.set_source_rgba(1.0, 0.9, 0.8, 1.0)
          cr.paint()
  
          cr.translate(self.dx, self.dy)
          cr.scale(self.zoom_ratio,self.zoom_ratio)
  
          self.draw(cr)
  
      def draw(self, cr):
          n = 150
          cr.set_source_rgba(0.,1.,1.,1.0)
          for i in range(n):
              for j in range(n):
                  cr.arc(i*30, j*30, 10, 0, 6.2832)
  
                  cr.close_path()
                  cr.fill()
  
          cr.set_source_rgba(0.,0.,1.,1.0)
          for i in range(n):
              for j in range(n):
                  cr.arc(i*30, j*30, 10, 0, 6.2832)
                  cr.move_to(i*30-10, j*30)
                  cr.show_text("hu")
                  cr.stroke()
  
      def on_zoom(self, zoom_factor):
          self.zoom_ratio *= zoom_factor
          self.queue_draw()
  
      def on_translate(self,dx,dy):
          self.dx += dx
          self.dy += dy
          self.queue_draw()
  
  class TestWindow(gtk.Window):
      def __init__(self):
          gtk.Window.__init__(self)
  
          self.widget = GraphWidget(self)
  
          self.add(self.widget)
  
          self.show_all()
  
          # connect key press events
  
          self.connect('key-press-event', self.on_key_press_event)
          self.connect('destroy', gtk.main_quit)
  
          self.widget.queue_draw()
  
      def on_key_press_event(self, widget, event):
  
          if event.keyval == gtk.keysyms.space and not (event.state &amp; gtk.gdk.CONTROL_MASK):
              self.on_run(widget)
              return True
          elif event.keyval == gtk.keysyms.r:
              self.on_refresh(widget)
              return True
          elif event.keyval == gtk.keysyms.Left:
              self.widget.on_translate(-100, 0)
          elif event.keyval == gtk.keysyms.Right:
              self.widget.on_translate(100, 0)
          elif event.keyval == gtk.keysyms.Up:
              self.widget.on_translate(0, -100)
          elif event.keyval == gtk.keysyms.Down:
              self.widget.on_translate(0, 100)
          elif event.keyval == gtk.keysyms.Page_Down:
              self.widget.on_zoom(0.7)
          elif event.keyval == gtk.keysyms.Page_Up:
              self.widget.on_zoom(1.3)
  
  if __name__ == '__main__':
      win = TestWindow()
      gtk.main()
  </code></pre>
  
  <p>And the SDL experiment:</p>
  
  <pre><code>#!/usr/bin/env python
  
  import sdl2
  import sdl2.ext as sdl2ext
  
  dx = 0
  dy = 0
  zoom_factor = 1.
  n_objects = 150
  
  sdl2ext.init()
  
  window = sdl2ext.Window('hallo', 
                          size=(800, 600), 
                          flags= sdl2.SDL_WINDOW_RESIZABLE)
  window.show()
  
  renderer = sdl2ext.RenderContext(window)
  renderer.color = sdl2ext.Color(255,155,25)
  
  def draw():
      renderer.clear()
      for i in xrange(n_objects):
          for j in xrange(n_objects):
              renderer.fill([int((i*30+dx)*zoom_factor), 
                             int((j*30+dy)*zoom_factor), 
                             int(20*zoom_factor), 
                             int(20*zoom_factor)], 
                            sdl2ext.Color(255,25,55))
              renderer.draw_rect([int((i*30+dx)*zoom_factor), 
                                  int((j*30+dy)*zoom_factor), 
                                  int(20*zoom_factor), 
                                  int(20*zoom_factor)], 
                                 sdl2ext.Color(255,255,255))
  
      renderer.present()
  
  draw()
  
  running = True
  while running:
      for e in sdl2ext.get_events():
          if e.type == sdl2.SDL_QUIT:
              running = False
              break
          if e.type == sdl2.SDL_KEYDOWN:
              if e.key.keysym.sym == sdl2.SDLK_ESCAPE:
                  running = False
                  break
              elif e.key.keysym.sym == sdl2.SDLK_RIGHT:
                  dx += 50
                  draw()
              elif e.key.keysym.sym == sdl2.SDLK_LEFT:
                  dx -= 50
                  draw()
              elif e.key.keysym.sym == sdl2.SDLK_UP:
                  dy += 50
                  draw()
              elif e.key.keysym.sym == sdl2.SDLK_DOWN:
                  dy -= 50
                  draw()
              elif e.key.keysym.sym == sdl2.SDLK_PAGEUP:
                  zoom_factor *= 1.2
                  draw()
              elif e.key.keysym.sym == sdl2.SDLK_PAGEDOWN:
                  zoom_factor /= 1.2
                  draw()
  </code></pre>
  
  <p>The Qt test was done by my colleague so I don't have the code right now...</p>