Skip to content

Instantly share code, notes, and snippets.

@mattharrison
Created December 3, 2010 18:18
Show Gist options
  • Save mattharrison/727312 to your computer and use it in GitHub Desktop.
Save mattharrison/727312 to your computer and use it in GitHub Desktop.
attempt to see if drawing charts caused leaks, note that this removes the drawer portion and goes straight to ctx. I'm not seeing leaks with this.
import time
import random
import sys, os, gc
import pango
import cairo
import pangocairo
class _Graph():
fixed_upper_bound = False
defaults = (
("graph_color", "18BAEB", "Graph color"),
("fill_color", "1667EB.3", "Fill color for linefill graph"),
("background", "000000", "Widget background"),
("border_color", "215578", "Widget border color"),
("border_width", 2, "Widget background"),
("margin_x", 3, "Margin X"),
("margin_y", 3, "Margin Y"),
("samples", 100, "Count of graph samples."),
("frequency", 0.5, "Update frequency in seconds"),
("type", "linefill", "'box', 'line', 'linefill'"),
("line_width", 3, "Line width"),
)
def __init__(self, ctx, width = 100, **config):
#base._Widget.__init__(self, width, **config)
self.offset = 0
self.ctx = ctx
self.width = 300
self.height = 100
self.samples = 100
for name, value, ignore in self.defaults:
setattr(self, name, value)
self.values = [0]*self.samples
self.lasttick = 0
self.maxvalue = 0
@property
def graphwidth(self):
return self.width - self.border_width*2 - self.margin_x*2
@property
def graphheight(self):
return self.height - self.margin_y*2 - self.border_width*2
def draw_box(self, x, y, values):
step = self.graphwidth/float(self.samples)
for val in values:
self.fillrect(x, y-val, step, val, self.graph_color)
x += step
def draw_line(self, x, y, values):
step = self.graphwidth/float(self.samples-1)
self.ctx.set_line_join(cairo.LINE_JOIN_ROUND)
self.set_source_rgb(self.graph_color)
self.ctx.set_line_width(self.line_width)
for val in values:
self.ctx.line_to(x, y-val)
x += step
self.ctx.stroke()
def draw_linefill(self, x, y, values):
step = self.graphwidth/float(self.samples-1)
self.ctx.set_line_join(cairo.LINE_JOIN_ROUND)
self.set_source_rgb(self.graph_color)
self.ctx.set_line_width(self.line_width)
current = x
for val in values:
self.ctx.line_to(current, y-val)
current += step
self.ctx.stroke_preserve()
self.ctx.line_to(current, y + self.line_width/2.0)
self.ctx.line_to(x, y + self.line_width/2.0)
self.set_source_rgb(self.fill_color)
self.ctx.fill()
def draw(self):
self.clear(self.background)
if self.border_width:
self.set_source_rgb(self.border_color)
self.ctx.set_line_width(self.border_width)
self.ctx.rectangle(
self.margin_x + self.border_width/2.0, self.margin_y + self.border_width/2.0,
self.graphwidth + self.border_width,
self.height - self.margin_y*2 - self.border_width,
)
self.ctx.stroke()
x = self.margin_x + self.border_width
y = self.margin_y + self.graphheight + self.border_width
k = 1.0/(self.maxvalue or 1)
scaled = [self.graphheight * val * k for val in reversed(self.values)]
if self.type == "box":
self.draw_box(x, y, scaled)
elif self.type == "line":
self.draw_line(x, y, scaled)
elif self.type == "linefill":
self.draw_linefill(x, y, scaled)
else:
raise ValueError("Unknown graph type: %s."%self.type)
#self.draw(self.offset, self.width)
def push(self, value):
self.values.insert(0, value)
self.values.pop()
if not self.fixed_upper_bound:
self.maxvalue = max(self.values)
self.draw()
def _configure(self, qtile, bar):
base._Widget._configure(self, qtile, bar)
hook.subscribe.tick(self.update)
def update(self):
t = time.time()
if self.lasttick + self.frequency < t:
self.lasttick = t
self.update_graph()
def set_source_rgb(self, colour):
self.ctx.set_source_rgba(*rgb(colour))
# hacks
def clear(self, colour):
self.set_source_rgb(colour)
self.ctx.rectangle(0, 0, self.width, self.height)
self.ctx.fill()
self.ctx.stroke()
def rgb(x):
"""
Returns a valid RGBA tuple.
Here are some valid specifcations:
#ff0000
ff0000
with alpha: ff0000.5
(255, 0, 0)
(255, 0, 0, 0.5)
"""
if isinstance(x, tuple) or isinstance(x, list):
if len(x) == 4:
alpha = x[3]
else:
alpha = 1
return (x[0]/255.0, x[1]/255.0, x[2]/255.0, alpha)
elif isinstance(x, basestring):
if x.startswith("#"):
x = x[1:]
if "." in x:
x, alpha = x.split(".")
alpha = float("0."+alpha)
else:
alpha = 1
if len(x) != 6:
raise ValueError("RGB specifier must be 6 characters long.")
vals = [int(i, 16) for i in (x[0:2], x[2:4], x[4:6])]
vals.append(alpha)
return rgb(vals)
raise ValueError("Invalid RGB specifier.")
if __name__ == '__main__':
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 400, 300)
cr = pangocairo.CairoContext(cairo.Context(surface))
g = _Graph(cr)
cr.set_source_rgb(1.0, 0.0, 0.0)
layout = cr.create_layout()
for i in xrange(500000):
g.push(random.randint(0,100))
# cr.new_path()
# cr.move_to(100, 100)
# layout.set_text('text text text')
# cr.show_layout(layout)
#print len(gc.get_objects())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment