Spaces:
No application file
No application file
# Copyright 2001 by Brad Chapman. All rights reserved. | |
# | |
# This file is part of the Biopython distribution and governed by your | |
# choice of the "Biopython License Agreement" or the "BSD 3-Clause License". | |
# Please see the LICENSE file that should have been included as part of this | |
# package. | |
"""Plots to compare information between different sources. | |
This file contains high level plots which are designed to be used to | |
compare different types of information. The most basic example is comparing | |
two variables in a traditional scatter plot. | |
""" | |
# reportlab | |
from reportlab.lib import colors | |
from reportlab.graphics.charts.lineplots import LinePlot | |
from reportlab.lib.pagesizes import letter | |
from reportlab.lib.units import inch | |
from reportlab.graphics.shapes import Drawing, String | |
from reportlab.graphics.charts.markers import makeEmptySquare, makeFilledSquare | |
from reportlab.graphics.charts.markers import makeFilledDiamond, makeSmiley | |
from reportlab.graphics.charts.markers import makeFilledCircle, makeEmptyCircle | |
from Bio.Graphics import _write | |
class ComparativeScatterPlot: | |
"""Display a scatter-type plot comparing two different kinds of info. | |
Attributes; | |
- display_info - a 2D list of the information we'll be outputting. Each | |
top level list is a different data type, and each data point is a | |
two-tuple of the coordinates of a point. | |
So if you had two distributions of points, it should look like:: | |
display_info = [[(1, 2), (3, 4)], | |
[(5, 6), (7, 8)]] | |
If everything is just one set of points, display_info can look like:: | |
display_info = [[(1, 2), (3, 4), (5, 6)]] | |
""" | |
def __init__(self, output_format="pdf"): | |
"""Initialize the class.""" | |
# customizable attributes | |
self.number_of_columns = 1 | |
self.page_size = letter | |
self.title_size = 20 | |
self.output_format = output_format | |
# the information we'll be writing | |
self.display_info = [] | |
# initial colors and shapes used for drawing points | |
self.color_choices = [ | |
colors.red, | |
colors.green, | |
colors.blue, | |
colors.yellow, | |
colors.orange, | |
colors.black, | |
] | |
self.shape_choices = [ | |
makeFilledCircle, | |
makeEmptySquare, | |
makeFilledDiamond, | |
makeFilledSquare, | |
makeEmptyCircle, | |
makeSmiley, | |
] | |
def draw_to_file(self, output_file, title): | |
"""Write the comparative plot to a file. | |
Arguments: | |
- output_file - The name of the file to output the information to, | |
or a handle to write to. | |
- 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) | |
start_x = inch * 0.5 | |
end_x = width - inch * 0.5 | |
end_y = height - 1.5 * inch | |
start_y = 0.5 * inch | |
self._draw_scatter_plot(cur_drawing, start_x, start_y, end_x, end_y) | |
return _write(cur_drawing, output_file, self.output_format) | |
def _draw_title(self, cur_drawing, title, width, height): | |
"""Add a title to the page we are outputting (PRIVATE).""" | |
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_scatter_plot(self, cur_drawing, x_start, y_start, x_end, y_end): | |
"""Draw a scatter plot on the drawing with the given coordinates (PRIVATE).""" | |
scatter_plot = LinePlot() | |
# set the dimensions of the scatter plot | |
scatter_plot.x = x_start | |
scatter_plot.y = y_start | |
scatter_plot.width = abs(x_start - x_end) | |
scatter_plot.height = abs(y_start - y_end) | |
scatter_plot.data = self.display_info | |
scatter_plot.joinedLines = 0 | |
# set the axes of the plot | |
x_min, x_max, y_min, y_max = self._find_min_max(self.display_info) | |
scatter_plot.xValueAxis.valueMin = x_min | |
scatter_plot.xValueAxis.valueMax = x_max | |
scatter_plot.xValueAxis.valueStep = (x_max - x_min) / 10.0 | |
scatter_plot.yValueAxis.valueMin = y_min | |
scatter_plot.yValueAxis.valueMax = y_max | |
scatter_plot.yValueAxis.valueStep = (y_max - y_min) / 10.0 | |
self._set_colors_and_shapes(scatter_plot, self.display_info) | |
cur_drawing.add(scatter_plot) | |
def _set_colors_and_shapes(self, scatter_plot, display_info): | |
"""Set the colors and shapes of the points displayed (PRIVATE). | |
By default this just sets all of the points according to the order | |
of colors and shapes defined in self.color_choices and | |
self.shape_choices. The first 5 shapes and colors are unique, the | |
rest of them are just set to the same color and shape (since I | |
ran out of shapes!). | |
You can change how this function works by either changing the | |
values of the color_choices and shape_choices attributes, or | |
by inheriting from this class and overriding this function. | |
""" | |
for value_num in range(len(display_info)): | |
# if we have unique colors, add them | |
if (value_num + 1) < len(self.color_choices): | |
scatter_plot.lines[value_num].strokeColor = self.color_choices[ | |
value_num | |
] | |
scatter_plot.lines[value_num].symbol = self.shape_choices[value_num] | |
# otherwise just use the last number | |
else: | |
scatter_plot.lines[value_num].strokeColor = self.color_choices[-1] | |
scatter_plot.lines[value_num].symbol = self.shape_choices[-1] | |
def _find_min_max(self, info): | |
"""Find min and max for x and y coordinates in the given data (PRIVATE).""" | |
x_min = info[0][0][0] | |
x_max = info[0][0][0] | |
y_min = info[0][0][1] | |
y_max = info[0][0][1] | |
for two_d_list in info: | |
for x, y in two_d_list: | |
if x > x_max: | |
x_max = x | |
if x < x_min: | |
x_min = x | |
if y > y_max: | |
y_max = y | |
if y < y_min: | |
y_min = y | |
return x_min, x_max, y_min, y_max | |