1.1 --- a/SVGChartSupport.py Sat Oct 08 22:41:09 2011 +0200
1.2 +++ b/SVGChartSupport.py Sun Oct 09 01:30:41 2011 +0200
1.3 @@ -55,13 +55,50 @@
1.4
1.5 "Support for plotting points and lines."
1.6
1.7 - def __init__(self, xmin, ymin, xmax, ymax, xmultiplier, ymultiplier):
1.8 - self.xmin = xmin
1.9 - self.ymin = ymin
1.10 - self.xmax = xmax
1.11 - self.ymax = ymax
1.12 - self.xmultiplier = xmultiplier
1.13 - self.ymultiplier = ymultiplier
1.14 + def __init__(self, data, xorigin, yorigin, xdivisions, ydivisions):
1.15 +
1.16 + # Get the data properties.
1.17 +
1.18 + min_x = min([t[0] for t in data])
1.19 + min_y = min([t[1] for t in data])
1.20 + max_x = max([t[0] for t in data])
1.21 + max_y = max([t[1] for t in data])
1.22 +
1.23 + # Get the chart properties.
1.24 +
1.25 + xinterval = math.pow(10, math.floor(math.log10(max(abs(max_x), abs(min_x)))))
1.26 + yinterval = math.pow(10, math.floor(math.log10(max(abs(max_y), abs(min_y)))))
1.27 +
1.28 + xstep = float(xinterval) / xdivisions
1.29 + ystep = float(yinterval) / ydivisions
1.30 +
1.31 + # Store various attributes.
1.32 +
1.33 + self.xmin, self.xmax = round(min_x, xinterval, -1), round(max_x, xinterval)
1.34 + self.ymin, self.ymax = round(min_y, yinterval, -1), round(max_y, yinterval)
1.35 +
1.36 + self.xsequence = frange(min(xorigin, self.xmin), max(xorigin, self.xmax) + xstep, xstep)
1.37 + self.ysequence = frange(min(xorigin, self.ymin), max(yorigin, self.ymax) + ystep, ystep)
1.38 +
1.39 + self.xmultiplier = float(self.ymax) / self.xmax
1.40 + self.ymultiplier = -1
1.41 +
1.42 + # Work out the extent of the chart.
1.43 +
1.44 + self.left = min(self.get_xbase(), self.scale_x(xorigin)) - self.scaled_xpc(40)
1.45 + self.left_to_right = self.scaled_xpc(180)
1.46 + self.bottom = min(self.get_ybase(), self.scale_y(yorigin)) - self.scaled_ypc(10)
1.47 + self.bottom_to_top = self.scaled_ypc(180)
1.48 +
1.49 + def get_dimensions(self, chart_width=None, chart_height=None):
1.50 + if chart_width is not None:
1.51 + if chart_height is None:
1.52 + chart_height = chart_width / self.left_to_right * self.bottom_to_top
1.53 + else:
1.54 + if chart_height is not None:
1.55 + chart_width = chart_height / self.bottom_to_top * self.left_to_right
1.56 +
1.57 + return map(int, (chart_width, chart_height))
1.58
1.59 def get_width(self):
1.60 return abs(self.xmax - self.xmin)
1.61 @@ -374,42 +411,27 @@
1.62 value += step
1.63 return l
1.64
1.65 -def get_chart(data, chart_width=900, chart_height=None, xorigin=0, yorigin=0, xdivisions=10, ydivisions=10, encoding="utf-8",
1.66 - styles_url=""):
1.67 -
1.68 +def convert_data(data):
1.69 new_data = []
1.70 for t in data:
1.71 x, y = t[:2]
1.72 new_data.append([float(x), float(y)] + t[2:])
1.73 - data = new_data
1.74 -
1.75 - # Get the data properties.
1.76 + return new_data
1.77
1.78 - min_x = min([t[0] for t in data])
1.79 - min_y = min([t[1] for t in data])
1.80 - max_x = max([t[0] for t in data])
1.81 - max_y = max([t[1] for t in data])
1.82 -
1.83 - # Get the chart properties.
1.84 +def get_dimensions(data, chart_width=900, chart_height=None, xorigin=0, yorigin=0, xdivisions=10, ydivisions=10):
1.85
1.86 - xinterval = math.pow(10, math.floor(math.log10(max(abs(max_x), abs(min_x)))))
1.87 - yinterval = math.pow(10, math.floor(math.log10(max(abs(max_y), abs(min_y)))))
1.88 -
1.89 - xmin, xmax = round(min_x, xinterval, -1), round(max_x, xinterval)
1.90 - ymin, ymax = round(min_y, yinterval, -1), round(max_y, yinterval)
1.91 + data = convert_data(data)
1.92 + plot = Plot(data, xorigin, yorigin, xdivisions, ydivisions)
1.93 + return plot.get_dimensions(chart_width, chart_height)
1.94
1.95 - xstep = float(xinterval) / xdivisions
1.96 - ystep = float(yinterval) / ydivisions
1.97 +def get_chart(data, chart_width=900, chart_height=None, xorigin=0, yorigin=0, xdivisions=10, ydivisions=10, encoding="utf-8",
1.98 + styles_url=""):
1.99
1.100 - xsequence = frange(min(xorigin, xmin), max(xorigin, xmax) + xstep, xstep)
1.101 - ysequence = frange(min(xorigin, ymin), max(yorigin, ymax) + ystep, ystep)
1.102 -
1.103 - xmultiplier = float(ymax) / xmax
1.104 - ymultiplier = -1
1.105 + data = convert_data(data)
1.106
1.107 # Initialise the chart components.
1.108
1.109 - plot = Plot(xmin, ymin, xmax, ymax, xmultiplier, ymultiplier)
1.110 + plot = Plot(data, xorigin, yorigin, xdivisions, ydivisions)
1.111
1.112 axis_label_x = plot.xpc(20)
1.113 axis_label_y = plot.ypc(15)
1.114 @@ -417,8 +439,8 @@
1.115 width = plot.get_width()
1.116 height = plot.get_height()
1.117
1.118 - x_axis = Axis(plot, 0, yorigin, xsequence, xdivisions, plot.ypc(0.5), plot.ypc(1))
1.119 - y_axis = Axis(plot, 1, xorigin, ysequence, ydivisions, plot.xpc(0.5), plot.xpc(1))
1.120 + x_axis = Axis(plot, 0, yorigin, plot.xsequence, xdivisions, plot.ypc(0.5), plot.ypc(1))
1.121 + y_axis = Axis(plot, 1, xorigin, plot.ysequence, ydivisions, plot.xpc(0.5), plot.xpc(1))
1.122
1.123 # Render the chart.
1.124
1.125 @@ -471,27 +493,15 @@
1.126 all_elements.append(get_labelled_points(plot, x_axis, y_axis, points, labelx, labely, font_height,
1.127 axis_label_x, axis_label_y, attributes=styles))
1.128
1.129 - # Work out the extent of the chart.
1.130 -
1.131 - left = min(plot.get_xbase(), plot.scale_x(xorigin)) - plot.scaled_xpc(40)
1.132 - left_to_right = plot.scaled_xpc(180)
1.133 - bottom = min(plot.get_ybase(), plot.scale_y(yorigin)) - plot.scaled_ypc(10)
1.134 - bottom_to_top = plot.scaled_ypc(180)
1.135 -
1.136 - if chart_width is not None:
1.137 - if chart_height is None:
1.138 - chart_height = chart_width / left_to_right * bottom_to_top
1.139 - else:
1.140 - if chart_height is not None:
1.141 - chart_width = chart_height / bottom_to_top * left_to_right
1.142 + chart_width, chart_height = plot.get_dimensions(chart_width, chart_height)
1.143
1.144 # Write the SVG file.
1.145
1.146 - return template % {
1.147 - "width" : int(chart_width),
1.148 - "height" : int(chart_height),
1.149 + return chart_width, chart_height, template % {
1.150 + "width" : chart_width,
1.151 + "height" : chart_height,
1.152 "viewBox" : "%d %d %d %d" % (
1.153 - left, bottom, left_to_right, bottom_to_top,
1.154 + plot.left, plot.bottom, plot.left_to_right, plot.bottom_to_top,
1.155 ),
1.156 "chart" : "".join(all_elements),
1.157 "styles_url" : styles_url,
2.1 --- a/parsers/SVGChart.py Sat Oct 08 22:41:09 2011 +0200
2.2 +++ b/parsers/SVGChart.py Sun Oct 09 01:30:41 2011 +0200
2.3 @@ -8,7 +8,7 @@
2.4
2.5 from MoinMoin.action import cache
2.6 from MoinMoin import wikiutil
2.7 -from SVGChartSupport import get_chart
2.8 +from SVGChartSupport import get_chart, get_dimensions
2.9
2.10 Dependencies = ["pages"]
2.11
2.12 @@ -36,8 +36,13 @@
2.13 # The attributes returned from the formatting arguments are encoded like
2.14 # strings.
2.15
2.16 - self.xorigin = float((attrs.get("xorigin") or '"0"')[1:-1])
2.17 - self.yorigin = float((attrs.get("yorigin") or '"0"')[1:-1])
2.18 + quotes = '"' + "'"
2.19 + self.xorigin = float((attrs.get("xorigin") or '0').strip(quotes))
2.20 + self.yorigin = float((attrs.get("yorigin") or '0').strip(quotes))
2.21 + width = (attrs.get("width") or '').strip(quotes) or None
2.22 + height = (attrs.get("height") or '').strip(quotes) or None
2.23 + self.width = width and int(width)
2.24 + self.height = height and int(height)
2.25
2.26 def format(self, fmt):
2.27
2.28 @@ -47,16 +52,18 @@
2.29 page = request.page
2.30 _ = request.getText
2.31
2.32 - # NOTE: Store and retrieve the width and height.
2.33 + cache_key = cache.key(request, itemname=page.page_name, content="%s,%s,%s,%s,%s" % (
2.34 + self.width, self.height, self.xorigin, self.yorigin, self.raw))
2.35
2.36 - cache_key = cache.key(request, itemname=page.page_name, content="%s,%s,%s" % (self.xorigin, self.yorigin, self.raw))
2.37 if not cache.exists(request, cache_key):
2.38 - chart = get_chart(self.data, xorigin=self.xorigin, yorigin=self.yorigin,
2.39 + width, height, chart = get_chart(self.data, self.width, self.height, self.xorigin, self.yorigin,
2.40 styles_url="%s/%s/css/svgchart.css" % (request.cfg.url_prefix_static, request.theme.name))
2.41 cache.put(request, cache_key, chart, content_type="image/svg+xml")
2.42 + else:
2.43 + width, height = get_dimensions(self.data, self.width, self.height, self.xorigin, self.yorigin)
2.44
2.45 request.write(fmt.div(1, css_class="svgchart"))
2.46 - request.write(fmt.transclusion(1, data=cache.url(request, cache_key)))
2.47 + request.write(fmt.transclusion(1, data=cache.url(request, cache_key), width=width, height=height))
2.48 request.write(fmt.text(_("SVG chart of CSV data.")))
2.49 request.write(fmt.transclusion(0))
2.50 request.write(fmt.div(0))