19 import re, codecs, os, platform, copy, itertools, math, cmath, random, sys, copy
23 if re.search(
"windows", platform.system(), re.I):
26 _default_directory = _winreg.QueryValueEx(_winreg.OpenKey(_winreg.HKEY_CURRENT_USER, \
27 r"Software\Microsoft\Windows\Current Version\Explorer\Shell Folders"),
"Desktop")[0]
32 _default_directory = os.path.expanduser(
"~") + os.sep +
"Desktop" 34 _default_fileName =
"tmp.svg" 37 _hacks[
"inkscape-text-vertical-shift"] =
False 39 def rgb(r, g, b, maximum=1.):
40 """Create an SVG color string "#xxyyzz" from r, g, and b. 42 r,g,b = 0 is black and r,g,b = maximum is white. 44 return "#%02x%02x%02x" % (
max(0,
min(r*255./maximum, 255)),
max(0,
min(g*255./maximum, 255)),
max(0,
min(b*255./maximum, 255)))
47 for name
in attr.keys():
48 name_colon = re.sub(
"__",
":", name)
49 if name_colon != name:
50 attr[name_colon] = attr[name]
54 name_dash = re.sub(
"_",
"-", name)
56 attr[name_dash] = attr[name]
63 """A tree representation of an SVG image or image fragment. 65 SVG(t, sub, sub, sub..., attribute=value) 67 t required SVG type name 68 sub optional list nested SVG elements or text/Unicode 69 attribute=value pairs optional keywords SVG attributes 71 In attribute names, "__" becomes ":" and "_" becomes "-". 75 <g id="mygroup" fill="blue"> 76 <rect x="1" y="1" width="2" height="2" /> 77 <rect x="3" y="3" width="2" height="2" /> 82 >>> svg = SVG("g", SVG("rect", x=1, y=1, width=2, height=2), \ 83 ... SVG("rect", x=3, y=3, width=2, height=2), \ 84 ... id="mygroup", fill="blue") 86 Sub-elements and attributes may be accessed through tree-indexing: 88 >>> svg = SVG("text", SVG("tspan", "hello there"), stroke="none", fill="black") 96 Iteration is depth-first: 98 >>> svg = SVG("g", SVG("g", SVG("line", x1=0, y1=0, x2=1, y2=1)), \ 99 ... SVG("text", SVG("tspan", "hello again"))) 101 >>> for ti, s in svg: 102 ... print ti, repr(s) 105 (0, 0) <line x2=1 y1=0 x1=0 y2=1 /> 110 (1,) <text (1 sub) /> 111 (1, 0) <tspan (1 sub) /> 112 (1, 0, 0) 'hello again' 114 Use "print" to navigate: 119 [0, 0] <line x2=1 y1=0 x1=0 y2=1 /> 121 [1, 0] <tspan (1 sub) /> 124 if len(t_sub) == 0:
raise TypeError(
"SVG element must have a t (SVG type)")
136 """Index is a list that descends tree, returning a sub-element if 137 it ends with a number and an attribute if it ends with a string.""" 139 if isinstance(ti, (list, tuple)):
140 for i
in ti[:-1]: obj = obj[i]
143 if isinstance(ti, (int, long, slice)):
return obj.sub[ti]
144 else:
return obj.attr[ti]
147 """Index is a list that descends tree, returning a sub-element if 148 it ends with a number and an attribute if it ends with a string.""" 150 if isinstance(ti, (list, tuple)):
151 for i
in ti[:-1]: obj = obj[i]
154 if isinstance(ti, (int, long, slice)): obj.sub[ti] = value
155 else: obj.attr[ti] = value
158 """Index is a list that descends tree, returning a sub-element if 159 it ends with a number and an attribute if it ends with a string.""" 161 if isinstance(ti, (list, tuple)):
162 for i
in ti[:-1]: obj = obj[i]
165 if isinstance(ti, (int, long, slice)): del obj.sub[ti]
166 else: del obj.attr[ti]
169 """x in svg == True iff x is an attribute in svg.""" 170 return value
in self.
attr 173 """x == y iff x represents the same SVG as y.""" 174 if id(self) ==
id(other):
return True 175 return isinstance(other, SVG)
and self.
t == other.t
and self.
sub == other.sub
and self.
attr == other.attr
178 """x != y iff x does not represent the same SVG as y.""" 179 return not (self == other)
182 """Appends x to the list of sub-elements (drawn last, overlaps 183 other primatives).""" 187 """Prepends x to the list of sub-elements (drawn first may be 188 overlapped by other primatives).""" 192 """Extends list of sub-elements by a list x.""" 196 """Deep copy of SVG tree. Set shallow=True for a shallow copy.""" 198 return copy.copy(self)
200 return copy.deepcopy(self)
204 """Manages SVG iteration.""" 218 return self.
ti, self.
svg 220 if not isinstance(self.
svg, SVG):
raise StopIteration
223 if "iterators" not in self.__dict__:
225 for i, s
in enumerate(self.svg.sub):
226 self.iterators.append(self.__class__(s, self.
ti + (i,), self.
depth_limit))
227 for k, s
in self.svg.attr.items():
228 self.iterators.append(self.__class__(s, self.
ti + (k,), self.
depth_limit))
235 """Returns a depth-first generator over the SVG. If depth_limit 236 is a number, stop recursion at that depth.""" 240 """Not implemented yet. Any ideas on how to do it? 242 Returns a breadth-first generator over the SVG. If depth_limit 243 is a number, stop recursion at that depth.""" 244 raise NotImplementedError(
"Got an algorithm for breadth-first searching a tree without effectively copying the tree?")
248 def items(self, sub=True, attr=True, text=True):
249 """Get a recursively-generated list of tree-index, sub-element/attribute pairs. 251 If sub == False, do not show sub-elements. 252 If attr == False, do not show attributes. 253 If text == False, do not show text/Unicode sub-elements. 258 if isinstance(ti[-1], (int, long)):
259 if isinstance(s, str): show = text
263 if show: output.append((ti, s))
266 def keys(self, sub=True, attr=True, text=True):
267 """Get a recursively-generated list of tree-indexes. 269 If sub == False, do not show sub-elements. 270 If attr == False, do not show attributes. 271 If text == False, do not show text/Unicode sub-elements. 273 return [ti
for ti, s
in self.
items(sub, attr, text)]
275 def values(self, sub=True, attr=True, text=True):
276 """Get a recursively-generated list of sub-elements and attributes. 278 If sub == False, do not show sub-elements. 279 If attr == False, do not show attributes. 280 If text == False, do not show text/Unicode sub-elements. 282 return [s
for ti, s
in self.
items(sub, attr, text)]
287 """Print (actually, return a string of) the tree in a form useful for browsing.""" 288 return self.
tree(sub=
True, attr=
False, text=
False)
290 def tree(self, depth_limit=None, sub=True, attr=True, text=True, tree_width=20, obj_width=80):
291 """Print (actually, return a string of) the tree in a form useful for browsing. 293 If depth_limit == a number, stop recursion at that depth. 294 If sub == False, do not show sub-elements. 295 If attr == False, do not show attributes. 296 If text == False, do not show text/Unicode sub-elements. 297 tree_width is the number of characters reserved for printing tree indexes. 298 obj_width is the number of characters reserved for printing sub-elements/attributes. 303 line =
"%s %s" % ((
"%%-%ds" % tree_width) % repr(
None), (
"%%-%ds" % obj_width) % (repr(self))[0:obj_width])
308 if isinstance(ti[-1], (int, long)):
309 if isinstance(s, str): show = text
314 line =
"%s %s" % ((
"%%-%ds" % tree_width) % repr(
list(ti)), (
"%%-%ds" % obj_width) % (
" "*len(ti) + repr(s))[0:obj_width])
317 return "\n".
join(output)
319 def xml(self, indent=" ", newl="\n", depth_limit=None, depth=0):
320 """Get an XML representation of the SVG. 322 indent string used for indenting 323 newl string used for newlines 324 If depth_limit == a number, stop recursion at that depth. 325 depth starting depth (not useful for users) 331 for n, v
in self.attr.items():
332 if isinstance(v, dict):
333 v =
"; ".
join([
"%s:%s" % (ni, vi)
for ni, vi
in v.items()])
334 elif isinstance(v, (list, tuple)):
336 attrstr.append(
" %s=%s" % (n, repr(v)))
337 attrstr =
"".
join(attrstr)
339 if len(self.
sub) == 0:
return "%s<%s%s />" % (indent * depth, self.
t, attrstr)
341 if depth_limit ==
None or depth_limit > depth:
344 if isinstance(s, SVG):
345 substr.append(s.xml(indent, newl, depth_limit, depth + 1) + newl)
346 elif isinstance(s, str):
347 substr.append(
"%s%s%s" % (indent * (depth + 1), s, newl))
349 substr.append(
"%s%s%s" % (indent * (depth + 1), repr(s), newl))
350 substr =
"".
join(substr)
352 return "%s<%s%s>%s%s%s</%s>" % (indent * depth, self.
t, attrstr, newl, substr, indent * depth, self.
t)
355 return "%s<%s (%d sub)%s />" % (indent * depth, self.
t, len(self.
sub), attrstr)
358 """Get an XML representation of the SVG that can be saved/rendered. 360 indent string used for indenting 361 newl string used for newlines 364 if self.
t ==
"svg": top = self
367 <?xml version="1.0" standalone="no"?> 368 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> 370 """ + (
"".
join(top.__standalone_xml(indent, newl)))
373 output = [
u"<%s" % self.
t]
375 for n, v
in self.attr.items():
376 if isinstance(v, dict):
377 v =
"; ".
join([
"%s:%s" % (ni, vi)
for ni, vi
in v.items()])
378 elif isinstance(v, (list, tuple)):
380 output.append(
u" %s=\"%s\"" % (n, v))
382 if len(self.
sub) == 0:
383 output.append(
u" />%s%s" % (newl, newl))
386 elif self.
t ==
"text" or self.
t ==
"tspan" or self.
t ==
"style":
390 output.append(
u">%s%s" % (newl, newl))
393 if isinstance(s, SVG): output.extend(s.__standalone_xml(indent, newl))
394 else: output.append(unicode(s))
396 if self.
t ==
"tspan": output.append(
u"</%s>" % self.
t)
397 else: output.append(
u"</%s>%s%s" % (self.
t, newl, newl))
403 fileName = _default_fileName
404 if re.search(
"windows", platform.system(), re.I)
and not os.path.isabs(fileName):
405 fileName = _default_directory + os.sep + fileName
408 def save(self, fileName=None, encoding="utf-8", compresslevel=None):
409 """Save to a file for viewing. Note that svg.save() overwrites the file named _default_fileName. 411 fileName default=None note that _default_fileName will be overwritten if 412 no fileName is specified. If the extension 413 is ".svgz" or ".gz", the output will be gzipped 414 encoding default="utf-8" file encoding (default is Unicode) 415 compresslevel default=None if a number, the output will be gzipped with that 416 compression level (1-9, 1 being fastest and 9 most 421 if compresslevel !=
None or re.search(
"\.svgz$", fileName, re.I)
or re.search(
"\.gz$", fileName, re.I):
423 if compresslevel ==
None:
424 f = gzip.GzipFile(fileName,
"w")
426 f = gzip.GzipFile(fileName,
"w", compresslevel)
428 f = codecs.EncodedFile(f,
"utf-8", encoding)
433 f = codecs.open(fileName,
"w", encoding=encoding)
437 def inkview(self, fileName=None, encoding="utf-8"):
438 """View in "inkview", assuming that program is available on your system. 440 fileName default=None note that any file named _default_fileName will be 441 overwritten if no fileName is specified. If the extension 442 is ".svgz" or ".gz", the output will be gzipped 443 encoding default="utf-8" file encoding (default is Unicode) 446 self.
save(fileName, encoding)
447 os.spawnvp(os.P_NOWAIT,
"inkview", (
"inkview", fileName))
449 def inkscape(self, fileName=None, encoding="utf-8"):
450 """View in "inkscape", assuming that program is available on your system. 452 fileName default=None note that any file named _default_fileName will be 453 overwritten if no fileName is specified. If the extension 454 is ".svgz" or ".gz", the output will be gzipped 455 encoding default="utf-8" file encoding (default is Unicode) 458 self.
save(fileName, encoding)
459 os.spawnvp(os.P_NOWAIT,
"inkscape", (
"inkscape", fileName))
461 def firefox(self, fileName=None, encoding="utf-8"):
462 """View in "firefox", assuming that program is available on your system. 464 fileName default=None note that any file named _default_fileName will be 465 overwritten if no fileName is specified. If the extension 466 is ".svgz" or ".gz", the output will be gzipped 467 encoding default="utf-8" file encoding (default is Unicode) 470 self.
save(fileName, encoding)
471 os.spawnvp(os.P_NOWAIT,
"firefox", (
"firefox", fileName))
475 _canvas_defaults = {
"width":
"400px",
"height":
"400px",
"viewBox":
"0 0 100 100", \
476 "xmlns":
"http://www.w3.org/2000/svg",
"xmlns:xlink":
"http://www.w3.org/1999/xlink",
"version":
"1.1", \
477 "style": {
"stroke":
"black",
"fill":
"none",
"stroke-width":
"0.5pt",
"stroke-linejoin":
"round",
"text-anchor":
"middle"}, \
478 "font-family": [
"Helvetica",
"Arial",
"FreeSans",
"Sans",
"sans",
"sans-serif"], \
482 """Creates a top-level SVG object, allowing the user to control the 483 image size and aspect ratio. 485 canvas(sub, sub, sub..., attribute=value) 487 sub optional list nested SVG elements or text/Unicode 488 attribute=value pairs optional keywords SVG attributes 490 Default attribute values: 494 viewBox "0 0 100 100" 495 xmlns "http://www.w3.org/2000/svg" 496 xmlns:xlink "http://www.w3.org/1999/xlink" 498 style "stroke:black; fill:none; stroke-width:0.5pt; stroke-linejoin:round; text-anchor:middle" 499 font-family "Helvetica,Arial,FreeSans?,Sans,sans,sans-serif" 501 attributes =
dict(_canvas_defaults)
502 attributes.update(attr)
504 if sub ==
None or sub == ():
505 return SVG(
"svg", **attributes)
507 return SVG(
"svg", *sub, **attributes)
510 """Same as canvas(), but draws an outline around the drawable area, 511 so that you know how close your image is to the edges.""" 512 svg =
canvas(*sub, **attr)
513 match = re.match(
"[, \t]*([0-9e.+\-]+)[, \t]+([0-9e.+\-]+)[, \t]+([0-9e.+\-]+)[, \t]+([0-9e.+\-]+)[, \t]*", svg[
"viewBox"])
514 if match ==
None:
raise ValueError(
"canvas viewBox is incorrectly formatted")
515 x, y, width, height = [
float(x)
for x
in match.groups()]
516 svg.prepend(
SVG(
"rect", x=x, y=y, width=width, height=height, stroke=
"none", fill=
"cornsilk"))
517 svg.append(
SVG(
"rect", x=x, y=y, width=width, height=height, stroke=
"black", fill=
"none"))
520 def template(fileName, svg, replaceme="REPLACEME"):
521 """Loads an SVG image from a file, replacing instances of 522 <REPLACEME /> with a given svg object. 524 fileName required name of the template SVG 525 svg required SVG object for replacement 526 replaceme default="REPLACEME" fake SVG element to be replaced by the given object 528 >>> print load("template.svg") 529 None <svg (2 sub) style=u'stroke:black; fill:none; stroke-width:0.5pt; stroke-linejoi 530 [0] <rect height=u'100' width=u'100' stroke=u'none' y=u'0' x=u'0' fill=u'yellow' 533 >>> print template("template.svg", SVG("circle", cx=50, cy=50, r=30)) 534 None <svg (2 sub) style=u'stroke:black; fill:none; stroke-width:0.5pt; stroke-linejoi 535 [0] <rect height=u'100' width=u'100' stroke=u'none' y=u'0' x=u'0' fill=u'yellow' 536 [1] <circle cy=50 cx=50 r=30 /> 538 output =
load(fileName)
540 if isinstance(s, SVG)
and s.t == replaceme:
547 """Loads an SVG image from a file.""" 551 """Loads an SVG image from a stream (can be a string or a file object).""" 553 from xml.sax
import handler, make_parser
554 from xml.sax.handler
import feature_namespaces, feature_external_ges, feature_external_pes
556 class ContentHandler(handler.ContentHandler):
560 self.all_whitespace = re.compile(
"^\s*$")
562 def startElement(self, name, attr):
564 s.attr =
dict(attr.items())
565 if len(self.stack) > 0:
566 last = self.stack[-1]
570 def characters(self, ch):
571 if not isinstance(ch, str)
or self.all_whitespace.match(ch) ==
None:
572 if len(self.stack) > 0:
573 last = self.stack[-1]
574 if len(last.sub) > 0
and isinstance(last.sub[-1], str):
575 last.sub[-1] = last.sub[-1] +
"\n" + ch
579 def endElement(self, name):
580 if len(self.stack) > 0:
581 last = self.stack[-1]
582 if isinstance(last, SVG)
and last.t ==
"style" and "type" in last.attr
and last.attr[
"type"] ==
"text/css" and len(last.sub) == 1
and isinstance(last.sub[0], str):
583 last.sub[0] =
"<![CDATA[\n" + last.sub[0] +
"]]>" 585 self.output = self.stack.pop()
587 ch = ContentHandler()
588 parser = make_parser()
589 parser.setContentHandler(ch)
590 parser.setFeature(feature_namespaces, 0)
591 parser.setFeature(feature_external_ges, 0)
597 def totrans(expr, vars=(
"x",
"y"), globals=
None, locals=
None):
598 """Converts to a coordinate transformation (a function that accepts 599 two arguments and returns two values). 601 expr required a string expression or a function 602 of two real or one complex value 603 vars default=("x", "y") independent variable names; 604 a singleton ("z",) is interpreted 606 globals default=None dict of global variables 607 locals default=None dict of local variables 611 if expr.__code__.co_argcount == 2:
614 elif expr.__code__.co_argcount == 1:
615 split =
lambda z: (z.real, z.imag)
616 output =
lambda x, y:
split(
expr(x + y*1j))
617 output.__name__ = expr.__name__
621 raise TypeError(
"must be a function of 2 or 1 variables")
625 if globals !=
None: g.update(globals)
626 output = eval(
"lambda %s, %s: (%s)" % (vars[0], vars[1], expr), g, locals)
627 output.__name__ =
"%s,%s -> %s" % (vars[0], vars[1], expr)
632 if globals !=
None: g.update(globals)
633 output = eval(
"lambda %s: (%s)" % (vars[0], expr), g, locals)
634 split =
lambda z: (z.real, z.imag)
636 output2.__name__ =
"%s -> %s" % (vars[0], expr)
640 raise TypeError(
"vars must have 2 or 1 elements")
642 def window(xmin, xmax, ymin, ymax, x=0, y=0, width=100, height=100, xlogbase=None, ylogbase=None, minusInfinity=-1000, flipx=False, flipy=True):
643 """Creates and returns a coordinate transformation (a function that 644 accepts two arguments and returns two values) that transforms from 645 (xmin, ymin), (xmax, ymax) 647 (x, y), (x + width, y + height). 649 xlogbase, ylogbase default=None, None if a number, transform 650 logarithmically with given base 651 minusInfinity default=-1000 what to return if 652 log(0 or negative) is attempted 653 flipx default=False if true, reverse the direction of x 654 flipy default=True if true, reverse the direction of y 656 (When composing windows, be sure to set flipy=False.) 676 if xlogbase !=
None and (ix1 <= 0.
or ix2 <= 0.):
raise ValueError(
"x range incompatible with log scaling: (%g, %g)" % (ix1, ix2))
678 if ylogbase !=
None and (iy1 <= 0.
or iy2 <= 0.):
raise ValueError(
"y range incompatible with log scaling: (%g, %g)" % (iy1, iy2))
680 def maybelog(t, it1, it2, ot1, ot2, logbase):
681 if t <= 0.:
return minusInfinity
683 return ot1 + 1.*(math.log(t, logbase) - math.log(it1, logbase))/(math.log(it2, logbase) - math.log(it1, logbase)) * (ot2 - ot1)
685 xlogstr, ylogstr =
"",
"" 688 xfunc =
lambda x: ox1 + 1.*(x - ix1)/(ix2 - ix1) * (ox2 - ox1)
690 xfunc =
lambda x: maybelog(x, ix1, ix2, ox1, ox2, xlogbase)
691 xlogstr =
" xlog=%g" % xlogbase
694 yfunc =
lambda y: oy1 + 1.*(y - iy1)/(iy2 - iy1) * (oy2 - oy1)
696 yfunc =
lambda y: maybelog(y, iy1, iy2, oy1, oy2, ylogbase)
697 ylogstr =
" ylog=%g" % ylogbase
699 output =
lambda x, y: (xfunc(x), yfunc(y))
701 output.__name__ =
"(%g, %g), (%g, %g) -> (%g, %g), (%g, %g)%s%s" % (ix1, ix2, iy1, iy2, ox1, ox2, oy1, oy2, xlogstr, ylogstr)
705 """Creates and returns a coordinate transformation which rotates 706 around (cx,cy) by "angle" degrees.""" 707 angle *= math.pi/180.
708 return lambda x, y: (cx + math.cos(angle)*(x - cx) - math.sin(angle)*(y - cy), cy + math.sin(angle)*(x - cx) + math.cos(angle)*(y - cy))
711 """Stores graphics primitive objects and applies a single coordinate 712 transformation to them. To compose coordinate systems, nest Fig 715 Fig(obj, obj, obj..., trans=function) 717 obj optional list a list of drawing primatives 718 trans default=None a coordinate transformation function 720 >>> fig = Fig(Line(0,0,1,1), Rect(0.2,0.2,0.8,0.8), trans="2*x, 2*y") 721 >>> print fig.SVG().xml() 723 <path d='M0 0L2 2' /> 724 <path d='M0.4 0.4L1.6 0.4ZL1.6 1.6ZL0.4 1.6ZL0.4 0.4ZZ' /> 726 >>> print Fig(fig, trans="x/2., y/2.").SVG().xml() 728 <path d='M0 0L1 1' /> 729 <path d='M0.2 0.2L0.8 0.2ZL0.8 0.8ZL0.2 0.8ZL0.2 0.2ZZ' /> 735 return "<Fig (%d items)>" % len(self.
d)
736 elif isinstance(self.
trans, str):
737 return "<Fig (%d items) x,y -> %s>" % (len(self.
d), self.
trans)
739 return "<Fig (%d items) %s>" % (len(self.
d), self.trans.__name__)
743 defaults = {
"trans":
None}
744 defaults.update(kwds)
747 self.
trans = kwds[
"trans"]; del kwds[
"trans"]
749 raise TypeError(
"Fig() got unexpected keyword arguments %s" % kwds.keys())
751 def SVG(self, trans=None):
752 """Apply the transformation "trans" and return an SVG object. 754 Coordinate transformations in nested Figs will be composed. 757 if trans ==
None: trans = self.
trans 758 if isinstance(trans, str): trans =
totrans(trans)
762 if isinstance(s, SVG):
765 elif isinstance(s, Fig):
767 if isinstance(strans, str): strans =
totrans(strans)
769 if trans ==
None: subtrans = strans
770 elif strans ==
None: subtrans = trans
771 else: subtrans =
lambda x,y:
trans(*strans(x, y))
773 output.sub += s.SVG(subtrans).sub
778 output.append(s.SVG(trans))
783 """Acts like Fig, but draws a coordinate axis. You also need to supply plot ranges. 785 Plot(xmin, xmax, ymin, ymax, obj, obj, obj..., keyword options...) 787 xmin, xmax required minimum and maximum x values (in the objs' coordinates) 788 ymin, ymax required minimum and maximum y values (in the objs' coordinates) 789 obj optional list drawing primatives 790 keyword options keyword list options defined below 792 The following are keyword options, with their default values: 794 trans None transformation function 795 x, y 5, 5 upper-left corner of the Plot in SVG coordinates 796 width, height 90, 90 width and height of the Plot in SVG coordinates 797 flipx, flipy False, True flip the sign of the coordinate axis 798 minusInfinity -1000 if an axis is logarithmic and an object is plotted at 0 or 799 a negative value, -1000 will be used as a stand-in for NaN 800 atx, aty 0, 0 the place where the coordinate axes cross 801 xticks -10 request ticks according to the standard tick specification 803 xminiticks True request miniticks according to the standard minitick 805 xlabels True request tick labels according to the standard tick label 807 xlogbase None if a number, the axis and transformation are logarithmic 808 with ticks at the given base (10 being the most common) 810 arrows None if a new identifier, create arrow markers and draw them 811 at the ends of the coordinate axes 812 text_attr {} a dictionary of attributes for label text 813 axis_attr {} a dictionary of attributes for the axis lines 818 return "<Plot (%d items)>" % len(self.
d)
820 return "<Plot (%d items) %s>" % (len(self.
d), self.trans.__name__)
822 def __init__(self, xmin, xmax, ymin, ymax, *d, **kwds):
823 self.xmin, self.xmax, self.ymin, self.
ymax = xmin, xmax, ymin, ymax
825 defaults = {
"trans":
None,
"x":5,
"y":5,
"width":90,
"height":90,
"flipx":
False,
"flipy":
True,
"minusInfinity":-1000, \
826 "atx":0,
"xticks":-10,
"xminiticks":
True,
"xlabels":
True,
"xlogbase":
None, \
827 "aty":0,
"yticks":-10,
"yminiticks":
True,
"ylabels":
True,
"ylogbase":
None, \
828 "arrows":
None,
"text_attr":{},
"axis_attr":{}}
829 defaults.update(kwds)
832 self.
trans = kwds[
"trans"]; del kwds[
"trans"]
833 self.
x = kwds[
"x"]; del kwds[
"x"]
834 self.
y = kwds[
"y"]; del kwds[
"y"]
835 self.
width = kwds[
"width"]; del kwds[
"width"]
836 self.
height = kwds[
"height"]; del kwds[
"height"]
837 self.
flipx = kwds[
"flipx"]; del kwds[
"flipx"]
838 self.
flipy = kwds[
"flipy"]; del kwds[
"flipy"]
840 self.
atx = kwds[
"atx"]; del kwds[
"atx"]
841 self.
xticks = kwds[
"xticks"]; del kwds[
"xticks"]
843 self.
xlabels = kwds[
"xlabels"]; del kwds[
"xlabels"]
844 self.
xlogbase = kwds[
"xlogbase"]; del kwds[
"xlogbase"]
845 self.
aty = kwds[
"aty"]; del kwds[
"aty"]
846 self.
yticks = kwds[
"yticks"]; del kwds[
"yticks"]
848 self.
ylabels = kwds[
"ylabels"]; del kwds[
"ylabels"]
849 self.
ylogbase = kwds[
"ylogbase"]; del kwds[
"ylogbase"]
850 self.
arrows = kwds[
"arrows"]; del kwds[
"arrows"]
851 self.
text_attr = kwds[
"text_attr"]; del kwds[
"text_attr"]
852 self.
axis_attr = kwds[
"axis_attr"]; del kwds[
"axis_attr"]
854 raise TypeError(
"Plot() got unexpected keyword arguments %s" % kwds.keys())
856 def SVG(self, trans=None):
857 """Apply the transformation "trans" and return an SVG object.""" 858 if trans ==
None: trans = self.
trans 859 if isinstance(trans, str): trans =
totrans(trans)
864 d = [
Axes(self.xmin, self.xmax, self.ymin, self.
ymax, self.
atx, self.
aty, \
873 text_defaults = {
"stroke":
"none",
"fill":
"black",
"font-size":5}
877 minitick_length = 0.75
878 text_xaxis_offset = 1.
879 text_yaxis_offset = 2.
880 text_xtitle_offset = 6.
881 text_ytitle_offset = 12.
884 return "<Frame (%d items)>" % len(self.
d)
886 def __init__(self, xmin, xmax, ymin, ymax, *d, **kwds):
887 """Acts like Fig, but draws a coordinate frame around the data. You also need to supply plot ranges. 889 Frame(xmin, xmax, ymin, ymax, obj, obj, obj..., keyword options...) 891 xmin, xmax required minimum and maximum x values (in the objs' coordinates) 892 ymin, ymax required minimum and maximum y values (in the objs' coordinates) 893 obj optional list drawing primatives 894 keyword options keyword list options defined below 896 The following are keyword options, with their default values: 898 x, y 20, 5 upper-left corner of the Frame in SVG coordinates 899 width, height 75, 80 width and height of the Frame in SVG coordinates 900 flipx, flipy False, True flip the sign of the coordinate axis 901 minusInfinity -1000 if an axis is logarithmic and an object is plotted at 0 or 902 a negative value, -1000 will be used as a stand-in for NaN 903 xtitle None if a string, label the x axis 904 xticks -10 request ticks according to the standard tick specification 906 xminiticks True request miniticks according to the standard minitick 908 xlabels True request tick labels according to the standard tick label 910 xlogbase None if a number, the axis and transformation are logarithmic 911 with ticks at the given base (10 being the most common) 913 text_attr {} a dictionary of attributes for label text 914 axis_attr {} a dictionary of attributes for the axis lines 917 self.xmin, self.xmax, self.ymin, self.
ymax = xmin, xmax, ymin, ymax
919 defaults = {
"x":20,
"y":5,
"width":75,
"height":80,
"flipx":
False,
"flipy":
True,
"minusInfinity":-1000, \
920 "xtitle":
None,
"xticks":-10,
"xminiticks":
True,
"xlabels":
True,
"x2labels":
None,
"xlogbase":
None, \
921 "ytitle":
None,
"yticks":-10,
"yminiticks":
True,
"ylabels":
True,
"y2labels":
None,
"ylogbase":
None, \
922 "text_attr":{},
"axis_attr":{}}
923 defaults.update(kwds)
926 self.
x = kwds[
"x"]; del kwds[
"x"]
927 self.
y = kwds[
"y"]; del kwds[
"y"]
928 self.
width = kwds[
"width"]; del kwds[
"width"]
929 self.
height = kwds[
"height"]; del kwds[
"height"]
930 self.
flipx = kwds[
"flipx"]; del kwds[
"flipx"]
931 self.
flipy = kwds[
"flipy"]; del kwds[
"flipy"]
933 self.
xtitle = kwds[
"xtitle"]; del kwds[
"xtitle"]
934 self.
xticks = kwds[
"xticks"]; del kwds[
"xticks"]
936 self.
xlabels = kwds[
"xlabels"]; del kwds[
"xlabels"]
937 self.
x2labels = kwds[
"x2labels"]; del kwds[
"x2labels"]
938 self.
xlogbase = kwds[
"xlogbase"]; del kwds[
"xlogbase"]
939 self.
ytitle = kwds[
"ytitle"]; del kwds[
"ytitle"]
940 self.
yticks = kwds[
"yticks"]; del kwds[
"yticks"]
942 self.
ylabels = kwds[
"ylabels"]; del kwds[
"ylabels"]
943 self.
y2labels = kwds[
"y2labels"]; del kwds[
"y2labels"]
944 self.
ylogbase = kwds[
"ylogbase"]; del kwds[
"ylogbase"]
947 self.text_attr.update(kwds[
"text_attr"]); del kwds[
"text_attr"]
950 self.axis_attr.update(kwds[
"axis_attr"]); del kwds[
"axis_attr"]
953 raise TypeError(
"Frame() got unexpected keyword arguments %s" % kwds.keys())
956 """Apply the window transformation and return an SVG object.""" 961 left =
YAxis(self.ymin, self.
ymax, self.xmin, self.
yticks, self.
yminiticks, self.
ylabels, self.
ylogbase,
None,
None,
None, self.
text_attr, **self.
axis_attr)
962 right =
YAxis(self.ymin, self.
ymax, self.xmax, self.
yticks, self.
yminiticks, self.
y2labels, self.
ylogbase,
None,
None,
None, self.
text_attr, **self.
axis_attr)
963 bottom =
XAxis(self.xmin, self.xmax, self.ymin, self.
xticks, self.
xminiticks, self.
xlabels, self.
xlogbase,
None,
None,
None, self.
text_attr, **self.
axis_attr)
964 top =
XAxis(self.xmin, self.xmax, self.
ymax, self.
xticks, self.
xminiticks, self.
x2labels, self.
xlogbase,
None,
None,
None, self.
text_attr, **self.
axis_attr)
969 left.minitick_end = 0.
972 right.tick_start = 0.
974 right.minitick_start = 0.
977 right.text_attr[
"text-anchor"] =
"start" 979 bottom.tick_start = 0.
981 bottom.minitick_start = 0.
988 top.minitick_end = 0.
990 top.text_attr[
"dominant-baseline"] =
"text-after-edge" 1007 """Converts SVG("path", d="...") into Path(d=[...]).""" 1008 if not isinstance(svg, SVG)
or svg.t !=
"path":
1009 raise TypeError(
"Only SVG <path /> objects can be converted into Paths")
1010 attr =
dict(svg.attr)
1013 for key
in attr.keys():
1014 if not isinstance(key, str):
1017 attr[
str(key)] = value
1018 return Path(d, **attr)
1021 """Path represents an SVG path, an arbitrary set of curves and 1022 straight segments. Unlike SVG("path", d="..."), Path stores 1023 coordinates as a list of numbers, rather than a string, so that it is 1024 transformable in a Fig. 1026 Path(d, attribute=value) 1028 d required path data 1029 attribute=value pairs keyword list SVG attributes 1031 See http://www.w3.org/TR/SVG/paths.html for specification of paths 1034 Internally, Path data is a list of tuples with these definitions: 1036 * ("Z/z",): close the current path 1037 * ("H/h", x) or ("V/v", y): a horizontal or vertical line 1039 * ("M/m/L/l/T/t", x, y, global): moveto, lineto, or smooth 1040 quadratic curveto point (x, y). If global=True, (x, y) should 1042 * ("S/sQ/q", cx, cy, cglobal, x, y, global): polybezier or 1043 smooth quadratic curveto point (x, y) using (cx, cy) as a 1044 control point. If cglobal or global=True, (cx, cy) or (x, y) 1045 should not be transformed. 1046 * ("C/c", c1x, c1y, c1global, c2x, c2y, c2global, x, y, global): 1047 cubic curveto point (x, y) using (c1x, c1y) and (c2x, c2y) as 1048 control points. If c1global, c2global, or global=True, (c1x, c1y), 1049 (c2x, c2y), or (x, y) should not be transformed. 1050 * ("A/a", rx, ry, rglobal, x-axis-rotation, angle, large-arc-flag, 1051 sweep-flag, x, y, global): arcto point (x, y) using the 1052 aforementioned parameters. 1053 * (",/.", rx, ry, rglobal, angle, x, y, global): an ellipse at 1054 point (x, y) with radii (rx, ry). If angle is 0, the whole 1055 ellipse is drawn; otherwise, a partial ellipse is drawn. 1060 return "<Path (%d nodes) %s>" % (len(self.
d), self.
attr)
1063 if isinstance(d, str): self.
d = self.
parse(d)
1064 else: self.
d =
list(d)
1067 self.attr.update(attr)
1070 """Part of Path's text-command parsing algorithm; used internally.""" 1071 while index < len(pathdata)
and pathdata[index]
in (
" ",
"\t",
"\r",
"\n",
","): index += 1
1072 return index, pathdata
1075 """Part of Path's text-command parsing algorithm; used internally.""" 1078 if index >= len(pathdata):
return None, index, pathdata
1079 command = pathdata[index]
1080 if "A" <= command <=
"Z" or "a" <= command <=
"z":
1082 return command, index, pathdata
1084 return None, index, pathdata
1087 """Part of Path's text-command parsing algorithm; used internally.""" 1090 if index >= len(pathdata):
return None, index, pathdata
1091 first_digit = pathdata[index]
1093 if "0" <= first_digit <=
"9" or first_digit
in (
"-",
"+",
"."):
1095 while index < len(pathdata)
and (
"0" <= pathdata[index] <=
"9" or pathdata[index]
in (
"-",
"+",
".",
"e",
"E")):
1100 return float(pathdata[start:end]), index, pathdata
1102 return None, index, pathdata
1105 """Part of Path's text-command parsing algorithm; used internally.""" 1108 if index >= len(pathdata):
return None, index, pathdata
1109 first_digit = pathdata[index]
1111 if first_digit
in (
"0",
"1"):
1113 return int(first_digit), index, pathdata
1115 return None, index, pathdata
1118 """Parses text-commands, converting them into a list of tuples. 1119 Called by the constructor.""" 1123 command, index, pathdata = self.
parse_command(index, pathdata)
1126 if command ==
None and index == len(pathdata):
break 1127 if command
in (
"Z",
"z"):
1128 output.append((command,))
1131 elif command
in (
"H",
"h",
"V",
"v"):
1132 errstring =
"Path command \"%s\" requires a number at index %d" % (command, index)
1133 num1, index, pathdata = self.
parse_number(index, pathdata)
1134 if num1 ==
None:
raise ValueError(errstring)
1137 output.append((command, num1))
1138 num1, index, pathdata = self.
parse_number(index, pathdata)
1141 elif command
in (
"M",
"m",
"L",
"l",
"T",
"t"):
1142 errstring =
"Path command \"%s\" requires an x,y pair at index %d" % (command, index)
1143 num1, index, pathdata = self.
parse_number(index, pathdata)
1144 num2, index, pathdata = self.
parse_number(index, pathdata)
1146 if num1 ==
None:
raise ValueError(errstring)
1149 if num2 ==
None:
raise ValueError(errstring)
1150 output.append((command, num1, num2,
False))
1152 num1, index, pathdata = self.
parse_number(index, pathdata)
1153 num2, index, pathdata = self.
parse_number(index, pathdata)
1156 elif command
in (
"S",
"s",
"Q",
"q"):
1157 errstring =
"Path command \"%s\" requires a cx,cy,x,y quadruplet at index %d" % (command, index)
1158 num1, index, pathdata = self.
parse_number(index, pathdata)
1159 num2, index, pathdata = self.
parse_number(index, pathdata)
1160 num3, index, pathdata = self.
parse_number(index, pathdata)
1161 num4, index, pathdata = self.
parse_number(index, pathdata)
1163 if num1 ==
None:
raise ValueError(errstring)
1166 if num2 ==
None or num3 ==
None or num4 ==
None:
raise ValueError(errstring)
1167 output.append((command, num1, num2,
False, num3, num4,
False))
1169 num1, index, pathdata = self.
parse_number(index, pathdata)
1170 num2, index, pathdata = self.
parse_number(index, pathdata)
1171 num3, index, pathdata = self.
parse_number(index, pathdata)
1172 num4, index, pathdata = self.
parse_number(index, pathdata)
1175 elif command
in (
"C",
"c"):
1176 errstring =
"Path command \"%s\" requires a c1x,c1y,c2x,c2y,x,y sextuplet at index %d" % (command, index)
1177 num1, index, pathdata = self.
parse_number(index, pathdata)
1178 num2, index, pathdata = self.
parse_number(index, pathdata)
1179 num3, index, pathdata = self.
parse_number(index, pathdata)
1180 num4, index, pathdata = self.
parse_number(index, pathdata)
1181 num5, index, pathdata = self.
parse_number(index, pathdata)
1182 num6, index, pathdata = self.
parse_number(index, pathdata)
1184 if num1 ==
None:
raise ValueError(errstring)
1187 if num2 ==
None or num3 ==
None or num4 ==
None or num5 ==
None or num6 ==
None:
raise ValueError(errstring)
1189 output.append((command, num1, num2,
False, num3, num4,
False, num5, num6,
False))
1191 num1, index, pathdata = self.
parse_number(index, pathdata)
1192 num2, index, pathdata = self.
parse_number(index, pathdata)
1193 num3, index, pathdata = self.
parse_number(index, pathdata)
1194 num4, index, pathdata = self.
parse_number(index, pathdata)
1195 num5, index, pathdata = self.
parse_number(index, pathdata)
1196 num6, index, pathdata = self.
parse_number(index, pathdata)
1199 elif command
in (
"A",
"a"):
1200 errstring =
"Path command \"%s\" requires a rx,ry,angle,large-arc-flag,sweep-flag,x,y septuplet at index %d" % (command, index)
1201 num1, index, pathdata = self.
parse_number(index, pathdata)
1202 num2, index, pathdata = self.
parse_number(index, pathdata)
1203 num3, index, pathdata = self.
parse_number(index, pathdata)
1206 num6, index, pathdata = self.
parse_number(index, pathdata)
1207 num7, index, pathdata = self.
parse_number(index, pathdata)
1209 if num1 ==
None:
raise ValueError(errstring)
1212 if num2 ==
None or num3 ==
None or num4 ==
None or num5 ==
None or num6 ==
None or num7 ==
None:
raise ValueError(errstring)
1214 output.append((command, num1, num2,
False, num3, num4, num5, num6, num7,
False))
1216 num1, index, pathdata = self.
parse_number(index, pathdata)
1217 num2, index, pathdata = self.
parse_number(index, pathdata)
1218 num3, index, pathdata = self.
parse_number(index, pathdata)
1221 num6, index, pathdata = self.
parse_number(index, pathdata)
1222 num7, index, pathdata = self.
parse_number(index, pathdata)
1227 """Apply the transformation "trans" and return an SVG object.""" 1228 if isinstance(trans, str): trans =
totrans(trans)
1230 x, y, X, Y =
None,
None,
None,
None 1232 for datum
in self.
d:
1233 if not isinstance(datum, (tuple, list)):
1234 raise TypeError(
"pathdata elements must be tuples/lists")
1239 if command
in (
"Z",
"z"):
1240 x, y, X, Y =
None,
None,
None,
None 1244 elif command
in (
"H",
"h",
"V",
"v"):
1245 command, num1 = datum
1247 if command ==
"H" or (command ==
"h" and x ==
None): x = num1
1248 elif command ==
"h": x += num1
1249 elif command ==
"V" or (command ==
"v" and y ==
None): y = num1
1250 elif command ==
"v": y += num1
1252 if trans ==
None: X, Y = x, y
1253 else: X, Y = trans(x, y)
1255 output.append(
"L%g %g" % (X, Y))
1258 elif command
in (
"M",
"m",
"L",
"l",
"T",
"t"):
1259 command, num1, num2, isglobal12 = datum
1261 if trans ==
None or isglobal12:
1262 if command.isupper()
or X ==
None or Y ==
None:
1270 if command.isupper()
or x ==
None or y ==
None:
1277 COMMAND = command.capitalize()
1278 output.append(
"%s%g %g" % (COMMAND, X, Y))
1281 elif command
in (
"S",
"s",
"Q",
"q"):
1282 command, num1, num2, isglobal12, num3, num4, isglobal34 = datum
1284 if trans ==
None or isglobal12:
1285 if command.isupper()
or X ==
None or Y ==
None:
1292 if command.isupper()
or x ==
None or y ==
None:
1297 CX, CY = trans(cx, cy)
1299 if trans ==
None or isglobal34:
1300 if command.isupper()
or X ==
None or Y ==
None:
1308 if command.isupper()
or x ==
None or y ==
None:
1315 COMMAND = command.capitalize()
1316 output.append(
"%s%g %g %g %g" % (COMMAND, CX, CY, X, Y))
1319 elif command
in (
"C",
"c"):
1320 command, num1, num2, isglobal12, num3, num4, isglobal34, num5, num6, isglobal56 = datum
1322 if trans ==
None or isglobal12:
1323 if command.isupper()
or X ==
None or Y ==
None:
1324 C1X, C1Y = num1, num2
1330 if command.isupper()
or x ==
None or y ==
None:
1331 c1x, c1y = num1, num2
1335 C1X, C1Y = trans(c1x, c1y)
1337 if trans ==
None or isglobal34:
1338 if command.isupper()
or X ==
None or Y ==
None:
1339 C2X, C2Y = num3, num4
1345 if command.isupper()
or x ==
None or y ==
None:
1346 c2x, c2y = num3, num4
1350 C2X, C2Y = trans(c2x, c2y)
1352 if trans ==
None or isglobal56:
1353 if command.isupper()
or X ==
None or Y ==
None:
1361 if command.isupper()
or x ==
None or y ==
None:
1368 COMMAND = command.capitalize()
1369 output.append(
"%s%g %g %g %g %g %g" % (COMMAND, C1X, C1Y, C2X, C2Y, X, Y))
1372 elif command
in (
"A",
"a"):
1373 command, num1, num2, isglobal12, angle, large_arc_flag, sweep_flag, num3, num4, isglobal34 = datum
1378 if trans ==
None or isglobal34:
1379 if command.isupper()
or X ==
None or Y ==
None:
1387 if command.isupper()
or x ==
None or y ==
None:
1394 if x !=
None and y !=
None:
1395 centerx, centery = (x + oldx)/2., (y + oldy)/2.
1396 CENTERX, CENTERY = (X + OLDX)/2., (Y + OLDY)/2.
1398 if trans ==
None or isglobal12:
1405 RX, RY = trans(rx, ry)
1407 COMMAND = command.capitalize()
1408 output.append(
"%s%g %g %g %d %d %g %g" % (COMMAND, RX - CENTERX, RY - CENTERY, angle, large_arc_flag, sweep_flag, X, Y))
1410 elif command
in (
",",
"."):
1411 command, num1, num2, isglobal12, angle, num3, num4, isglobal34 = datum
1412 if trans ==
None or isglobal34:
1413 if command ==
"." or X ==
None or Y ==
None:
1421 if command ==
"." or x ==
None or y ==
None:
1428 if trans ==
None or isglobal12:
1435 RX, RY = trans(rx, ry)
1437 RX, RY = RX - X, RY - Y
1439 X1, Y1 = X + RX * math.cos(angle*math.pi/180.), Y + RX * math.sin(angle*math.pi/180.)
1440 X2, Y2 = X + RY * math.sin(angle*math.pi/180.), Y - RY * math.cos(angle*math.pi/180.)
1441 X3, Y3 = X - RX * math.cos(angle*math.pi/180.), Y - RX * math.sin(angle*math.pi/180.)
1442 X4, Y4 = X - RY * math.sin(angle*math.pi/180.), Y + RY * math.cos(angle*math.pi/180.)
1444 output.append(
"M%g %gA%g %g %g 0 0 %g %gA%g %g %g 0 0 %g %gA%g %g %g 0 0 %g %gA%g %g %g 0 0 %g %g" \
1445 % (X1, Y1, RX, RY, angle, X2, Y2, RX, RY, angle, X3, Y3, RX, RY, angle, X4, Y4, RX, RY, angle, X1, Y1))
1447 return SVG(
"path", d=
"".
join(output), **self.
attr)
1451 def funcRtoC(expr, var="t", globals=None, locals=None):
1452 """Converts a complex "z(t)" string to a function acceptable for Curve. 1454 expr required string in the form "z(t)" 1455 var default="t" name of the independent variable 1456 globals default=None dict of global variables used in the expression; 1457 you may want to use Python's builtin globals() 1458 locals default=None dict of local variables 1461 if globals !=
None: g.update(globals)
1462 output = eval(
"lambda %s: (%s)" % (var, expr), g, locals)
1463 split =
lambda z: (z.real, z.imag)
1465 output2.__name__ =
"%s -> %s" % (var, expr)
1469 """Converts a "f(t), g(t)" string to a function acceptable for Curve. 1471 expr required string in the form "f(t), g(t)" 1472 var default="t" name of the independent variable 1473 globals default=None dict of global variables used in the expression; 1474 you may want to use Python's builtin globals() 1475 locals default=None dict of local variables 1478 if globals !=
None: g.update(globals)
1479 output = eval(
"lambda %s: (%s)" % (var, expr), g, locals)
1480 output.__name__ =
"%s -> %s" % (var, expr)
1483 def funcRtoR(expr, var="x", globals=None, locals=None):
1484 """Converts a "f(x)" string to a function acceptable for Curve. 1486 expr required string in the form "f(x)" 1487 var default="x" name of the independent variable 1488 globals default=None dict of global variables used in the expression; 1489 you may want to use Python's builtin globals() 1490 locals default=None dict of local variables 1493 if globals !=
None: g.update(globals)
1494 output = eval(
"lambda %s: (%s, %s)" % (var, var, expr), g, locals)
1495 output.__name__ =
"%s -> %s" % (var, expr)
1499 """Draws a parametric function as a path. 1501 Curve(f, low, high, loop, attribute=value) 1503 f required a Python callable or string in 1504 the form "f(t), g(t)" 1505 low, high required left and right endpoints 1506 loop default=False if True, connect the endpoints 1507 attribute=value pairs keyword list SVG attributes 1510 random_sampling =
True 1511 recursion_limit = 15
1512 linearity_limit = 0.05
1513 discontinuity_limit = 5.
1516 return "<Curve %s [%s, %s] %s>" % (self.
f, self.
low, self.
high, self.
attr)
1525 self.attr.update(attr)
1530 t, x, y, X, Y = self.
t, self.x, self.
y, self.X, self.
Y 1531 if t !=
None: t =
"%g" % t
1532 if x !=
None: x =
"%g" % x
1533 if y !=
None: y =
"%g" % y
1534 if X !=
None: X =
"%g" % X
1535 if Y !=
None: Y =
"%g" % Y
1536 return "<Curve.Sample t=%s x=%s y=%s X=%s Y=%s>" % (t, x, y, X, Y)
1540 def link(self, left, right): self.left, self.
right = left, right
1545 self.X, self.
Y = self.x, self.
y 1547 self.X, self.
Y = trans(self.x, self.
y)
1552 def __repr__(self):
return "<Curve.Samples (%d samples)>" % len(self)
1559 while current !=
None:
1561 current = current.right
1570 if current ==
None:
raise StopIteration
1571 self.
current = self.current.right
1576 """Adaptive-sampling algorithm that chooses the best sample points 1577 for a parametric curve between two endpoints and detects 1578 discontinuities. Called by SVG().""" 1579 oldrecursionlimit = sys.getrecursionlimit()
1583 if not (self.
low < self.
high):
raise ValueError(
"low must be less than high")
1585 low.link(
None, high)
1586 high.link(low,
None)
1588 low.evaluate(self.
f, trans)
1589 high.evaluate(self.
f, trans)
1596 while left.right !=
None:
1600 if right !=
None and left.X !=
None and left.Y !=
None and mid.X !=
None and mid.Y !=
None and right.X !=
None and right.Y !=
None:
1601 numer = left.X*(right.Y - mid.Y) + mid.X*(left.Y - right.Y) + right.X*(mid.Y - left.Y)
1602 denom = math.sqrt((left.X - right.X)**2 + (left.Y - right.Y)**2)
1616 sys.setrecursionlimit(oldrecursionlimit)
1619 """Part of the adaptive-sampling algorithm that chooses the best 1620 sample points. Called by sample().""" 1623 mid = self.
Sample(left.t + random.uniform(0.3, 0.7) * (right.t - left.t))
1625 mid = self.
Sample(left.t + 0.5 * (right.t - left.t))
1629 mid.link(left, right)
1630 mid.evaluate(self.
f, trans)
1633 numer = left.X*(right.Y - mid.Y) + mid.X*(left.Y - right.Y) + right.X*(mid.Y - left.Y)
1634 denom = math.sqrt((left.X - right.X)**2 + (left.Y - right.Y)**2)
1641 self.
subsample(left, mid, depth+1, trans)
1642 self.
subsample(mid, right, depth+1, trans)
1647 mid.y = mid.Y =
None 1650 """Apply the transformation "trans" and return an SVG object.""" 1653 def Path(self, trans=None, local=False):
1654 """Apply the transformation "trans" and return a Path object in 1655 global coordinates. If local=True, return a Path in local coordinates 1656 (which must be transformed again).""" 1658 if isinstance(trans, str): trans =
totrans(trans)
1665 if s.X !=
None and s.Y !=
None:
1666 if s.left ==
None or s.left.Y ==
None:
1671 if local: output.append((command, s.x, s.y,
False))
1672 else: output.append((command, s.X, s.Y,
True))
1674 if self.
loop: output.append((
"Z",))
1680 """Draws a curve specified by a sequence of points. The curve may be 1681 piecewise linear, like a polygon, or a Bezier curve. 1683 Poly(d, mode, loop, attribute=value) 1685 d required list of tuples representing points 1686 and possibly control points 1687 mode default="L" "lines", "bezier", "velocity", 1688 "foreback", "smooth", or an abbreviation 1689 loop default=False if True, connect the first and last 1690 point, closing the loop 1691 attribute=value pairs keyword list SVG attributes 1693 The format of the tuples in d depends on the mode. 1695 "lines"/"L" d=[(x,y), (x,y), ...] 1696 piecewise-linear segments joining the (x,y) points 1697 "bezier"/"B" d=[(x, y, c1x, c1y, c2x, c2y), ...] 1698 Bezier curve with two control points (control points 1699 preceed (x,y), as in SVG paths). If (c1x,c1y) and 1700 (c2x,c2y) both equal (x,y), you get a linear 1701 interpolation ("lines") 1702 "velocity"/"V" d=[(x, y, vx, vy), ...] 1703 curve that passes through (x,y) with velocity (vx,vy) 1704 (one unit of arclength per unit time); in other words, 1705 (vx,vy) is the tangent vector at (x,y). If (vx,vy) is 1706 (0,0), you get a linear interpolation ("lines"). 1707 "foreback"/"F" d=[(x, y, bx, by, fx, fy), ...] 1708 like "velocity" except that there is a left derivative 1709 (bx,by) and a right derivative (fx,fy). If (bx,by) 1710 equals (fx,fy) (with no minus sign), you get a 1712 "smooth"/"S" d=[(x,y), (x,y), ...] 1713 a "velocity" interpolation with (vx,vy)[i] equal to 1714 ((x,y)[i+1] - (x,y)[i-1])/2: the minimal derivative 1719 return "<Poly (%d nodes) mode=%s loop=%s %s>" % (len(self.
d), self.
mode, repr(self.
loop), self.
attr)
1721 def __init__(self, d=[], mode="L", loop=False, **attr):
1727 self.attr.update(attr)
1730 """Apply the transformation "trans" and return an SVG object.""" 1733 def Path(self, trans=None, local=False):
1734 """Apply the transformation "trans" and return a Path object in 1735 global coordinates. If local=True, return a Path in local coordinates 1736 (which must be transformed again).""" 1737 if isinstance(trans, str): trans =
totrans(trans)
1739 if self.
mode[0] ==
"L" or self.
mode[0] ==
"l": mode =
"L" 1740 elif self.
mode[0] ==
"B" or self.
mode[0] ==
"b": mode =
"B" 1741 elif self.
mode[0] ==
"V" or self.
mode[0] ==
"v": mode =
"V" 1742 elif self.
mode[0] ==
"F" or self.
mode[0] ==
"f": mode =
"F" 1743 elif self.
mode[0] ==
"S" or self.
mode[0] ==
"s":
1746 vx, vy = [0.]*len(self.
d), [0.]*len(self.
d)
1747 for i
in xrange(len(self.
d)):
1748 inext = (i+1) % len(self.
d)
1749 iprev = (i-1) % len(self.
d)
1751 vx[i] = (self.
d[inext][0] - self.
d[iprev][0])/2.
1752 vy[i] = (self.
d[inext][1] - self.
d[iprev][1])/2.
1753 if not self.
loop and (i == 0
or i == len(self.
d)-1):
1754 vx[i], vy[i] = 0., 0.
1757 raise ValueError(
"mode must be \"lines\", \"bezier\", \"velocity\", \"foreback\", \"smooth\", or an abbreviation")
1760 indexes = range(len(self.
d))
1761 if self.
loop and len(self.
d) > 0: indexes.append(0)
1764 inext = (i+1) % len(self.
d)
1765 iprev = (i-1) % len(self.
d)
1767 x, y = self.
d[i][0], self.
d[i][1]
1769 if trans ==
None: X, Y = x, y
1770 else: X, Y = trans(x, y)
1773 if local: d.append((
"M", x, y,
False))
1774 else: d.append((
"M", X, Y,
True))
1777 if local: d.append((
"L", x, y,
False))
1778 else: d.append((
"L", X, Y,
True))
1781 c1x, c1y = self.
d[i][2], self.
d[i][3]
1782 if trans ==
None: C1X, C1Y = c1x, c1y
1783 else: C1X, C1Y = trans(c1x, c1y)
1785 c2x, c2y = self.
d[i][4], self.
d[i][5]
1786 if trans ==
None: C2X, C2Y = c2x, c2y
1787 else: C2X, C2Y = trans(c2x, c2y)
1789 if local: d.append((
"C", c1x, c1y,
False, c2x, c2y,
False, x, y,
False))
1790 else: d.append((
"C", C1X, C1Y,
True, C2X, C2Y,
True, X, Y,
True))
1793 c1x, c1y = self.
d[iprev][2]/3. + self.
d[iprev][0], self.
d[iprev][3]/3. + self.
d[iprev][1]
1794 c2x, c2y = self.
d[i][2]/-3. + x, self.
d[i][3]/-3. + y
1796 if trans ==
None: C1X, C1Y = c1x, c1y
1797 else: C1X, C1Y = trans(c1x, c1y)
1798 if trans ==
None: C2X, C2Y = c2x, c2y
1799 else: C2X, C2Y = trans(c2x, c2y)
1801 if local: d.append((
"C", c1x, c1y,
False, c2x, c2y,
False, x, y,
False))
1802 else: d.append((
"C", C1X, C1Y,
True, C2X, C2Y,
True, X, Y,
True))
1805 c1x, c1y = self.
d[iprev][4]/3. + self.
d[iprev][0], self.
d[iprev][5]/3. + self.
d[iprev][1]
1806 c2x, c2y = self.
d[i][2]/-3. + x, self.
d[i][3]/-3. + y
1808 if trans ==
None: C1X, C1Y = c1x, c1y
1809 else: C1X, C1Y = trans(c1x, c1y)
1810 if trans ==
None: C2X, C2Y = c2x, c2y
1811 else: C2X, C2Y = trans(c2x, c2y)
1813 if local: d.append((
"C", c1x, c1y,
False, c2x, c2y,
False, x, y,
False))
1814 else: d.append((
"C", C1X, C1Y,
True, C2X, C2Y,
True, X, Y,
True))
1817 c1x, c1y = vx[iprev]/3. + self.
d[iprev][0], vy[iprev]/3. + self.
d[iprev][1]
1818 c2x, c2y = vx[i]/-3. + x, vy[i]/-3. + y
1820 if trans ==
None: C1X, C1Y = c1x, c1y
1821 else: C1X, C1Y = trans(c1x, c1y)
1822 if trans ==
None: C2X, C2Y = c2x, c2y
1823 else: C2X, C2Y = trans(c2x, c2y)
1825 if local: d.append((
"C", c1x, c1y,
False, c2x, c2y,
False, x, y,
False))
1826 else: d.append((
"C", C1X, C1Y,
True, C2X, C2Y,
True, X, Y,
True))
1828 if self.
loop and len(self.
d) > 0: d.append((
"Z",))
1835 """Draws at text string at a specified point in local coordinates. 1837 x, y required location of the point in local coordinates 1838 d required text/Unicode string 1839 attribute=value pairs keyword list SVG attributes 1842 defaults = {
"stroke":
"none",
"fill":
"black",
"font-size":5}
1845 return "<Text %s at (%g, %g) %s>" % (repr(self.
d), self.
x, self.
y, self.
attr)
1852 self.attr.update(attr)
1855 """Apply the transformation "trans" and return an SVG object.""" 1856 if isinstance(trans, str): trans =
totrans(trans)
1858 X, Y = self.
x, self.
y 1859 if trans !=
None: X, Y = trans(X, Y)
1860 return SVG(
"text", self.
d, x=X, y=Y, **self.
attr)
1863 """Draws at text string at a specified point in global coordinates. 1865 x, y required location of the point in global coordinates 1866 d required text/Unicode string 1867 attribute=value pairs keyword list SVG attributes 1869 defaults = {
"stroke":
"none",
"fill":
"black",
"font-size":5}
1872 return "<TextGlobal %s at (%s, %s) %s>" % (repr(self.
d),
str(self.
x),
str(self.
y), self.
attr)
1879 self.attr.update(attr)
1882 """Apply the transformation "trans" and return an SVG object.""" 1883 return SVG(
"text", self.
d, x=self.
x, y=self.
y, **self.
attr)
1887 _symbol_templates = {
"dot":
SVG(
"symbol",
SVG(
"circle", cx=0, cy=0, r=1, stroke=
"none", fill=
"black"), viewBox=
"0 0 1 1", overflow=
"visible"), \
1888 "box":
SVG(
"symbol",
SVG(
"rect", x1=-1, y1=-1, x2=1, y2=1, stroke=
"none", fill=
"black"), viewBox=
"0 0 1 1", overflow=
"visible"), \
1889 "uptri":
SVG(
"symbol",
SVG(
"path", d=
"M -1 0.866 L 1 0.866 L 0 -0.866 Z", stroke=
"none", fill=
"black"), viewBox=
"0 0 1 1", overflow=
"visible"), \
1890 "downtri":
SVG(
"symbol",
SVG(
"path", d=
"M -1 -0.866 L 1 -0.866 L 0 0.866 Z", stroke=
"none", fill=
"black"), viewBox=
"0 0 1 1", overflow=
"visible"), \
1894 """Creates a new instance of an SVG symbol to avoid cross-linking objects. 1896 id required a new identifier (string/Unicode) 1897 shape default="dot" the shape name from _symbol_templates 1898 attribute=value list keyword list modify the SVG attributes of the new symbol 1900 output = copy.deepcopy(_symbol_templates[shape])
1908 """Dots draws SVG symbols at a set of points. 1910 d required list of (x,y) points 1911 symbol default=None SVG symbol or a new identifier to 1912 label an auto-generated symbol; 1913 if None, use pre-defined _circular_dot 1914 width, height default=1, 1 width and height of the symbols 1916 attribute=value pairs keyword list SVG attributes 1921 return "<Dots (%d nodes) %s>" % (len(self.
d), self.
attr)
1923 def __init__(self, d=[], symbol=None, width=1., height=1., **attr):
1929 self.attr.update(attr)
1933 elif isinstance(symbol, SVG):
1939 """Apply the transformation "trans" and return an SVG object.""" 1940 if isinstance(trans, str): trans =
totrans(trans)
1943 id =
"#%s" % self.
symbol[
"id"]
1948 if trans ==
None: X, Y = x, y
1949 else: X, Y = trans(x, y)
1951 item =
SVG(
"use", x=X, y=Y, xlink__href=id)
1952 if self.
width !=
None: item[
"width"] = self.
width 1960 _marker_templates = {
"arrow_start":
SVG(
"marker",
SVG(
"path", d=
"M 9 3.6 L 10.5 0 L 0 3.6 L 10.5 7.2 L 9 3.6 Z"), viewBox=
"0 0 10.5 7.2", refX=
"9", refY=
"3.6", markerWidth=
"10.5", markerHeight=
"7.2", markerUnits=
"strokeWidth", orient=
"auto", stroke=
"none", fill=
"black"), \
1961 "arrow_end":
SVG(
"marker",
SVG(
"path", d=
"M 1.5 3.6 L 0 0 L 10.5 3.6 L 0 7.2 L 1.5 3.6 Z"), viewBox=
"0 0 10.5 7.2", refX=
"1.5", refY=
"3.6", markerWidth=
"10.5", markerHeight=
"7.2", markerUnits=
"strokeWidth", orient=
"auto", stroke=
"none", fill=
"black"), \
1965 """Creates a new instance of an SVG marker to avoid cross-linking objects. 1967 id required a new identifier (string/Unicode) 1968 shape required the shape name from _marker_templates 1969 attribute=value list keyword list modify the SVG attributes of the new marker 1971 output = copy.deepcopy(_marker_templates[shape])
1977 """Draws a line between two points. 1979 Line(x1, y1, x2, y2, arrow_start, arrow_end, attribute=value) 1981 x1, y1 required the starting point 1982 x2, y2 required the ending point 1983 arrow_start default=None if an identifier string/Unicode, 1984 draw a new arrow object at the 1985 beginning of the line; if a marker, 1986 draw that marker instead 1987 arrow_end default=None same for the end of the line 1988 attribute=value pairs keyword list SVG attributes 1993 return "<Line (%g, %g) to (%g, %g) %s>" % (self.x1, self.y1, self.x2, self.
y2, self.
attr)
1995 def __init__(self, x1, y1, x2, y2, arrow_start=None, arrow_end=None, **attr):
1996 self.x1, self.y1, self.x2, self.
y2 = x1, y1, x2, y2
2000 self.attr.update(attr)
2003 """Apply the transformation "trans" and return an SVG object.""" 2007 if (self.arrow_start !=
False and self.arrow_start !=
None)
or (self.
arrow_end !=
False and self.
arrow_end !=
None):
2010 if self.arrow_start !=
False and self.arrow_start !=
None:
2011 if isinstance(self.arrow_start, SVG):
2012 defs.append(self.arrow_start)
2013 line.attr[
"marker-start"] =
"url(#%s)" % self.arrow_start[
"id"]
2014 elif isinstance(self.arrow_start, str):
2015 defs.append(
make_marker(self.arrow_start,
"arrow_start"))
2016 line.attr[
"marker-start"] =
"url(#%s)" % self.arrow_start
2018 raise TypeError(
"arrow_start must be False/None or an id string for the new marker")
2023 line.attr[
"marker-end"] =
"url(#%s)" % self.
arrow_end[
"id"]
2026 line.attr[
"marker-end"] =
"url(#%s)" % self.
arrow_end 2028 raise TypeError(
"arrow_end must be False/None or an id string for the new marker")
2030 return SVG(
"g", defs, line)
2034 def Path(self, trans=None, local=False):
2035 """Apply the transformation "trans" and return a Path object in 2036 global coordinates. If local=True, return a Path in local coordinates 2037 (which must be transformed again).""" 2038 self.
f =
lambda t: (self.x1 + t*(self.x2 - self.x1), self.y1 + t*(self.
y2 - self.y1))
2044 return Path([(
"M", self.x1, self.y1,
not local), (
"L", self.x2, self.
y2,
not local)], **self.
attr)
2046 return Curve.Path(self, trans, local)
2049 """Draws a line between two points, one or both of which is in 2052 Line(x1, y1, x2, y2, lcoal1, local2, arrow_start, arrow_end, attribute=value) 2054 x1, y1 required the starting point 2055 x2, y2 required the ending point 2056 local1 default=False if True, interpret first point as a 2057 local coordinate (apply transform) 2058 local2 default=False if True, interpret second point as a 2059 local coordinate (apply transform) 2060 arrow_start default=None if an identifier string/Unicode, 2061 draw a new arrow object at the 2062 beginning of the line; if a marker, 2063 draw that marker instead 2064 arrow_end default=None same for the end of the line 2065 attribute=value pairs keyword list SVG attributes 2070 local1, local2 =
"",
"" 2071 if self.local1: local1 =
"L" 2072 if self.
local2: local2 =
"L" 2074 return "<LineGlobal %s(%s, %s) to %s(%s, %s) %s>" % (local1,
str(self.x1),
str(self.y1), local2,
str(self.x2),
str(self.
y2), self.
attr)
2076 def __init__(self, x1, y1, x2, y2, local1=False, local2=False, arrow_start=None, arrow_end=None, **attr):
2077 self.x1, self.y1, self.x2, self.
y2 = x1, y1, x2, y2
2082 self.attr.update(attr)
2085 """Apply the transformation "trans" and return an SVG object.""" 2086 if isinstance(trans, str): trans =
totrans(trans)
2088 X1, Y1, X2, Y2 = self.x1, self.y1, self.x2, self.
y2 2090 if self.local1: X1, Y1 = trans(X1, Y1)
2091 if self.
local2: X2, Y2 = trans(X2, Y2)
2093 line =
SVG(
"path", d=
"M%s %s L%s %s" % (X1, Y1, X2, Y2), **self.
attr)
2095 if (self.arrow_start !=
False and self.arrow_start !=
None)
or (self.
arrow_end !=
False and self.
arrow_end !=
None):
2098 if self.arrow_start !=
False and self.arrow_start !=
None:
2099 if isinstance(self.arrow_start, SVG):
2100 defs.append(self.arrow_start)
2101 line.attr[
"marker-start"] =
"url(#%s)" % self.arrow_start[
"id"]
2102 elif isinstance(self.arrow_start, str):
2103 defs.append(
make_marker(self.arrow_start,
"arrow_start"))
2104 line.attr[
"marker-start"] =
"url(#%s)" % self.arrow_start
2106 raise TypeError(
"arrow_start must be False/None or an id string for the new marker")
2111 line.attr[
"marker-end"] =
"url(#%s)" % self.
arrow_end[
"id"]
2114 line.attr[
"marker-end"] =
"url(#%s)" % self.
arrow_end 2116 raise TypeError(
"arrow_end must be False/None or an id string for the new marker")
2118 return SVG(
"g", defs, line)
2123 """Draws a vertical line. 2125 VLine(y1, y2, x, attribute=value) 2127 y1, y2 required y range 2128 x required x position 2129 attribute=value pairs keyword list SVG attributes 2134 return "<VLine (%g, %g) at x=%s %s>" % (self.y1, self.
y2, self.
x, self.
attr)
2139 self.attr.update(attr)
2140 Line.__init__(self, x, y1, x, y2, **self.
attr)
2142 def Path(self, trans=None, local=False):
2143 """Apply the transformation "trans" and return a Path object in 2144 global coordinates. If local=True, return a Path in local coordinates 2145 (which must be transformed again).""" 2148 return Line.Path(self, trans, local)
2151 """Draws a horizontal line. 2153 HLine(x1, x2, y, attribute=value) 2155 x1, x2 required x range 2156 y required y position 2157 attribute=value pairs keyword list SVG attributes 2162 return "<HLine (%g, %g) at y=%s %s>" % (self.x1, self.x2, self.
y, self.
attr)
2167 self.attr.update(attr)
2168 Line.__init__(self, x1, y, x2, y, **self.
attr)
2170 def Path(self, trans=None, local=False):
2171 """Apply the transformation "trans" and return a Path object in 2172 global coordinates. If local=True, return a Path in local coordinates 2173 (which must be transformed again).""" 2176 return Line.Path(self, trans, local)
2181 """Draws a rectangle. 2183 Rect(x1, y1, x2, y2, attribute=value) 2185 x1, y1 required the starting point 2186 x2, y2 required the ending point 2187 attribute=value pairs keyword list SVG attributes 2192 return "<Rect (%g, %g), (%g, %g) %s>" % (self.x1, self.y1, self.x2, self.
y2, self.
attr)
2195 self.x1, self.y1, self.x2, self.
y2 = x1, y1, x2, y2
2198 self.attr.update(attr)
2201 """Apply the transformation "trans" and return an SVG object.""" 2204 def Path(self, trans=None, local=False):
2205 """Apply the transformation "trans" and return a Path object in 2206 global coordinates. If local=True, return a Path in local coordinates 2207 (which must be transformed again).""" 2209 return Path([(
"M", self.x1, self.y1,
not local), (
"L", self.x2, self.y1,
not local), (
"L", self.x2, self.
y2,
not local), (
"L", self.x1, self.
y2,
not local), (
"Z",)], **self.
attr)
2216 self.
f =
lambda t: (self.x1 + t*(self.x2 - self.x1), self.y1)
2217 d1 = Curve.Path(self, trans, local).d
2219 self.
f =
lambda t: (self.x2, self.y1 + t*(self.
y2 - self.y1))
2220 d2 = Curve.Path(self, trans, local).d
2223 self.
f =
lambda t: (self.x2 + t*(self.x1 - self.x2), self.
y2)
2224 d3 = Curve.Path(self, trans, local).d
2227 self.
f =
lambda t: (self.x1, self.
y2 + t*(self.y1 - self.
y2))
2228 d4 = Curve.Path(self, trans, local).d
2231 return Path(d=(d1 + d2 + d3 + d4 + [(
"Z",)]), **self.
attr)
2236 """Draws an ellipse from a semimajor vector (ax,ay) and a semiminor 2239 Ellipse(x, y, ax, ay, b, attribute=value) 2241 x, y required the center of the ellipse/circle 2242 ax, ay required a vector indicating the length 2243 and direction of the semimajor axis 2244 b required the length of the semiminor axis. 2245 If equal to sqrt(ax2 + ay2), the 2247 attribute=value pairs keyword list SVG attributes 2249 (If sqrt(ax**2 + ay**2) is less than b, then (ax,ay) is actually the 2255 return "<Ellipse (%g, %g) a=(%g, %g), b=%g %s>" % (self.x, self.y, self.ax, self.ay, self.
b, self.
attr)
2258 self.x, self.y, self.ax, self.ay, self.
b = x, y, ax, ay, b
2261 self.attr.update(attr)
2264 """Apply the transformation "trans" and return an SVG object.""" 2267 def Path(self, trans=None, local=False):
2268 """Apply the transformation "trans" and return a Path object in 2269 global coordinates. If local=True, return a Path in local coordinates 2270 (which must be transformed again).""" 2271 angle = math.atan2(self.ay, self.ax) + math.pi/2.
2272 bx = self.
b * math.cos(angle)
2273 by = self.
b * math.sin(angle)
2275 self.
f =
lambda t: (self.x + self.ax*math.cos(t) + bx*math.sin(t), self.y + self.ay*math.cos(t) + by*math.sin(t))
2279 return Curve.Path(self, trans, local)
2284 """Converts numbers to a Unicode string, taking advantage of special 2285 Unicode characters to make nice minus signs and scientific notation. 2289 if output[0] ==
u"-":
2290 output =
u"\u2013" + output[1:]
2292 index = output.find(
u"e")
2294 uniout = unicode(output[:index]) +
u"\u00d710" 2296 for n
in output[index+1:]:
2298 elif n ==
u"-": uniout +=
u"\u207b" 2300 if saw_nonzero: uniout +=
u"\u2070" 2310 elif u"4" <= n <=
u"9":
2312 if saw_nonzero: uniout += eval(
"u\"\\u%x\"" % (0x2070 + ord(n) - ord(
u"0")))
2315 if uniout[:2] ==
u"1\u00d7": uniout = uniout[2:]
2321 """Superclass for all graphics primatives that draw ticks, 2322 miniticks, and tick labels. This class only draws the ticks. 2324 Ticks(f, low, high, ticks, miniticks, labels, logbase, arrow_start, 2325 arrow_end, text_attr, attribute=value) 2327 f required parametric function along which ticks 2328 will be drawn; has the same format as 2329 the function used in Curve 2330 low, high required range of the independent variable 2331 ticks default=-10 request ticks according to the standard 2332 tick specification (see below) 2333 miniticks default=True request miniticks according to the 2334 standard minitick specification (below) 2335 labels True request tick labels according to the 2336 standard tick label specification (below) 2337 logbase default=None if a number, the axis is logarithmic with 2338 ticks at the given base (usually 10) 2339 arrow_start default=None if a new string identifier, draw an arrow 2340 at the low-end of the axis, referenced by 2341 that identifier; if an SVG marker object, 2343 arrow_end default=None if a new string identifier, draw an arrow 2344 at the high-end of the axis, referenced by 2345 that identifier; if an SVG marker object, 2347 text_attr default={} SVG attributes for the text labels 2348 attribute=value pairs keyword list SVG attributes for the tick marks 2350 Standard tick specification: 2352 * True: same as -10 (below). 2353 * Positive number N: draw exactly N ticks, including the endpoints. To 2354 subdivide an axis into 10 equal-sized segments, ask for 11 ticks. 2355 * Negative number -N: draw at least N ticks. Ticks will be chosen with 2356 "natural" values, multiples of 2 or 5. 2357 * List of values: draw a tick mark at each value. 2358 * Dict of value, label pairs: draw a tick mark at each value, labeling 2359 it with the given string. This lets you say things like {3.14159: "pi"}. 2360 * False or None: no ticks. 2362 Standard minitick specification: 2364 * True: draw miniticks with "natural" values, more closely spaced than 2366 * Positive number N: draw exactly N miniticks, including the endpoints. 2367 To subdivide an axis into 100 equal-sized segments, ask for 101 miniticks. 2368 * Negative number -N: draw at least N miniticks. 2369 * List of values: draw a minitick mark at each value. 2370 * False or None: no miniticks. 2372 Standard tick label specification: 2374 * True: use the unumber function (described below) 2375 * Format string: standard format strings, e.g. "%5.2f" for 12.34 2376 * Python callable: function that converts numbers to strings 2377 * False or None: no labels 2379 defaults = {
"stroke-width":
"0.25pt"}
2380 text_defaults = {
"stroke":
"none",
"fill":
"black",
"font-size":5}
2383 minitick_start = -0.75
2391 def __init__(self, f, low, high, ticks=-10, miniticks=True, labels=True, logbase=None, arrow_start=None, arrow_end=None, text_attr={}, **attr):
2403 self.attr.update(attr)
2406 self.text_attr.update(text_attr)
2409 """Return the position, normalized local x vector, normalized 2410 local y vector, and angle of a tick at position t. 2412 Normally only used internally. 2414 if isinstance(trans, str): trans =
totrans(trans)
2418 f =
lambda t: trans(*self.
f(t))
2423 Xprime, Yprime =
f(t + eps)
2424 xhatx, xhaty = (Xprime - X)/eps, (Yprime - Y)/eps
2426 norm = math.sqrt(xhatx**2 + xhaty**2)
2427 if norm != 0: xhatx, xhaty = xhatx/norm, xhaty/norm
2428 else: xhatx, xhaty = 1., 0.
2430 angle = math.atan2(xhaty, xhatx) + math.pi/2.
2431 yhatx, yhaty = math.cos(angle), math.sin(angle)
2433 return (X, Y), (xhatx, xhaty), (yhatx, yhaty), angle
2436 """Apply the transformation "trans" and return an SVG object.""" 2437 if isinstance(trans, str): trans =
totrans(trans)
2441 minitickmarks =
Path([], **self.
attr)
2453 raise TypeError(
"arrow_start must be False/None or an id string for the new marker")
2461 raise TypeError(
"arrow_end must be False/None or an id string for the new marker")
2465 eps = _epsilon * (self.
high - self.
low)
2467 for t, label
in self.last_ticks.items():
2468 (X, Y), (xhatx, xhaty), (yhatx, yhaty), angle = self.
orient_tickmark(t, trans)
2472 tickmarks.d.append((
"L", X - yhatx*self.
tick_end, Y - yhaty*self.
tick_end,
True))
2474 angle = (angle - math.pi/2.)*180./math.pi + self.
text_angle 2477 if _hacks[
"inkscape-text-vertical-shift"]:
2479 X += math.cos(angle*math.pi/180. + math.pi/2.) * 2.
2480 Y += math.sin(angle*math.pi/180. + math.pi/2.) * 2.
2482 X += math.cos(angle*math.pi/180. + math.pi/2.) * 2. * 2.5
2483 Y += math.sin(angle*math.pi/180. + math.pi/2.) * 2. * 2.5
2487 output.append(
SVG(
"text", label, transform=
"translate(%g, %g) rotate(%g)" % \
2492 for tt
in self.last_ticks.keys():
2493 if abs(t - tt) < eps:
2497 (X, Y), (xhatx, xhaty), (yhatx, yhaty), angle = self.
orient_tickmark(t, trans)
2503 output.prepend(tickmarks.SVG(trans))
2504 output.prepend(minitickmarks.SVG(trans))
2508 """Evaluate and return optimal ticks and miniticks according to 2509 the standard minitick specification. 2511 Normally only used internally. 2515 format =
lambda x:
"" 2517 elif self.
labels ==
True:
2520 elif isinstance(self.
labels, str):
2521 format =
lambda x: (self.
labels % x)
2523 elif callable(self.
labels):
2526 else:
raise TypeError(
"labels must be None/False, True, a format string, or a number->string function")
2532 if ticks ==
None or ticks ==
False:
return {}, []
2535 elif isinstance(ticks, (int, long)):
2536 if ticks ==
True: ticks = -10
2550 elif isinstance(self.
miniticks, (int, long)):
2553 elif getattr(self.
miniticks,
"__iter__",
False):
2560 raise TypeError(
"miniticks must be None/False, True, a number of desired miniticks, or a list of numbers")
2563 elif getattr(ticks,
"__iter__",
False):
2566 if not isinstance(ticks, dict):
2568 eps = _epsilon * (self.
high - self.
low)
2570 if format == unumber
and abs(x) < eps:
2586 elif isinstance(self.
miniticks, (int, long)):
2589 elif getattr(self.
miniticks,
"__iter__",
False):
2596 raise TypeError(
"miniticks must be None/False, True, a number of desired miniticks, or a list of numbers")
2599 raise TypeError(
"ticks must be None/False, a number of desired ticks, a list of numbers, or a dictionary of explicit markers")
2602 """Return less than -N or exactly N optimal linear ticks. 2604 Normally only used internally. 2606 if self.
low >= self.
high:
raise ValueError(
"low must be less than high")
2607 if N == 1:
raise ValueError(
"N can be 0 or >1 to specify the exact number of ticks or negative to specify a maximum")
2609 eps = _epsilon * (self.
high - self.
low)
2615 if format == unumber
and abs(x) < eps: label =
u"0" 2618 x += (self.
high - self.
low)/(N-1.)
2624 granularity = 10**math.ceil(math.log10(
max(
abs(self.
low),
abs(self.
high))))
2625 lowN = math.ceil(1.*self.
low / granularity)
2626 highN = math.floor(1.*self.
high / granularity)
2628 while (lowN > highN):
2629 countermod3 = counter % 3
2630 if countermod3 == 0: granularity *= 0.5
2631 elif countermod3 == 1: granularity *= 0.4
2632 else: granularity *= 0.5
2634 lowN = math.ceil(1.*self.
low / granularity)
2635 highN = math.floor(1.*self.
high / granularity)
2637 last_granularity = granularity
2642 for n
in range(
int(lowN),
int(highN)+1):
2644 if format == unumber
and abs(x) < eps: label =
u"0" 2648 if int(highN)+1 -
int(lowN) >= N:
2649 if last_trial ==
None:
2653 low_in_ticks, high_in_ticks =
False,
False 2654 for t
in last_trial.keys():
2655 if 1.*
abs(t - self.
low)/last_granularity < _epsilon: low_in_ticks =
True 2656 if 1.*
abs(t - self.
high)/last_granularity < _epsilon: high_in_ticks =
True 2658 lowN = 1.*self.
low / last_granularity
2659 highN = 1.*self.
high / last_granularity
2660 if abs(lowN - round(lowN)) < _epsilon
and not low_in_ticks:
2662 if abs(highN - round(highN)) < _epsilon
and not high_in_ticks:
2666 last_granularity = granularity
2669 countermod3 = counter % 3
2670 if countermod3 == 0: granularity *= 0.5
2671 elif countermod3 == 1: granularity *= 0.4
2672 else: granularity *= 0.5
2674 lowN = math.ceil(1.*self.
low / granularity)
2675 highN = math.floor(1.*self.
high / granularity)
2678 """Return exactly N linear ticks. 2680 Normally only used internally. 2686 x += (self.
high - self.
low)/(N-1.)
2690 """Return optimal linear miniticks, given a set of ticks. 2692 Normally only used internally. 2694 if len(original_ticks) < 2: original_ticks =
ticks(self.
low, self.
high)
2695 original_ticks = sorted(original_ticks.keys())
2697 if self.
low > original_ticks[0] + _epsilon
or self.
high < original_ticks[-1] - _epsilon:
2698 raise ValueError(
"original_ticks {%g...%g} extend beyond [%g, %g]" % (original_ticks[0], original_ticks[-1], self.
low, self.
high))
2701 for i
in range(len(original_ticks)-1):
2702 granularities.append(original_ticks[i+1] - original_ticks[i])
2703 spacing = 10**(math.ceil(math.log10(
min(granularities)) - 1))
2706 x = original_ticks[0] - math.ceil(1.*(original_ticks[0] - self.
low) / spacing) * spacing
2708 while x <= self.
high:
2710 already_in_ticks =
False 2711 for t
in original_ticks:
2712 if abs(x-t) < _epsilon * (self.
high - self.
low): already_in_ticks =
True 2713 if not already_in_ticks: output.append(x)
2718 """Return less than -N or exactly N optimal logarithmic ticks. 2720 Normally only used internally. 2722 if self.
low >= self.
high:
raise ValueError(
"low must be less than high")
2723 if N == 1:
raise ValueError(
"N can be 0 or >1 to specify the exact number of ticks or negative to specify a maximum")
2725 eps = _epsilon * (self.
high - self.
low)
2731 if format == unumber
and abs(x) < eps: label =
u"0" 2734 x += (self.
high - self.
low)/(N-1.)
2739 lowN = math.floor(math.log(self.
low, base))
2740 highN = math.ceil(math.log(self.
high, base))
2742 for n
in range(
int(lowN),
int(highN)+1):
2745 if self.
low <= x <= self.
high: output[x] = label
2747 for i
in range(1, len(output)):
2748 keys = sorted(output.keys())
2750 values =
map(
lambda k: output[k], keys)
2751 if len(values) <= N:
2752 for k
in output.keys():
2757 if len(output) <= 2:
2759 lowest =
min(output2)
2762 if k < lowest: output2[k] = output[k]
2768 """Return optimal logarithmic miniticks, given a set of ticks. 2770 Normally only used internally. 2772 if self.
low >= self.
high:
raise ValueError(
"low must be less than high")
2774 lowN = math.floor(math.log(self.
low, base))
2775 highN = math.ceil(math.log(self.
high, base))
2778 for n
in range(
int(lowN),
int(highN)+1):
2780 if self.
low <= x <= self.
high: num_ticks += 1
2781 for m
in range(2,
int(math.ceil(base))):
2783 if self.
low <= minix <= self.
high: output.append(minix)
2785 if num_ticks <= 2:
return []
2791 """Draw an axis with tick marks along a parametric curve. 2793 CurveAxis(f, low, high, ticks, miniticks, labels, logbase, arrow_start, arrow_end, 2794 text_attr, attribute=value) 2796 f required a Python callable or string in 2797 the form "f(t), g(t)", just like Curve 2798 low, high required left and right endpoints 2799 ticks default=-10 request ticks according to the standard 2800 tick specification (see help(Ticks)) 2801 miniticks default=True request miniticks according to the 2802 standard minitick specification 2803 labels True request tick labels according to the 2804 standard tick label specification 2805 logbase default=None if a number, the x axis is logarithmic 2806 with ticks at the given base (10 being 2808 arrow_start default=None if a new string identifier, draw an 2809 arrow at the low-end of the axis, 2810 referenced by that identifier; if an 2811 SVG marker object, use that marker 2812 arrow_end default=None if a new string identifier, draw an 2813 arrow at the high-end of the axis, 2814 referenced by that identifier; if an 2815 SVG marker object, use that marker 2816 text_attr default={} SVG attributes for the text labels 2817 attribute=value pairs keyword list SVG attributes 2819 defaults = {
"stroke-width":
"0.25pt"}
2820 text_defaults = {
"stroke":
"none",
"fill":
"black",
"font-size":5}
2825 def __init__(self, f, low, high, ticks=-10, miniticks=True, labels=True, logbase=None, arrow_start=None, arrow_end=None, text_attr={}, **attr):
2827 tattr.update(text_attr)
2828 Curve.__init__(self, f, low, high)
2829 Ticks.__init__(self, f, low, high, ticks, miniticks, labels, logbase, arrow_start, arrow_end, tattr, **attr)
2832 """Apply the transformation "trans" and return an SVG object.""" 2833 func = Curve.SVG(self, trans)
2834 ticks = Ticks.SVG(self, trans)
2838 func.attr[
"marker-start"] =
"url(#%s)" % self.
arrow_start 2840 func.attr[
"marker-start"] =
"url(#%s)" % self.arrow_start.id
2844 func.attr[
"marker-end"] =
"url(#%s)" % self.
arrow_end 2846 func.attr[
"marker-end"] =
"url(#%s)" % self.arrow_end.id
2852 """Draws an axis with tick marks along a line. 2854 LineAxis(x1, y1, x2, y2, start, end, ticks, miniticks, labels, logbase, 2855 arrow_start, arrow_end, text_attr, attribute=value) 2857 x1, y1 required starting point 2858 x2, y2 required ending point 2859 start, end default=0, 1 values to start and end labeling 2860 ticks default=-10 request ticks according to the standard 2861 tick specification (see help(Ticks)) 2862 miniticks default=True request miniticks according to the 2863 standard minitick specification 2864 labels True request tick labels according to the 2865 standard tick label specification 2866 logbase default=None if a number, the x axis is logarithmic 2867 with ticks at the given base (usually 10) 2868 arrow_start default=None if a new string identifier, draw an arrow 2869 at the low-end of the axis, referenced by 2870 that identifier; if an SVG marker object, 2872 arrow_end default=None if a new string identifier, draw an arrow 2873 at the high-end of the axis, referenced by 2874 that identifier; if an SVG marker object, 2876 text_attr default={} SVG attributes for the text labels 2877 attribute=value pairs keyword list SVG attributes 2879 defaults = {
"stroke-width":
"0.25pt"}
2880 text_defaults = {
"stroke":
"none",
"fill":
"black",
"font-size":5}
2883 return "<LineAxis (%g, %g) to (%g, %g) ticks=%s labels=%s %s>" % (self.x1, self.y1, self.x2, self.
y2,
str(self.
ticks),
str(self.
labels), self.
attr)
2885 def __init__(self, x1, y1, x2, y2, start=0., end=1., ticks=-10, miniticks=True, labels=True, logbase=None, arrow_start=None, arrow_end=None, exclude=None, text_attr={}, **attr):
2890 tattr.update(text_attr)
2891 Line.__init__(self, x1, y1, x2, y2, **attr)
2892 Ticks.__init__(self,
None,
None,
None, ticks, miniticks, labels, logbase, arrow_start, arrow_end, tattr, **attr)
2895 if self.
exclude !=
None and not (isinstance(self.
exclude, (tuple, list))
and len(self.
exclude) == 2
and \
2896 isinstance(self.
exclude[0], (int, long, float))
and isinstance(self.
exclude[1], (int, long, float))):
2897 raise TypeError(
"exclude must either be None or (low, high)")
2899 ticks, miniticks = Ticks.interpret(self)
2900 if self.
exclude ==
None:
return ticks, miniticks
2903 for loc, label
in ticks.items():
2909 return ticks2, miniticks
2912 """Apply the transformation "trans" and return an SVG object.""" 2913 line = Line.SVG(self, trans)
2922 line.attr[
"marker-start"] =
"url(#%s)" % self.
arrow_start 2924 line.attr[
"marker-start"] =
"url(#%s)" % self.arrow_start.id
2928 line.attr[
"marker-end"] =
"url(#%s)" % self.
arrow_end 2930 line.attr[
"marker-end"] =
"url(#%s)" % self.arrow_end.id
2932 ticks = Ticks.SVG(self, trans)
2937 """Draws an x axis with tick marks. 2939 XAxis(xmin, xmax, aty, ticks, miniticks, labels, logbase, arrow_start, arrow_end, 2940 exclude, text_attr, attribute=value) 2942 xmin, xmax required the x range 2943 aty default=0 y position to draw the axis 2944 ticks default=-10 request ticks according to the standard 2945 tick specification (see help(Ticks)) 2946 miniticks default=True request miniticks according to the 2947 standard minitick specification 2948 labels True request tick labels according to the 2949 standard tick label specification 2950 logbase default=None if a number, the x axis is logarithmic 2951 with ticks at the given base (usually 10) 2952 arrow_start default=None if a new string identifier, draw an arrow 2953 at the low-end of the axis, referenced by 2954 that identifier; if an SVG marker object, 2956 arrow_end default=None if a new string identifier, draw an arrow 2957 at the high-end of the axis, referenced by 2958 that identifier; if an SVG marker object, 2960 exclude default=None if a (low, high) pair, don't draw text 2961 labels within this range 2962 text_attr default={} SVG attributes for the text labels 2963 attribute=value pairs keyword list SVG attributes for all lines 2965 The exclude option is provided for Axes to keep text from overlapping 2966 where the axes cross. Normal users are not likely to need it. 2968 defaults = {
"stroke-width":
"0.25pt"}
2969 text_defaults = {
"stroke":
"none",
"fill":
"black",
"font-size":5,
"dominant-baseline":
"text-before-edge"}
2974 return "<XAxis (%g, %g) at y=%g ticks=%s labels=%s %s>" % (self.xmin, self.xmax, self.
aty,
str(self.
ticks),
str(self.
labels), self.
attr)
2976 def __init__(self, xmin, xmax, aty=0, ticks=-10, miniticks=True, labels=True, logbase=None, arrow_start=None, arrow_end=None, exclude=None, text_attr={}, **attr):
2979 tattr.update(text_attr)
2980 LineAxis.__init__(self, xmin, aty, xmax, aty, xmin, xmax, ticks, miniticks, labels, logbase, arrow_start, arrow_end, exclude, tattr, **attr)
2983 """Apply the transformation "trans" and return an SVG object.""" 2986 return LineAxis.SVG(self, trans)
2989 """Draws a y axis with tick marks. 2991 YAxis(ymin, ymax, atx, ticks, miniticks, labels, logbase, arrow_start, arrow_end, 2992 exclude, text_attr, attribute=value) 2994 ymin, ymax required the y range 2995 atx default=0 x position to draw the axis 2996 ticks default=-10 request ticks according to the standard 2997 tick specification (see help(Ticks)) 2998 miniticks default=True request miniticks according to the 2999 standard minitick specification 3000 labels True request tick labels according to the 3001 standard tick label specification 3002 logbase default=None if a number, the y axis is logarithmic 3003 with ticks at the given base (usually 10) 3004 arrow_start default=None if a new string identifier, draw an arrow 3005 at the low-end of the axis, referenced by 3006 that identifier; if an SVG marker object, 3008 arrow_end default=None if a new string identifier, draw an arrow 3009 at the high-end of the axis, referenced by 3010 that identifier; if an SVG marker object, 3012 exclude default=None if a (low, high) pair, don't draw text 3013 labels within this range 3014 text_attr default={} SVG attributes for the text labels 3015 attribute=value pairs keyword list SVG attributes for all lines 3017 The exclude option is provided for Axes to keep text from overlapping 3018 where the axes cross. Normal users are not likely to need it. 3020 defaults = {
"stroke-width":
"0.25pt"}
3021 text_defaults = {
"stroke":
"none",
"fill":
"black",
"font-size":5,
"text-anchor":
"end",
"dominant-baseline":
"middle"}
3026 return "<YAxis (%g, %g) at x=%g ticks=%s labels=%s %s>" % (self.ymin, self.ymax, self.
atx,
str(self.
ticks),
str(self.
labels), self.
attr)
3028 def __init__(self, ymin, ymax, atx=0, ticks=-10, miniticks=True, labels=True, logbase=None, arrow_start=None, arrow_end=None, exclude=None, text_attr={}, **attr):
3031 tattr.update(text_attr)
3032 LineAxis.__init__(self, atx, ymin, atx, ymax, ymin, ymax, ticks, miniticks, labels, logbase, arrow_start, arrow_end, exclude, tattr, **attr)
3035 """Apply the transformation "trans" and return an SVG object.""" 3038 return LineAxis.SVG(self, trans)
3041 """Draw a pair of intersecting x-y axes. 3043 Axes(xmin, xmax, ymin, ymax, atx, aty, xticks, xminiticks, xlabels, xlogbase, 3044 yticks, yminiticks, ylabels, ylogbase, arrows, text_attr, attribute=value) 3046 xmin, xmax required the x range 3047 ymin, ymax required the y range 3048 atx, aty default=0, 0 point where the axes try to cross; 3049 if outside the range, the axes will 3050 cross at the closest corner 3051 xticks default=-10 request ticks according to the standard 3052 tick specification (see help(Ticks)) 3053 xminiticks default=True request miniticks according to the 3054 standard minitick specification 3055 xlabels True request tick labels according to the 3056 standard tick label specification 3057 xlogbase default=None if a number, the x axis is logarithmic 3058 with ticks at the given base (usually 10) 3059 yticks default=-10 request ticks according to the standard 3061 yminiticks default=True request miniticks according to the 3062 standard minitick specification 3063 ylabels True request tick labels according to the 3064 standard tick label specification 3065 ylogbase default=None if a number, the y axis is logarithmic 3066 with ticks at the given base (usually 10) 3067 arrows default=None if a new string identifier, draw arrows 3068 referenced by that identifier 3069 text_attr default={} SVG attributes for the text labels 3070 attribute=value pairs keyword list SVG attributes for all lines 3072 defaults = {
"stroke-width":
"0.25pt"}
3073 text_defaults = {
"stroke":
"none",
"fill":
"black",
"font-size":5}
3076 return "<Axes x=(%g, %g) y=(%g, %g) at (%g, %g) %s>" % (self.xmin, self.
xmax, self.ymin, self.
ymax, self.atx, self.
aty, self.
attr)
3078 def __init__(self, xmin, xmax, ymin, ymax, atx=0, aty=0, xticks=-10, xminiticks=True, xlabels=True, xlogbase=None, yticks=-10, yminiticks=True, ylabels=True, ylogbase=None, arrows=None, text_attr={}, **attr):
3082 self.xticks, self.xminiticks, self.xlabels, self.
xlogbase = xticks, xminiticks, xlabels, xlogbase
3083 self.yticks, self.yminiticks, self.ylabels, self.
ylogbase = yticks, yminiticks, ylabels, ylogbase
3087 self.text_attr.update(text_attr)
3090 self.attr.update(attr)
3093 """Apply the transformation "trans" and return an SVG object.""" 3094 atx, aty = self.atx, self.
aty 3095 if atx < self.xmin: atx = self.xmin
3096 if atx > self.
xmax: atx = self.
xmax 3097 if aty < self.ymin: aty = self.ymin
3098 if aty > self.
ymax: aty = self.
ymax 3100 xmargin = 0.1 *
abs(self.ymin - self.
ymax)
3101 xexclude = atx - xmargin, atx + xmargin
3103 ymargin = 0.1 *
abs(self.xmin - self.
xmax)
3104 yexclude = aty - ymargin, aty + ymargin
3107 xarrow_start = self.
arrows +
".xstart" 3108 xarrow_end = self.
arrows +
".xend" 3109 yarrow_start = self.
arrows +
".ystart" 3110 yarrow_end = self.
arrows +
".yend" 3112 xarrow_start = xarrow_end = yarrow_start = yarrow_end =
None 3114 xaxis =
XAxis(self.xmin, self.
xmax, aty, self.xticks, self.xminiticks, self.xlabels, self.
xlogbase, xarrow_start, xarrow_end, exclude=xexclude, text_attr=self.
text_attr, **self.
attr).
SVG(trans)
3115 yaxis =
YAxis(self.ymin, self.
ymax, atx, self.yticks, self.yminiticks, self.ylabels, self.
ylogbase, yarrow_start, yarrow_end, exclude=yexclude, text_attr=self.
text_attr, **self.
attr).
SVG(trans)
3116 return SVG(
"g", *(xaxis.sub + yaxis.sub))
3121 """Draws the horizontal lines of a grid over a specified region 3122 using the standard tick specification (see help(Ticks)) to place the 3125 HGrid(xmin, xmax, low, high, ticks, miniticks, logbase, mini_attr, attribute=value) 3127 xmin, xmax required the x range 3128 low, high required the y range 3129 ticks default=-10 request ticks according to the standard 3130 tick specification (see help(Ticks)) 3131 miniticks default=False request miniticks according to the 3132 standard minitick specification 3133 logbase default=None if a number, the axis is logarithmic 3134 with ticks at the given base (usually 10) 3135 mini_attr default={} SVG attributes for the minitick-lines 3136 (if miniticks != False) 3137 attribute=value pairs keyword list SVG attributes for the major tick lines 3139 defaults = {
"stroke-width":
"0.25pt",
"stroke":
"gray"}
3140 mini_defaults = {
"stroke-width":
"0.25pt",
"stroke":
"lightgray",
"stroke-dasharray":
"1,1"}
3145 def __init__(self, xmin, xmax, low, high, ticks=-10, miniticks=False, logbase=None, mini_attr={}, **attr):
3149 self.mini_attr.update(mini_attr)
3151 Ticks.__init__(self,
None, low, high, ticks, miniticks,
None, logbase)
3154 self.attr.update(attr)
3157 """Apply the transformation "trans" and return an SVG object.""" 3161 for t
in self.last_ticks.keys():
3162 ticksd +=
Line(self.xmin, t, self.
xmax, t).
Path(trans).d
3166 miniticksd +=
Line(self.xmin, t, self.
xmax, t).
Path(trans).d
3171 """Draws the vertical lines of a grid over a specified region 3172 using the standard tick specification (see help(Ticks)) to place the 3175 HGrid(ymin, ymax, low, high, ticks, miniticks, logbase, mini_attr, attribute=value) 3177 ymin, ymax required the y range 3178 low, high required the x range 3179 ticks default=-10 request ticks according to the standard 3180 tick specification (see help(Ticks)) 3181 miniticks default=False request miniticks according to the 3182 standard minitick specification 3183 logbase default=None if a number, the axis is logarithmic 3184 with ticks at the given base (usually 10) 3185 mini_attr default={} SVG attributes for the minitick-lines 3186 (if miniticks != False) 3187 attribute=value pairs keyword list SVG attributes for the major tick lines 3189 defaults = {
"stroke-width":
"0.25pt",
"stroke":
"gray"}
3190 mini_defaults = {
"stroke-width":
"0.25pt",
"stroke":
"lightgray",
"stroke-dasharray":
"1,1"}
3195 def __init__(self, ymin, ymax, low, high, ticks=-10, miniticks=False, logbase=None, mini_attr={}, **attr):
3199 self.mini_attr.update(mini_attr)
3201 Ticks.__init__(self,
None, low, high, ticks, miniticks,
None, logbase)
3204 self.attr.update(attr)
3207 """Apply the transformation "trans" and return an SVG object.""" 3211 for t
in self.last_ticks.keys():
3212 ticksd +=
Line(t, self.ymin, t, self.
ymax).
Path(trans).d
3216 miniticksd +=
Line(t, self.ymin, t, self.
ymax).
Path(trans).d
3221 """Draws a grid over a specified region using the standard tick 3222 specification (see help(Ticks)) to place the grid lines. 3224 Grid(xmin, xmax, ymin, ymax, ticks, miniticks, logbase, mini_attr, attribute=value) 3226 xmin, xmax required the x range 3227 ymin, ymax required the y range 3228 ticks default=-10 request ticks according to the standard 3229 tick specification (see help(Ticks)) 3230 miniticks default=False request miniticks according to the 3231 standard minitick specification 3232 logbase default=None if a number, the axis is logarithmic 3233 with ticks at the given base (usually 10) 3234 mini_attr default={} SVG attributes for the minitick-lines 3235 (if miniticks != False) 3236 attribute=value pairs keyword list SVG attributes for the major tick lines 3238 defaults = {
"stroke-width":
"0.25pt",
"stroke":
"gray"}
3239 mini_defaults = {
"stroke-width":
"0.25pt",
"stroke":
"lightgray",
"stroke-dasharray":
"1,1"}
3242 return "<Grid x=(%g, %g) y=(%g, %g) ticks=%s miniticks=%s %s>" % (self.xmin, self.
xmax, self.ymin, self.
ymax,
str(self.
ticks),
str(self.
miniticks), self.
attr)
3244 def __init__(self, xmin, xmax, ymin, ymax, ticks=-10, miniticks=False, logbase=None, mini_attr={}, **attr):
3249 self.mini_attr.update(mini_attr)
3251 Ticks.__init__(self,
None,
None,
None, ticks, miniticks,
None, logbase)
3254 self.attr.update(attr)
3257 """Apply the transformation "trans" and return an SVG object.""" 3264 for t
in self.last_xticks.keys():
3265 ticksd +=
Line(t, self.ymin, t, self.
ymax).
Path(trans).d
3266 for t
in self.last_yticks.keys():
3267 ticksd +=
Line(self.xmin, t, self.
xmax, t).
Path(trans).d
3271 miniticksd +=
Line(t, self.ymin, t, self.
ymax).
Path(trans).d
3273 miniticksd +=
Line(self.xmin, t, self.
xmax, t).
Path(trans).d
3280 """Draws x error bars at a set of points. This is usually used 3281 before (under) a set of Dots at the same points. 3283 XErrorBars(d, attribute=value) 3285 d required list of (x,y,xerr...) points 3286 attribute=value pairs keyword list SVG attributes 3290 * 3 elements, the third is the symmetric error bar 3291 * 4 elements, the third and fourth are the asymmetric lower and 3292 upper error bar. The third element should be negative, 3293 e.g. (5, 5, -1, 2) is a bar from 4 to 7. 3294 * more than 4, a tick mark is placed at each value. This lets 3295 you nest errors from different sources, correlated and 3296 uncorrelated, statistical and systematic, etc. 3298 defaults = {
"stroke-width":
"0.25pt"}
3301 return "<XErrorBars (%d nodes)>" % len(self.
d)
3307 self.attr.update(attr)
3310 """Apply the transformation "trans" and return an SVG object.""" 3311 if isinstance(trans, str): trans =
totrans(trans)
3317 if len(p) == 3: bars = [x - p[2], x + p[2]]
3318 else: bars = [x + pi
for pi
in p[2:]]
3320 start, end =
min(bars),
max(bars)
3321 output.append(
LineAxis(start, y, end, y, start, end, bars,
False,
False, **self.
attr).
SVG(trans))
3326 """Draws y error bars at a set of points. This is usually used 3327 before (under) a set of Dots at the same points. 3329 YErrorBars(d, attribute=value) 3331 d required list of (x,y,yerr...) points 3332 attribute=value pairs keyword list SVG attributes 3336 * 3 elements, the third is the symmetric error bar 3337 * 4 elements, the third and fourth are the asymmetric lower and 3338 upper error bar. The third element should be negative, 3339 e.g. (5, 5, -1, 2) is a bar from 4 to 7. 3340 * more than 4, a tick mark is placed at each value. This lets 3341 you nest errors from different sources, correlated and 3342 uncorrelated, statistical and systematic, etc. 3344 defaults = {
"stroke-width":
"0.25pt"}
3347 return "<YErrorBars (%d nodes)>" % len(self.
d)
3353 self.attr.update(attr)
3356 """Apply the transformation "trans" and return an SVG object.""" 3357 if isinstance(trans, str): trans =
totrans(trans)
3363 if len(p) == 3: bars = [y - p[2], y + p[2]]
3364 else: bars = [y + pi
for pi
in p[2:]]
3366 start, end =
min(bars),
max(bars)
3367 output.append(
LineAxis(x, start, x, end, start, end, bars,
False,
False, **self.
attr).
SVG(trans))
def inkscape(self, fileName=None, encoding="utf-8")
def Path(self, trans=None, local=False)
def __init__(self, x, y, d, attr)
def parse_number(self, index, pathdata)
def Path(self, trans=None, local=False)
def __init__(self, x1, y1, x2, y2, attr)
def __init__(self, d=[], symbol=None, width=1., height=1., attr)
def __init__(self, f, low, high, ticks=-10, miniticks=True, labels=True, logbase=None, arrow_start=None, arrow_end=None, text_attr={}, attr)
def __init__(self, x1, x2, y, attr)
def subsample(self, left, right, depth, trans=None)
def funcRtoR2(expr, var="t", globals=None, locals=None)
def funcRtoC(expr, var="t", globals=None, locals=None)
def SVG(self, trans=None)
def depth_first(self, depth_limit=None)
end nested class
def make_marker(id, shape, attr)
def __init__(self, xmin, xmax, low, high, ticks=-10, miniticks=False, logbase=None, mini_attr={}, attr)
def SVG(self, trans=None)
def __init__(self, f, low, high, loop=False, attr)
def parse(self, pathdata)
def evaluate(self, f, trans)
def parse_boolean(self, index, pathdata)
def SVG(self, trans=None)
def compute_logminiticks(self, base)
def compute_miniticks(self, original_ticks)
def __init__(self, xmin, xmax, ymin, ymax, d, kwds)
def SVG(self, trans=None)
def __init__(self, x, y, ax, ay, b, attr)
def __init__(self, d=[], attr)
def SVG(self, trans=None)
def SVG(self, trans=None)
def canvas_outline(sub, attr)
def __init__(self, xmin, xmax, ymin, ymax, d, kwds)
def __init__(self, f, low, high, ticks=-10, miniticks=True, labels=True, logbase=None, arrow_start=None, arrow_end=None, text_attr={}, attr)
def link(self, left, right)
def __init__(self, x1, y1, x2, y2, arrow_start=None, arrow_end=None, attr)
def SVG(self, trans=None)
def __init__(self, xmin, xmax, ymin, ymax, atx=0, aty=0, xticks=-10, xminiticks=True, xlabels=True, xlogbase=None, yticks=-10, yminiticks=True, ylabels=True, ylogbase=None, arrows=None, text_attr={}, attr)
def __init__(self, d, kwds)
def SVG(self, trans=None)
def SVG(self, trans=None)
def attr_preprocess(attr)
def __init__(self, x, y, d, attr)
def regular_miniticks(self, N)
def __init__(self, x1, y1, x2, y2, local1=False, local2=False, arrow_start=None, arrow_end=None, attr)
def __getitem__(self, ti)
def SVG(self, trans=None)
def save(self, fileName=None, encoding="utf-8", compresslevel=None)
def Path(self, trans=None, local=False)
def firefox(self, fileName=None, encoding="utf-8")
def SVG(self, trans=None)
def __init__(self, svg, ti, depth_limit)
def SVG(self, trans=None)
def SVG(self, trans=None)
def standalone_xml(self, indent=" ", newl="\n")
def __init__(self, ymin, ymax, atx=0, ticks=-10, miniticks=True, labels=True, logbase=None, arrow_start=None, arrow_end=None, exclude=None, text_attr={}, attr)
Abs< T >::type abs(const T &t)
def template(fileName, svg, replaceme="REPLACEME")
def sample(self, trans=None)
end nested class
def window(xmin, xmax, ymin, ymax, x=0, y=0, width=100, height=100, xlogbase=None, ylogbase=None, minusInfinity=-1000, flipx=False, flipy=True)
def tree(self, depth_limit=None, sub=True, attr=True, text=True, tree_width=20, obj_width=80)
def inkview(self, fileName=None, encoding="utf-8")
def SVG(self, trans=None)
def breadth_first(self, depth_limit=None)
def Path(self, trans=None, local=False)
def compute_logticks(self, base, N, format)
def SVG(self, trans=None)
def SVG(self, trans=None)
def __init__(self, t_sub, attr)
def SVG(self, trans=None)
def interpret_fileName(self, fileName=None)
def __init__(self, ymin, ymax, low, high, ticks=-10, miniticks=False, logbase=None, mini_attr={}, attr)
def make_symbol(id, shape="dot", attr)
static std::string join(char **cmd)
def values(self, sub=True, attr=True, text=True)
def __init__(self, d=[], mode="L", loop=False, attr)
def funcRtoR(expr, var="x", globals=None, locals=None)
def orient_tickmark(self, t, trans=None)
def __init__(self, left, right)
def SVG(self, trans=None)
def __setitem__(self, ti, value)
def clone(self, shallow=False)
def Path(self, trans=None, local=False)
def __contains__(self, value)
def __init__(self, d=[], attr)
def __delitem__(self, ti)
def SVG(self, trans=None)
def __standalone_xml(self, indent, newl)
def SVG(self, trans=None)
def SVG(self, trans=None)
def xml(self, indent=" ", newl="\n", depth_limit=None, depth=0)
def SVG(self, trans=None)
def keys(self, sub=True, attr=True, text=True)
def __init__(self, xmin, xmax, ymin, ymax, ticks=-10, miniticks=False, logbase=None, mini_attr={}, attr)
def Path(self, trans=None, local=False)
def __init__(self, xmin, xmax, aty=0, ticks=-10, miniticks=True, labels=True, logbase=None, arrow_start=None, arrow_end=None, exclude=None, text_attr={}, attr)
def __init__(self, y1, y2, x, attr)
def rotate(angle, cx=0, cy=0)
def rgb(r, g, b, maximum=1.)
def parse_whitespace(self, index, pathdata)
def items(self, sub=True, attr=True, text=True)
def Path(self, trans=None, local=False)
def parse_command(self, index, pathdata)
def totrans(expr, vars=("x","y"), globals=None, locals=None)
def __init__(self, x1, y1, x2, y2, start=0., end=1., ticks=-10, miniticks=True, labels=True, logbase=None, arrow_start=None, arrow_end=None, exclude=None, text_attr={}, attr)
def SVG(self, trans=None)
def compute_ticks(self, N, format)
How EventSelector::AcceptEvent() decides whether to accept an event for output otherwise it is excluding the probing of A single or multiple positive and the trigger will pass if any such matching triggers are PASS or EXCEPTION[A criterion thatmatches no triggers at all is detected and causes a throw.] A single negative with an expectation of appropriate bit checking in the decision and the trigger will pass if any such matching triggers are FAIL or EXCEPTION A wildcarded negative criterion that matches more than one trigger in the trigger list("!*","!HLTx*"if it matches 2 triggers or more) will accept the event if all the matching triggers are FAIL.It will reject the event if any of the triggers are PASS or EXCEPTION(this matches the behavior of"!*"before the partial wildcard feature was incorporated).Triggers which are in the READY state are completely ignored.(READY should never be returned since the trigger paths have been run
def __init__(self, d=[], attr)