Source code for genomeview.axis

import math

from genomeview.track import Track

[docs]class Axis(Track): """ Displays coordinates for the current genomic view """ def __init__(self, name=None): self.name = name self.scale = None self.height = 50 self.font_size = 16 def render(self, renderer): start, end = self.scale.start, self.scale.end yield from renderer.line(self.scale.topixels(start), 5, self.scale.topixels(end), 5) ticks = get_ticks(start, end, max(1,self.scale.pixel_width/120)) prev_right = -1e6 for i, (tick, label) in enumerate(ticks): x = self.scale.topixels(tick) if x < 0 or x > self.scale.pixel_width: continue yield from renderer.line(x, 0, x, 20) anchor = "middle" cur_left = x - len(label) / 2 * self.font_size * 0.8 if x < 50 and i == 0: anchor = "start" x = min(x, 5) cur_left = x elif x > self.scale.pixel_width-50 and i == len(ticks)-1: anchor = "end" x = max(x, self.scale.pixel_width-5) cur_left = x - len(label) * self.font_size * 0.8 # make sure we don't clobber label text we've already rendered if cur_left > prev_right: yield from renderer.text(x, 35, label, anchor=anchor, size=self.font_size) if anchor == "start": prev_right = x + len(label) * self.font_size * 0.8 elif anchor == "middle": prev_right = x + len(label) / 2 * self.font_size * 0.8 else: prev_right = x
[docs]def get_ticks(start, end, target_n_labels=10): """ Tries to put an appropriate number of ticks at nice round coordinates between the genomic positions `start` and `end`. Tries but doesn't guarantee to create `target_n_labels` number of ticks / labels. Returns: a list of tuples (coordinate, label), where "label" is a nicely formatted string describing the coordinate """ ticks = [] start = int(start) end = int(end) width = end - start res = (10 ** round(math.log10(end - start))) / (10**math.floor(math.log10(target_n_labels))) if width / res > target_n_labels*2: res *= 5 elif width / res > target_n_labels*1.5: res *= 2.5 elif width / res < target_n_labels*0.15: res /= 10.0 elif width / res < target_n_labels*0.25: res /= 8.0 elif width / res < target_n_labels*0.5: res /= 4.0 elif width / res < target_n_labels*0.8: res /= 2.0 roundStart = start - (start%res) res = max(1, int(res)) for i in range(int(roundStart), end, res): res_digits = math.log10(res) if res_digits >= 6: label = "{}mb".format(i / 1e6) elif res_digits >= 3: label = "{:,}kb".format(i / 1e3) else: label = "{:,}".format(i) ticks.append((i, label)) return ticks
if __name__ == '__main__': params = [(10000, 11060, 10), (0, 10311, 10), (0, 143600, 10), (0, 1002552, 10)] for param in params: print(params) print(get_ticks(*param)) print("")