Public Member Functions | |
def | __init__ |
def | __repr__ |
def | compute_logminiticks |
def | compute_logticks |
def | compute_miniticks |
def | compute_ticks |
def | interpret |
def | orient_tickmark |
def | regular_miniticks |
def | SVG |
Public Attributes | |
arrow_end | |
arrow_start | |
attr | |
f | |
high | |
labels | |
last_miniticks | |
logbase | |
low | |
miniticks | |
text_attr | |
ticks | |
Static Public Attributes | |
dictionary | defaults = {"stroke-width":"0.25pt"} |
float | minitick_end = 0.75 |
float | minitick_start = 0.75 |
int | text_angle = 0 |
dictionary | text_defaults = {"stroke":"none", "fill":"black", "font-size":5} |
float | text_start = 2.5 |
float | tick_end = 1.5 |
float | tick_start = 1.5 |
Superclass for all graphics primatives that draw ticks, miniticks, and tick labels. This class only draws the ticks. Ticks(f, low, high, ticks, miniticks, labels, logbase, arrow_start, arrow_end, text_attr, attribute=value) f required parametric function along which ticks will be drawn; has the same format as the function used in Curve low, high required range of the independent variable ticks default=-10 request ticks according to the standard tick specification (see below) miniticks default=True request miniticks according to the standard minitick specification (below) labels True request tick labels according to the standard tick label specification (below) logbase default=None if a number, the axis is logarithmic with ticks at the given base (usually 10) arrow_start default=None if a new string identifier, draw an arrow at the low-end of the axis, referenced by that identifier; if an SVG marker object, use that marker arrow_end default=None if a new string identifier, draw an arrow at the high-end of the axis, referenced by that identifier; if an SVG marker object, use that marker text_attr default={} SVG attributes for the text labels attribute=value pairs keyword list SVG attributes for the tick marks Standard tick specification: * True: same as -10 (below). * Positive number N: draw exactly N ticks, including the endpoints. To subdivide an axis into 10 equal-sized segments, ask for 11 ticks. * Negative number -N: draw at least N ticks. Ticks will be chosen with "natural" values, multiples of 2 or 5. * List of values: draw a tick mark at each value. * Dict of value, label pairs: draw a tick mark at each value, labeling it with the given string. This lets you say things like {3.14159: "pi"}. * False or None: no ticks. Standard minitick specification: * True: draw miniticks with "natural" values, more closely spaced than the ticks. * Positive number N: draw exactly N miniticks, including the endpoints. To subdivide an axis into 100 equal-sized segments, ask for 101 miniticks. * Negative number -N: draw at least N miniticks. * List of values: draw a minitick mark at each value. * False or None: no miniticks. Standard tick label specification: * True: use the unumber function (described below) * Format string: standard format strings, e.g. "%5.2f" for 12.34 * Python callable: function that converts numbers to strings * False or None: no labels
def svgfig::Ticks::__init__ | ( | self, | |
f, | |||
low, | |||
high, | |||
ticks = -10 , |
|||
miniticks = True , |
|||
labels = True , |
|||
logbase = None , |
|||
arrow_start = None , |
|||
arrow_end = None , |
|||
text_attr = {} , |
|||
attr | |||
) |
Reimplemented in svgfig::CurveAxis.
Definition at line 2391 of file svgfig.py.
02391 {}, **attr): 02392 self.f = f 02393 self.low = low 02394 self.high = high 02395 self.ticks = ticks 02396 self.miniticks = miniticks 02397 self.labels = labels 02398 self.logbase = logbase 02399 self.arrow_start = arrow_start 02400 self.arrow_end = arrow_end 02401 02402 self.attr = dict(self.defaults) 02403 self.attr.update(attr) 02404 02405 self.text_attr = dict(self.text_defaults) 02406 self.text_attr.update(text_attr) 02407
def svgfig::Ticks::__repr__ | ( | self | ) |
Reimplemented in svgfig::CurveAxis, svgfig::LineAxis, svgfig::XAxis, svgfig::YAxis, svgfig::HGrid, svgfig::VGrid, and svgfig::Grid.
def svgfig::Ticks::compute_logminiticks | ( | self, | |
base | |||
) |
Return optimal logarithmic miniticks, given a set of ticks. Normally only used internally.
Definition at line 2769 of file svgfig.py.
02770 : 02771 """Return optimal logarithmic miniticks, given a set of ticks. 02772 02773 Normally only used internally. 02774 """ 02775 if self.low >= self.high: raise ValueError, "low must be less than high" 02776 02777 lowN = math.floor(math.log(self.low, base)) 02778 highN = math.ceil(math.log(self.high, base)) 02779 output = [] 02780 num_ticks = 0 02781 for n in range(int(lowN), int(highN)+1): 02782 x = base**n 02783 if self.low <= x <= self.high: num_ticks += 1 02784 for m in range(2, int(math.ceil(base))): 02785 minix = m * x 02786 if self.low <= minix <= self.high: output.append(minix) 02787 02788 if num_ticks <= 2: return [] 02789 else: return output
def svgfig::Ticks::compute_logticks | ( | self, | |
base, | |||
N, | |||
format | |||
) |
Return less than -N or exactly N optimal logarithmic ticks. Normally only used internally.
Definition at line 2718 of file svgfig.py.
02719 : 02720 """Return less than -N or exactly N optimal logarithmic ticks. 02721 02722 Normally only used internally. 02723 """ 02724 if self.low >= self.high: raise ValueError, "low must be less than high" 02725 if N == 1: raise ValueError, "N can be 0 or >1 to specify the exact number of ticks or negative to specify a maximum" 02726 02727 eps = _epsilon * (self.high - self.low) 02728 02729 if N >= 0: 02730 output = {} 02731 x = self.low 02732 for i in xrange(N): 02733 if format == unumber and abs(x) < eps: label = u"0" 02734 else: label = format(x) 02735 output[x] = label 02736 x += (self.high - self.low)/(N-1.) 02737 return output 02738 02739 N = -N 02740 02741 lowN = math.floor(math.log(self.low, base)) 02742 highN = math.ceil(math.log(self.high, base)) 02743 output = {} 02744 for n in range(int(lowN), int(highN)+1): 02745 x = base**n 02746 label = format(x) 02747 if self.low <= x <= self.high: output[x] = label 02748 02749 for i in range(1, len(output)): 02750 keys = output.keys() 02751 keys.sort() 02752 keys = keys[::i] 02753 values = map(lambda k: output[k], keys) 02754 if len(values) <= N: 02755 for k in output.keys(): 02756 if k not in keys: 02757 output[k] = "" 02758 break 02759 02760 if len(output) <= 2: 02761 output2 = self.compute_ticks(N=-int(math.ceil(N/2.)), format=format) 02762 lowest = min(output2) 02763 02764 for k in output: 02765 if k < lowest: output2[k] = output[k] 02766 output = output2 02767 02768 return output
def svgfig::Ticks::compute_miniticks | ( | self, | |
original_ticks | |||
) |
Return optimal linear miniticks, given a set of ticks. Normally only used internally.
Definition at line 2689 of file svgfig.py.
02690 : 02691 """Return optimal linear miniticks, given a set of ticks. 02692 02693 Normally only used internally. 02694 """ 02695 if len(original_ticks) < 2: original_ticks = ticks(self.low, self.high) 02696 original_ticks = original_ticks.keys() 02697 original_ticks.sort() 02698 02699 if self.low > original_ticks[0] + _epsilon or self.high < original_ticks[-1] - _epsilon: 02700 raise ValueError, "original_ticks {%g...%g} extend beyond [%g, %g]" % (original_ticks[0], original_ticks[-1], self.low, self.high) 02701 02702 granularities = [] 02703 for i in range(len(original_ticks)-1): 02704 granularities.append(original_ticks[i+1] - original_ticks[i]) 02705 spacing = 10**(math.ceil(math.log10(min(granularities)) - 1)) 02706 02707 output = [] 02708 x = original_ticks[0] - math.ceil(1.*(original_ticks[0] - self.low) / spacing) * spacing 02709 02710 while x <= self.high: 02711 if x >= self.low: 02712 already_in_ticks = False 02713 for t in original_ticks: 02714 if abs(x-t) < _epsilon * (self.high - self.low): already_in_ticks = True 02715 if not already_in_ticks: output.append(x) 02716 x += spacing 02717 return output
def svgfig::Ticks::compute_ticks | ( | self, | |
N, | |||
format | |||
) |
Return less than -N or exactly N optimal linear ticks. Normally only used internally.
Definition at line 2601 of file svgfig.py.
02602 : 02603 """Return less than -N or exactly N optimal linear ticks. 02604 02605 Normally only used internally. 02606 """ 02607 if self.low >= self.high: raise ValueError, "low must be less than high" 02608 if N == 1: raise ValueError, "N can be 0 or >1 to specify the exact number of ticks or negative to specify a maximum" 02609 02610 eps = _epsilon * (self.high - self.low) 02611 02612 if N >= 0: 02613 output = {} 02614 x = self.low 02615 for i in xrange(N): 02616 if format == unumber and abs(x) < eps: label = u"0" 02617 else: label = format(x) 02618 output[x] = label 02619 x += (self.high - self.low)/(N-1.) 02620 return output 02621 02622 N = -N 02623 02624 counter = 0 02625 granularity = 10**math.ceil(math.log10(max(abs(self.low), abs(self.high)))) 02626 lowN = math.ceil(1.*self.low / granularity) 02627 highN = math.floor(1.*self.high / granularity) 02628 02629 while (lowN > highN): 02630 countermod3 = counter % 3 02631 if countermod3 == 0: granularity *= 0.5 02632 elif countermod3 == 1: granularity *= 0.4 02633 else: granularity *= 0.5 02634 counter += 1 02635 lowN = math.ceil(1.*self.low / granularity) 02636 highN = math.floor(1.*self.high / granularity) 02637 02638 last_granularity = granularity 02639 last_trial = None 02640 02641 while True: 02642 trial = {} 02643 for n in range(int(lowN), int(highN)+1): 02644 x = n * granularity 02645 if format == unumber and abs(x) < eps: label = u"0" 02646 else: label = format(x) 02647 trial[x] = label 02648 02649 if int(highN)+1 - int(lowN) >= N: 02650 if last_trial == None: 02651 v1, v2 = self.low, self.high 02652 return {v1: format(v1), v2: format(v2)} 02653 else: 02654 low_in_ticks, high_in_ticks = False, False 02655 for t in last_trial.keys(): 02656 if 1.*abs(t - self.low)/last_granularity < _epsilon: low_in_ticks = True 02657 if 1.*abs(t - self.high)/last_granularity < _epsilon: high_in_ticks = True 02658 02659 lowN = 1.*self.low / last_granularity 02660 highN = 1.*self.high / last_granularity 02661 if abs(lowN - round(lowN)) < _epsilon and not low_in_ticks: 02662 last_trial[self.low] = format(self.low) 02663 if abs(highN - round(highN)) < _epsilon and not high_in_ticks: 02664 last_trial[self.high] = format(self.high) 02665 return last_trial 02666 02667 last_granularity = granularity 02668 last_trial = trial 02669 02670 countermod3 = counter % 3 02671 if countermod3 == 0: granularity *= 0.5 02672 elif countermod3 == 1: granularity *= 0.4 02673 else: granularity *= 0.5 02674 counter += 1 02675 lowN = math.ceil(1.*self.low / granularity) 02676 highN = math.floor(1.*self.high / granularity)
def svgfig::Ticks::interpret | ( | self | ) |
Evaluate and return optimal ticks and miniticks according to the standard minitick specification. Normally only used internally.
Reimplemented in svgfig::LineAxis.
Definition at line 2507 of file svgfig.py.
02508 : 02509 """Evaluate and return optimal ticks and miniticks according to 02510 the standard minitick specification. 02511 02512 Normally only used internally. 02513 """ 02514 02515 if self.labels == None or self.labels == False: 02516 format = lambda x: "" 02517 02518 elif self.labels == True: 02519 format = unumber 02520 02521 elif isinstance(self.labels, basestring): 02522 format = lambda x: (self.labels % x) 02523 02524 elif callable(self.labels): 02525 format = self.labels 02526 02527 else: raise TypeError, "labels must be None/False, True, a format string, or a number->string function" 02528 02529 # Now for the ticks 02530 ticks = self.ticks 02531 02532 # Case 1: ticks is None/False 02533 if ticks == None or ticks == False: return {}, [] 02534 02535 # Case 2: ticks is the number of desired ticks 02536 elif isinstance(ticks, (int, long)): 02537 if ticks == True: ticks = -10 02538 02539 if self.logbase == None: 02540 ticks = self.compute_ticks(ticks, format) 02541 else: 02542 ticks = self.compute_logticks(self.logbase, ticks, format) 02543 02544 # Now for the miniticks 02545 if self.miniticks == True: 02546 if self.logbase == None: 02547 return ticks, self.compute_miniticks(ticks) 02548 else: 02549 return ticks, self.compute_logminiticks(self.logbase) 02550 02551 elif isinstance(self.miniticks, (int, long)): 02552 return ticks, self.regular_miniticks(self.miniticks) 02553 02554 elif getattr(self.miniticks, "__iter__", False): 02555 return ticks, self.miniticks 02556 02557 elif self.miniticks == False or self.miniticks == None: 02558 return ticks, [] 02559 02560 else: 02561 raise TypeError, "miniticks must be None/False, True, a number of desired miniticks, or a list of numbers" 02562 02563 # Cases 3 & 4: ticks is iterable 02564 elif getattr(ticks, "__iter__", False): 02565 02566 # Case 3: ticks is some kind of list 02567 if not isinstance(ticks, dict): 02568 output = {} 02569 eps = _epsilon * (self.high - self.low) 02570 for x in ticks: 02571 if format == unumber and abs(x) < eps: 02572 output[x] = u"0" 02573 else: 02574 output[x] = format(x) 02575 ticks = output 02576 02577 # Case 4: ticks is a dict 02578 else: pass 02579 02580 # Now for the miniticks 02581 if self.miniticks == True: 02582 if self.logbase == None: 02583 return ticks, self.compute_miniticks(ticks) 02584 else: 02585 return ticks, self.compute_logminiticks(self.logbase) 02586 02587 elif isinstance(self.miniticks, (int, long)): 02588 return ticks, self.regular_miniticks(self.miniticks) 02589 02590 elif getattr(self.miniticks, "__iter__", False): 02591 return ticks, self.miniticks 02592 02593 elif self.miniticks == False or self.miniticks == None: 02594 return ticks, [] 02595 02596 else: 02597 raise TypeError, "miniticks must be None/False, True, a number of desired miniticks, or a list of numbers" 02598 02599 else: 02600 raise TypeError, "ticks must be None/False, a number of desired ticks, a list of numbers, or a dictionary of explicit markers"
def svgfig::Ticks::orient_tickmark | ( | self, | |
t, | |||
trans = None |
|||
) |
Return the position, normalized local x vector, normalized local y vector, and angle of a tick at position t. Normally only used internally.
Definition at line 2408 of file svgfig.py.
02409 : 02410 """Return the position, normalized local x vector, normalized 02411 local y vector, and angle of a tick at position t. 02412 02413 Normally only used internally. 02414 """ 02415 if isinstance(trans, basestring): trans = totrans(trans) 02416 if trans == None: 02417 f = self.f 02418 else: 02419 f = lambda t: trans(*self.f(t)) 02420 02421 eps = _epsilon * abs(self.high - self.low) 02422 02423 X, Y = f(t) 02424 Xprime, Yprime = f(t + eps) 02425 xhatx, xhaty = (Xprime - X)/eps, (Yprime - Y)/eps 02426 02427 norm = math.sqrt(xhatx**2 + xhaty**2) 02428 if norm != 0: xhatx, xhaty = xhatx/norm, xhaty/norm 02429 else: xhatx, xhaty = 1., 0. 02430 02431 angle = math.atan2(xhaty, xhatx) + math.pi/2. 02432 yhatx, yhaty = math.cos(angle), math.sin(angle) 02433 02434 return (X, Y), (xhatx, xhaty), (yhatx, yhaty), angle
def svgfig::Ticks::regular_miniticks | ( | self, | |
N | |||
) |
Return exactly N linear ticks. Normally only used internally.
def svgfig::Ticks::SVG | ( | self, | |
trans = None |
|||
) |
Apply the transformation "trans" and return an SVG object.
Reimplemented in svgfig::CurveAxis, svgfig::LineAxis, svgfig::XAxis, svgfig::YAxis, svgfig::HGrid, svgfig::VGrid, and svgfig::Grid.
Definition at line 2435 of file svgfig.py.
02436 : 02437 """Apply the transformation "trans" and return an SVG object.""" 02438 if isinstance(trans, basestring): trans = totrans(trans) 02439 02440 self.last_ticks, self.last_miniticks = self.interpret() 02441 tickmarks = Path([], **self.attr) 02442 minitickmarks = Path([], **self.attr) 02443 output = SVG("g") 02444 02445 if (self.arrow_start != False and self.arrow_start != None) or (self.arrow_end != False and self.arrow_end != None): 02446 defs = SVG("defs") 02447 02448 if self.arrow_start != False and self.arrow_start != None: 02449 if isinstance(self.arrow_start, SVG): 02450 defs.append(self.arrow_start) 02451 elif isinstance(self.arrow_start, basestring): 02452 defs.append(make_marker(self.arrow_start, "arrow_start")) 02453 else: 02454 raise TypeError, "arrow_start must be False/None or an id string for the new marker" 02455 02456 if self.arrow_end != False and self.arrow_end != None: 02457 if isinstance(self.arrow_end, SVG): 02458 defs.append(self.arrow_end) 02459 elif isinstance(self.arrow_end, basestring): 02460 defs.append(make_marker(self.arrow_end, "arrow_end")) 02461 else: 02462 raise TypeError, "arrow_end must be False/None or an id string for the new marker" 02463 02464 output.append(defs) 02465 02466 eps = _epsilon * (self.high - self.low) 02467 02468 for t, label in self.last_ticks.items(): 02469 (X, Y), (xhatx, xhaty), (yhatx, yhaty), angle = self.orient_tickmark(t, trans) 02470 02471 if (not self.arrow_start or abs(t - self.low) > eps) and (not self.arrow_end or abs(t - self.high) > eps): 02472 tickmarks.d.append(("M", X - yhatx*self.tick_start, Y - yhaty*self.tick_start, True)) 02473 tickmarks.d.append(("L", X - yhatx*self.tick_end, Y - yhaty*self.tick_end, True)) 02474 02475 angle = (angle - math.pi/2.)*180./math.pi + self.text_angle 02476 02477 ########### a HACK! ############ (to be removed when Inkscape handles baselines) 02478 if _hacks["inkscape-text-vertical-shift"]: 02479 if self.text_start > 0: 02480 X += math.cos(angle*math.pi/180. + math.pi/2.) * 2. 02481 Y += math.sin(angle*math.pi/180. + math.pi/2.) * 2. 02482 else: 02483 X += math.cos(angle*math.pi/180. + math.pi/2.) * 2. * 2.5 02484 Y += math.sin(angle*math.pi/180. + math.pi/2.) * 2. * 2.5 02485 ########### end hack ########### 02486 02487 if label != "": 02488 output.append(SVG("text", label, transform="translate(%g, %g) rotate(%g)" % \ 02489 (X - yhatx*self.text_start, Y - yhaty*self.text_start, angle), **self.text_attr)) 02490 02491 for t in self.last_miniticks: 02492 skip = False 02493 for tt in self.last_ticks.keys(): 02494 if abs(t - tt) < eps: 02495 skip = True 02496 break 02497 if not skip: 02498 (X, Y), (xhatx, xhaty), (yhatx, yhaty), angle = self.orient_tickmark(t, trans) 02499 02500 if (not self.arrow_start or abs(t - self.low) > eps) and (not self.arrow_end or abs(t - self.high) > eps): 02501 minitickmarks.d.append(("M", X - yhatx*self.minitick_start, Y - yhaty*self.minitick_start, True)) 02502 minitickmarks.d.append(("L", X - yhatx*self.minitick_end, Y - yhaty*self.minitick_end, True)) 02503 02504 output.prepend(tickmarks.SVG(trans)) 02505 output.prepend(minitickmarks.SVG(trans)) 02506 return output
Reimplemented in svgfig::HGrid, svgfig::VGrid, and svgfig::Grid.
dictionary svgfig::Ticks::defaults = {"stroke-width":"0.25pt"} [static] |
Reimplemented in svgfig::CurveAxis, svgfig::LineAxis, svgfig::XAxis, svgfig::YAxis, svgfig::HGrid, svgfig::VGrid, and svgfig::Grid.
Reimplemented in svgfig::LineAxis.
Reimplemented in svgfig::LineAxis, and svgfig::Grid.
Reimplemented in svgfig::HGrid, and svgfig::VGrid.
Reimplemented in svgfig::LineAxis.
float svgfig::Ticks::minitick_end = 0.75 [static] |
float svgfig::Ticks::minitick_start = 0.75 [static] |
int svgfig::Ticks::text_angle = 0 [static] |
Reimplemented in svgfig::XAxis, and svgfig::YAxis.
dictionary svgfig::Ticks::text_defaults = {"stroke":"none", "fill":"black", "font-size":5} [static] |
Reimplemented in svgfig::CurveAxis, svgfig::LineAxis, svgfig::XAxis, and svgfig::YAxis.
float svgfig::Ticks::text_start = 2.5 [static] |
Reimplemented in svgfig::XAxis, and svgfig::YAxis.
float svgfig::Ticks::tick_end = 1.5 [static] |
float svgfig::Ticks::tick_start = 1.5 [static] |