2 # -*- coding: ISO-8859-1 -*-
5 # Copyright (C) 2002-2004 Jörg Lehmann <joergl@users.sourceforge.net>
6 # Copyright (C) 2003-2004 Michael Schindler <m-schindler@users.sourceforge.net>
7 # Copyright (C) 2002-2004 André Wobst <wobsta@users.sourceforge.net>
9 # This file is part of PyX (http://pyx.sourceforge.net/).
11 # PyX is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 2 of the License, or
14 # (at your option) any later version.
16 # PyX is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
21 # You should have received a copy of the GNU General Public License
22 # along with PyX; if not, write to the Free Software
23 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 from pyx
import helper
30 # partitioner (parter)
31 # please note the nomenclature:
32 # - a part (partition) is a list of tick instances; thus ticks `==' part
33 # - a parter (partitioner) is a class creating ticks
37 """fraction class for rational arithmetics
38 the axis partitioning uses rational arithmetics (with infinite accuracy)
39 basically it contains self.enum and self.denom"""
41 def stringfrac(self
, s
):
42 "converts a string 0.123 into a frac"
43 expparts
= s
.split("e")
45 raise ValueError("multiple 'e' found in '%s'" % s
)
46 commaparts
= expparts
[0].split(".")
47 if len(commaparts
) > 2:
48 raise ValueError("multiple '.' found in '%s'" % expparts
[0])
49 if len(commaparts
) == 1:
50 commaparts
= [commaparts
[0], ""]
51 result
= frac((1, 10l), power
=len(commaparts
[1]))
52 neg
= len(commaparts
[0]) and commaparts
[0][0] == "-"
54 commaparts
[0] = commaparts
[0][1:]
55 elif len(commaparts
[0]) and commaparts
[0][0] == "+":
56 commaparts
[0] = commaparts
[0][1:]
57 if len(commaparts
[0]):
58 if not commaparts
[0].isdigit():
59 raise ValueError("unrecognized characters in '%s'" % s
)
60 x
= long(commaparts
[0])
63 if len(commaparts
[1]):
64 if not commaparts
[1].isdigit():
65 raise ValueError("unrecognized characters in '%s'" % s
)
66 y
= long(commaparts
[1])
69 result
.enum
= x
*result
.denom
+y
71 result
.enum
= -result
.enum
72 if len(expparts
) == 2:
73 neg
= expparts
[1][0] == "-"
75 expparts
[1] = expparts
[1][1:]
76 elif expparts
[1][0] == "+":
77 expparts
[1] = expparts
[1][1:]
78 if not expparts
[1].isdigit():
79 raise ValueError("unrecognized characters in '%s'" % s
)
81 result
*= frac((1, 10l), power
=long(expparts
[1]))
83 result
*= frac((10, 1l), power
=long(expparts
[1]))
86 def floatfrac(self
, x
, floatprecision
):
87 "converts a float into a frac with finite resolution"
88 if helper
.isinteger(floatprecision
) and floatprecision
< 0:
89 raise RuntimeError("float resolution must be non-negative integer")
90 return self
.stringfrac(("%%.%ig" % floatprecision
) % x
)
92 def __init__(self
, x
, power
=None, floatprecision
=10):
93 "for power!=None: frac=(enum/denom)**power"
94 if helper
.isnumber(x
):
95 value
= self
.floatfrac(x
, floatprecision
)
96 enum
, denom
= value
.enum
, value
.denom
97 elif helper
.isstring(x
):
98 fraction
= x
.split("/")
100 raise ValueError("multiple '/' found in '%s'" % x
)
101 value
= self
.stringfrac(fraction
[0])
102 if len(fraction
) == 2:
103 value2
= self
.stringfrac(fraction
[1])
104 value
= value
/ value2
105 enum
, denom
= value
.enum
, value
.denom
109 except (TypeError, AttributeError):
110 enum
, denom
= x
.enum
, x
.denom
111 if not helper
.isinteger(enum
) or not helper
.isinteger(denom
): raise TypeError("integer type expected")
112 if not denom
: raise ZeroDivisionError("zero denominator")
114 if not helper
.isinteger(power
): raise TypeError("integer type expected")
116 self
.enum
= long(enum
) ** power
117 self
.denom
= long(denom
) ** power
119 self
.enum
= long(denom
) ** (-power
)
120 self
.denom
= long(enum
) ** (-power
)
125 def __cmp__(self
, other
):
128 return cmp(self
.enum
* other
.denom
, other
.enum
* self
.denom
)
131 return frac((abs(self
.enum
), abs(self
.denom
)))
133 def __mul__(self
, other
):
134 return frac((self
.enum
* other
.enum
, self
.denom
* other
.denom
))
136 def __div__(self
, other
):
137 return frac((self
.enum
* other
.denom
, self
.denom
* other
.enum
))
140 "caution: avoid final precision of floats"
141 return float(self
.enum
) / self
.denom
144 return "%i/%i" % (self
.enum
, self
.denom
)
149 a tick is a frac enhanced by
150 - self.ticklevel (0 = tick, 1 = subtick, etc.)
151 - self.labellevel (0 = label, 1 = sublabel, etc.)
152 - self.label (a string) and self.labelattrs (a list, defaults to [])
153 When ticklevel or labellevel is None, no tick or label is present at that value.
154 When label is None, it should be automatically created (and stored), once the
155 an axis painter needs it. Classes, which implement _Itexter do precisely that."""
157 def __init__(self
, pos
, ticklevel
=0, labellevel
=0, label
=None, labelattrs
=[], **kwargs
):
158 """initializes the instance
159 - see class description for the parameter description
160 - **kwargs are passed to the frac constructor"""
161 frac
.__init
__(self
, pos
, **kwargs
)
162 self
.ticklevel
= ticklevel
163 self
.labellevel
= labellevel
165 self
.labelattrs
= labelattrs
167 def merge(self
, other
):
168 """merges two ticks together:
169 - the lower ticklevel/labellevel wins
170 - the label is *never* taken over from other
171 - the ticks should be at the same position (otherwise it doesn't make sense)
172 -> this is NOT checked"""
173 if self
.ticklevel
is None or (other
.ticklevel
is not None and other
.ticklevel
< self
.ticklevel
):
174 self
.ticklevel
= other
.ticklevel
175 if self
.labellevel
is None or (other
.labellevel
is not None and other
.labellevel
< self
.labellevel
):
176 self
.labellevel
= other
.labellevel
179 def _mergeticklists(list1
, list2
):
180 """helper function to merge tick lists
181 - return a merged list of ticks out of list1 and list2
182 - CAUTION: original lists have to be ordered
183 (the returned list is also ordered)"""
184 # TODO: improve this using bisect?!
186 # do not destroy original lists
191 while 1: # we keep on going until we reach an index error
192 while list2
[j
] < list1
[i
]: # insert tick
193 list1
.insert(i
, list2
[j
])
196 if list2
[j
] == list1
[i
]: # merge tick
197 list1
[i
].merge(list2
[j
])
206 def _mergelabels(ticks
, labels
):
207 """helper function to merge labels into ticks
208 - when labels is not None, the label of all ticks with
209 labellevel different from None are set
210 - labels need to be a list of lists of strings,
211 where the first list contain the strings to be
212 used as labels for the ticks with labellevel 0,
213 the second list for labellevel 1, etc.
214 - when the maximum labellevel is 0, just a list of
215 strings might be provided as the labels argument
216 - IndexError is raised, when a list length doesn't match"""
217 if helper
.issequenceofsequences(labels
):
220 usetext
= helper
.ensuresequence(label
)
223 if tick
.labellevel
== level
:
224 tick
.label
= usetext
[i
]
226 if i
!= len(usetext
):
227 raise IndexError("wrong list length of labels at level %i" % level
)
229 elif labels
is not None:
230 usetext
= helper
.ensuresequence(labels
)
233 if tick
.labellevel
== 0:
234 tick
.label
= usetext
[i
]
236 if i
!= len(usetext
):
237 raise IndexError("wrong list length of labels")
239 def _maxlevels(ticks
):
240 "returns a tuple maxticklist, maxlabellevel from a list of tick instances"
241 maxticklevel
= maxlabellevel
= 0
243 if tick
.ticklevel
is not None and tick
.ticklevel
>= maxticklevel
:
244 maxticklevel
= tick
.ticklevel
+ 1
245 if tick
.labellevel
is not None and tick
.labellevel
>= maxlabellevel
:
246 maxlabellevel
= tick
.labellevel
+ 1
247 return maxticklevel
, maxlabellevel
251 """interface definition of a partition scheme
252 partition schemes are used to create a list of ticks"""
254 def defaultpart(self
, min, max, extendmin
, extendmax
):
255 """create a partition
256 - returns an ordered list of ticks for the interval min to max
257 - the interval is given in float numbers, thus an appropriate
258 conversion to rational numbers has to be performed
259 - extendmin and extendmax are booleans (integers)
260 - when extendmin or extendmax is set, the ticks might
261 extend the min-max range towards lower and higher
262 ranges, respectively"""
265 """create another partition which contains less ticks
266 - this method is called several times after a call of defaultpart
267 - returns an ordered list of ticks with less ticks compared to
268 the partition returned by defaultpart and by previous calls
270 - the creation of a partition with strictly *less* ticks
271 is not to be taken serious
272 - the method might return None, when no other appropriate
273 partition can be created"""
277 """create another partition which contains more ticks
278 see lesspart, but increase the number of ticks"""
282 """linear partition scheme
283 ticks and label distances are explicitly provided to the constructor"""
285 __implements__
= _Iparter
287 def __init__(self
, tickdist
=None, labeldist
=None, labels
=None, extendtick
=0, extendlabel
=None, epsilon
=1e-10):
288 """configuration of the partition scheme
289 - tickdist and labeldist should be a list, where the first value
290 is the distance between ticks with ticklevel/labellevel 0,
291 the second list for ticklevel/labellevel 1, etc.;
292 a single entry is allowed without being a list
293 - tickdist and labeldist values are passed to the frac constructor
294 - when labeldist is None and tickdist is not None, the tick entries
295 for ticklevel 0 are used for labels and vice versa (ticks<->labels)
296 - labels are applied to the resulting partition via the
297 mergelabels function (additional information available there)
298 - extendtick allows for the extension of the range given to the
299 defaultpart method to include the next tick with the specified
300 level (None turns off this feature); note, that this feature is
301 also disabled, when an axis prohibits its range extension by
302 the extendmin/extendmax variables given to the defaultpart method
303 - extendlabel is analogous to extendtick, but for labels
304 - epsilon allows for exceeding the axis range by this relative
305 value (relative to the axis range given to the defaultpart method)
306 without creating another tick specified by extendtick/extendlabel"""
307 if tickdist
is None and labeldist
is not None:
308 self
.ticklist
= (frac(helper
.ensuresequence(labeldist
)[0]),)
310 self
.ticklist
= map(frac
, helper
.ensuresequence(tickdist
))
311 if labeldist
is None and tickdist
is not None:
312 self
.labellist
= (frac(helper
.ensuresequence(tickdist
)[0]),)
314 self
.labellist
= map(frac
, helper
.ensuresequence(labeldist
))
316 self
.extendtick
= extendtick
317 self
.extendlabel
= extendlabel
318 self
.epsilon
= epsilon
320 def extendminmax(self
, min, max, frac
, extendmin
, extendmax
):
321 """return new min, max tuple extending the range min, max
322 - frac is the tick distance to be used
323 - extendmin and extendmax are booleans to allow for the extension"""
325 min = float(frac
) * math
.floor(min / float(frac
) + self
.epsilon
)
327 max = float(frac
) * math
.ceil(max / float(frac
) - self
.epsilon
)
330 def getticks(self
, min, max, frac
, ticklevel
=None, labellevel
=None):
331 """return a list of equal spaced ticks
332 - the tick distance is frac, the ticklevel is set to ticklevel and
333 the labellevel is set to labellevel
334 - min, max is the range where ticks should be placed"""
335 imin
= int(math
.ceil(min / float(frac
) - 0.5 * self
.epsilon
))
336 imax
= int(math
.floor(max / float(frac
) + 0.5 * self
.epsilon
))
338 for i
in range(imin
, imax
+ 1):
339 ticks
.append(tick((long(i
) * frac
.enum
, frac
.denom
), ticklevel
=ticklevel
, labellevel
=labellevel
))
342 def defaultpart(self
, min, max, extendmin
, extendmax
):
343 if self
.extendtick
is not None and len(self
.ticklist
) > self
.extendtick
:
344 min, max = self
.extendminmax(min, max, self
.ticklist
[self
.extendtick
], extendmin
, extendmax
)
345 if self
.extendlabel
is not None and len(self
.labellist
) > self
.extendlabel
:
346 min, max = self
.extendminmax(min, max, self
.labellist
[self
.extendlabel
], extendmin
, extendmax
)
349 for i
in range(len(self
.ticklist
)):
350 ticks
= _mergeticklists(ticks
, self
.getticks(min, max, self
.ticklist
[i
], ticklevel
= i
))
351 for i
in range(len(self
.labellist
)):
352 ticks
= _mergeticklists(ticks
, self
.getticks(min, max, self
.labellist
[i
], labellevel
= i
))
354 _mergelabels(ticks
, self
.labels
)
366 """automatic linear partition scheme
367 - possible tick distances are explicitly provided to the constructor
368 - tick distances are adjusted to the axis range by multiplication or division by 10"""
370 __implements__
= _Iparter
372 defaultvariants
= ((frac((1, 1)), frac((1, 2))),
373 (frac((2, 1)), frac((1, 1))),
374 (frac((5, 2)), frac((5, 4))),
375 (frac((5, 1)), frac((5, 2))))
377 def __init__(self
, variants
=defaultvariants
, extendtick
=0, epsilon
=1e-10):
378 """configuration of the partition scheme
379 - variants is a list of tickdist
380 - tickdist should be a list, where the first value
381 is the distance between ticks with ticklevel 0,
382 the second for ticklevel 1, etc.
383 - tickdist values are passed to the frac constructor
384 - labellevel is set to None except for those ticks in the partitions,
385 where ticklevel is zero. There labellevel is also set to zero.
386 - extendtick allows for the extension of the range given to the
387 defaultpart method to include the next tick with the specified
388 level (None turns off this feature); note, that this feature is
389 also disabled, when an axis prohibits its range extension by
390 the extendmin/extendmax variables given to the defaultpart method
391 - epsilon allows for exceeding the axis range by this relative
392 value (relative to the axis range given to the defaultpart method)
393 without creating another tick specified by extendtick"""
394 self
.variants
= variants
395 self
.extendtick
= extendtick
396 self
.epsilon
= epsilon
398 def defaultpart(self
, min, max, extendmin
, extendmax
):
399 logmm
= math
.log(max - min) / math
.log(10)
400 if logmm
< 0: # correction for rounding towards zero of the int routine
401 base
= frac((10L, 1), int(logmm
- 1))
403 base
= frac((10L, 1), int(logmm
))
404 ticks
= map(frac
, self
.variants
[0])
405 useticks
= [tick
* base
for tick
in ticks
]
406 self
.lesstickindex
= self
.moretickindex
= 0
407 self
.lessbase
= frac((base
.enum
, base
.denom
))
408 self
.morebase
= frac((base
.enum
, base
.denom
))
409 self
.min, self
.max, self
.extendmin
, self
.extendmax
= min, max, extendmin
, extendmax
410 part
= linparter(tickdist
=useticks
, extendtick
=self
.extendtick
, epsilon
=self
.epsilon
)
411 return part
.defaultpart(self
.min, self
.max, self
.extendmin
, self
.extendmax
)
414 if self
.lesstickindex
< len(self
.variants
) - 1:
415 self
.lesstickindex
+= 1
417 self
.lesstickindex
= 0
418 self
.lessbase
.enum
*= 10
419 ticks
= map(frac
, self
.variants
[self
.lesstickindex
])
420 useticks
= [tick
* self
.lessbase
for tick
in ticks
]
421 part
= linparter(tickdist
=useticks
, extendtick
=self
.extendtick
, epsilon
=self
.epsilon
)
422 return part
.defaultpart(self
.min, self
.max, self
.extendmin
, self
.extendmax
)
425 if self
.moretickindex
:
426 self
.moretickindex
-= 1
428 self
.moretickindex
= len(self
.variants
) - 1
429 self
.morebase
.denom
*= 10
430 ticks
= map(frac
, self
.variants
[self
.moretickindex
])
431 useticks
= [tick
* self
.morebase
for tick
in ticks
]
432 part
= linparter(tickdist
=useticks
, extendtick
=self
.extendtick
, epsilon
=self
.epsilon
)
433 return part
.defaultpart(self
.min, self
.max, self
.extendmin
, self
.extendmax
)
437 """storage class for the definition of logarithmic axes partitions
438 instances of this class define tick positions suitable for
439 logarithmic axes by the following instance variables:
440 - exp: integer, which defines multiplicator (usually 10)
441 - pres: list of tick positions (rational numbers, e.g. instances of frac)
442 possible positions are these tick positions and arbitrary divisions
443 and multiplications by the exp value"""
445 def __init__(self
, pres
, exp
):
446 "create a preexp instance and store its pres and exp information"
447 self
.pres
= helper
.ensuresequence(pres
)
451 class logparter(linparter
):
452 """logarithmic partition scheme
453 ticks and label positions are explicitly provided to the constructor"""
455 __implements__
= _Iparter
457 pre1exp5
= preexp(frac((1, 1)), 100000)
458 pre1exp4
= preexp(frac((1, 1)), 10000)
459 pre1exp3
= preexp(frac((1, 1)), 1000)
460 pre1exp2
= preexp(frac((1, 1)), 100)
461 pre1exp
= preexp(frac((1, 1)), 10)
462 pre125exp
= preexp((frac((1, 1)), frac((2, 1)), frac((5, 1))), 10)
463 pre1to9exp
= preexp(map(lambda x
: frac((x
, 1)), range(1, 10)), 10)
464 # ^- we always include 1 in order to get extendto(tick|label)level to work as expected
466 def __init__(self
, tickpos
=None, labelpos
=None, labels
=None, extendtick
=0, extendlabel
=None, epsilon
=1e-10):
467 """configuration of the partition scheme
468 - tickpos and labelpos should be a list, where the first entry
469 is a preexp instance describing ticks with ticklevel/labellevel 0,
470 the second is a preexp instance for ticklevel/labellevel 1, etc.;
471 a single entry is allowed without being a list
472 - when labelpos is None and tickpos is not None, the tick entries
473 for ticklevel 0 are used for labels and vice versa (ticks<->labels)
474 - labels are applied to the resulting partition via the
475 mergetexts function (additional information available there)
476 - extendtick allows for the extension of the range given to the
477 defaultpart method to include the next tick with the specified
478 level (None turns off this feature); note, that this feature is
479 also disabled, when an axis prohibits its range extension by
480 the extendmin/extendmax variables given to the defaultpart method
481 - extendlabel is analogous to extendtick, but for labels
482 - epsilon allows for exceeding the axis range by this relative
483 logarithm value (relative to the logarithm axis range given
484 to the defaultpart method) without creating another tick
485 specified by extendtick/extendlabel"""
486 if tickpos
is None and labels
is not None:
487 self
.ticklist
= (helper
.ensuresequence(labelpos
)[0],)
489 self
.ticklist
= helper
.ensuresequence(tickpos
)
491 if labelpos
is None and tickpos
is not None:
492 self
.labellist
= (helper
.ensuresequence(tickpos
)[0],)
494 self
.labellist
= helper
.ensuresequence(labelpos
)
496 self
.extendtick
= extendtick
497 self
.extendlabel
= extendlabel
498 self
.epsilon
= epsilon
500 def extendminmax(self
, min, max, preexp
, extendmin
, extendmax
):
501 """return new min, max tuple extending the range min, max
502 preexp describes the allowed tick positions
503 extendmin and extendmax are booleans to allow for the extension"""
506 for i
in xrange(len(preexp
.pres
)):
507 imin
= int(math
.floor(math
.log(min / float(preexp
.pres
[i
])) /
508 math
.log(preexp
.exp
) + self
.epsilon
)) + 1
509 imax
= int(math
.ceil(math
.log(max / float(preexp
.pres
[i
])) /
510 math
.log(preexp
.exp
) - self
.epsilon
)) - 1
511 if minpower
is None or imin
< minpower
:
512 minpower
, minindex
= imin
, i
513 if maxpower
is None or imax
>= maxpower
:
514 maxpower
, maxindex
= imax
, i
516 minfrac
= preexp
.pres
[minindex
- 1]
518 minfrac
= preexp
.pres
[-1]
520 if maxindex
!= len(preexp
.pres
) - 1:
521 maxfrac
= preexp
.pres
[maxindex
+ 1]
523 maxfrac
= preexp
.pres
[0]
526 min = float(minfrac
) * float(preexp
.exp
) ** minpower
528 max = float(maxfrac
) * float(preexp
.exp
) ** maxpower
531 def getticks(self
, min, max, preexp
, ticklevel
=None, labellevel
=None):
532 """return a list of ticks
533 - preexp describes the allowed tick positions
534 - the ticklevel of the ticks is set to ticklevel and
535 the labellevel is set to labellevel
536 - min, max is the range where ticks should be placed"""
540 for f
in preexp
.pres
:
542 imin
= int(math
.ceil(math
.log(min / float(f
)) /
543 math
.log(preexp
.exp
) - 0.5 * self
.epsilon
))
544 imax
= int(math
.floor(math
.log(max / float(f
)) /
545 math
.log(preexp
.exp
) + 0.5 * self
.epsilon
))
546 for i
in range(imin
, imax
+ 1):
547 pos
= f
* frac((preexp
.exp
, 1), i
)
548 fracticks
.append(tick((pos
.enum
, pos
.denom
), ticklevel
= ticklevel
, labellevel
= labellevel
))
549 ticks
= _mergeticklists(ticks
, fracticks
)
553 class autologparter(logparter
):
554 """automatic logarithmic partition scheme
555 possible tick positions are explicitly provided to the constructor"""
557 __implements__
= _Iparter
559 defaultvariants
= (((logparter
.pre1exp
, # ticks
560 logparter
.pre1to9exp
), # subticks
561 (logparter
.pre1exp
, # labels
562 logparter
.pre125exp
)), # sublevels
564 ((logparter
.pre1exp
, # ticks
565 logparter
.pre1to9exp
), # subticks
566 None), # labels like ticks
568 ((logparter
.pre1exp2
, # ticks
569 logparter
.pre1exp
), # subticks
570 None), # labels like ticks
572 ((logparter
.pre1exp3
, # ticks
573 logparter
.pre1exp
), # subticks
574 None), # labels like ticks
576 ((logparter
.pre1exp4
, # ticks
577 logparter
.pre1exp
), # subticks
578 None), # labels like ticks
580 ((logparter
.pre1exp5
, # ticks
581 logparter
.pre1exp
), # subticks
582 None)) # labels like ticks
584 def __init__(self
, variants
=defaultvariants
, extendtick
=0, extendlabel
=None, epsilon
=1e-10):
585 """configuration of the partition scheme
586 - variants should be a list of pairs of lists of preexp
588 - within each pair the first list contains preexp, where
589 the first preexp instance describes ticks positions with
590 ticklevel 0, the second preexp for ticklevel 1, etc.
591 - the second list within each pair describes the same as
592 before, but for labels
593 - within each pair: when the second entry (for the labels) is None
594 and the first entry (for the ticks) ticks is not None, the tick
595 entries for ticklevel 0 are used for labels and vice versa
597 - extendtick allows for the extension of the range given to the
598 defaultpart method to include the next tick with the specified
599 level (None turns off this feature); note, that this feature is
600 also disabled, when an axis prohibits its range extension by
601 the extendmin/extendmax variables given to the defaultpart method
602 - extendlabel is analogous to extendtick, but for labels
603 - epsilon allows for exceeding the axis range by this relative
604 logarithm value (relative to the logarithm axis range given
605 to the defaultpart method) without creating another tick
606 specified by extendtick/extendlabel"""
607 self
.variants
= variants
608 if len(variants
) > 2:
609 self
.variantsindex
= divmod(len(variants
), 2)[0]
611 self
.variantsindex
= 0
612 self
.extendtick
= extendtick
613 self
.extendlabel
= extendlabel
614 self
.epsilon
= epsilon
616 def defaultpart(self
, min, max, extendmin
, extendmax
):
617 self
.min, self
.max, self
.extendmin
, self
.extendmax
= min, max, extendmin
, extendmax
618 self
.morevariantsindex
= self
.variantsindex
619 self
.lessvariantsindex
= self
.variantsindex
620 part
= logparter(tickpos
=self
.variants
[self
.variantsindex
][0], labelpos
=self
.variants
[self
.variantsindex
][1],
621 extendtick
=self
.extendtick
, extendlabel
=self
.extendlabel
, epsilon
=self
.epsilon
)
622 return part
.defaultpart(self
.min, self
.max, self
.extendmin
, self
.extendmax
)
625 self
.lessvariantsindex
+= 1
626 if self
.lessvariantsindex
< len(self
.variants
):
627 part
= logparter(tickpos
=self
.variants
[self
.lessvariantsindex
][0], labelpos
=self
.variants
[self
.lessvariantsindex
][1],
628 extendtick
=self
.extendtick
, extendlabel
=self
.extendlabel
, epsilon
=self
.epsilon
)
629 return part
.defaultpart(self
.min, self
.max, self
.extendmin
, self
.extendmax
)
632 self
.morevariantsindex
-= 1
633 if self
.morevariantsindex
>= 0:
634 part
= logparter(tickpos
=self
.variants
[self
.morevariantsindex
][0], labelpos
=self
.variants
[self
.morevariantsindex
][1],
635 extendtick
=self
.extendtick
, extendlabel
=self
.extendlabel
, epsilon
=self
.epsilon
)
636 return part
.defaultpart(self
.min, self
.max, self
.extendmin
, self
.extendmax
)