def partfunction(self, data): if data.first: data.first = 0 min = data.min max = data.max if self.extendtick is not None and len( self.ticklist) > self.extendtick: min, max = self.extendminmax(min, max, self.ticklist[self.extendtick], data.extendmin, data.extendmax) if self.extendlabel is not None and len( self.labellist) > self.extendlabel: min, max = self.extendminmax(min, max, self.labellist[self.extendlabel], data.extendmin, data.extendmax) ticks = [] for i in range(len(self.ticklist)): ticks = tick.mergeticklists( ticks, self.getticks(min, max, self.ticklist[i], ticklevel=i)) for i in range(len(self.labellist)): ticks = tick.mergeticklists( ticks, self.getticks(min, max, self.labellist[i], labellevel=i)) return ticks return None
def partfunction(self, data): if data.first: data.first = 0 min = data.min max = data.max if self.extendtick is not None and len(self.ticklist) > self.extendtick: min, max = self.extendminmax(min, max, self.ticklist[self.extendtick], data.extendmin, data.extendmax) if self.extendlabel is not None and len(self.labellist) > self.extendlabel: min, max = self.extendminmax(min, max, self.labellist[self.extendlabel], data.extendmin, data.extendmax) ticks = [] for i in range(len(self.ticklist)): ticks = tick.mergeticklists(ticks, self.getticks(min, max, self.ticklist[i], ticklevel=i)) for i in range(len(self.labellist)): ticks = tick.mergeticklists(ticks, self.getticks(min, max, self.labellist[i], labellevel=i)) return ticks return None
def getticks(self, min, max, preexp, ticklevel=None, labellevel=None): ticks = [] minimin = 0 maximax = 0 for f in preexp.pres: thisticks = [] imin = int(math.ceil(math.log(min / float(f)) / math.log(preexp.exp) - 0.5 * self.epsilon)) imax = int(math.floor(math.log(max / float(f)) / math.log(preexp.exp) + 0.5 * self.epsilon)) for i in range(imin, imax + 1): pos = f * tick.rational((preexp.exp, 1), power=i) thisticks.append(tick.tick((pos.num, pos.denom), ticklevel = ticklevel, labellevel = labellevel)) ticks = tick.mergeticklists(ticks, thisticks) return ticks
def _create(self, data, positioner, graphtexrunner, parter, rater, errorname): errorname = " for axis %s" % errorname if data.min is None or data.max is None: raise RuntimeError("incomplete axis range%s" % errorname) if data.max == data.min: if self.fallbackrange is not None: try: data.min, data.max = data.min - 0.5*self.fallbackrange, data.min + 0.5*self.fallbackrange except TypeError: data.min, data.max = self.fallbackrange[0], self.fallbackrange[1] else: raise RuntimeError("zero axis range%s" % errorname) def layout(data): self.adjustaxis(data, data.ticks, graphtexrunner, errorname) self.texter.labels(data.ticks) if self.divisor: for t in data.ticks: t *= tick.rational(self.divisor) canvas = painter.axiscanvas(self.painter, graphtexrunner) if self.painter is not None: self.painter.paint(canvas, data, self, positioner) return canvas if parter is None: data.ticks = self.manualticks return layout(data) # a variant is a data copy with local modifications to test several partitions class variant: def __init__(self, data, **kwargs): self.data = data for key, value in kwargs.items(): setattr(self, key, value) def __getattr__(self, key): return getattr(data, key) def __cmp__(self, other): # we can also sort variants by their rate return cmp(self.rate, other.rate) # build a list of variants bestrate = None if self.divisor is not None: if data.min is not None: data_min_divided = data.min/self.divisor else: data_min_divided = None if data.max is not None: data_max_divided = data.max/self.divisor else: data_max_divided = None partfunctions = parter.partfunctions(data_min_divided, data_max_divided, self.min is None, self.max is None) else: partfunctions = parter.partfunctions(data.min, data.max, self.min is None, self.max is None) variants = [] for partfunction in partfunctions: worse = 0 while worse < self.maxworse: worse += 1 ticks = partfunction() if ticks is None: break ticks = [t for t in tick.mergeticklists(self.manualticks, ticks, mergeequal=0) if t.ticklevel is not None or t.labellevel is not None] if ticks: rate = rater.rateticks(self, ticks, self.density) if self.reverse: rate += rater.raterange(self.convert(data, ticks[0]) - self.convert(data, ticks[-1]), 1) else: rate += rater.raterange(self.convert(data, ticks[-1]) - self.convert(data, ticks[0]), 1) if bestrate is None or rate < bestrate: bestrate = rate worse = 0 variants.append(variant(data, rate=rate, ticks=ticks)) if not variants: raise RuntimeError("no axis partitioning found%s" % errorname) if len(variants) == 1 or self.painter is None: # When the painter is None, we could sort the variants here by their rating. # However, we didn't did this so far and there is no real reason to change that. data.ticks = variants[0].ticks return layout(data) # build the layout for best variants for variant in variants: variant.storedcanvas = None variants.sort() while not variants[0].storedcanvas: variants[0].storedcanvas = layout(variants[0]) ratelayout = rater.ratelayout(variants[0].storedcanvas, self.density) if ratelayout is None: del variants[0] if not variants: raise NoValidPartitionError("no valid axis partitioning found%s" % errorname) else: variants[0].rate += ratelayout variants.sort() self.adjustaxis(data, variants[0].ticks, graphtexrunner, errorname) data.ticks = variants[0].ticks return variants[0].storedcanvas
def _create(self, data, positioner, graphtextengine, parter, rater, errorname): errorname = " for axis %s" % errorname if data.min is None or data.max is None: raise RuntimeError("incomplete axis range%s" % errorname) if data.max == data.min: if self.fallbackrange is not None: try: data.min, data.max = data.min - 0.5 * self.fallbackrange, data.min + 0.5 * self.fallbackrange except TypeError: data.min, data.max = self.fallbackrange[ 0], self.fallbackrange[1] else: raise RuntimeError("zero axis range%s" % errorname) if self.divisor is not None: rational_divisor = tick.rational(self.divisor) convert_tick = lambda x: float(x) * self.divisor else: convert_tick = lambda x: x def layout(data): if data.ticks: self.adjustaxis(data, [ convert_tick(data.ticks[0]), convert_tick(data.ticks[-1]) ], graphtextengine, errorname) self.texter.labels(data.ticks) if self.divisor: for t in data.ticks: t *= rational_divisor canvas = painter.axiscanvas(self.painter, graphtextengine) if self.painter is not None: self.painter.paint(canvas, data, self, positioner) return canvas if parter is None: data.ticks = self.manualticks return layout(data) # a variant is a data copy with local modifications to test several partitions @functools.total_ordering class variant: def __init__(self, data, **kwargs): self.data = data for key, value in list(kwargs.items()): setattr(self, key, value) def __getattr__(self, key): return getattr(data, key) def __lt__(self, other): # we can also sort variants by their rate return self.rate < other.rate def __eq__(self, other): # we can also sort variants by their rate return self.rate == other.rate # build a list of variants bestrate = None if self.divisor is not None: if data.min is not None: data_min_divided = data.min / self.divisor else: data_min_divided = None if data.max is not None: data_max_divided = data.max / self.divisor else: data_max_divided = None partfunctions = parter.partfunctions(data_min_divided, data_max_divided, self.min is None, self.max is None) else: partfunctions = parter.partfunctions(data.min, data.max, self.min is None, self.max is None) variants = [] for partfunction in partfunctions: worse = 0 while worse < self.maxworse: worse += 1 ticks = partfunction() if ticks is None: break ticks = tick.mergeticklists(self.manualticks, ticks, mergeequal=0) if ticks: rate = rater.rateticks(self, ticks, self.density) if rate is not None: if self.reverse: rate += rater.raterange( self.convert(data, convert_tick(ticks[0])) - self.convert(data, convert_tick(ticks[-1])), 1) else: rate += rater.raterange( self.convert(data, convert_tick(ticks[-1])) - self.convert(data, convert_tick(ticks[0])), 1) if bestrate is None or rate < bestrate: bestrate = rate worse = 0 variants.append(variant(data, rate=rate, ticks=ticks)) if not variants: raise RuntimeError("no axis partitioning found%s" % errorname) if len(variants) == 1 or self.painter is None: # When the painter is None, we could sort the variants here by their rating. # However, we didn't did this so far and there is no real reason to change that. data.ticks = variants[0].ticks return layout(data) # build the layout for best variants for variant in variants: variant.storedcanvas = None variants.sort() while not variants[0].storedcanvas: variants[0].storedcanvas = layout(variants[0]) ratelayout = rater.ratelayout(variants[0].storedcanvas, self.density) if ratelayout is None: del variants[0] if not variants: raise NoValidPartitionError( "no valid axis partitioning found%s" % errorname) else: variants[0].rate += ratelayout variants.sort() self.adjustaxis(data, variants[0].ticks, graphtextengine, errorname) data.ticks = variants[0].ticks return variants[0].storedcanvas
def _create(self, data, positioner, graphtexrunner, parter, rater, errorname): errorname = " for axis %s" % errorname if data.min is None or data.max is None: raise RuntimeError("incomplete axis range%s" % errorname) def layout(data): self.adjustaxis(data, data.ticks, graphtexrunner, errorname) self.texter.labels(data.ticks) if self.divisor: for t in data.ticks: t *= tick.rational(self.divisor) canvas = painter.axiscanvas(self.painter, graphtexrunner) if self.painter is not None: self.painter.paint(canvas, data, self, positioner) return canvas if parter is None: data.ticks = self.manualticks return layout(data) # a variant is a data copy with local modifications to test several partitions class variant: def __init__(self, data, **kwargs): self.data = data for key, value in kwargs.items(): setattr(self, key, value) def __getattr__(self, key): return getattr(data, key) def __cmp__(self, other): # we can also sort variants by their rate return cmp(self.rate, other.rate) # build a list of variants bestrate = None if self.divisor is not None: partfunctions = parter.partfunctions(data.min / self.divisor, data.max / self.divisor, self.min is None, self.max is None) else: partfunctions = parter.partfunctions(data.min, data.max, self.min is None, self.max is None) variants = [] for partfunction in partfunctions: worse = 0 while worse < self.maxworse: worse += 1 ticks = partfunction() if ticks is None: break ticks = tick.mergeticklists(self.manualticks, ticks, mergeequal=0) if ticks: rate = rater.rateticks(self, ticks, self.density) if self.reverse: rate += rater.raterange( self.convert(data, ticks[0]) - self.convert(data, ticks[-1]), 1) else: rate += rater.raterange( self.convert(data, ticks[-1]) - self.convert(data, ticks[0]), 1) if bestrate is None or rate < bestrate: bestrate = rate worse = 0 variants.append(variant(data, rate=rate, ticks=ticks)) if not variants: raise RuntimeError("no axis partitioning found%s" % errorname) if len(variants) == 1 or self.painter is None: # When the painter is None, we could sort the variants here by their rating. # However, we didn't did this so far and there is no real reason to change that. data.ticks = variants[0].ticks return layout(data) # build the layout for best variants for variant in variants: variant.storedcanvas = None variants.sort() while not variants[0].storedcanvas: variants[0].storedcanvas = layout(variants[0]) ratelayout = rater.ratelayout(variants[0].storedcanvas, self.density) if ratelayout is None: del variants[0] if not variants: raise NoValidPartitionError( "no valid axis partitioning found%s" % errorname) else: variants[0].rate += ratelayout variants.sort() self.adjustaxis(data, variants[0].ticks, graphtexrunner, errorname) data.ticks = variants[0].ticks return variants[0].storedcanvas