/usr/share/pyshared/Bio/Graphics/Distribution.py is in python-biopython 1.58-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | """Display information distributed across a Chromosome-like object.
These classes are meant to show the distribution of some kind of information
as it changes across any kind of segment. It was designed with chromosome
distributions in mind, but could also work for chromosome regions, BAC clones
or anything similar.
Reportlab is used for producing the graphical output.
"""
# standard library
import math
# reportlab
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from reportlab.lib.units import inch
from reportlab.lib import colors
from reportlab.graphics.shapes import Drawing, String
from reportlab.graphics.charts.barcharts import VerticalBarChart
from reportlab.graphics.charts.barcharts import BarChartProperties
from reportlab.graphics.widgetbase import TypedPropertyCollection
from reportlab.graphics import renderPDF, renderPS
from Bio.Graphics import _write
class DistributionPage(object):
"""Display a grouping of distributions on a page.
This organizes Distributions, and will display them nicely
on a single page.
"""
def __init__(self, output_format = 'pdf'):
self.distributions = []
# customizable attributes
self.number_of_columns = 1
self.page_size = letter
self.title_size = 20
self.output_format = output_format
def draw(self, output_file, title):
"""Draw out the distribution information.
Arguments:
o output_file - The name of the file to output the information to,
or a handle to write to.
o title - A title to display on the graphic.
"""
width, height = self.page_size
cur_drawing = Drawing(width, height)
self._draw_title(cur_drawing, title, width, height)
# calculate the x and y position changes for each distribution
cur_x_pos = inch * .5
end_x_pos = width - inch * .5
cur_y_pos = height - 1.5 * inch
end_y_pos = .5 * inch
x_pos_change = ((end_x_pos - cur_x_pos) /
float(self.number_of_columns))
num_y_rows = math.ceil(float(len(self.distributions))
/ float(self.number_of_columns))
y_pos_change = (cur_y_pos - end_y_pos) / num_y_rows
self._draw_distributions(cur_drawing, cur_x_pos, x_pos_change,
cur_y_pos, y_pos_change, num_y_rows)
self._draw_legend(cur_drawing, 2.5 * inch, width)
return _write(cur_drawing, output_file, self.output_format)
def _draw_title(self, cur_drawing, title, width, height):
"""Add the title of the figure to the drawing.
"""
title_string = String(width / 2, height - inch, title)
title_string.fontName = 'Helvetica-Bold'
title_string.fontSize = self.title_size
title_string.textAnchor = "middle"
cur_drawing.add(title_string)
def _draw_distributions(self, cur_drawing, start_x_pos, x_pos_change,
start_y_pos, y_pos_change, num_y_drawings):
"""Draw all of the distributions on the page.
Arguments:
o cur_drawing - The drawing we are working with.
o start_x_pos - The x position on the page to start drawing at.
o x_pos_change - The change in x position between each figure.
o start_y_pos - The y position on the page to start drawing at.
o y_pos_change - The change in y position between each figure.
o num_y_drawings - The number of drawings we'll have in the y
(up/down) direction.
"""
for y_drawing in range(int(num_y_drawings)):
# if we are on the last y position, we may not be able
# to fill all of the x columns
if ((y_drawing + 1) * self.number_of_columns >
len(self.distributions)):
num_x_drawings = len(self.distributions) - \
y_drawing * self.number_of_columns
else:
num_x_drawings = self.number_of_columns
for x_drawing in range(num_x_drawings):
dist_num = y_drawing * self.number_of_columns + x_drawing
cur_distribution = self.distributions[dist_num]
# find the x and y boundaries of the distribution
x_pos = start_x_pos + x_drawing * x_pos_change
end_x_pos = x_pos + x_pos_change
end_y_pos = start_y_pos - y_drawing * y_pos_change
y_pos = end_y_pos - y_pos_change
# draw the distribution
cur_distribution.draw(cur_drawing, x_pos, y_pos, end_x_pos,
end_y_pos)
def _draw_legend(self, cur_drawing, start_y, width):
"""Add a legend to the figure.
Subclasses can implement to provide a specialized legend.
"""
pass
class BarChartDistribution(object):
"""Display the distribution of values as a bunch of bars.
"""
def __init__(self, display_info = []):
"""Initialize a Bar Chart display of distribution info.
Class attributes:
o display_info - the information to be displayed in the distribution.
This should be ordered as a list of lists, where each internal list
is a data set to display in the bar chart.
"""
self.display_info = display_info
self.x_axis_title = ""
self.y_axis_title = ""
self.chart_title = ""
self.chart_title_size = 10
self.padding_percent = 0.15
def draw(self, cur_drawing, start_x, start_y, end_x, end_y):
"""Draw a bar chart with the info in the specified range.
"""
bar_chart = VerticalBarChart()
if self.chart_title:
self._draw_title(cur_drawing, self.chart_title,
start_x, start_y, end_x, end_y)
# set the position of the bar chart
x_start, x_end, y_start, y_end = \
self._determine_position(start_x, start_y, end_x, end_y)
bar_chart.x = x_start
bar_chart.y = y_start
bar_chart.width = abs(x_start - x_end)
bar_chart.height = abs(y_start - y_end)
# set the information in the bar chart
bar_chart.data = self.display_info
bar_chart.valueAxis.valueMin = min(self.display_info[0])
bar_chart.valueAxis.valueMax = max(self.display_info[0])
for data_set in self.display_info[1:]:
if min(data_set) < bar_chart.valueAxis.valueMin:
bar_chart.valueAxis.valueMin = min(data_set)
if max(data_set) > bar_chart.valueAxis.valueMax:
bar_chart.valueAxis.valueMax = max(data_set)
# set other formatting options
if len(self.display_info) == 1:
bar_chart.groupSpacing = 0
style = TypedPropertyCollection(BarChartProperties)
style.strokeWidth = 0
style.strokeColor = colors.green
style[0].fillColor = colors.green
bar_chart.bars = style
# set the labels
# XXX labels don't work yet
# bar_chart.valueAxis.title = self.x_axis_title
# bar_chart.categoryAxis.title = self.y_axis_title
cur_drawing.add(bar_chart)
def _draw_title(self, cur_drawing, title, start_x, start_y, end_x, end_y):
"""Add the title of the figure to the drawing.
"""
x_center = start_x + (end_x - start_x) / 2
y_pos = end_y + (self.padding_percent * (start_y - end_y)) / 2
title_string = String(x_center, y_pos, title)
title_string.fontName = 'Helvetica-Bold'
title_string.fontSize = self.chart_title_size
title_string.textAnchor = "middle"
cur_drawing.add(title_string)
def _determine_position(self, start_x, start_y, end_x, end_y):
"""Calculate the position of the chart with blank space.
This uses some padding around the chart, and takes into account
whether the chart has a title. It returns 4 values, which are,
in order, the x_start, x_end, y_start and y_end of the chart
itself.
"""
x_padding = self.padding_percent * (end_x - start_x)
y_padding = self.padding_percent * (start_y - end_y)
new_x_start = start_x + x_padding
new_x_end = end_x - x_padding
if self.chart_title:
new_y_start = start_y - y_padding - self.chart_title_size
else:
new_y_start = start_y - y_padding
new_y_end = end_y + y_padding
return new_x_start, new_x_end, new_y_start, new_y_end
class LineDistribution(object):
"""Display the distribution of values as connected lines.
This distribution displays the change in values across the object as
lines. This also allows multiple distributions to be displayed on a
single graph.
"""
def __init__(self):
pass
def draw(self, cur_drawing, start_x, start_y, end_x, end_y):
pass
|