Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorReinier Heeres <reinier@heeres.eu>2007-09-07 14:04:24 (GMT)
committer Reinier Heeres <reinier@heeres.eu>2007-09-07 14:04:24 (GMT)
commitb0cca9f16f0a57ea07c8a27f4421311e96b41680 (patch)
tree99128b2f913aaaf3bd3f4bb6345f2cb1fca304e0
parentd804d55f4cdde65b74bb105fca60b0494211f4d5 (diff)
Basic plot() support!
-rw-r--r--calculate.py131
-rw-r--r--eqnparser.py105
-rw-r--r--layout.py9
-rw-r--r--mathlib.py5
-rw-r--r--plotlib.py138
-rw-r--r--svgimage.py55
6 files changed, 338 insertions, 105 deletions
diff --git a/calculate.py b/calculate.py
index 5e78185..ff00a1d 100644
--- a/calculate.py
+++ b/calculate.py
@@ -31,6 +31,7 @@ import pygtk
pygtk.require('2.0')
import gtk
import pango
+import base64
from sugar.activity import activity
from sugar.presence import presenceservice
@@ -43,6 +44,7 @@ from sharedstate.sharedstate import SharingHelper
from layout import CalcLayout
from mathlib import MathLib
from eqnparser import EqnParser
+from svgimage import SVGImage
class Equation:
def __init__(self, label=None, eqn=None, res=None, col=None, owner=None, str=None):
@@ -59,8 +61,13 @@ class Equation:
self.owner = owner
def __str__(self):
- return "%s;%s;%s;%s;%s\n" % \
- (self.label, self.equation, self.result, self.color.to_string(), self.owner)
+ if isinstance(self.result, SVGImage):
+ svg_data = "<svg>" + base64.b64encode(self.result.get_svg_data())
+ return "%s;%s;%s;%s;%s\n" % \
+ (self.label, self.equation, svg_data, self.color.to_string(), self.owner)
+ else:
+ return "%s;%s;%s;%s;%s\n" % \
+ (self.label, self.equation, self.result, self.color.to_string(), self.owner)
def parse(self, str):
str = str.rstrip("\r\n")
@@ -68,6 +75,10 @@ class Equation:
if len(l) != 5:
_logger.error('Equation.parse() string invalid (%s)', str)
return False
+
+ if l[2].startswith("<svg>"):
+ l[2] = SVGImage(data=base64.b64decode(l[2][5:]))
+
self.set(l[0], l[1], l[2], XoColor(color_string=l[3]), l[4])
class Calculate(activity.Activity):
@@ -133,10 +144,19 @@ class Calculate(activity.Activity):
IDENTIFIER_CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_ "
def __init__(self, handle):
- try:
- activity.Activity.__init__(self, handle)
- except Exception, inst:
- _logger.error('Exception: %s', inst)
+ activity.Activity.__init__(self, handle)
+
+ self.helper_old_eqs = []
+
+ self.ml = MathLib()
+ self.parser = EqnParser(self.ml)
+
+ self.clipboard = ""
+ self.select_reason = self.SELECT_SELECT
+ self.buffer = ""
+ self.showing_version = 0
+ self.showing_error = False
+ self.show_vars = False
self.set_title("Calculate")
self.connect("key_press_event", self.keypress_cb)
@@ -145,29 +165,18 @@ class Calculate(activity.Activity):
## self.icon = CanvasIcon(
## icon_name = 'theme:stock-buddy',
## xo_color = XoColor(self.color))
+
self.layout = CalcLayout(self)
self.label_entry = self.layout.label_entry
self.text_entry = self.layout.text_entry
self.history = self.layout.history
self.last_eq = self.layout.last_eq.get_buffer()
-
- self.ml = MathLib()
- self.parser = EqnParser(self.ml)
-
- self.clipboard = ""
- self.select_reason = self.SELECT_SELECT
- self.buffer = ""
- self.showing_version = 0
- self.showing_error = False
- self.show_vars = False
self.presence = presenceservice.get_instance()
self.owner = self.presence.get_owner()
self.owner_id = str(self.owner._properties["nick"])
_logger.debug('Owner_id: %s', self.owner_id)
- self.helper_old_eqs = []
-
options = {
'receive_message': self.receive_message,
'on_connect': lambda: self.helper.send_message("req_sync", "")
@@ -187,7 +196,7 @@ class Calculate(activity.Activity):
_logger.info('\t%s', f)
self.reset()
- self.load_journal_entry()
+ self.layout.show_it()
def ignore_key_cb(self, widget, event):
return True
@@ -234,12 +243,15 @@ class Calculate(activity.Activity):
offset = 0
if eqn.result is not None:
- text += '\n= ' + self.ml.format_number(eqn.result)
+ if isinstance(eqn.result, SVGImage):
+ pass
+ else:
+ text += '\n= ' + self.ml.format_number(eqn.result)
+ self.parser.set_var('Ans', self.ml.format_number(eqn.result))
+ if len(eqn.label) > 0:
+ self.parser.set_var(eqn.label, eqn.equation)
self.text_entry.set_text('')
- self.parser.set_var('Ans', self.ml.format_number(eqn.result))
- if len(eqn.label) > 0:
- self.label_entry.set_text('')
- self.parser.set_var(eqn.label, eqn.equation)
+ self.label_entry.set_text('')
else:
pos = self.parser.get_error_offset()
if pos == len(text) - 1:
@@ -263,6 +275,8 @@ class Calculate(activity.Activity):
label = self.label_entry.get_text()
_logger.debug('process(): parsing \'%s\', label: \'%s\'', s, label)
res = self.parser.parse(s)
+ if type(res) == types.StringType and res.find('</svg>') > -1:
+ res = SVGImage(data=res)
eqn = Equation(label, s, res, self.color, self.owner_id)
# Result ok
@@ -270,7 +284,6 @@ class Calculate(activity.Activity):
self.insert_equation(eqn)
self.helper.send_message("add_eq", str(eqn))
self.showing_error = False
- ans_but = self.layout.buttons["Ans"] # To change label
# Show error
else:
@@ -309,7 +322,7 @@ class Calculate(activity.Activity):
continue
w = gtk.TextView()
b = w.get_buffer()
- b.set_text(name + ":\t" + value)
+ b.set_text(name + ":\t" + str(value))
self.format_var_buf(b)
list.append(w)
self.layout.show_history(list)
@@ -350,20 +363,30 @@ class Calculate(activity.Activity):
if not last_eq_drawn and e.owner == self.owner_id:
self.set_last_equation(e)
last_eq_drawn = True
+ if not isinstance(e.result, SVGImage):
+ continue
+
+# Skip if only drawing own equations
+ if self.layout.minebut.selected == 1 and e.owner != self.ownder_id:
continue
- text = ""
- if len(e.label) > 0:
- text += str(e.label) + ": "
- r = self.ml.format_number(e.result)
- text += str(e.equation) + "\n=" + r
- w = gtk.TextView()
- w.connect('button-press-event', lambda w, e, j: self.equation_pressed_cb(j), i)
- b = w.get_buffer()
-## b.modify_bg(gtk.STATE_ACTIVE | gtk.STATE_NORMAL,
-## gtk.gdk.color_parse(e.color.get_fill_color())
- b.set_text(text)
- self.format_history_buf(b, e)
+ if isinstance(e.result, SVGImage):
+ w = e.result.get_image()
+
+ else:
+ text = ""
+ if len(e.label) > 0:
+ text += str(e.label) + ": "
+ r = self.ml.format_number(e.result)
+ text += str(e.equation) + "\n=" + r
+ w = gtk.TextView()
+ w.connect('button-press-event', lambda w, e, j: self.equation_pressed_cb(j), i)
+ b = w.get_buffer()
+## b.modify_bg(gtk.STATE_ACTIVE | gtk.STATE_NORMAL,
+## gtk.gdk.color_parse(e.color.get_fill_color())
+ b.set_text(text)
+ self.format_history_buf(b, e)
+
list.append(w)
i += 1
@@ -401,19 +424,6 @@ class Calculate(activity.Activity):
f.close()
-# We're not using the set_canvas function, which currently takes care of
-# (setting up) loading journal entries!
- def load_journal_entry(self):
- if self._jobject and self._jobject.file_path:
- ret = self.read_file(self._jobject.file_path)
- if ret:
- _logger.info('Loading from journal succesful')
-# self.refresh_bar() # Done by SharingHelper
- else:
- _logger.info('Loading from journal failed')
- else:
- return False
-
def read_file(self, file_path):
"""Read journal entries, version 1.0"""
@@ -444,10 +454,14 @@ class Calculate(activity.Activity):
eqs = []
for str in f:
eq = Equation(str=str)
- if eq.equation is not None:
- eqs.append(Equation(l[0], l[1], l[2], XoColor(color_string=l[3]), l[4]))
+ if eq.equation is not None and len(eq.equation) > 0:
+ eqs.append(eq)
+ if eq.label is not None and len(eq.label) > 0:
+ self.parser.set_var(eq.label, eq.result)
self.helper_old_eqs = eqs
+ self.refresh_bar()
+
return True
else:
_logger.error('Unable to read journal entry, unknown version (%s)', version)
@@ -632,14 +646,15 @@ class Calculate(activity.Activity):
elif type == self.TYPE_OP_PRE:
if len(sel) is 2:
pos = start
- elif pos == 0:
- str = 'Ans' + str
self.text_entry.insert_text(str, pos)
self.text_entry.set_position(pos + len(str))
elif type == self.TYPE_OP_POST:
if len(sel) is 2:
pos = end
+ elif pos == 0:
+ ans = self.parser.ml.format_number(self.parser.get_var('Ans'))
+ str = ans + str
self.text_entry.insert_text(str, pos)
self.text_entry.set_position(pos + len(str))
@@ -648,8 +663,10 @@ class Calculate(activity.Activity):
if len(sel) == 2:
tlen -= (end - start)
- if tlen == 0 and str in self.parser.get_diadic_operators():
- self.text_entry.set_text('Ans' + str)
+ if tlen == 0 and (str in self.parser.get_diadic_operators() \
+ or str in self.parser.get_post_operators()):
+ ans = self.parser.ml.format_number(self.parser.get_var('Ans'))
+ self.text_entry.set_text(ans + str)
self.text_entry.set_position(3 + len(str))
elif len(sel) is 2:
self.text_entry.set_text(text[:start] + str + text[end:])
diff --git a/eqnparser.py b/eqnparser.py
index 9b0e243..5e9a05c 100644
--- a/eqnparser.py
+++ b/eqnparser.py
@@ -22,6 +22,7 @@ _logger = logging.getLogger('EqnParser')
import types
from mathlib import MathLib
+from plotlib import PlotLib
class Equation:
def __init__(self, eqn):
@@ -109,45 +110,50 @@ class EqnParser:
else:
self.ml = ml
+ self.pl = PlotLib(self)
+
self.error_offset = 0
self.variables = {}
self.functions = {}
self.operators = []
- self.register_function('exp', 1, lambda x: self.ml.exp(x[0]))
- self.register_function('ln', 1, lambda x: self.ml.ln(x[0]))
- self.register_function('log', 1, lambda x: self.ml.log10(x[0]))
- self.register_function('log10', 1, lambda x: self.ml.log10(x[0]))
- self.register_function('pow', 2, lambda x: self.ml.pow(x[0], x[1]))
+ self.cached_diadic_ops = None
+ self.cached_post_ops = None
+
+ self.register_function('exp', lambda x: self.ml.exp(x[0]), {"nargs": 1})
+ self.register_function('ln', lambda x: self.ml.ln(x[0]), {"nargs": 1})
+ self.register_function('log', lambda x: self.ml.log10(x[0]), {"nargs": 1})
+ self.register_function('log10', lambda x: self.ml.log10(x[0]), {"nargs": 1})
+ self.register_function('pow', lambda x: self.ml.pow(x[0], x[1]), {"nargs": 2})
- self.register_function('sqrt', 1, lambda x: self.ml.sqrt(x[0]))
+ self.register_function('sqrt', lambda x: self.ml.sqrt(x[0]), {"nargs": 1})
- self.register_function('sin', 1, lambda x: self.ml.sin(x[0]))
- self.register_function('cos', 1, lambda x: self.ml.cos(x[0]))
- self.register_function('tan', 1, lambda x: self.ml.tan(x[0]))
+ self.register_function('sin', lambda x: self.ml.sin(x[0]), {"nargs": 1})
+ self.register_function('cos', lambda x: self.ml.cos(x[0]), {"nargs": 1})
+ self.register_function('tan', lambda x: self.ml.tan(x[0]), {"nargs": 1})
- self.register_function('asin', 1, lambda x: self.ml.asin(x[0]))
- self.register_function('acos', 1, lambda x: self.ml.acos(x[0]))
- self.register_function('atan', 1, lambda x: self.ml.atan(x[0]))
+ self.register_function('asin', lambda x: self.ml.asin(x[0]), {"nargs": 1})
+ self.register_function('acos', lambda x: self.ml.acos(x[0]), {"nargs": 1})
+ self.register_function('atan', lambda x: self.ml.atan(x[0]), {"nargs": 1})
- self.register_function('sinh', 1, lambda x: self.ml.sinh(x[0]))
- self.register_function('cosh', 1, lambda x: self.ml.cosh(x[0]))
- self.register_function('tanh', 1, lambda x: self.ml.tanh(x[0]))
+ self.register_function('sinh', lambda x: self.ml.sinh(x[0]), {"nargs": 1})
+ self.register_function('cosh', lambda x: self.ml.cosh(x[0]), {"nargs": 1})
+ self.register_function('tanh', lambda x: self.ml.tanh(x[0]), {"nargs": 1})
- self.register_function('asinh', 1, lambda x: self.ml.asinh(x[0]))
- self.register_function('acosh', 1, lambda x: self.ml.acosh(x[0]))
- self.register_function('atanh', 1, lambda x: self.ml.atanh(x[0]))
+ self.register_function('asinh', lambda x: self.ml.asinh(x[0]), {"nargs": 1})
+ self.register_function('acosh', lambda x: self.ml.acosh(x[0]), {"nargs": 1})
+ self.register_function('atanh', lambda x: self.ml.atanh(x[0]), {"nargs": 1})
- self.register_function('round', 1, lambda x: self.ml.round(x[0]))
- self.register_function('floor', 1, lambda x: self.ml.floor(x[0]))
- self.register_function('ceil', 1, lambda x: self.ml.ceil(x[0]))
+ self.register_function('round', lambda x: self.ml.round(x[0]), {"nargs": 1})
+ self.register_function('floor', lambda x: self.ml.floor(x[0]), {"nargs": 1})
+ self.register_function('ceil', lambda x: self.ml.ceil(x[0]), {"nargs": 1})
- self.register_function('mod', 2, lambda x: self.ml.mod(x[0], x[1]))
+ self.register_function('mod', lambda x: self.ml.mod(x[0], x[1]), {"nargs": 2})
- self.register_function('factorize', 1, lambda x: self.ml.factorize(x[0]))
+ self.register_function('factorize', lambda x: self.ml.factorize(x[0]), {"nargs": 1})
- self.register_function('plot', 2, lambda x: self.pl.plot(x[0], x[1]))
+ self.register_function('plot', lambda x: self.pl.plot(x[0], x[1]), {"nargs": 2, 'parse_options': False})
self.register_operator('+', self.OP_DIADIC, 0, lambda x: self.ml.add(x[0], x[1]))
self.register_operator('+', self.OP_PRE, 1, lambda x: x[0])
@@ -173,8 +179,8 @@ class EqnParser:
self.register_operator('%', self.OP_DIADIC, 0, lambda x: self.ml.mod(x[0], x[1]))
- def register_function(self, name, nargs, f):
- self.functions[name] = (nargs, f)
+ def register_function(self, name, f, opts):
+ self.functions[name] = (f, opts)
def register_operator(self, op, type, presedence, f):
self.operators.append((op, type, presedence, f))
@@ -186,11 +192,20 @@ class EqnParser:
self.OP_CHARS += c
def get_diadic_operators(self):
- res = []
- for (op, type, presedence, f) in self.operators:
- if type == self.OP_DIADIC:
- res.append(op)
- return res
+ if self.cached_diadic_ops == None:
+ self.cached_diadic_ops = []
+ for (op, type, presedence, f) in self.operators:
+ if type == self.OP_DIADIC:
+ self.cached_diadic_ops.append(op)
+ return self.cached_diadic_ops
+
+ def get_post_operators(self):
+ if self.cached_post_ops == None:
+ self.cached_post_ops = []
+ for (op, type, presedence, f) in self.operators:
+ if type == self.OP_POST:
+ self.cached_post_ops.append(op)
+ return self.cached_post_ops
def reset_variable_level(self, level):
return
@@ -198,9 +213,12 @@ class EqnParser:
# self.variables[i].highest_level = level
def set_var(self, name, val):
- self.variables[name] = val
+ if type(val) is types.FloatType:
+ self.variables[name] = self.ml.d(val)
+ else:
+ self.variables[name] = val
- def get_var(self, name, val):
+ def get_var(self, name):
if name in self.variables:
return self.variables[name]
else:
@@ -254,17 +272,20 @@ class EqnParser:
_logger.error('Function \'%s\' not defined', func)
return None
- (nargs, f) = self.functions[func]
- if len(args) != nargs:
- _logger.error('Invalid number of arguments (%d instead of %d)', len(args), nargs)
+ (f, opts) = self.functions[func]
+ if len(args) != opts['nargs']:
+ _logger.error('Invalid number of arguments (%d instead of %d)', len(args), opts['nargs'])
return None
- pargs = []
- for i in range(len(args)):
- pargs.append(self.parse(args[i]))
- if pargs[i] is None:
- _logger.error('Unable to parse argument %d: \'%s\'', i, args[i])
- return None
+ if 'parse_options' in opts and opts['parse_options'] == False:
+ pargs = args
+ else:
+ pargs = []
+ for i in range(len(args)):
+ pargs.append(self.parse(args[i]))
+ if pargs[i] is None:
+ _logger.error('Unable to parse argument %d: \'%s\'', i, args[i])
+ return None
res = f(pargs)
_logger.debug('Function \'%s\' returned %s', func, self.ml.format_number(res))
diff --git a/layout.py b/layout.py
index 10992e4..4f748c2 100644
--- a/layout.py
+++ b/layout.py
@@ -39,7 +39,9 @@ class CalcLayout:
[0, 3, 1, '0', self.col_gray2, lambda w: self._parent.add_text('0')],
[1, 3, 1, '.', self.col_gray2, lambda w: self._parent.add_text('.')],
- [2, 3, 1, 'Ans', self.col_gray2, lambda w: self._parent.add_text('Ans')],
+
+# Deprecated -- functionality available through interface and labels
+# [2, 3, 1, 'Ans', self.col_gray2, lambda w: self._parent.add_text('Ans')],
[3, 0, 3, 'clear', self.col_gray1, lambda w: self._parent.clear()],
@@ -80,8 +82,6 @@ class CalcLayout:
self.grid.set_row_spacings(6)
self.grid.set_col_spacings(6)
- self._parent.set_canvas(self.grid)
-
# Left part: container and input
hc1 = gtk.HBox(False, 10)
label1 = gtk.Label(_('Label:'))
@@ -140,6 +140,9 @@ class CalcLayout:
self.history.set_border_width(6)
scrolled_window.add_with_viewport(self.history)
self.grid.attach(scrolled_window, 6, 10, 5, 16)
+
+ def show_it(self):
+ self._parent.set_canvas(self.grid)
self._parent.show_all()
def show_history(self, window_list):
diff --git a/mathlib.py b/mathlib.py
index 6ded7d2..e1a7eed 100644
--- a/mathlib.py
+++ b/mathlib.py
@@ -22,8 +22,7 @@ import math
from decimal import Decimal
import logging
-_logger = logging.getLogger('calc-activity')
-
+_logger = logging.getLogger('MathLib')
class MathLib:
ANGLE_DEG = math.pi/180
@@ -170,7 +169,7 @@ class MathLib:
def pow(self, x, y):
if self.is_int(y):
- return x ** y
+ return x ** int(y)
else:
return self.d(math.pow(x, y))
diff --git a/plotlib.py b/plotlib.py
new file mode 100644
index 0000000..07db19c
--- /dev/null
+++ b/plotlib.py
@@ -0,0 +1,138 @@
+# plotlib.py, svg plot generator by Reinier Heeres <reinier@heeres.eu>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Change log:
+# 2007-09-04: rwh, first version
+
+import logging
+_logger = logging.getLogger('PlotLib')
+
+class PlotLib:
+ """Class to generate an svg plot for a function.
+ Evaluation of values is done using the EqnParser class."""
+
+ def __init__(self, parser):
+ self.parser = parser
+
+ self.svg_data = ""
+ self.set_size(0, 0)
+
+ def set_size(self, width, height):
+ self.width = width
+ self.height = height
+
+ def get_svg(self):
+ return self.svg_data
+
+ def parse_range(self, range):
+ p1 = range.split('=')
+ if len(p1) != 2:
+ return None
+ p2 = p1[1].split('..')
+ if len(p2) != 2:
+ return None
+ return (p1[0], (float(p2[0]), float(p2[1])))
+
+ def evaluate(self, eqn, var, range, n=100):
+ x_old = self.parser.get_var(var)
+
+ res = []
+ d = float((range[1] - range[0])) / (n - 1)
+ x = range[0]
+ while n > 0:
+ self.parser.set_var(var, x)
+ v = float(self.parser.parse(eqn))
+ res.append((x, v))
+ x += d
+ n -= 1
+
+ self.parser.set_var(var, x_old)
+ return res
+
+ def create_image(self):
+ self.svg_data = '<?xml version="1.0" standalone="no"?>\n'
+ self.svg_data += '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n'
+ self.svg_data += '<svg width="%d" height="%d" version="1.1" xmlns="http://www.w3.org/2000/svg">\n' % (self.width, self.height)
+
+ def finish_image(self):
+ self.svg_data += '</svg>'
+
+ def plot_line(self, c0, c1, col):
+ c0 = self.rcoords_to_coords(c0)
+ c1 = self.rcoords_to_coords(c1)
+ self.svg_data += '<line style="stroke:%s;stroke-width:1" x1="%f" y1="%f" x2="%f" y2="%f" />\n' % (col, c0[0], c0[1], c1[0], c1[1])
+
+ def plot_polyline(self, coords, col):
+ self.svg_data += '<polyline style="fill:none;stroke:%s;stroke-width:1" points="' % (col)
+ for c in coords:
+ c = self.rcoords_to_coords(c)
+ self.svg_data += '%f,%f ' % (c[0], c[1])
+ self.svg_data += '" />\n'
+
+ def determine_bounds(self, vals):
+ self.minx = self.miny = 1e99
+ self.maxx = self.maxy = -1e99
+ for (x, y) in vals:
+ self.minx = min(float(x), self.minx)
+ self.miny = min(float(y), self.miny)
+ self.maxx = max(float(x), self.maxx)
+ self.maxy = max(float(y), self.maxy)
+
+ def rcoords_to_coords(self, pair):
+ return (pair[0] * self.width, pair[1] * self.height)
+
+ def vals_to_rcoords(self, pair):
+ ret = (0.1 + (pair[0] - self.minx) / (self.maxx - self.minx) * 0.8, \
+ 0.9 - (pair[1] - self.miny) / (self.maxy - self.miny) * 0.8)
+ return ret
+
+ def add_curve(self, vals):
+ self.determine_bounds(vals)
+
+ self.plot_line((0.08, 0.08), (0.08, 0.92), "black")
+ self.plot_line((0.08, 0.92), (0.92, 0.92), "black")
+
+ c = []
+ for v in vals:
+ c.append(self.vals_to_rcoords(v))
+# print 'coords: %r' % c
+
+ self.plot_polyline(c, "blue")
+
+ def export_plot(self, fn):
+ f = open(fn, "w")
+ f.write(self.svg_data)
+ f.close()
+
+ def plot(self, eqn, range_spec):
+ (var, range) = self.parse_range(range_spec)
+ if range is None:
+ _logger.error('Unable to parse range')
+ return False
+ _logger.info('Plot range for var %s: %r', var, range)
+
+ self.set_size(200, 200)
+ self.create_image()
+
+ vals = self.evaluate(eqn, var, range)
+# print 'vals: %r' % vals
+ self.add_curve(vals)
+
+ self.finish_image()
+
+ self.export_plot("/tmp/calculate_graph.svg")
+
+ return self.get_svg()
diff --git a/svgimage.py b/svgimage.py
new file mode 100644
index 0000000..1584873
--- /dev/null
+++ b/svgimage.py
@@ -0,0 +1,55 @@
+# svgimage.py, svg image class by Reinier Heeres <reinier@heeres.eu>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Change log:
+# 2007-09-07: rwh, first version
+
+import logging
+_logger = logging.getLogger('SVGImage')
+
+import gtk
+import rsvg
+
+class SVGImage:
+
+ def __init__(self, fn=None, data=None):
+ if fn is not None:
+ self.load(fn)
+ elif data is not None:
+ self.load_data(data)
+
+ def get_image(self):
+ return self._image
+
+ def get_svg_data(self):
+ return self._svg_data
+
+ def render_svg(self):
+ self._handle = rsvg.Handle(data=self._svg_data)
+ self._pixbuf = self._handle.get_pixbuf()
+ self._image = gtk.Image()
+ self._image.set_from_pixbuf(self._pixbuf)
+ return self._image
+
+ def load(self, fn):
+ f = open(fn, 'rb')
+ self._svg_data = f.read()
+ f.close()
+ return self.render_svg()
+
+ def load_data(self, svgdat):
+ self._svg_data = svgdat
+ return self.render_svg()