Created
September 9, 2012 18:34
-
-
Save magnunleno/3686319 to your computer and use it in GitHub Desktop.
Overlaping Horizontal Bars Plotting example - built with Python+Cairo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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