def get_animation_frame(image_format, physical_size, scale, newick, eigenvector_index, yaw, pitch): """ This function is about drawing the tree. @param image_format: the image extension @param physical_size: the width and height of the image in pixels @param scale: a scaling factor @return: the animation frame as an image as a string """ # before we begin drawing we need to create the cairo surface and context cairo_helper = CairoUtil.CairoHelper(image_format) surface = cairo_helper.create_surface(physical_size[0], physical_size[1]) ctx = cairo.Context(surface) # draw a white background ctx.save() ctx.set_source_rgb(1, 1, 1) ctx.paint() ctx.restore() # define some helper variables x0 = physical_size[0] / 2.0 y0 = physical_size[1] / 2.0 # translate to the center of the frame ctx.translate(x0, y0) ctx.scale(1, -1) # draw the info TreeProjection.draw_cairo_frame(ctx, scale, newick, eigenvector_index, yaw, pitch) # create the image return cairo_helper.get_image_string()
def get_image_string(self, colors, radii, image_format): """ @param colors: point colors as rgb triples in [0,1] @param radii: point radii should be about 2.0 @param image_format: the requested format of the image @return: the image string """ # create the surface cairo_helper = CairoUtil.CairoHelper(image_format) surface = cairo_helper.create_surface(self.t_width, self.t_height) context = cairo.Context(surface) # draw the background context.save() context.set_source_rgb(.9, .9, .9) context.paint() context.restore() # draw the edges for i, j in self.edges: context.save() context.move_to(self.x_final[i], self.y_final[i]) context.line_to(self.x_final[j], self.y_final[j]) context.close_path() context.stroke() context.restore() # draw the points for r, c, x, y in zip(radii, colors, self.x_final, self.y_final): # draw a filled circle context.save() context.set_source_rgb(*c) context.arc(x, y, r, 0, 2 * math.pi) context.close_path() context.fill() context.restore() # get the image string return cairo_helper.get_image_string()
def get_animation_frame(image_format, physical_size, scale, index_edges, points): """ This function is about drawing the tree. @param image_format: the image extension @param physical_size: the width and height of the image in pixels @param scale: a scaling factor @param index_edges: defines the connectivity of the tree @param points: an array of 2D points, the first few of which are leaves @return: the animation frame as an image as a string """ # before we begin drawing we need to create the cairo surface and context cairo_helper = CairoUtil.CairoHelper(image_format) surface = cairo_helper.create_surface(physical_size[0], physical_size[1]) context = cairo.Context(surface) # define some helper variables x0 = physical_size[0] / 2.0 y0 = physical_size[1] / 2.0 npoints = len(points) # draw an off-white background context.save() context.set_source_rgb(.9, .9, .9) context.paint() context.restore() # draw the axes which are always in the center of the image context.save() context.set_source_rgb(.9, .7, .7) context.move_to(x0, 0) context.line_to(x0, physical_size[1]) context.stroke() context.move_to(0, y0) context.line_to(physical_size[0], y0) context.stroke() context.restore() # draw the edges context.save() context.set_source_rgb(.8, .8, .8) for edge in index_edges: ai, bi = tuple(edge) ax, ay = points[ai].tolist() bx, by = points[bi].tolist() context.move_to(x0 + ax * scale, y0 + ay * scale) context.line_to(x0 + bx * scale, y0 + by * scale) context.stroke() context.restore() # Draw vertices as translucent circles. context.save() context.set_source_rgba(0.2, 0.2, 1.0, 0.5) for point in points: x, y = point.tolist() nx = x0 + x * scale ny = y0 + y * scale dot_radius = 2.0 context.arc(nx, ny, dot_radius, 0, 2 * math.pi) context.fill() context.restore() # create the image return cairo_helper.get_image_string()
def create_image(ext, size, xscale, yscale, xoffset, yoffset, D_in, ntips, nticks_horz, denom, fn, target_ws): """ @param ext: image extension @param size: width and height of the image in pixels @param D_in: the original distance matrix @param ntips: the number of tips in the tree @param nticks_horz: the number of ticks on the horizontal axis @return: image file contents """ # get the raw eigenvalues of the augmented matrix ndups_list = range(denom, nticks_horz + denom) raw_eigenvalue_grid = [fn(D_in, ntips, k, denom) for k in ndups_list] # get augmented eigenvalues aug_ws = [w for ws in raw_eigenvalue_grid for w in ws] + target_ws.tolist() max_eigenvalue = max(aug_ws) # get all of the scaled eigenvalues we want to plot scaled_eigenvalue_grid = [ np.array(w) / max_eigenvalue for w in raw_eigenvalue_grid ] # get the scaled target eigenvalues scaled_target_ws = np.array(target_ws) / max_eigenvalue # before we begin drawing we need to create the cairo surface and context cairo_helper = CairoUtil.CairoHelper(ext) surface = cairo_helper.create_surface(size[0], size[1]) context = cairo.Context(surface) # draw an off-white background context.save() context.set_source_rgb(.9, .9, .9) context.paint() context.restore() # draw the target eigenvalues as horizontal lines context.save() context.set_source_rgba(.8, .1, .1, 0.8) context.set_line_width(0.5) for w in scaled_target_ws: y = size[1] - (yoffset + w * yscale) context.move_to(0, y) context.line_to(size[0], y) context.stroke() context.restore() # draw eigenvalues as translucent disks context.save() context.set_source_rgba(0.2, 0.2, 1.0, 0.5) dot_radius = 2 for htick, ws in enumerate(scaled_eigenvalue_grid): x = xoffset + htick * xscale for w in ws: y = size[1] - (yoffset + w * yscale) context.arc(x, y, dot_radius, 0, 2 * math.pi) context.fill() context.restore() # create the image return cairo_helper.get_image_string()
def get_animation_frame(image_format, physical_size, scale, v_to_index, T, X, w): """ This function is about drawing the tree. @param image_format: the image extension @param physical_size: the width and height of the image in pixels @param scale: a scaling factor @param v_to_index: maps vertices to their index @param T: defines the connectivity of the tree @param X: an array of 2D points @param w: eigenvalues @return: the animation frame as an image as a string """ # before we begin drawing we need to create the cairo surface and context cairo_helper = CairoUtil.CairoHelper(image_format) surface = cairo_helper.create_surface(physical_size[0], physical_size[1]) context = cairo.Context(surface) # define some helper variables x0 = physical_size[0] / 2.0 y0 = physical_size[1] / 2.0 npoints = len(X) # draw an off-white background context.save() context.set_source_rgb(.9, .9, .9) context.paint() context.restore() # draw the axes which are always in the center of the image context.save() context.set_source_rgb(.9, .7, .7) context.move_to(x0, 0) context.line_to(x0, physical_size[1]) context.stroke() context.move_to(0, y0) context.line_to(physical_size[0], y0) context.stroke() context.restore() # draw the edges context.save() context.set_source_rgb(.8, .8, .8) for va, vb in T: a = v_to_index[va] b = v_to_index[vb] ax, ay = X[a].tolist() bx, by = X[b].tolist() context.move_to(x0 + ax * scale, y0 + ay * scale) context.line_to(x0 + bx * scale, y0 + by * scale) context.stroke() context.restore() # draw the eigenvalues width, height = physical_size draw_eigenvalues(context, 0.9 * height, 0.05 * width, 0.95 * width, w) # create the image return cairo_helper.get_image_string()
def get_tree_image(tree, max_size, image_format): """ Get the image of the tree. @param tree: something like a SpatialTree @param max_size: (max_width, max_height) @param image_format: a string that determines the image format @return: a string containing the image data """ # rotate and center the tree on (0, 0) tree.fit(max_size) # get the width and height of the tree image xmin, ymin, xmax, ymax = tree.get_extents() width = xmax - xmin height = ymax - ymin # create the surface cairo_helper = CairoUtil.CairoHelper(image_format) surface = cairo_helper.create_surface(width, height) context = cairo.Context(surface) # draw the background context.save() context.set_source_rgb(.9, .9, .9) context.paint() context.restore() # center on the tree context.translate(width / 2.0, height / 2.0) # draw the branches for branch in tree.gen_branches(): context.save() color = getattr(branch, 'branch_color', None) if color: context.set_source_rgb(*CairoUtil.hex_string_to_cairo_rgb(color)) context.move_to(*branch.src_location) context.line_to(*branch.dst_location) context.stroke() context.restore() # get the image string return cairo_helper.get_image_string()
def get_image_string(points, edges, point_colors, all_black, image_info): """ @param points: an ordered list of (x, y) pairs @param edges: a set of point index pairs @param point_colors: a list of rgb float triples @param all_black: a flag that overrides the fancy coloring @param image_info: an object with image presentation details """ # unpack some image info t_width = image_info.total_width t_height = image_info.total_height border = image_info.border image_format = image_info.image_format # define the drawable region width = image_info.get_drawable_width() height = image_info.get_drawable_height() # get the x and y coordinates of the points x_coords, y_coords_raw = zip(*points) # Flip the y coordinates so that greater values of y # are shown near the top of the image. y_coords = [-y for y in y_coords_raw] unscaled_width = max(x_coords) - min(x_coords) unscaled_height = max(y_coords) - min(y_coords) # rescale the points to fit in the drawable part of the image c_width = width / unscaled_width c_height = height / unscaled_height c = min(c_width, c_height) x_rescaled = [x * c for x in x_coords] y_rescaled = [y * c for y in y_coords] # translate the points so that their minimum coordinate is zero x_min = min(x_rescaled) y_min = min(y_rescaled) x_trans = [x - x_min for x in x_rescaled] y_trans = [y - y_min for y in y_rescaled] # translate the points to account for the border x_final = [x + border for x in x_trans] y_final = [y + border for y in y_trans] # create the surface cairo_helper = CairoUtil.CairoHelper(image_format) surface = cairo_helper.create_surface(t_width, t_height) context = cairo.Context(surface) # draw the background context.save() context.set_source_rgb(.9, .9, .9) context.paint() context.restore() # draw the edges for i, j in edges: context.save() if not all_black: context.set_source_rgb(0.6, 0.6, 0.6) context.move_to(x_final[i], y_final[i]) context.line_to(x_final[j], y_final[j]) context.close_path() context.stroke() context.restore() # draw the points radius = 3.0 for x, y, point_color in zip(x_final, y_final, point_colors): # draw a filled circle context.save() if not all_black: context.set_source_rgb(*point_color) context.arc(x, y, radius, 0, 2 * math.pi) context.close_path() context.fill() context.restore() # get the image string return cairo_helper.get_image_string()
def get_image(row_major_matrix, incidence_matrix, ordered_names, width_and_height, image_format, draw_axes, draw_connections): """ @param row_major_matrix: this is supposed to be a rate matrix @param incidence_matrix: for drawing connections @param ordered_names: the labels corresponding to rows of the matrix @param width_and_height: the dimensions of the output image @param image_format: like 'svg', 'png', 'ps', 'pdf', et cetera @param draw_axes: True if axes should be drawn @param draw_connections: True if connections should be drawn @return: a string containing the image data """ width, height = width_and_height n = len(row_major_matrix) # get eigenvectors scaled to [0, 1] va, vb = get_eigenvectors(row_major_matrix) rescaled_a = get_rescaled_vector(va) rescaled_b = get_rescaled_vector(vb) # create the surface cairo_helper = CairoUtil.CairoHelper(image_format) surface = cairo_helper.create_surface(width, height) context = cairo.Context(surface) # draw the background context.save() context.set_source_rgb(.9, .9, .9) context.paint() context.restore() # define the border border_fraction = .1 # draw the axes if requested if draw_axes: # begin drawing context.save() context.set_source_rgb(.9, .7, .7) # draw the y axis dx = max(va) - min(va) tx = -min(va) / dx xzero = (tx * (1 - 2 * border_fraction) + border_fraction) * width context.move_to(xzero, 0) context.line_to(xzero, height) context.stroke() # draw the x axis dy = max(vb) - min(vb) ty = -min(vb) / dy yzero = (ty * (1 - 2 * border_fraction) + border_fraction) * height context.move_to(0, yzero) context.line_to(width, yzero) context.stroke() # stop drawing context.restore() # draw the connections if requested if draw_connections: # begin drawing context.save() context.set_source_rgb(.8, .8, .8) for i in range(n): for j in range(n): if not (i < j and incidence_matrix[i][j] > 0): break x, y = rescaled_a[i], rescaled_b[i] nx = (x * (1 - 2 * border_fraction) + border_fraction) * width ny = (y * (1 - 2 * border_fraction) + border_fraction) * height context.move_to(nx, ny) x, y = rescaled_a[j], rescaled_b[j] nx = (x * (1 - 2 * border_fraction) + border_fraction) * width ny = (y * (1 - 2 * border_fraction) + border_fraction) * height context.line_to(nx, ny) context.stroke() # stop drawing context.restore() # draw a scatter plot of the states using the eigenvectors as axes for i, (x, y) in enumerate(zip(rescaled_a, rescaled_b)): state_string = ordered_names[i] nx = (x * (1 - 2 * border_fraction) + border_fraction) * width ny = (y * (1 - 2 * border_fraction) + border_fraction) * height context.move_to(nx, ny) context.show_text(state_string) # get the image string return cairo_helper.get_image_string()
def create_image_string(image_format, physical_size, F, xaxis_length): """ This function is about drawing the tree. param image_format: the image extension @param physical_size: the width and height of the image in pixels @param F: eigenfunction samples @param xaxis_length: True if plotting vs length; False if plotting vs PC1 @return: the image as a string """ # before we begin drawing we need to create the cairo surface and context cairo_helper = CairoUtil.CairoHelper(image_format) surface = cairo_helper.create_surface(physical_size[0], physical_size[1]) context = cairo.Context(surface) # define some helper variables x0 = physical_size[0] / 2.0 y0 = physical_size[1] / 2.0 # draw an off-white background context.save() context.set_source_rgb(.9, .9, .9) context.paint() context.restore() # draw the axes which are always in the center of the image context.save() context.set_source_rgb(0, 0, 0) context.move_to(x0, 0) context.line_to(x0, physical_size[1]) context.stroke() context.move_to(0, y0) context.line_to(physical_size[0], y0) context.stroke() context.restore() # define red, blue, green, orange colors = [ (1.0, 0.0, 0.0), (0.0, 0.0, 1.0), (0.0, 1.0, 0.0), (1.0, 0.5, 0.0)] # add the sum of the eigenfunctions with a gray color #F = np.vstack([F, np.sum(F, 0)]) #colors.append((0.5, 0.5, 0.5)) # draw the eigenfunctions for i, v in enumerate(F): # define the color if i < len(colors): color = colors[i] else: color = (0,0,0) # define the sequence of physical points seq = [] for i, y in enumerate(v): xprogress = i / (len(v) - 1.0) if xaxis_length: x = x0 + (xprogress - 0.5) * 0.75 * physical_size[0] else: x = x0 + F[0][i] * physical_size[0] y = y0 + y * physical_size[1] seq.append((x, y)) # draw the eigenfunction context.save() context.set_source_rgb(*color) for (xa, ya), (xb, yb) in iterutils.pairwise(seq): context.move_to(xa, ya) context.line_to(xb, yb) context.stroke() context.restore() # create the image return cairo_helper.get_image_string()
def get_image_helper(xmin, ymin, xmax, ymax, vx, vy, image_size, image_format): """ Get an image string. Input comprises excruciating details about the image and its scaling properties. @param xmin: the smallest x value allowed in the viewport @param ymin: the smallest y value allowed in the viewport @param xmax: the greatest x value allowed in the viewport @param ymax: the greatest y value allowed in the viewport @param vx: the list of x coordinates of the points @param vy: the list of y coordinates of the points @param image_size: the width and height of the image in pixels @param image_format: like 'svg', 'png', 'ps', 'pdf', et cetera @return: an image string """ width, height = image_size n = len(vx) # rescale the x and y vectors to be between zero and one xextent = xmax - xmin yextent = ymax - ymin rescaled_vx = [(x - xmin) / xextent for x in vx] rescaled_vy = [(y - ymin) / yextent for y in vy] # create the surface cairo_helper = CairoUtil.CairoHelper(image_format) surface = cairo_helper.create_surface(width, height) context = cairo.Context(surface) # draw the background context.save() context.set_source_rgb(.9, .9, .9) context.paint() context.restore() # define the border border_fraction = .1 # begin drawing the axes context.save() context.set_source_rgb(.9, .7, .7) # draw the y axis tx = -xmin / xextent xzero = (tx * (1 - 2 * border_fraction) + border_fraction) * width context.move_to(xzero, 0) context.line_to(xzero, height) context.stroke() # draw the x axis ty = -ymin / yextent yzero = (ty * (1 - 2 * border_fraction) + border_fraction) * height context.move_to(0, yzero) context.line_to(width, yzero) context.stroke() # stop drawing the axes context.restore() # draw a scatter plot of the states using the eigenvectors as axes for i, (x, y) in enumerate(zip(rescaled_vx, rescaled_vy)): if i < n / 2: state_string = 'x' else: state_string = 'o' nx = (x * (1 - 2 * border_fraction) + border_fraction) * width ny = (y * (1 - 2 * border_fraction) + border_fraction) * height context.move_to(nx, ny) context.show_text(state_string) # get the image string return cairo_helper.get_image_string()
def get_image_string(x_coords, y_coords, labels, image_info): # unpack the total width and height of the image t_width = image_info.width t_height = image_info.height # unpack axis visualization options show_x = image_info.axis_info.show_x show_y = image_info.axis_info.show_y # flip axes if necessary if image_info.axis_info.flip_x: x_coords = [-x for x in x_coords] if image_info.axis_info.flip_y: y_coords = [-y for y in y_coords] # unpack border info border_x = image_info.border_info.border_x border_y = image_info.border_info.border_y # unpack the image format image_format = image_info.image_format # Define the scaling factors in the x+, x-, y+, and y- directions # which would fill the entire drawable (non-border) region. # The smallest of these scaling factors will be used for all directions. xpos_coords = [x for x in x_coords if x > 0] xneg_coords = [x for x in x_coords if x < 0] ypos_coords = [y for y in y_coords if y > 0] yneg_coords = [y for y in y_coords if y < 0] sf_list = [] if xpos_coords: available = (t_width / 2.0) - border_x used = max(xpos_coords) sf_list.append(available / used) if xneg_coords: available = (t_width / 2.0) - border_x used = -min(xneg_coords) sf_list.append(available / used) if ypos_coords: available = (t_height / 2.0) - border_y used = max(ypos_coords) sf_list.append(available / used) if yneg_coords: available = (t_height / 2.0) - border_y used = -min(yneg_coords) sf_list.append(available / used) scaling_factor = min(sf_list) # Update the coordinates using the new scaling factor. x_coords = [x * scaling_factor for x in x_coords] y_coords = [y * scaling_factor for y in y_coords] # Translate the coordinates # so that the origin is at the center of the image. x_coords = [x + t_width / 2.0 for x in x_coords] y_coords = [y + t_height / 2.0 for y in y_coords] # create the surface cairo_helper = CairoUtil.CairoHelper(image_format) surface = cairo_helper.create_surface(t_width, t_height) context = cairo.Context(surface) # draw the background context.save() context.set_source_rgb(.9, .9, .9) context.paint() context.restore() # Draw the x axis if requested. if show_x: context.save() context.set_source_rgb(.9, .7, .7) context.move_to(0, t_height / 2.0) context.line_to(t_width, t_height / 2.0) context.stroke() context.restore() # Draw the y axis if requested. if show_y: context.save() context.set_source_rgb(.9, .7, .7) context.move_to(t_width / 2.0, 0) context.line_to(t_width / 2.0, t_height) context.stroke() context.restore() # Draw the points. dot_radius = 2.0 for x, y in zip(x_coords, y_coords): context.save() context.arc(x, y, dot_radius, 0, 2 * math.pi) context.close_path() context.fill() context.restore() # Draw the labels. for label, x, y in zip(labels, x_coords, y_coords): context.save() context.move_to(x, y) context.show_text(label) context.restore() # get the image string return cairo_helper.get_image_string()
def get_image_string(points, edges, t_width, t_height, border, image_format): """ @param points: an ordered list of (x, y) pairs @param edges: a set of point index pairs @param t_width: the image width in pixels @param t_height: the image height in pixels @param border: the width and height of the image border in pixels @param image_format: the requested format of the image """ width = t_width - 2 * border height = t_height - 2 * border assert width >= 1 assert height >= 1 # get the x and y coordinates of the points x_coords, y_coords_raw = zip(*points) # Flip the y coordinates so that greater values of y # are shown near the top of the image. y_coords = [-y for y in y_coords_raw] unscaled_width = max(x_coords) - min(x_coords) unscaled_height = max(y_coords) - min(y_coords) # rescale the points to fit in the drawable part of the image c_width = width / unscaled_width c_height = height / unscaled_height c = min(c_width, c_height) x_rescaled = [x * c for x in x_coords] y_rescaled = [y * c for y in y_coords] # translate the points so that their minimum coordinate is zero x_min = min(x_rescaled) y_min = min(y_rescaled) x_trans = [x - x_min for x in x_rescaled] y_trans = [y - y_min for y in y_rescaled] # translate the points to account for the border x_final = [x + border for x in x_trans] y_final = [y + border for y in y_trans] # create the surface cairo_helper = CairoUtil.CairoHelper(image_format) surface = cairo_helper.create_surface(t_width, t_height) context = cairo.Context(surface) # draw the background context.save() context.set_source_rgb(.9, .9, .9) context.paint() context.restore() # draw the points radius = 2.0 for x, y in zip(x_final, y_final): # draw a filled circle context.save() context.arc(x, y, radius, 0, 2 * math.pi) context.close_path() context.fill() context.restore() # draw the edges for i, j in edges: context.save() context.move_to(x_final[i], y_final[i]) context.line_to(x_final[j], y_final[j]) context.close_path() context.stroke() context.restore() # get the image string return cairo_helper.get_image_string()
def get_image_string(x_coords, y_coords, point_colors, edges, image_info, scaling_factor): """ @param edges: ignore this for now """ # unpack the total width and height of the image t_width = image_info.width t_height = image_info.height # unpack axis options show_x = image_info.axis_info.show_x show_y = image_info.axis_info.show_y show_labels = image_info.show_labels all_black = image_info.all_black # flip axes if necessary if image_info.axis_info.flip_x: x_coords = [-x for x in x_coords] if image_info.axis_info.flip_y: y_coords = [-y for y in y_coords] # unpack border info border_x = image_info.border_info.border_x border_y = image_info.border_info.border_y # unpack the image format image_format = image_info.image_format # Update the coordinates using the new scaling factor. x_coords = [x*scaling_factor for x in x_coords] y_coords = [y*scaling_factor for y in y_coords] # Translate the coordinates # so that the origin is at the center of the image. x_coords = [x + t_width / 2.0 for x in x_coords] y_coords = [y + t_height / 2.0 for y in y_coords] # create the surface cairo_helper = CairoUtil.CairoHelper(image_format) surface = cairo_helper.create_surface(t_width, t_height) context = cairo.Context(surface) # draw the background context.save() context.set_source_rgb(.9, .9, .9) context.paint() context.restore() # Draw the x axis if requested. if show_x: context.save() context.set_source_rgb(.9, .7, .7) context.move_to(0, t_height / 2.0) context.line_to(t_width, t_height / 2.0) context.stroke() context.restore() # Draw the y axis if requested. if show_y: context.save() context.set_source_rgb(.9, .7, .7) context.move_to(t_width / 2.0, 0) context.line_to(t_width / 2.0, t_height) context.stroke() context.restore() # Draw the points. dot_radius = 3.0 for x, y, point_color in zip(x_coords, y_coords, point_colors): context.save() if not all_black: context.set_source_rgb(*point_color) context.arc(x, y, dot_radius, 0, 2 * math.pi) context.close_path() context.fill() context.restore() # Draw the labels. if show_labels: labels = [str(i) for i, x in enumerate(x_coords)] for label, x, y in zip(labels, x_coords, y_coords): context.save() context.move_to(x, y) context.show_text(label) context.restore() # get the image string return cairo_helper.get_image_string()
def get_image(projected_points, nleaves, incidence_matrix, ordered_names, width_and_height, image_format): """ @param projected_points: points projected onto the 2d plane @param nleaves: the first few points are leaves @param incidence_matrix: for drawing connections @param ordered_names: the labels corresponding to rows of the row major matrix @param width_and_height: the dimensions of the output image @param image_format: like 'svg', 'png', 'ps', 'pdf', et cetera @return: a string containing the image data """ width, height = width_and_height n = len(projected_points) # set some values that used to be arguments draw_axes = True draw_connections = True # get eigenvectors scaled to [0, 1] va, vb = projected_points.T.tolist() rescaled_a = get_rescaled_vector(va) rescaled_b = get_rescaled_vector(vb) # create the surface cairo_helper = CairoUtil.CairoHelper(image_format) surface = cairo_helper.create_surface(width, height) context = cairo.Context(surface) # draw the background context.save() context.set_source_rgb(.9, .9, .9) context.paint() context.restore() # define the border border_fraction = .1 # draw the axes if requested if draw_axes: # begin drawing context.save() context.set_source_rgb(.9, .7, .7) # draw the y axis dx = max(va) - min(va) tx = -min(va) / dx xzero = (tx * (1 - 2 * border_fraction) + border_fraction) * width context.move_to(xzero, 0) context.line_to(xzero, height) context.stroke() # draw the x axis dy = max(vb) - min(vb) ty = -min(vb) / dy yzero = (ty * (1 - 2 * border_fraction) + border_fraction) * height context.move_to(0, yzero) context.line_to(width, yzero) context.stroke() # stop drawing context.restore() # draw the connections if requested if draw_connections: # begin drawing context.save() context.set_source_rgb(.8, .8, .8) for i in range(n): for j in range(n): if i < j and incidence_matrix[i][j] > 0: x, y = rescaled_a[i], rescaled_b[i] nx = (x * (1 - 2 * border_fraction) + border_fraction) * width ny = (y * (1 - 2 * border_fraction) + border_fraction) * height context.move_to(nx, ny) x, y = rescaled_a[j], rescaled_b[j] nx = (x * (1 - 2 * border_fraction) + border_fraction) * width ny = (y * (1 - 2 * border_fraction) + border_fraction) * height context.line_to(nx, ny) context.stroke() # stop drawing context.restore() # draw blue internal vertex dots and then green leaf vertex dots dot_radius = 2.0 context.save() leaf_rgba = (0.5, 1.0, 0.5, 0.5) internal_rgba = (0.5, 0.5, 1.0, 0.5) context.set_source_rgba(*internal_rgba) for i, (x, y) in enumerate(zip(rescaled_a, rescaled_b)[nleaves:]): nx = (x * (1 - 2 * border_fraction) + border_fraction) * width ny = (y * (1 - 2 * border_fraction) + border_fraction) * height context.move_to(nx, ny) context.arc(nx, ny, dot_radius, 0, 2 * math.pi) context.fill() context.set_source_rgba(*leaf_rgba) for i, (x, y) in enumerate(zip(rescaled_a, rescaled_b)[:nleaves]): nx = (x * (1 - 2 * border_fraction) + border_fraction) * width ny = (y * (1 - 2 * border_fraction) + border_fraction) * height context.move_to(nx, ny) context.arc(nx, ny, dot_radius, 0, 2 * math.pi) context.fill() context.restore() # draw a scatter plot of the states using the eigenvectors as axes for i, (x, y) in enumerate(zip(rescaled_a, rescaled_b)): state_string = ordered_names[i] nx = (x * (1 - 2 * border_fraction) + border_fraction) * width ny = (y * (1 - 2 * border_fraction) + border_fraction) * height context.move_to(nx, ny) context.show_text(state_string) # get the image string return cairo_helper.get_image_string()
def get_image_string(pvalue_lists, header_list, wild_list, mutant_list, image_format): """ @param pvalue_lists: for each amino acid column, a list of aa pvalues @param wild_list: for each amino acid column, the wild type amino acid @param mutant_list: for each amino acid column, the mutant amino acid @param image_format: something like 'png' """ # start with unrealistic image dimensions to get some font size information initial_width = 100 initial_height = 100 initial_cairo_helper = CairoUtil.CairoHelper(image_format) initial_surface = initial_cairo_helper.create_surface( initial_width, initial_height) initial_context = cairo.Context(initial_surface) initial_context.select_font_face('monospace', cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) initial_context.set_font_size(12) extents = initial_context.font_extents() ascent, descent, font_height, max_x_advance, max_y_advance = extents # get the blank image because multiple surfaces cannot exist simultaneously dummy_string = initial_cairo_helper.get_image_string() # use a standard image width image_width = 640 # Use one row of text for each alignment column header, # and three rows for the axis. image_height = font_height * (3 + len(header_list)) # create the context with realistic image dimensions cairo_helper = CairoUtil.CairoHelper(image_format) surface = cairo_helper.create_surface(image_width, image_height) context = cairo.Context(surface) # set the font size to be used throughout the visualization context.select_font_face('monospace', cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) context.set_font_size(12) # draw a light gray background so you can see it in a white canvas context.save() context.set_source_rgb(.9, .9, .9) context.paint() context.restore() # get the x advance of the longest header max_header_advance = max( context.text_extents(header)[4] for header in header_list) # draw the right-justified headers for i, header in enumerate(header_list): extents = context.text_extents(header) x_bearing, y_bearing, text_w, text_h, x_advance, y_advance = extents x_offset = max_header_advance - x_advance y_offset = font_height * (i + 1) context.move_to(x_offset, y_offset) context.show_text(header) context.stroke() # get the p-value range pvalue_min = min(min(pvalue_list) for pvalue_list in pvalue_lists) pvalue_max = max(max(pvalue_list) for pvalue_list in pvalue_lists) # get the pixel offset to start the x axis x_axis_offset = max_header_advance + max_x_advance # get the pixel width of the x axis x_axis_width = (image_width - max_x_advance) - x_axis_offset # get the number of pixels per log p-value pixels_per_log_pvalue = (x_axis_width / (math.log(pvalue_min) / math.log(10))) # draw the amino acid letters in gray, # but do not draw the wild type or the mutant amino acids context.save() context.set_source_rgb(.7, .7, .7) for header_index, header in enumerate(header_list): y_offset = font_height * (header_index + 1) for aa_index, aa_letter in enumerate(Codon.g_aa_letters): if aa_letter == wild_list[header_index]: continue if aa_letter == mutant_list[header_index]: continue pvalue = pvalue_lists[header_index][aa_index] log_pvalue = math.log(pvalue) / math.log(10) x_offset = x_axis_offset + pixels_per_log_pvalue * log_pvalue context.move_to(x_offset, y_offset) context.show_text(aa_letter) context.stroke() context.restore() # draw the x axis x_axis_y_offset = font_height * (len(header_list) + 0.5) context.save() context.set_line_cap(cairo.LINE_CAP_ROUND) context.move_to(x_axis_offset, x_axis_y_offset) context.line_to(x_axis_offset + x_axis_width, x_axis_y_offset) context.stroke() context.restore() # draw the x axis ticks context.save() context.set_line_cap(cairo.LINE_CAP_ROUND) log_pvalue = 0 while math.exp(log_pvalue) > pvalue_min: x_offset = x_axis_offset + log_pvalue * pixels_per_log_pvalue context.move_to(x_offset, x_axis_y_offset) context.line_to(x_offset, x_axis_y_offset + font_height * 0.5) context.stroke() log_pvalue -= 1 context.restore() # draw the x axis tick labels log_pvalue = 0 while math.exp(log_pvalue) > pvalue_min: x_offset = x_axis_offset + log_pvalue * pixels_per_log_pvalue y_offset = font_height * (len(header_list) + 2) context.move_to(x_offset, y_offset) context.show_text('1E%d' % log_pvalue) context.stroke() log_pvalue -= 1 # make a utility dictionary aa_letter_to_index = {} for i, aa_letter in enumerate(Codon.g_sorted_aa_letters): aa_letter_to_index[aa_letter] = i # draw the wild type amino acids in blue context.save() context.set_source_rgb(0.2, 0.2, 1.0) for header_index, aa_letter in enumerate(wild_list): y_offset = font_height * (header_index + 1) pvalue = pvalue_lists[header_index][aa_letter_to_index[aa_letter]] log_pvalue = math.log(pvalue) / math.log(10) x_offset = x_axis_offset + pixels_per_log_pvalue * log_pvalue context.move_to(x_offset, y_offset) context.show_text(aa_letter) context.stroke() context.restore() # draw the mutant amino acids in red context.save() context.set_source_rgb(1.0, 0.2, 0.2) for header_index, aa_letter in enumerate(mutant_list): y_offset = font_height * (header_index + 1) pvalue = pvalue_lists[header_index][aa_letter_to_index[aa_letter]] log_pvalue = math.log(pvalue) / math.log(10) x_offset = x_axis_offset + pixels_per_log_pvalue * log_pvalue context.move_to(x_offset, y_offset) context.show_text(aa_letter) context.stroke() context.restore() # get the image string return cairo_helper.get_image_string()