Skip to content

Instantly share code, notes, and snippets.

@magnunleno
Created September 9, 2012 18:34
Show Gist options
  • Save magnunleno/3686319 to your computer and use it in GitHub Desktop.
Save magnunleno/3686319 to your computer and use it in GitHub Desktop.
Overlaping Horizontal Bars Plotting example - built with Python+Cairo
#!/usr/bin/env python
# encoding: utf-8
# Python plotting "module" based in the graph found here:
# http://www.techdrivein.com/2012/09/chrome-overtakes-ie-to-become-worlds.html
#
# License: GPLv3
# Credits: Magnun Leno (@mind_bend)
# Site: http://www.mindbending.org
import cairo
LABELS = (
"Chrome",
"Internet Explorer",
"Firefox",
"Safari",
"Opera",
)
data = (
0.283,
0.276,
0.228,
0.144,
0.022,
)
colors = [
(0.95, 0.20, 0.20),
(0.99, 0.75, 0.30),
(0.99, 0.96, 0.34),
(0.72, 0.92, 0.23),
(0.20, 0.41, 0.84),
]
# Image Size
X, Y = 700, 250
# Percentage of overlapping bars
OVERLAPPING = 0.2
# Alpha value for bars (transparency)
ALPHA = 0.85
# Graph padding
LEFT_PAD = 0.02
RIGHT_PAD = 0.05
TOP_PAD = 0.1
BOTTOM_PAD = 0.1
# Padding between text (label) and graph bars
TEXT_PAD = 0.02
TEXT_FONT = "Ubuntu"
BIG_FONT_SIZE = 16
SMALL_FONT_SIZE = 13
SORT_MAP = {}
for n, value in enumerate(data):
SORT_MAP[value] = n
SORTED_DATA = sorted(SORT_MAP, reverse=True)
def draw_background(ctx, x1, y1):
ctx.set_source_rgb(1.0, 1.0, 1.0)
ctx.rectangle(0, 0, X, Y)
ctx.fill()
def draw_labels(ctx, title, x0, y0):
lwidth, lheight = ctx.text_extents(title)[2:4]
ctx.set_source_rgb(0.15, 0.15, 0.15)
ctx.move_to(x0 - lwidth, y0)
ctx.show_text(title)
def draw_bar(ctx, x0, y0, w, h, color):
ctx.set_source_rgba(*color)
ctx.rectangle(x0, y0, w, h)
ctx.fill()
def draw_blackbox(ctx, x0, y0, w, h):
ctx.set_source_rgb(0.12, 0.12, 0.12)
ctx.rectangle(x0, y0, w, h)
ctx.fill()
def draw_percentage(ctx, x0, y0, text):
ctx.select_font_face(TEXT_FONT, cairo.FONT_SLANT_NORMAL)
ctx.set_font_size(SMALL_FONT_SIZE)
ctx.set_source_rgb(0.9, 0.9, 0.9)
ctx.move_to(x0, y0)
ctx.show_text(text)
if __name__ == '__main__':
# Initialize Cairo Surface and Context
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, X, Y)
ctx = cairo.Context(surface)
# Configure font
ctx.select_font_face(TEXT_FONT, cairo.FONT_SLANT_OBLIQUE)
ctx.set_font_size(BIG_FONT_SIZE)
# Parametrize data values
MAX_VALUE = max(data)
data_param = [value/MAX_VALUE for value in data]
# Calculates Label Max Text Size
MAX_TEXT = max([ctx.text_extents(text)[2] for text in LABELS])
# Convert percentage padding to real size
LEFT_PADDING = LEFT_PAD * X
RIGHT_PADDING = RIGHT_PAD * X
TOP_PADDING = TOP_PAD * Y
BOTTOM_PADDING = BOTTOM_PAD * Y
TEXT_PADDING = X * TEXT_PAD
# Usable graph space
X_PLOT_SIZE = X - RIGHT_PADDING - LEFT_PADDING - MAX_TEXT
Y_PLOT_SIZE = Y - TOP_PADDING - BOTTOM_PADDING
# Usable height for each bar
SLOT_SIZE = Y_PLOT_SIZE / len(SORTED_DATA)
# Convert Overlapping percentage to real size
OVERLAPPING = OVERLAPPING * SLOT_SIZE
draw_background(ctx, X, Y)
x0 = LEFT_PADDING
y0 = TOP_PADDING
ctx.select_font_face(TEXT_FONT, cairo.FONT_SLANT_NORMAL)
ctx.set_font_size(SMALL_FONT_SIZE)
for key in SORTED_DATA:
n = SORT_MAP[key]
value = data_param[n]
# Calculates the "black box value"
value_orig = data[n]
p_value = '%.1f %%'%(value_orig*100)
pvwidth, pvheight = ctx.text_extents(p_value)[2:4]
ctx.select_font_face(TEXT_FONT, cairo.FONT_SLANT_OBLIQUE)
ctx.set_font_size(BIG_FONT_SIZE)
# Black box dimensions
bb_pad_w = pvwidth*0.2
bb_pad_h = pvheight*0.5
bb_w = pvwidth + (2*bb_pad_w)
bb_h = pvheight + (2*bb_pad_h)
# Calculates the ending points
x_bar_size = (X_PLOT_SIZE - bb_w) * value
y_bar_size = SLOT_SIZE + OVERLAPPING
########## Label
title = LABELS[n]
draw_labels(ctx, title, x0 + MAX_TEXT, y0 + (OVERLAPPING) + (SLOT_SIZE/2))
########## Horizontal Bar
# Bars starting X point
draw_bar(ctx, x0 + MAX_TEXT + TEXT_PADDING, y0,
x_bar_size, y_bar_size, colors[n] + (ALPHA, ))
########## Value's Black Box
draw_blackbox(ctx, x0 + MAX_TEXT + TEXT_PADDING + x_bar_size,
y0 + (y_bar_size - bb_h)/2, bb_w, bb_h)
########## Value's Label
draw_percentage(ctx, x0 + MAX_TEXT + TEXT_PADDING + x_bar_size + bb_pad_w,
y0 + (y_bar_size - bb_h)/2 + pvheight + bb_pad_h, p_value)
y0 += SLOT_SIZE
surface.write_to_png("grafico.png")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment