Browse Source

Extract margin calculs

pull/8/head
Florian Mounier 13 years ago
parent
commit
f696dc07df
  1. 11
      pygal/graph.css
  2. 130
      pygal/graph.py
  3. 108
      pygal/util/boundary.py
  4. 3
      test/moulinrouge/__init__.py
  5. 6
      test/moulinrouge/data.py

11
pygal/graph.css

@ -4,6 +4,9 @@ $Id$
Base styles for pygal.Graph
*/
* {
font-family: monospace;
}
.svgBackground{
fill:#ffffff;
}
@ -16,14 +19,12 @@ Base styles for pygal.Graph
text-anchor: middle;
fill: #000000;
font-size: %(title_font_size)dpx;
font-family: "Arial", sans-serif;
font-weight: normal;
}
.subTitle{
text-anchor: middle;
fill: #999999;
font-size: %(subtitle_font_size)dpx;
font-family: "Arial", sans-serif;
font-weight: normal;
}
@ -42,7 +43,6 @@ Base styles for pygal.Graph
text-anchor: middle;
fill: #000000;
font-size: %(x_label_font_size)dpx;
font-family: "Arial", sans-serif;
font-weight: normal;
}
@ -50,7 +50,6 @@ Base styles for pygal.Graph
text-anchor: end;
fill: #000000;
font-size: %(y_label_font_size)dpx;
font-family: "Arial", sans-serif;
font-weight: normal;
}
@ -58,7 +57,6 @@ Base styles for pygal.Graph
text-anchor: middle;
fill: #ff0000;
font-size: %(x_title_font_size)dpx;
font-family: "Arial", sans-serif;
font-weight: normal;
}
@ -66,14 +64,12 @@ Base styles for pygal.Graph
fill: #ff0000;
text-anchor: middle;
font-size: %(y_title_font_size)dpx;
font-family: "Arial", sans-serif;
font-weight: normal;
}
.dataPointLabel{
text-anchor:middle;
font-size: 10px;
font-family: "Arial", sans-serif;
font-weight: normal;
}
@ -87,6 +83,5 @@ Base styles for pygal.Graph
fill: #000000;
text-anchor:start;
font-size: %(key_font_size)dpx;
font-family: "Arial", sans-serif;
font-weight: normal;
}

130
pygal/graph.py

@ -11,11 +11,13 @@ from operator import itemgetter
from itertools import islice
import pkg_resources
import functools
import math
import cssutils
from lxml import etree
from pygal.util.boundary import (calculate_right_margin, calculate_left_margin,
calculate_bottom_margin, calculate_top_margin,
calculate_offsets_bottom)
from pygal import css # causes the SVG profile to be loaded
try:
@ -24,14 +26,6 @@ except ImportError:
zlib = None
def cos(angle):
return math.cos(angle * math.pi / 180)
def sin(angle):
return math.sin(angle * math.pi / 180)
def sort_multiple(arrays):
"sort multiple lists (of equal size) "
"using the first list for the sort keys"
@ -98,6 +92,7 @@ class Graph(object):
y_label_font_size = 12
y_title_font_size = 14
key_font_size = 10
key_box_size = 10
add_popups = False
@ -195,36 +190,6 @@ class Graph(object):
return data
KEY_BOX_SIZE = 12
def calculate_left_margin(self):
"""
Calculates the margin to the left of the plot area, setting
border_left.
"""
bl = 7
# Check for Y labels
if self.rotate_y_labels:
max_y_label_height_px = self.y_label_font_size
else:
label_lengths = map(len, self.get_y_labels())
max_y_label_len = max(label_lengths)
max_y_label_height_px = (0.6 * max_y_label_len *
self.y_label_font_size)
if self.show_y_labels:
bl += max_y_label_height_px
if self.stagger_y_labels:
bl += max_y_label_height_px + 10
if self.show_y_title:
bl += self.y_title_font_size + 5
if self.x_label_rotation:
label_lengths = map(len, self.get_x_labels())
max_x_label_len = reduce(max, label_lengths)
max_x_label_height_px = self.x_label_font_size
max_x_label_height_px *= max_x_label_len * 0.6
bl += max_x_label_height_px * cos(self.x_label_rotation)
self.border_left = bl
def max_y_label_width_px(self):
"""
Calculate the width of the widest Y label. This will be the
@ -233,31 +198,6 @@ class Graph(object):
if self.rotate_y_labels:
return self.font_size
def calculate_right_margin(self):
"""
Calculate the margin in pixels to the right of the plot area,
setting border_right.
"""
br = 7
if self.key and self.key_position == 'right':
max_key_len = max(map(len, self.keys()))
br += max_key_len * self.key_font_size * 0.6
br += self.KEY_BOX_SIZE
br += 10 # Some padding around the box
self.border_right = br
def calculate_top_margin(self):
"""
Calculate the margin in pixels above the plot area, setting
border_top.
"""
self.border_top = 5
if self.show_graph_title:
self.border_top += self.title_font_size
self.border_top += 5
if self.show_graph_subtitle:
self.border_top += self.subtitle_font_size
def add_popup(self, x, y, label):
"""
Add pop-up information to a point on the graph.
@ -288,29 +228,6 @@ class Graph(object):
'onmouseout': visibility % 'hidden',
})
def calculate_bottom_margin(self):
"""
Calculate the margin in pixels below the plot area, setting
border_bottom.
"""
bb = 7
if self.key and self.key_position == 'bottom':
bb += len(self.data) * (self.font_size + 5)
bb += 10
if self.show_x_labels:
max_x_label_height_px = self.x_label_font_size
if self.x_label_rotation:
label_lengths = map(len, self.get_x_labels())
max_x_label_len = reduce(max, label_lengths)
max_x_label_height_px *= max_x_label_len * 0.8
max_x_label_height_px *= sin(self.x_label_rotation)
bb += max_x_label_height_px
if self.stagger_x_labels:
bb += max_x_label_height_px + 10
if self.show_x_title:
bb += self.x_title_font_size + 5
self.border_bottom = bb
def draw_graph(self):
"""
The central logic for drawing the graph.
@ -573,17 +490,17 @@ class Graph(object):
group = etree.SubElement(self.root, 'g')
for key_count, key_name in enumerate(self.keys()):
y_offset = (self.KEY_BOX_SIZE * key_count) + (key_count * 5)
y_offset = (self.key_box_size * key_count) + (key_count * 5)
etree.SubElement(group, 'rect', {
'x': '0',
'y': str(y_offset),
'width': str(self.KEY_BOX_SIZE),
'height': str(self.KEY_BOX_SIZE),
'width': str(self.key_box_size),
'height': str(self.key_box_size),
'class': 'key key%s' % (key_count + 1),
})
text = etree.SubElement(group, 'text', {
'x': str(self.KEY_BOX_SIZE + 5),
'y': str(y_offset + self.KEY_BOX_SIZE),
'x': str(self.key_box_size + 5),
'y': str(y_offset + self.key_box_size),
'class': 'keyText'})
text.text = key_name
@ -591,25 +508,9 @@ class Graph(object):
x_offset = self.graph_width + self.border_left + 10
y_offset = self.border_top + 20
if self.key_position == 'bottom':
x_offset, y_offset = self.calculate_offsets_bottom()
x_offset, y_offset = calculate_offsets_bottom(self)
group.set('transform', 'translate(%(x_offset)d %(y_offset)d)' % vars())
def calculate_offsets_bottom(self):
x_offset = self.border_left + 20
y_offset = self.border_top + self.graph_height + 5
if self.show_x_labels:
max_x_label_height_px = self.x_label_font_size
if self.x_label_rotation:
longest_label_length = max(map(len, self.get_x_labels()))
max_x_label_height_px *= longest_label_length
max_x_label_height_px *= sin(self.x_label_rotation)
y_offset += max_x_label_height_px
if self.stagger_x_labels:
y_offset += max_x_label_height_px + 5
if self.show_x_title:
y_offset += self.x_title_font_size + 5
return x_offset, y_offset
def parse_css(self):
"""
Take a .css file (classes only please) and parse it into a dictionary
@ -676,10 +577,11 @@ class Graph(object):
'class': 'svgBackground'})
def calculate_graph_dimensions(self):
self.calculate_left_margin()
self.calculate_right_margin()
self.calculate_bottom_margin()
self.calculate_top_margin()
self.border_right = calculate_right_margin(self)
self.border_top = calculate_top_margin(self)
self.border_left = calculate_left_margin(self)
self.border_bottom = calculate_bottom_margin(self)
self.graph_width = self.width - self.border_left - self.border_right
self.graph_height = self.height - self.border_top - self.border_bottom

108
pygal/util/boundary.py

@ -1 +1,109 @@
# -*- coding: utf-8 -*-
import math
pi = math.pi
def cos(angle):
return math.cos(angle * pi / 180)
def sin(angle):
return math.sin(angle * pi / 180)
def calculate_right_margin(graph):
"""
Calculate the margin in pixels to the right of the plot area,
setting border_right.
"""
br = 7
if graph.key and graph.key_position == 'right':
max_key_len = max(map(len, graph.keys()))
br += max_key_len * graph.key_font_size * 0.6
br += graph.key_box_size
br += 10 # Some padding around the box
return br
def calculate_top_margin(graph):
"""
Calculate the margin in pixels above the plot area, setting
border_top.
"""
bt = 10
if graph.show_graph_title:
bt += graph.title_font_size
if graph.show_graph_subtitle:
bt += graph.subtitle_font_size
return bt
def calculate_bottom_margin(graph):
"""
Calculate the margin in pixels below the plot area, setting
border_bottom.
"""
bb = 7
if graph.key and graph.key_position == 'bottom':
bb += len(graph.data) * (graph.font_size + 5)
bb += 10
if graph.show_x_labels:
max_x_label_height_px = graph.x_label_font_size
if graph.x_label_rotation:
label_lengths = map(len, graph.get_x_labels())
max_x_label_len = reduce(max, label_lengths)
max_x_label_height_px *= max_x_label_len * 0.6
max_x_label_height_px *= sin(graph.x_label_rotation)
bb += max_x_label_height_px
if graph.stagger_x_labels:
bb += max_x_label_height_px + 10
if graph.show_x_title:
bb += graph.x_title_font_size + 5
return bb
def calculate_left_margin(graph):
"""
Calculates the margin to the left of the plot area, setting
border_left.
"""
bl = 7
# Check for Y labels
if graph.rotate_y_labels:
max_y_label_height_px = graph.y_label_font_size
else:
label_lengths = map(len, graph.get_y_labels())
max_y_label_len = max(label_lengths)
max_y_label_height_px = (0.6 * max_y_label_len *
graph.y_label_font_size)
if graph.show_y_labels:
bl += max_y_label_height_px
if graph.stagger_y_labels:
bl += max_y_label_height_px + 10
if graph.show_y_title:
bl += graph.y_title_font_size + 5
if graph.x_label_rotation:
label_lengths = map(len, graph.get_x_labels())
max_x_label_len = reduce(max, label_lengths)
max_x_label_height_px = graph.x_label_font_size
max_x_label_height_px *= max_x_label_len * 0.6
bl += max_x_label_height_px * cos(graph.x_label_rotation)
return bl
def calculate_offsets_bottom(graph):
x_offset = graph.border_left + 20
y_offset = graph.border_top + graph.graph_height + 5
if graph.show_x_labels:
max_x_label_height_px = graph.x_label_font_size
if graph.x_label_rotation:
longest_label_length = max(map(len, graph.get_x_labels()))
max_x_label_height_px *= longest_label_length
max_x_label_height_px *= sin(graph.x_label_rotation)
y_offset += max_x_label_height_px
if graph.stagger_x_labels:
y_offset += max_x_label_height_px + 5
if graph.show_x_title:
y_offset += graph.x_title_font_size + 5
return x_offset, y_offset

3
test/moulinrouge/__init__.py

@ -35,8 +35,7 @@ def create_app():
def rotation_svg(angle):
return generate_vbar(
title="Rotation %d" % angle,
x_label_rotation=angle,
key_position='bottom')
x_label_rotation=angle)
@app.route("/rotation")
def rotation():

6
test/moulinrouge/data.py

@ -1,6 +1,10 @@
# -*- coding: utf-8 -*-
labels = ['Internet', 'TV', 'Newspaper', 'Magazine', 'Radio']
labels = ['iiiiiiiiii',
'mmmmmmmmmm',
'aaaaaaaaaa',
'wwwwwwwwww',
u'éàé瀮ð{æə|&']
series = {
'Female': [4, 2, 3, 0, 2],
'Male': [5, 1, 1, 3, 2]

Loading…
Cancel
Save