We introduce analogues of graph.data.function etc. to be used as data
sources for graph.graphxy.
Naming is changed in order to make things more consistent with grah/graphxy.
* rename functionxy to functionlambda (2D function given as lambda
expression)
* rename paramfunctionxy to paramfunctionlambda (2D parametric
function given as lambda expression)
* new functionxy (3D function given as textual expression)
* new functionxylambda (3D function given as lambda expression)
* new paramtsfunction (function of 2 parameters given as textual
expression)
* new paramtsfunctionlambda (function of 2 parameters given as
lambda expression)
Note that all parametric functions can provide 2D as well 3D data.
Signed-off-by: Michael J Gruber <[EMAIL PROTECTED]>
---
pyx/graph/data.py | 134
++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 132 insertions(+), 2 deletions(-)
diff --git a/pyx/graph/data.py b/pyx/graph/data.py
index 9e525ba..8ce2607 100644
--- a/pyx/graph/data.py
+++ b/pyx/graph/data.py
@@ -573,7 +573,7 @@ class function(_data):
return dynamiccolumns
-class functionxy(function):
+class functionlambda(function):
def __init__(self, f, min=None, max=None, **kwargs):
function.__init__(self, "y(x)=f(x)", context={"f": f},
min=min, max=max, **kwargs)
@@ -606,7 +606,137 @@ class paramfunction(_data):
self.columnnames = self.columns.keys()
-class paramfunctionxy(paramfunction):
+class paramfunctionlambda(paramfunction):
def __init__(self, f, min, max, **kwargs):
paramfunction.__init__(self, "t", min, max, "x, y = f(t)",
context={"f": f}, **kwargs)
+
+
+class functionxy(_data):
+
+ defaultstyles = defaultlines
+
+ assignmentpattern =
re.compile(r"\s*([a-z_][a-z0-9_]*)\s*\(\s*([a-z_][a-z0-9_]*)\s*,\s*([a-z_][a-z0-9_]*)\s*\)\s*=",
re.IGNORECASE)
+
+ def __init__(self, expression, title=_notitle, xmin=None,
xmax=None, ymin=None, ymax=None,
+ points=10, context={}):
+
+ if title is _notitle:
+ self.title = expression
+ else:
+ self.title = title
+ self.xmin = xmin
+ self.xmax = xmax
+ self.ymin = ymin
+ self.ymax = ymax
+ self.numberofpoints = points
+ self.context = context.copy() # be safe on late evaluations
+ m = self.assignmentpattern.match(expression)
+ if m:
+ self.zname, self.xname, self.yname = m.groups()
+ expression = expression[m.end():]
+ else:
+ raise ValueError("z(x,y)=... or similar expected")
+ if context.has_key(self.xname):
+ raise ValueError("xname in context")
+ if context.has_key(self.yname):
+ raise ValueError("yname in context")
+ self.expression = compile(expression.strip(), __file__, "eval")
+ self.columns = {}
+ self.columnnames = [self.xname, self.yname, self.zname]
+
+ def dynamiccolumns(self, graph):
+ dynamiccolumns = {self.xname: [], self.yname: [], self.zname: []}
+
+ xaxis = graph.axes[self.xname]
+ yaxis = graph.axes[self.yname]
+ from pyx.graph.axis import logarithmic
+ logxaxis = isinstance(xaxis.axis, logarithmic)
+ logyaxis = isinstance(yaxis.axis, logarithmic)
+ if self.xmin is not None:
+ xmin = self.xmin
+ else:
+ xmin = xaxis.data.min
+ if self.xmax is not None:
+ xmax = self.xmax
+ else:
+ xmax = xaxis.data.max
+ if logxaxis:
+ xmin = math.log(xmin)
+ xmax = math.log(xmax)
+ if self.ymin is not None:
+ ymin = self.ymin
+ else:
+ ymin = yaxis.data.min
+ if self.ymax is not None:
+ ymax = self.ymax
+ else:
+ ymax = yaxis.data.max
+ if logyaxis:
+ ymin = math.log(ymin)
+ ymax = math.log(ymax)
+ for i in range(self.numberofpoints):
+ x = xmin + (xmax-xmin)*i / (self.numberofpoints-1.0)
+ if logxaxis:
+ x = math.exp(x)
+ self.context[self.xname] = x
+ for j in range(self.numberofpoints):
+ y = ymin + (ymax-ymin)*j / (self.numberofpoints-1.0)
+ if logyaxis:
+ y = math.exp(y)
+ dynamiccolumns[self.xname].append(x)
+ dynamiccolumns[self.yname].append(y)
+ self.context[self.yname] = y
+ try:
+ z = eval(self.expression, _mathglobals, self.context)
+ except (ArithmeticError, ValueError):
+ z = None
+ dynamiccolumns[self.zname].append(z)
+ return dynamiccolumns
+
+
+class functionxylambda(functionxy):
+
+ def __init__(self, f, xmin=None, xmax=None, ymin=None, ymax=None,
**kwargs):
+ functionxy.__init__(self, "z(x,y)=f(x,y)", context={"f": f},
xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax, **kwargs)
+
+
+class paramtsfunction(_data):
+
+ defaultstyles = defaultlines
+
+ def __init__(self, tname, tmin, tmax, sname, smin, smax,
expression, title=_notitle, points=10, context={}):
+ if context.has_key(tname):
+ raise ValueError("tname in context")
+ if context.has_key(sname):
+ raise ValueError("sname in context")
+ if title is _notitle:
+ self.title = expression
+ else:
+ self.title = title
+ varlist, expression = expression.split("=")
+ expression = compile(expression.strip(), __file__, "eval")
+ keys = [key.strip() for key in varlist.split(",")]
+ self.columns = dict([(key, []) for key in keys])
+ context = context.copy()
+ for i in range(points):
+ tparam = tmin + (tmax-tmin)*i / (points-1.0)
+ context[tname] = tparam
+ for j in range(points):
+ sparam = smin + (smax-smin)*j / (points-1.0)
+ context[sname] = sparam
+ values = eval(expression, _mathglobals, context)
+ for key, value in zip(keys, values):
+ self.columns[key].append(value)
+ if len(keys) != len(values):
+ raise ValueError("unpack tuple of wrong size")
+ self.columnnames = self.columns.keys()
+
+
+class paramtsfunctionlambda(paramtsfunction):
+
+ def __init__(self, f, tmin, tmax, smin, smax, **kwargs):
+ paramtsfunction.__init__(self, "t", tmin, tmax, "s", smin,
smax, "x, y, z = f(t,s)", context={"f": f}, **kwargs)
+
+
+
-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://sourceforge.net/services/buy/index.php
_______________________________________________
PyX-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/pyx-devel