def test_one_trace(self): """should still produce a valid figure""" d = Drawable() trace = dict(type="scatter", x=[0, 1], y=[0, 1]) d.add_trace(trace) f = d.figure self.assertEqual(f.data, [trace])
def test_add_traces(self): """test trace add method""" d = Drawable() self.assertEqual(d.traces, []) trace = dict(type="scatter", x=[0, 1], y=[0, 1]) d.add_trace(trace) self.assertEqual(d.traces, [trace]) self.assertTrue(isinstance(d.traces[0], UnionDict))
def test_traces(self): """test trace initialisation""" d = Drawable() self.assertEqual(d.traces, []) trace = dict(type="scatter", x=[0, 1], y=[0, 1]) d = Drawable(traces=[trace]) self.assertEqual(d.traces, [trace]) self.assertTrue(isinstance(d.traces[0], UnionDict)) with self.assertRaises(TypeError): trace = dict(type="scatter", x=[0, 1], y=[0, 1]) _ = Drawable(traces=trace)
def test_layout_with_overrides(self): """provided layout attributes should be overridden with provided parameters""" layout = dict(title="layout", width=20) d = Drawable(layout=layout) fig = d.figure self.assertEqual(fig.layout.title, None) self.assertEqual(fig.layout.width, None) d = Drawable(layout=layout, title="parameter", width=50) fig = d.figure self.assertEqual(fig.layout.title.text, "parameter") self.assertEqual(fig.layout.width, 50)
def test_layout_with_titles(self): """if provided layout has axis titles, keep them""" layout = dict(xaxis=dict(title="X"), yaxis=dict(title="Y")) d = Drawable(layout=layout) fig = d.figure self.assertEqual(fig.layout.xaxis.title, "X") self.assertEqual(fig.layout.yaxis.title, "Y") d = Drawable() fig = d.figure self.assertEqual(fig.layout.xaxis.title, None) self.assertEqual(fig.layout.yaxis.title, None)
def test_bound_to(self): """bound object should have the drawable object and show methods""" class TestObj: pass o = TestObj() d = Drawable() b = d.bound_to(o) self.assertEqual(b.drawable, d) self.assertTrue(hasattr(b, "iplot")) self.assertTrue(hasattr(b, "show"))
def test_figure(self): """figure should contain the same data and layout as Drawable""" trace = dict(type="scatter", x=[0, 1], y=[0, 1]) layout = dict(title="layout", width=20) d = Drawable(traces=[trace], layout=layout) f = d.figure self.assertEqual(f.data, d.traces) self.assertEqual(f.layout, d.layout)
def to_plotly(self, width=500, font_size=12, layout=None, **kwargs): """returns a Plotly Table""" import plotly.graph_objs as go from cogent3.draw.drawable import Drawable rows = self.array.tolist() header, rows = table_format.formatted_cells( rows, self.header, digits=self._digits, column_templates=self._column_templates, missing_data=self._missing_data, center=False, ) # we strip white space padding from header and cells header = [e.strip() for e in header] rows = [[e.strip() for e in row] for row in rows] rows = list(zip(*rows)) if self._row_ids: body_colour = ["white"] * self.shape[0] index_colour = ["rgba(161, 195, 209, 0.5)"] * self.shape[0] colours = [index_colour ] + [body_colour[:] for i in range(self.shape[1])] rows[0] = [f"<b>{e}</b>" for e in rows[0]] else: colours = "white" tab = UnionDict( type="table", header=dict( values=[f"<b>{c}</b>" for c in header], fill=dict(color="rgba(161, 195, 209, 1)"), font=dict(size=font_size), align="center", ), cells=dict(values=rows, fill=dict(color=colours)), ) draw = Drawable() aspect_ratio = self.shape[0] / self.shape[1] layout = layout or {} default_layout = dict( width=width, height=aspect_ratio * width, autosize=False, title=self.title, margin=dict(l=10, r=10, t=30, b=10, pad=10), ) default_layout.update(layout) draw.traces.append(tab) draw.layout |= default_layout return draw
def test__build_fig(self): """figure built should have the same traces as core and set yaxis to y3 if yaxis2 is overlaying""" trace = dict(type="scatter", x=[0, 1], y=[0, 1], xaxis="x", yaxis="y") layout = dict(title="layout", width=20, yaxis2=dict(overlaying="free")) cd = Drawable(traces=[trace]) ad = AnnotatedDrawable(cd, layout=layout) f = ad._build_fig() self.assertEqual(ad._traces, f["data"]) self.assertNotEqual(f["data"][0]["yaxis"], "y3") layout = dict(title="layout", width=20, yaxis2=dict(overlaying="y")) ad = AnnotatedDrawable(cd, layout=layout) f = ad._build_fig() self.assertEqual(f["data"][0]["yaxis"], "y3")
def get_drawable(self, width=600, vertical=False): """returns Drawable instance""" from cogent3.draw.drawable import Drawable drawables = self.get_drawables() if not drawables: return None # we order by tracks top = 0 space = 0.25 annotes = [] for feature_type in drawables: new_bottom = top + space for i, annott in enumerate(drawables[feature_type]): annott.shift(y=new_bottom - annott.bottom) if i > 0: annott._showlegend = False annotes.append(annott) top = annott.top top += space height = max((top / len(self)) * width, 300) xaxis = dict(range=[0, len(self)], zeroline=False, showline=True) yaxis = dict(range=[0, top], visible=False, zeroline=True, showline=True) if vertical: all_traces = [t.T.as_trace() for t in annotes] width, height = height, width xaxis, yaxis = yaxis, xaxis else: all_traces = [t.as_trace() for t in annotes] drawer = Drawable(title=self.name, traces=all_traces, width=width, height=height) drawer.layout.update(xaxis=xaxis, yaxis=yaxis) return drawer
def grid(fig_config, figpath, format, no_type3): """draws an arbitrary shaped grid of mutation motifs based on fig_config""" # we read in the config file and determine number of rows and columns # paths, headings, etc .. # then create the figure and axes and call the mutation_motif drawing code args = locals() if no_type3: util.exclude_type3_fonts() if not figpath: dirname = os.path.dirname(fig_config.name) figpath = os.path.join(dirname, "drawn_array.%s" % format) log_file_path = os.path.join(dirname, "drawn_array.log") else: figpath = util.abspath(figpath) log_file_path = "%s.log" % ".".join(figpath.split(".")[:-1]) util.makedirs(os.path.dirname(figpath)) LOGGER.log_file_path = log_file_path LOGGER.log_message(str(args), label='vars') ncols, nrows, figsize, col_labels, row_labels, paths, axis_cfg = \ read_plot_array_config(fig_config) print("ncols:", ncols) print("nrows:", nrows) print("figsize:", figsize) print("col_labels:", col_labels) print("row_labels:", row_labels) print("paths:", paths) print("axis_cfg:", axis_cfg) #TODO: Convert below into Cogent3 Plotly #-Plotly layout = UnionDict(shapes=[]) adaptive_y = 0 plottable = {} for coord in paths: data = util.load_loglin_stats(paths[coord]) positions = list(data) positions.sort() heights, characters, indices = get_plot_data(data, positions) adaptive_y = max(adaptive_y, logo.est_ylim(heights)) plottable[coord] = dict(char_heights=heights, characters=characters, position_indices=indices) ylim = axis_cfg.get("ylim", adaptive_y) for coord in plottable: kwargs = plottable[coord] kwargs["ax"] = coord kwargs["ylim"] = ylim r = logo.draw_multi_position_cogent3(**kwargs) for key in r: if key == "shapes": layout.shapes.extend(r.shapes) else: layout[key] = r[key] for i in range(0, ncols): xaxis = "xaxis" + str(i + 1 if i != 0 else "") layout[xaxis]["domain"] = [ 0.0 + (i * (1 / ncols)), (i * (1 / ncols)) + (1 / ncols) ] print(layout) MARGININCHES = 0 PPI = 100 fig = Drawable(layout=layout, width=(figsize[0] - MARGININCHES) * PPI, height=(figsize[1] - MARGININCHES) * PPI) #export fig.write(path=figpath) click.secho("Wrote Cogent3 %s" % figpath, fg="green") """
def test_no_trace(self): """should still produce a valid figure""" d = Drawable() f = d.figure self.assertEqual(f.data, [{}])
def get_logo( char_heights, axnum=1, height=400, width=800, ylim=None, ydomain=None, colours=None, layout=None, ): """ Parameters ---------- char_heights a seris of [[(base, value), ..], ..] or series of dicts with [{letter1: value, letter2: value}, ...] Dicts are coerced to list of lists. If values are < 0, the letter is inverted. Empty elements are ignored. axnum : int plotly axis number height, width: int figure dimensions in pixels ylim : float maximum y-value ydomain [start, end], specifies vertical positioning for this logo colours : dict dict mapping characters to colours. Defaults to custom 'dna' colours typically used for DNA layout : UnionDict Customised base layout Returns ------- Drawable """ if isinstance(char_heights, DictArray) or isinstance(char_heights[0], dict): char_heights = _char_hts_as_lists(char_heights) colours = colours or _dna_colours if layout is None: layout = get_base_logo_layout(axnum, 12, 12) stack_data = [] est_ylim = 0 for d in char_heights: if not d: stack_data.append(None) continue d = sorted(d, key=lambda x: x[1]) if ylim is None: est_ylim = max(est_ylim, max([e[-1] for e in d])) stack_data.append(d) stacks = [] for index, stack in enumerate(stack_data): if stack is None: continue middle, stack_shapes = letter_stack(stack, index - 0.5, 1, colours, axnum) stacks += stack_shapes layout["shapes"] = stacks if ylim is None: ylim = est_ylim * 1.05 yaxis = "yaxis" if axnum == 1 else f"yaxis{axnum}" layout[yaxis]["range"] = [0, ylim] if ydomain: layout[yaxis]["domain"] = ydomain return Drawable(layout=layout, height=height, width=width)