def plot(self, ax: Axes): plotted_objects = [] # plot all elements for i, element in enumerate(self.elements): plotted_objects += element.plot(ax) if i > 0: plotted_objects += plotting.plot_maximal_aperture( ax, self.elements[i - 1], element) elif self.obj is not None: plotted_objects += plotting.plot_maximal_aperture( ax, self.obj, element) # plot object if self.obj is not None: plotted_objects += self.obj.plot(ax) # plot rays plotted_objects += self.rays.plot(ax) ax.relim(visible_only=True) ax.autoscale_view() return plotted_objects
def removewave(self, axes: Axes, lines: Line2D): if lines is not None: lines.pop(0).remove() axes.relim() axes.autoscale_view(True, True, True) axes.clear() self.canvas.draw()
def _adjust_axe_timeaxis_view(ax: Axes) -> Axes: locator = AutoDateLocator() daysFmt = DateFormatter("%y%m%d\n%H:%M") ax.xaxis.set_major_locator(locator) ax.xaxis.set_major_formatter(daysFmt) ax.autoscale_view() return ax
class InteractiveGraph(object): def __init__(self, ax): self.ax = Axes(ax.get_figure(), ax.get_position(original=True)) self.ax.set_aspect("equal") self.ax.set_anchor("NE") self._visible_vertices, self._visible_edges = {}, {} self._hidden_vertices, self._hidden_edges = {}, {} self._press_action = "move" self._press_actions = { "move": None, } @property def press_actions(self): return self._press_actions.keys() def add_press_action(self, name, handler): self._press_actions[name] = handler def remove_press_action(self, name): del self._press_actions[name] def set_press_action(self, name): if name not in self._press_actions: raise Exception("Invalid action") self._press_action = name def do_press_action(self, vxid): self._press_actions[self._press_action](vxid) def add_vertex(self, vxid, xy, label, redraw=True, **props): if self.vertex_exists(vxid): raise DuplicateVertexError(vxid) circle = plt.Circle(xy, **props) self.ax.add_patch(circle) vx = Vertex(vxid, self, circle, label, props) vx._connect() self._visible_vertices[vxid] = vx if redraw: self.ax.figure.canvas.draw() def update_vertex_props(self, vxid, redraw=True, **props): vx = self.get_vertex(vxid) vx.update_circle_props(**props) if redraw: self.ax.figure.canvas.draw() def restore_vertex_props(self, vxid, redraw=True): vx = self.get_vertex(vxid) vx.restore_circle_props() if redraw: self.ax.figure.canvas.draw() def add_edge(self, edge_id, src_id, tgt_id, redraw=True, **props): if not self.vertex_exists(src_id): raise NonexistentVertexError(src_id, "add edge") elif not self.vertex_exists(tgt_id): raise NonexistentVertexError(tgt_id, "add edge") if self.edge_exists(edge_id): edge = self.get_edge(edge_id) src, tgt = edge.source, edge.target raise DuplicateEdgeError(edge_id, src, tgt, "add edge", "edge id already exists") if src_id == tgt_id: src = self.get_vertex(src_id) src.add_loop(edge_id) else: src, tgt = self.get_vertex(src_id), self.get_vertex(tgt_id) src.add_out_edge(edge_id) tgt.add_in_edge(edge_id) edge = Edge(edge_id, self, src_id, tgt_id, **props) if self.vertex_visible(src_id) and self.vertex_visible(tgt_id): self._visible_edges[edge_id] = edge else: self._hidden_edges[edge_id] = edge def hide_vertex(self, vxid, redraw=True): if not self.vertex_exists(vxid): raise NonexistentVertexError(vxid, "hide") elif not self.vertex_visible(vxid): raise VertexActionError(vxid, "hide", "vertex already hidden") vertex = self.get_vertex(vxid) self._hidden_vertices[vxid] = self._visible_vertices.pop(vxid) for edge_id in vertex.loops & self.visible_edges: self._hidden_edges[edge_id] = self._visible_edges.pop(edge_id) for edge_id in vertex.in_edges & self.visible_edges: self._hidden_edges[edge_id] = self._visible_edges.pop(edge_id) self.get_edge(edge_id).hide() for edge_id in vertex.out_edges & self.visible_edges: self._hidden_edges[edge_id] = self._visible_edges.pop(edge_id) self.get_edge(edge_id).hide() vertex.hide() if redraw: self.ax.figure.canvas.draw() def hide_edge(self, edge_id, redraw=True): if not self.edge_exists(edge_id): raise NonexistentEdgeError(edge_id, None, None, "hide") elif not self.edge_visible(edge_id): raise EdgeActionError(edge_id, "hide", "edge already hidden") self._hidden_edges[edge_id] = self._visible_edges.pop(edge_id) edge = self.get_edge(edge_id) if edge.source != edge.target: edge.hide() if redraw: self.ax.figure.canvas.draw() def restore_vertex(self, vxid, redraw=True): if not self.vertex_exists(vxid): raise NonexistentVertexError(vxid, "restore") if self.vertex_visible(vxid): raise VertexActionError(vxid, "restore", "vertex already visible") vertex = self.get_vertex(vxid) for edge_id in vertex.in_edges: edge = self.get_edge(edge_id) if self.vertex_visible(edge.source): self._visible_edges[edge_id] = self._hidden_edges.pop(edge_id) edge.restore(self.ax) for edge_id in vertex.out_edges: edge = self.get_edge(edge_id) if self.vertex_visible(edge.target): self._visible_edges[edge_id] = self._hidden_edges.pop(edge_id) edge.restore(self.ax) for edge_id in vertex.loops: self._visible_edges[edge_id] = self._hidden_edges.pop(edge_id) self._visible_vertices[vxid] = self._hidden_vertices.pop(vxid) vertex.restore(self.ax) if redraw: self.ax.figure.canvas.draw() def restore_edge(self, edge_id, redraw=True): if not self.edge_exists(edge_id): raise NonexistentEdgeError(edge_id, None, None, "restore") elif self.edge_visible(edge_id): edge = self.get_edge(edge_id) src_id, tgt_id = edge.source, edge.target raise EdgeActionError(edge_id, src_id, tgt_id, "restore", "edge already visible") edge = self.get_edge(edge_id) src_id, tgt_id = edge.source, edge.target if not self.vertex_visible(src_id): raise EdgeActionError(edge_id, src_id, tgt_id, "restore", "source vertex is hidden") if not self.vertex_visible(tgt_id): raise EdgeActionError(edge_id, src_id, tgt_id, "restore", "target vertex is hidden") self._visible_edges[edge_id] = self._hidden_edges.pop(edge_id) if src_id != tgt_id: edge.restore(self.ax) if redraw: self.ax.figure.canvas.draw() def remove_vertex(self, vxid, redraw=True): if not self.vertex_exists(vxid): raise NonexistentVertexError(vxid, "remove") vertex = self._visible_vertices[vxid] for edge_id in vertex.loops & self.visible_edges: edge = self._visible_edges.pop(edge_id) for edge_id in vertex.loops & self.hidden_edges: edge = self._hidden_edges.pop(edge_id) for edge_id in (vertex.in_edges | vertex.out_edges) & self.visible_edges: edge = self._visible_edges.pop(edge_id) edge.hide() for edge_id in (vertex.in_edges | vertex.out_edges) & self.hidden_edges: edge = self._hidden_edges.pop(edge_id) edge.hide() if self.vertex_visible: self._visible_vertices.pop(vxid) else: self._hidden_vertices.pop(vxid) vertex.remove() if redraw: self.ax.figure.canvas.draw() def remove_edge(self, edge_id, redraw=True): if not self.edge_exists(edge_id): raise NonexistentEdgeError(edge_id, "remove") if self.edge_visible(edge_id): edge = self._visible_edges.pop(edge_id) else: edge = self._hidden_edges.pop(edge_id) src_id, tgt_id = edge.source, edge.target src, tgt = self.get_vertex(src_id), self.get_vertex(tgt_id) if src_id == tgt_id: src.remove_loop(edge_id) else: src.remove_out_edge(edge_id) tgt.remove_in_edge(edge_id) edge.hide() if redraw: self.ax.figure.canvas.draw() def redraw(action): def f(self, *args, **kwargs): result = action(self, *args, **kwargs) self.ax.figure.canvas.draw() return result return f @redraw def add_vertices(self, vertices, **props): return filter( lambda v: v is not None, [self.add_vertex(*vx, redraw=False, **props) for vx in vertices]) @redraw def update_vertices_props(self, vertices, **props): return filter(lambda v: v is not None, [ self.update_vertex_props(vx, redraw=False, **props) for vx in vertices ]) @redraw def restore_vertices_props(self, vertices): return filter( lambda v: v is not None, [self.restore_vertex_props(vx, redraw=False) for vx in vertices]) @redraw def add_edges(self, edges, **props): return filter( lambda v: v is not None, [self.add_edge(*e, redraw=False, **props) for e in edges]) @redraw def hide_vertices(self, vertices): return filter(lambda v: v is not None, [self.hide_vertex(vx, False) for vx in vertices]) @redraw def hide_edges(self, edge_ids): return filter(lambda v: v is not None, [self.hide_edge(e, False) for e in edge_ids]) @redraw def restore_vertices(self, vertices): return filter(lambda v: v is not None, [self.restore_vertex(vx, False) for vx in vertices]) @redraw def restore_edges(self, edge_ids): return filter(lambda v: v is not None, [self.restore_edge(e, False) for e in edge_ids]) @redraw def remove_vertices(self, vertices): return filter(lambda v: v is not None, [self.remove_vertex(vx, False) for vx in vertices]) @redraw def remove_edges(self, edge_ids): return filter(lambda v: v is not None, [self.remove_edge(e, False) for e in edge_ids]) @redraw def restore_all(self): return filter( lambda v: v is not None, [self.restore_vertex(vx, False) for vx in self.hidden_vertices] + [self.restore_edge(e, False) for e in self.hidden_edges]) @redraw def clear(self): return filter(lambda v: v is not None, [ self.remove_vertex(vx, False) for vx in self._hidden_vertices.keys() + self._visible_vertices.keys() ] + [ self.remove_edge(e, False) for e in self._hidden_edges.keys() + self._visible_edges.keys() ]) @property def vertices(self): return set(self._visible_vertices.keys()) | set( self._hidden_vertices.keys()) @property def edges(self): return set(self._visible_edges.keys()) | set(self._hidden_edges.keys()) @property def visible_vertices(self): return set(self._visible_vertices.keys()) @property def visible_edges(self): return set(self._visible_edges.keys()) @property def hidden_vertices(self): return set(self._hidden_vertices.keys()) @property def hidden_edges(self): return set(self._hidden_edges.keys()) def vertex_exists(self, vxid): return vxid in self.vertices def edge_exists(self, edge_id): return edge_id in self.edges def vertex_visible(self, vxid): return vxid in self.visible_vertices def edge_visible(self, edge_id): return edge_id in self.visible_edges def get_vertex(self, vxid): if vxid in self._visible_vertices: return self._visible_vertices[vxid] elif vxid in self._hidden_vertices: return self._hidden_vertices[vxid] else: raise NonexistentVertexError(vxid, "get") def get_edge(self, edge_id): if edge_id in self._visible_edges: return self._visible_edges[edge_id] elif edge_id in self._hidden_edges: return self._hidden_edges[edge_id] else: raise NonexistentVertexError(vxid, "get") def get_edges(self, vertices): edges = set() for vxid in vertices: vertex = self.get_vertex(vxid) for edge_id in vertex.out_edges: edge = self.get_edge(edge_id) if edge.target in vertices: edges.add(edge_id) return edges def filter_edges(self, vxid, vertices): edges = set() vertex = self.get_vertex(vxid) for edge_id in vertex.edges: edge = self.get_edges(edge_id) if edge.source in vertices or edge.target in vertices: edges.add(edge_id) return edges def reset_view(self): self.ax.set_autoscale_on(True) self.ax.relim() self.ax.autoscale_view() self.ax.figure.canvas.toolbar.update()
def map(h2: Histogram2D, ax: Axes, *, show_zero: bool = True, show_values: bool = False, show_colorbar: bool = True, x=None, y=None, **kwargs): """Coloured-rectangle plot of 2D histogram. Parameters ---------- show_zero : Whether to show coloured box for bins with 0 frequency (otherwise background). show_values : Whether to show labels with frequencies/densities in the middle of the bin text_color : Optional Colour of text descriptions text_alpha : Optional[float] Alpha for the text labels only x : Optional[Callable] Transformation of x bin coordinates y : Optional[Callable] Transformation of y bin coordinates zorder : float z-order in the axis (higher number above lower) See Also -------- image, polar_map, surface_map Notes ----- If you transform axes using x or y parameters, the deduction of axis limits does not work well automatically. Please, make sure to attend to it yourself. The densities in transformed maps are calculated from original bins. """ # Detect transformation transformed = False if x is not None or y is not None: if not x: x = lambda x, y: x if not y: y = lambda x, y: y transformed = True value_format = kwargs.pop("value_format", lambda x: str(x)) # TODO: Implement correctly the text_kwargs if isinstance(value_format, str): format_str = "{0:" + value_format + "}" value_format = lambda x: format_str.format(x) rect_args = {} if "zorder" in kwargs: rect_args["zorder"] = kwargs.pop("zorder") data = get_data(h2, cumulative=False, flatten=True, density=kwargs.pop("density", False)) cmap = _get_cmap(kwargs) norm, cmap_data = _get_cmap_data(data, kwargs) colors = cmap(cmap_data) xpos, ypos = (arr.flatten() for arr in h2.get_bin_left_edges()) dx, dy = (arr.flatten() for arr in h2.get_bin_widths()) text_x, text_y = (arr.flatten() for arr in h2.get_bin_centers()) _apply_xy_lims(ax, h2, data=data, kwargs=kwargs) _add_labels(ax, h2, kwargs) ax.autoscale_view() alphas = _get_alpha_data(cmap_data, kwargs) if np.isscalar(alphas): alphas = np.ones_like(data) * alphas for i in range(len(xpos)): bin_color = colors[i] alpha = alphas[i] if data[i] != 0 or show_zero: if not transformed: rect = plt.Rectangle([xpos[i], ypos[i]], dx[i], dy[i], facecolor=bin_color, edgecolor=kwargs.get( "grid_color", cmap(0.5)), lw=kwargs.get("lw", 0.5), alpha=alpha, **rect_args) tx, ty = text_x[i], text_y[i] else: # See http://matplotlib.org/users/path_tutorial.html points = ((xpos[i], ypos[i]), (xpos[i] + dx[i], ypos[i]), (xpos[i] + dx[i], ypos[i] + dy[i]), (xpos[i], ypos[i] + dy[i]), (xpos[i], ypos[i])) verts = [(x(*p), y(*p)) for p in points] codes = [ path.Path.MOVETO, path.Path.LINETO, path.Path.LINETO, path.Path.LINETO, path.Path.CLOSEPOLY, ] rect_path = path.Path(verts, codes) rect = patches.PathPatch(rect_path, facecolor=bin_color, edgecolor=kwargs.get( "grid_color", cmap(0.5)), lw=kwargs.get("lw", 0.5), alpha=alpha, **rect_args) tx = x(text_x[i], text_y[i]) ty = y(text_x[i], text_y[i]) ax.add_patch(rect) if show_values: text = value_format(data[i]) yiq_y = np.dot(bin_color[:3], [0.299, 0.587, 0.114]) text_color = kwargs.get("text_color", None) if not text_color: if yiq_y > 0.5: text_color = (0.0, 0.0, 0.0, kwargs.get("text_alpha", alpha)) else: text_color = (1.0, 1.0, 1.0, kwargs.get("text_alpha", alpha)) ax.text(tx, ty, text, horizontalalignment='center', verticalalignment='center', color=text_color, clip_on=True, **rect_args) if show_colorbar: _add_colorbar(ax, cmap, cmap_data, norm)
def plot_extended_boxplot(ax: Axes, boxplot_stats: List[dict], positions: Optional[List[float]] = None, vert=True, showmeans: bool = True, showminmax: bool = True, offscale_minmax: bool = False, minmaxfmt='{:.1f}', manage_ticks: bool = True) -> None: """ Arguments like https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.bxp.html. offscale_minmax: Whether the min/max values should be labelled and drawn at a fixed location independent of the y scale. Useful when the min/max values are very different from the outer percentiles. """ N = len(boxplot_stats) if positions is None: positions = list(range(1, len(boxplot_stats) + 1)) elif len(positions) != N: raise ValueError( 'List of boxplot statistics and positions values must have the same length' ) # TODO: this could be made a function of number of percentiles boxplot_facecolors = ['0.25', '0.50', '0.75', 'white'] if any( len(stats['percentiles']) > 2 * len(boxplot_facecolors) for stats in boxplot_stats): raise NotImplementedError('Too many percentiles') if vert: def doplot(*args, **kwargs): return ax.plot(*args, **kwargs) def doannotate(*args, **kwargs): return ax.annotate(*args, **kwargs) def dohlines(*args, **kwargs): return ax.hlines(*args, **kwargs) def dovlines(*args, **kwargs): return ax.vlines(*args, **kwargs) def doset_xmargin(*args, **kwargs): return ax.set_xmargin(*args, **kwargs) def doset_ymargin(*args, **kwargs): return ax.set_ymargin(*args, **kwargs) else: def doplot(*args, **kwargs): shuffled = [] for i in range(0, len(args), 2): shuffled.extend([args[i + 1], args[i]]) return ax.plot(*shuffled, **kwargs) def doannotate(*args, **kwargs): xy = kwargs.pop('xy') xy = (xy[1], xy[0]) xytext = kwargs.pop('xytext', None) if xytext: xytext = (xytext[1], xytext[0]) ha_ = kwargs.pop('ha') va_ = kwargs.pop('va') if ha_ == 'center' and va_ == 'top': ha = 'right' va = 'center_baseline' elif ha_ == 'center' and va_ == 'bottom': ha = 'left' va = 'center_baseline' else: raise NotImplementedError return ax.annotate(*args, xy=xy, xytext=xytext, ha=ha, va=va, **kwargs) dohlines = ax.vlines dovlines = ax.hlines doset_xmargin = ax.set_ymargin doset_ymargin = ax.set_xmargin if offscale_minmax: buffer = 0.2 percentile_min = min(s['percentiles'][0] for s in boxplot_stats) percentile_max = max(s['percentiles'][-1] for s in boxplot_stats) percentile_range = abs(percentile_max - percentile_min) thresh_min = percentile_min - percentile_range * buffer thresh_max = percentile_max + percentile_range * buffer gap_start = 0.8 gap_end = 0.85 gap_min_start = percentile_min - percentile_range * (buffer * gap_start) gap_min_end = percentile_min - percentile_range * (buffer * gap_end) gap_max_start = percentile_max + percentile_range * (buffer * gap_start) gap_max_end = percentile_max + percentile_range * (buffer * gap_end) gap_linewidth = 0.5 def get_boxplot_x0(boxplot_center, boxplot_width): boxplot_x0 = boxplot_center - boxplot_width / 2 return boxplot_x0 need_y_margin = False labels = [] for stats, position in zip(boxplot_stats, positions): labels.append( stats['label'] if stats['label'] is not None else position) percentiles = stats['percentiles'] # Compute the number of iterations based on the number of percentiles percentiles_num_iter = int( len(percentiles) / 2 ) # List of percentiles are always pairs so always a multiple of 2 outermost_boxplot_width = 0.3 boxplot_width = outermost_boxplot_width for index in range(percentiles_num_iter): x = get_boxplot_x0(position, boxplot_width) y = percentiles[index] width = boxplot_width height = percentiles[-index - 1] - percentiles[index] if not vert: width, height = height, width x, y = y, x r = Rectangle((x, y), width, height, facecolor=boxplot_facecolors[index], fill=True, edgecolor='k') ax.add_patch(r) if index + 1 < percentiles_num_iter: boxplot_width = boxplot_width * 1.3 x0 = get_boxplot_x0(position, boxplot_width) x1 = x0 + boxplot_width dohlines(stats['median'], x0, x1, colors='r', linestyles='solid') if showmeans: doplot(position, stats['mean'], marker='o', markersize=3, color="k") if showminmax: x0 = get_boxplot_x0(position, outermost_boxplot_width) x1 = x0 + outermost_boxplot_width # For the bottom if stats['median'] != percentiles[0]: if offscale_minmax and stats['min'] < thresh_min: dovlines(position, percentiles[0], gap_min_start, colors='k', linestyles='solid') dovlines(position, gap_min_end, thresh_min, colors='k', linestyles='solid') dy = 0.3 * (gap_min_start - gap_min_end) doplot([x0, x1], [gap_min_start - dy, gap_min_start + dy], color='k', lw=gap_linewidth) doplot([x0, x1], [gap_min_end - dy, gap_min_end + dy], color='k', lw=gap_linewidth) text_buffer = 2 * (gap_min_start - gap_min_end) doannotate(minmaxfmt.format(stats['min']), xy=(position, thresh_min - text_buffer), ha='center', va='top', color='k') need_y_margin = True else: dovlines(position, percentiles[0], stats['min'], colors='k', linestyles='solid') # For the top if stats['median'] != percentiles[-1]: if offscale_minmax and stats['max'] > thresh_max: dovlines(position, percentiles[-1], gap_max_start, colors='k', linestyles='solid') dovlines(position, gap_max_end, thresh_max, colors='k', linestyles='solid') dy = 0.3 * (gap_max_end - gap_max_start) doplot([x0, x1], [gap_max_start - dy, gap_max_start + dy], color='k', lw=gap_linewidth) doplot([x0, x1], [gap_max_end - dy, gap_max_end + dy], color='k', lw=gap_linewidth) text_buffer = 2 * (gap_max_end - gap_max_start) doannotate(minmaxfmt.format(stats['max']), xy=(position, thresh_max + text_buffer), ha='center', va='bottom', color='k') need_y_margin = True else: dovlines(position, percentiles[-1], stats['max'], colors='k', linestyles='solid') if need_y_margin: doset_ymargin(0.1) if manage_ticks: doset_xmargin(0.05) axis_name = "x" if vert else "y" axis = getattr(ax, f"{axis_name}axis") locator = axis.get_major_locator() if not isinstance(axis.get_major_locator(), mticker.FixedLocator): locator = mticker.FixedLocator([]) axis.set_major_locator(locator) locator.locs = np.array([*locator.locs, *positions]) formatter = axis.get_major_formatter() if not isinstance(axis.get_major_formatter(), mticker.FixedFormatter): formatter = mticker.FixedFormatter([]) axis.set_major_formatter(formatter) formatter.seq = [*formatter.seq, *labels] ax.autoscale_view()
def autoscale_view(self, scalex=True, scaley=True): Axes.autoscale_view(self, scalex=scalex, scaley=scaley) self.calcWcsBbox()