scripts/last-dotplot
changeset 899 ccf8902bf86c
parent 898 f6a9c15287ea
child 900 5ce3e786e05a
     1.1 --- a/scripts/last-dotplot	Thu Nov 02 21:08:55 2017 +0900
     1.2 +++ b/scripts/last-dotplot	Thu Nov 02 21:56:30 2017 +0900
     1.3 @@ -164,18 +164,6 @@
     1.4      parts[1::2] = map(int, parts[1::2])
     1.5      return parts
     1.6  
     1.7 -def textDimensions(imageDraw, font, textRot, text):
     1.8 -    x, y = imageDraw.textsize(text, font=font)
     1.9 -    return (y, x) if textRot else (x, y)
    1.10 -
    1.11 -def get_text_sizes(my_strings, font, fontsize, image_mode, textRot):
    1.12 -    '''Get widths & heights, in pixels, of some strings.'''
    1.13 -    if fontsize == 0: return [(0, 0) for i in my_strings]
    1.14 -    image_size = 1, 1
    1.15 -    im = Image.new(image_mode, image_size)
    1.16 -    draw = ImageDraw.Draw(im)
    1.17 -    return [textDimensions(draw, font, textRot, i) for i in my_strings]
    1.18 -
    1.19  def prettyNum(n):
    1.20      t = str(n)
    1.21      groups = []
    1.22 @@ -203,6 +191,20 @@
    1.23          return seqName + ": " + prettyNum(beg) + " - " + prettyNum(end)
    1.24      return seqName
    1.25  
    1.26 +def rangeLabels(seqRanges, labelOpt, font, fontsize, image_mode, textRot):
    1.27 +    if fontsize:
    1.28 +        image_size = 1, 1
    1.29 +        im = Image.new(image_mode, image_size)
    1.30 +        draw = ImageDraw.Draw(im)
    1.31 +    x = y = 0
    1.32 +    for r in seqRanges:
    1.33 +        text = labelText(r, labelOpt)
    1.34 +        if fontsize:
    1.35 +            x, y = draw.textsize(text, font=font)
    1.36 +            if textRot:
    1.37 +                x, y = y, x
    1.38 +        yield text, x, y
    1.39 +
    1.40  def getSeqInfo(sortOpt, seqNames, seqLimits,
    1.41                 font, fontsize, image_mode, labelOpt, textRot):
    1.42      '''Return miscellaneous information about the sequences.'''
    1.43 @@ -219,11 +221,11 @@
    1.44          seqSizes = [i[0] for i in seqRecords]
    1.45          seqNames = [i[1] for i in seqRecords]
    1.46      seqRanges = [(i, seqLimits[i][0], seqLimits[i][1]) for i in seqNames]
    1.47 -    seqLabels = [labelText(i, labelOpt) for i in seqRanges]
    1.48 -    labelSizes = get_text_sizes(seqLabels, font, fontsize, image_mode, textRot)
    1.49 -    margin = max(i[1] for i in labelSizes)
    1.50 +    labelData = list(rangeLabels(seqRanges, labelOpt,
    1.51 +                                 font, fontsize, image_mode, textRot))
    1.52 +    margin = max(i[2] for i in labelData)
    1.53      # xxx the margin may be too big, because some labels may get omitted
    1.54 -    return seqNames, seqSizes, seqLabels, labelSizes, margin
    1.55 +    return seqNames, seqSizes, labelData, margin
    1.56  
    1.57  def div_ceil(x, y):
    1.58      '''Return x / y rounded up.'''
    1.59 @@ -430,9 +432,9 @@
    1.60      for layer, color, box in boxes:
    1.61          im.paste(color, box)
    1.62  
    1.63 -def make_label(text, text_size, range_start, range_size):
    1.64 +def make_label(labelData, range_start, range_size):
    1.65      '''Return an axis label with endpoint & sort-order information.'''
    1.66 -    text_width, text_height = text_size
    1.67 +    text, text_width, text_height = labelData
    1.68      label_start = range_start + (range_size - text_width) // 2
    1.69      label_end   = label_start + text_width
    1.70      sort_key    = text_width - range_size
    1.71 @@ -448,13 +450,13 @@
    1.72              out.append(i)
    1.73      return out
    1.74  
    1.75 -def axisImage(seqNames, name_sizes, seq_starts, seq_pix, textRot,
    1.76 +def axisImage(labelData, seq_starts, seq_pix, textRot,
    1.77                textAln, font, image_mode, opts):
    1.78      '''Make an image of axis labels.'''
    1.79      beg = seq_starts[0]
    1.80      end = seq_starts[-1] + seq_pix[-1]
    1.81 -    margin = max(i[1] for i in name_sizes)
    1.82 -    labels = map(make_label, seqNames, name_sizes, seq_starts, seq_pix)
    1.83 +    margin = max(i[2] for i in labelData)
    1.84 +    labels = map(make_label, labelData, seq_starts, seq_pix)
    1.85      labels = [i for i in labels if i[1] >= beg and i[2] <= end]
    1.86      labels.sort()
    1.87      minPixTweenLabels = 0 if textRot else opts.label_space
    1.88 @@ -491,12 +493,12 @@
    1.89      textRot1 = "vertical".startswith(opts.rot1)
    1.90      i1 = getSeqInfo(opts.sort1, seqNames1, seqLimits1,
    1.91                      font, opts.fontsize, image_mode, opts.labels1, textRot1)
    1.92 -    seqNames1, rangeSizes1, seqLabels1, labelSizes1, tMargin = i1
    1.93 +    seqNames1, rangeSizes1, labelData1, tMargin = i1
    1.94  
    1.95      textRot2 = "horizontal".startswith(opts.rot2)
    1.96      i2 = getSeqInfo(opts.sort2, seqNames2, seqLimits2,
    1.97                      font, opts.fontsize, image_mode, opts.labels2, textRot2)
    1.98 -    seqNames2, rangeSizes2, seqLabels2, labelSizes2, lMargin = i2
    1.99 +    seqNames2, rangeSizes2, labelData2, lMargin = i2
   1.100  
   1.101      warn("choosing bp per pixel...")
   1.102      maxPixels1 = opts.width  - lMargin
   1.103 @@ -553,11 +555,11 @@
   1.104              elif store_value == 3: im.putpixel(xy, overlap_color)
   1.105  
   1.106      if opts.fontsize != 0:
   1.107 -        axis1 = axisImage(seqLabels1, labelSizes1, seq_starts1, seq_pix1,
   1.108 +        axis1 = axisImage(labelData1, seq_starts1, seq_pix1,
   1.109                            textRot1, False, font, image_mode, opts)
   1.110          if textRot1:
   1.111              axis1 = axis1.transpose(Image.ROTATE_90)
   1.112 -        axis2 = axisImage(seqLabels2, labelSizes2, seq_starts2, seq_pix2,
   1.113 +        axis2 = axisImage(labelData2, seq_starts2, seq_pix2,
   1.114                            textRot2, textRot2, font, image_mode, opts)
   1.115          if not textRot2:
   1.116              axis2 = axis2.transpose(Image.ROTATE_270)