def fig(self): fig, axes = plt.subplots(nrows=self.nrows, ncols=self.ncols, figsize=self.figsize) divider = Divider(fig, (0.0, 0.0, 1.0, 1.0), self.h, self.v, aspect=False) if (self.nrows == 1) & (self.ncols == 1): axes = [axes] axes[0].set_axes_locator(divider.new_locator(nx=1, ny=1)) if self.n_axes > 1: for i in range(self.n_axes-1): axes.append(fig.add_subplot(111)) axes[i+1].set_axes_locator(divider.new_locator(nx=1, ny=1)) elif self.nrows > 1: for j in range(self.nrows): axes[j].set_axes_locator(divider.new_locator(nx=1, ny=j*2+1)) elif self.ncols > 1: for i in range(self.ncols): axes[i].set_axes_locator(divider.new_locator(nx=i*2+1, ny=1)) if (self.nrows > 1) & (self.ncols > 1): for j in range(self.nrows): for i in range(self.ncols): axes[i, j].set_axes_locator(divider.new_locator(nx=i*2+1, ny=j*2+1)) return fig, axes
def demo_fixed_pad_axes(): fig = plt.figure(2, (6, 6)) # The first & third items are for padding and the second items are for the axes. # sizes are in inch. h = [ Size.Fixed(1.0), Size.Scaled(1.), Size.Fixed(.2), ] v = [ Size.Fixed(0.7), Size.Scaled(1.), Size.Fixed(.5), ] divider = Divider(fig, (0.0, 0.0, 1., 1.), h, v, aspect=False) # the width and height of the rectangle is ignored. ax = LocatableAxes(fig, divider.get_position()) ax.set_axes_locator(divider.new_locator(nx=1, ny=1)) fig.add_axes(ax) ax.plot([1, 2, 3])
def metric_svg(self, host=None, title="undefined", ylabel="undefined", metrics=[], b64encode=True): fig = pyplot.figure(figsize=self.FIGSIZE) h = [Size.Fixed(1.2), Size.Scaled(1.), Size.Fixed(.2)] v = [Size.Fixed(0.7), Size.Scaled(1.), Size.Fixed(.5)] divider = Divider(fig, (0.0, 0.0, 1., 1.), h, v, aspect=False) plt = Axes(fig, divider.get_position()) plt.set_axes_locator(divider.new_locator(nx=1, ny=1)) fig.add_axes(plt) result = self.result runinfo = result.runinfo # ---- # The X limits are -rampupMins, runMins # ---- plt.set_xlim(-int(runinfo['rampupMins']), int(runinfo['runMins'])) plt.axvspan(-int(runinfo['rampupMins']), 0, facecolor='0.2', alpha=0.1) # ---- # Draw all the requested graphs # ---- x = None for m in metrics: if x is None: x, y = self._get_metric_tree(m) else: _, y = self._get_metric_tree(m, x) plt.plot(x, y, m['color'], label=m['label']) # ---- # Title and labels # ---- plt.set_title(title) plt.set_xlabel("Elapsed Minutes") plt.set_ylabel(ylabel) plt.legend(loc='upper left') plt.grid() # ---- # Now turn this into an in-memory SVG and return it as requested # (raw or b64-encoded) # ---- buf = io.StringIO() pyplot.savefig(buf, format='svg') if not b64encode: return buf.getvalue() return base64.b64encode(buf.getvalue().encode('utf-8')).decode('utf-8')
def plot_it(): # fig = plt.figure(1, figsize=(8, 4.5)) fig = plt.figure(1, figsize=(16, 12)) # h = [Size.Fixed(0.), Size.Fixed(6.5)] # v = [Size.Fixed(0.5), Size.Fixed(3.25)] h = [Size.Fixed(0.), Size.Fixed(13)] v = [Size.Fixed(0.5), Size.Fixed(7)] win = Divider(fig, (0.1, 0.08, 0.8, 0.8), h, v, aspect=False) ax = Axes(fig, win.get_position()) ax.set_axes_locator(win.new_locator(nx=1, ny=1)) fig.add_axes(ax) # fig = plt.figure(figsize=(16, 12)) # ax = fig.add_subplot(111) for ii, ellipse in enumerate(ellipses): ax.fill(ellipse[0], ellipse[1], color=cmap(norm_vals[ii]), zorder=0) ax.plot(ellipse[0], ellipse[1], 'k-', linewidth=0.2) ax.invert_yaxis() plt.xlabel('Northing (km)', fontsize=16) plt.ylabel(r'$\log_{10}$ Period (s)', fontsize=16) # ax.set_aspect(1) ax.tick_params(axis='both', labelsize=14) # locs, labels = plt.xticks() # plt.xticks(locs, [int(x * 10) for x in locs]) fake_vals = np.linspace(lower, upper, len(fill_vals)) fake_im = ax.scatter(loc, periods, c=fake_vals, cmap=cmap) fake_im.set_visible(False) # ax.set_ylim([-2.6, 3.25]) # ax.set_xlim([526.5, 538.2]) # ax.invert_yaxis() # cb = plt.colorbar(mappable=fake_im) ############################################# # Colour bar and site labelling # cbaxes = fig.add_axes([0.925, 0.1351, 0.015, 0.72]) # cb = plt.colorbar(fake_im) # if 'phi' in fill_param[:3]: # label = r'${}{}(\degree)$'.format('\phi', fill_param[-2:]) # else: # label = r'$\{}(\degree)$'.format(fill_param) # cb.set_label(label, # rotation=270, # labelpad=20, # fontsize=18) # ax.tick_params(axis='both', labelsize=14) # ax.set_xlim(x_lim) # for ii, site in enumerate(main_sites): # txt = site[-4:-1] # if linear_xaxis: # ax.text(linear_site[ii], # label_offset, site, rotation=45) # 3.6 # else: # ax.text(main_transect.sites[site].locations['X'], # label_offset, site, rotation=45) # 3.6 plt.show() return fig
def __init__(self, ax_size, wspace, dpi, cbar, cbar_width, left, bottom, right, top, fig_func=None): if not cbar: wspace = 0 cbar_width = 0 # convert arguments from pixels to inches ax_size = np.asarray(ax_size) / dpi wspace, cbar_width, left, bottom, right, top = np.array( (wspace, cbar_width, left, bottom, right, top)) / dpi horiz = [left, ax_size[0], wspace, cbar_width, right] vert = [bottom, ax_size[1], top] figsize = (sum(horiz), sum(vert)) fig_func = plt.figure if fig_func is None else fig_func fig = fig_func(figsize=figsize, dpi=dpi) horiz, vert = list(map(Size.Fixed, horiz)), list(map(Size.Fixed, vert)) divider = Divider(fig, (0.0, 0.0, 1., 1.), horiz, vert, aspect=False) ax = LocatableAxes(fig, divider.get_position()) ax.set_axes_locator(divider.new_locator(nx=1, ny=1)) fig.add_axes(ax) if cbar: cax = LocatableAxes(fig, divider.get_position()) cax.set_axes_locator(divider.new_locator(nx=3, ny=1)) fig.add_axes(cax) self.fig = fig self.ax = ax self.cax = cax if cbar else None
def _set_ax_height_to_cm(fig: Fig, ax: Ax, height: float) -> None: from mpl_toolkits.axes_grid1 import Size, Divider height /= 2.54 # cm to inches bbox = _get_ax_bbox(fig, ax) hori = [Size.Fixed(bbox.x0), Size.Fixed(bbox.width), Size.Fixed(bbox.x1)] vert = [Size.Fixed(bbox.y0), Size.Fixed(height), Size.Fixed(bbox.y1)] divider = Divider(fig, (0.0, 0.0, 1.0, 1.0), hori, vert, aspect=False) ax.set_axes_locator(divider.new_locator(nx=1, ny=1))
def demo_fixed_size_axes(): fig = plt.figure(figsize=(6, 6)) # The first items are for padding and the second items are for the axes. # sizes are in inch. h = [Size.Fixed(1.0), Size.Fixed(4.5)] v = [Size.Fixed(0.7), Size.Fixed(5.)] divider = Divider(fig, (0.0, 0.0, 1., 1.), h, v, aspect=False) # the width and height of the rectangle is ignored. ax = Axes(fig, divider.get_position()) ax.set_axes_locator(divider.new_locator(nx=1, ny=1)) fig.add_axes(ax) ax.plot([1, 2, 3])
def demo_fixed_size_axes(): fig1 = plt.figure(1, (10, 5)) # The first items are for padding and the second items are for the axes. # sizes are in inch. h = [Size.Fixed(1.0), Size.Fixed(7.5)] v = [Size.Fixed(0.7), Size.Fixed(4.5)] divider = Divider(fig1, (0.0, 0.0, 1., 1.), h, v, aspect=False) # the width and height of the rectangle is ignored. ax = LocatableAxes(fig1, divider.get_position()) ax.set_axes_locator(divider.new_locator(nx=1, ny=1)) fig1.add_axes(ax) ax.plot([1, 2, 3])
def demo_fixed_pad_axes(): fig = plt.figure(2, (6, 6)) # The first & third items are for padding and the second items are for the # axes. Sizes are in inches. h = [Size.Fixed(1.0), Size.Scaled(1.), Size.Fixed(.2)] v = [Size.Fixed(0.7), Size.Scaled(1.), Size.Fixed(.5)] divider = Divider(fig, (0.0, 0.0, 1., 1.), h, v, aspect=False) # the width and height of the rectangle is ignored. ax = LocatableAxes(fig, divider.get_position()) ax.set_axes_locator(divider.new_locator(nx=1, ny=1)) fig.add_axes(ax) ax.plot([1, 2, 3])
def fix_sz_fig(width, height, width_ext=2, padding=.5): # These code is to make fixed size article # Makesure matplotlib can draw Chinese characters plt.rcParams['font.sans-serif'] = ['SimHei'] # Init figure fig = plt.figure(figsize=(width + 2 * padding + width_ext, height + 2 * padding)) # The first items are for padding and the second items are for the axes. # Article width and height w = [Size.Fixed(padding), Size.Fixed(width)] h = [Size.Fixed(padding), Size.Fixed(height)] divider = Divider(fig, (0.0, 0.0, 1., 1.), w, h, aspect=False) # the width and height of the rectangle is ignored. ax = Axes(fig, divider.get_position()) ax.set_axes_locator(divider.new_locator(nx=1, ny=1)) fig.add_axes(ax) return fig, ax
def create_plot(two_sided=False, colors=[ '#6F4C9B', '#5568B8', '#4D8AC6', '#60AB9E', '#77B77D', '#A6BE54', '#D1B541', '#E49C39', '#DF4828', '#990D38' ], markers=['o', 'v', '^', 's', 'D', '*'], figsize=(5, 3.4)): """ Crée un environnement de plot Parameters ---------- twosided : bool allows to change the size of the figure accordingly. colors : list of strings a default list exists but this allows to change it if u want markers : list of strings a default list of markers exists, but u can change it if needed Returns ------- fig, ax : matplotlib objects to be used as normal """ color = cycle(colors) marker = cycle(markers) if two_sided: fig = plt.figure(figsize=(3.4, 3.4)) else: fig = plt.figure(figsize=figsize) # The first & third items are for padding and the second items are for the # axes. Sizes are in inches. h = [Size.Fixed(1.0), Size.Scaled(1.), Size.Fixed(.2)] v = [Size.Fixed(0.7), Size.Scaled(1.), Size.Fixed(.5)] divider = Divider(fig, (0.0, 0.0, 1., 1.), h, v, aspect=False) # the width and height of the rectangle is ignored. ax = Axes(fig, divider.get_position()) ax.set_axes_locator(divider.new_locator(nx=1, ny=1)) fig.add_axes(ax) return fig, ax, color, marker
def set_size3(ax, w, h): # https://newbedev.com/axes-class-set-explicitly-size-width-height-of-axes-in-given-units from mpl_toolkits.axes_grid1 import Divider, Size axew = w / 2.54 axeh = h / 2.54 # lets use the tight layout function to get a good padding size for our axes labels. # fig = plt.gcf() # ax = plt.gca() fig = ax.get_figure() fig.tight_layout() # obtain the current ratio values for padding and fix size oldw, oldh = fig.get_size_inches() l = ax.figure.subplotpars.left r = ax.figure.subplotpars.right t = ax.figure.subplotpars.top b = ax.figure.subplotpars.bottom # work out what the new ratio values for padding are, and the new fig size. # ps: adding a bit to neww and newh gives more padding # the axis size is set from axew and axeh neww = axew + oldw * (1 - r + l) + 0.4 newh = axeh + oldh * (1 - t + b) + 0.4 newr = r * oldw / neww - 0.4 newl = l * oldw / neww + 0.4 newt = t * oldh / newh - 0.4 newb = b * oldh / newh + 0.4 # right(top) padding, fixed axes size, left(bottom) pading hori = [Size.Scaled(newr), Size.Fixed(axew), Size.Scaled(newl)] vert = [Size.Scaled(newt), Size.Fixed(axeh), Size.Scaled(newb)] divider = Divider(fig, (0.0, 0.0, 1.0, 1.0), hori, vert, aspect=False) # the width and height of the rectangle is ignored. ax.set_axes_locator(divider.new_locator(nx=1, ny=1)) # we need to resize the figure now, as we have may have made our axes bigger than in. fig.set_size_inches(neww, newh)
def subplot_array(self, hsize, vsize=(1.0, ), figsize=(10, 10)): """ Use the axes_divider module to make a single row of plots hsize : list of floats horizontal spacing: alternates Scaled for plot, Fixed for between plots vsize : list of floats vertical spacing ref: http://matplotlib.org/mpl_toolkits/axes_grid/users/axes_divider.html """ nx = (len(hsize) + 1) / 2 ny = (len(vsize) + 1) / 2 fig, axx = plt.subplots( ny, nx, squeeze=False, figsize=figsize) # just to make the axes, will move them sizer = lambda x, i: axes_size.Scaled( x) if i % 2 == 0 else axes_size.Fixed(x) horiz = [sizer(h, i) for i, h in enumerate(hsize)] vert = [sizer(v, i) for i, v in enumerate(vsize)] divider = Divider(fig, (0.1, 0.1, 0.8, 0.8), horiz, vert, aspect=False) for i, ax in enumerate(axx.flatten()): iy = i // nx ix = i % nx ax.set_axes_locator(divider.new_locator(nx=2 * ix, ny=2 * iy)) return fig, axx
# <markdowncell> # make_axes_locatable() gives one way to handle this, by giving the append_axes() method. Another way is by creating a Divider object and giving it the layout up front. # <codecell> from mpl_toolkits.axes_grid1 import Size, Divider fig = plt.figure() ax = [fig.add_axes([0.1,0.1,0.8,0.8], label='%d'%i) for i in range(3)] # Create 3 Axes to be sized later horiz = [Size.Scaled(2), Size.Fixed(0.5), Size.Scaled(3), Size.Fixed(0.01)] vert = [Size.Scaled(1), Size.Fixed(0.5), Size.Scaled(1)] div = Divider(fig, (0.1, 0.1, 0.8, 0.8), horiz, vert, aspect=False) ax[0].set_axes_locator(div.new_locator(nx=0, ny=0)) ax[1].set_axes_locator(div.new_locator(nx=2, ny=0)) ax[2].set_axes_locator(div.new_locator(nx=0, nx1=2, ny=2)) ax[0].plot(t, x1) ax[1].plot(t, x2) ax[2].plot(t, x3) # <rawcell> # One obvious application of this is for doing grid of plots with colorbars. For this use case we can go one step further and make use of the ImageGrid class. # <codecell> from mpl_toolkits.axes_grid1 import ImageGrid x = y = np.linspace(-3, 3, 300)
os.remove(temppath) size(W, HEIGHT+dy+40) else: def pltshow(mplpyplot): mplpyplot.show() # nodebox section end fig1 = plt.figure(1, (5.5, 4.)) # the rect parameter will be ignore as we will set axes_locator rect = (0.1, 0.1, 0.8, 0.8) ax = [fig1.add_axes(rect, label="%d" % i) for i in range(4)] horiz = [Size.Scaled(1.5), Size.Fixed(.5), Size.Scaled(1.), Size.Scaled(.5)] vert = [Size.Scaled(1.), Size.Fixed(.5), Size.Scaled(1.5)] # divide the axes rectangle into grid whose size is specified by horiz * vert divider = Divider(fig1, rect, horiz, vert, aspect=False) ax[0].set_axes_locator(divider.new_locator(nx=0, ny=0)) ax[1].set_axes_locator(divider.new_locator(nx=0, ny=2)) ax[2].set_axes_locator(divider.new_locator(nx=2, ny=2)) ax[3].set_axes_locator(divider.new_locator(nx=2, nx1=4, ny=0)) for ax1 in ax: ax1.tick_params(labelbottom=False, labelleft=False) pltshow(plt)
import mpl_toolkits.axes_grid1.axes_size as Size from mpl_toolkits.axes_grid1 import Divider import matplotlib.pyplot as plt fig = plt.figure(figsize=(5.5, 4)) rect = (0.1, 0.1, 0.8, 0.8) ax = [fig.add_axes(rect, label="%d" % i) for i in range(4)] horiz = [Size.AxesX(ax[0]), Size.Fixed(.5), Size.AxesX(ax[1])] vert = [Size.AxesY(ax[0]), Size.Fixed(.5), Size.AxesY(ax[2])] divider = Divider(fig, rect, horiz, vert, aspect=False) ax[0].set_axes_locator(divider.new_locator(nx=0, ny=0)) ax[1].set_axes_locator(divider.new_locator(nx=2, ny=0)) ax[2].set_axes_locator(divider.new_locator(nx=0, ny=2)) ax[3].set_axes_locator(divider.new_locator(nx=2, ny=2)) ax[0].set_xlim(0, 2) ax[1].set_xlim(0, 1) ax[0].set_ylim(0, 1) ax[2].set_ylim(0, 2) divider.set_aspect(1.) for ax1 in ax: ax1.tick_params(labelbottom=False, labelleft=False) plt.show()
# <markdowncell> # make_axes_locatable() gives one way to handle this, by giving the append_axes() method. Another way is by creating a Divider object and giving it the layout up front. # <codecell> from mpl_toolkits.axes_grid1 import Size, Divider fig = plt.figure() ax = [fig.add_axes([0.1, 0.1, 0.8, 0.8], label='%d' % i) for i in range(3)] # Create 3 Axes to be sized later horiz = [Size.Scaled(2), Size.Fixed(0.5), Size.Scaled(3), Size.Fixed(0.01)] vert = [Size.Scaled(1), Size.Fixed(0.5), Size.Scaled(1)] div = Divider(fig, (0.1, 0.1, 0.8, 0.8), horiz, vert, aspect=False) ax[0].set_axes_locator(div.new_locator(nx=0, ny=0)) ax[1].set_axes_locator(div.new_locator(nx=2, ny=0)) ax[2].set_axes_locator(div.new_locator(nx=0, nx1=2, ny=2)) ax[0].plot(t, x1) ax[1].plot(t, x2) ax[2].plot(t, x3) # <rawcell> # One obvious application of this is for doing grid of plots with colorbars. For this use case we can go one step further and make use of the ImageGrid class. # <codecell> from mpl_toolkits.axes_grid1 import ImageGrid x = y = np.linspace(-3, 3, 300)
os.remove(temppath) size(W, HEIGHT+dy+40) else: def pltshow(mplpyplot): mplpyplot.show() # nodebox section end fig1 = plt.figure(1, (6, 6)) # fixed size in inch horiz = [Size.Fixed(1.), Size.Fixed(.5), Size.Fixed(1.5), Size.Fixed(.5)] vert = [Size.Fixed(1.5), Size.Fixed(.5), Size.Fixed(1.)] rect = (0.1, 0.1, 0.8, 0.8) # divide the axes rectangle into grid whose size is specified by horiz * vert divider = Divider(fig1, rect, horiz, vert, aspect=False) # the rect parameter will be ignore as we will set axes_locator ax1 = fig1.add_axes(rect, label="1") ax2 = fig1.add_axes(rect, label="2") ax3 = fig1.add_axes(rect, label="3") ax4 = fig1.add_axes(rect, label="4") ax1.set_axes_locator(divider.new_locator(nx=0, ny=0)) ax2.set_axes_locator(divider.new_locator(nx=0, ny=2)) ax3.set_axes_locator(divider.new_locator(nx=2, ny=2)) ax4.set_axes_locator(divider.new_locator(nx=2, nx1=4, ny=0)) pltshow(plt)
def memory_svg(self, host=None, title="Memory Usage", unit="Bytes", factor=1.0, b64encode=True): fig = pyplot.figure(figsize=self.FIGSIZE) h = [Size.Fixed(1.2), Size.Scaled(1.), Size.Fixed(.2)] v = [Size.Fixed(0.7), Size.Scaled(1.), Size.Fixed(.5)] divider = Divider(fig, (0.0, 0.0, 1., 1.), h, v, aspect=False) plt = Axes(fig, divider.get_position()) plt.set_axes_locator(divider.new_locator(nx=1, ny=1)) fig.add_axes(plt) result = self.result runinfo = result.runinfo # ---- # The X limits are -rampupMins, runMins # ---- plt.set_xlim(-int(runinfo['rampupMins']), int(runinfo['runMins'])) plt.axvspan(-int(runinfo['rampupMins']), 0, facecolor='0.2', alpha=0.1) x, y_used = self._get_metric_xy({ 'host': host, 'metric': 'memory.memory-used', 'factor': factor, }) _, y_cached = self._get_metric_xy( { 'host': host, 'metric': 'memory.memory-cached', 'factor': factor, }, x) _, y_buffered = self._get_metric_xy( { 'host': host, 'metric': 'memory.memory-buffered', 'factor': factor, }, x) _, y_free = self._get_metric_xy( { 'host': host, 'metric': 'memory.memory-free', 'factor': factor, }, x) # ---- # It is possible that the mqtt based metric collector produces # CSV files with different numbers of lines. We cut all of them # to a combined minimum length. # ---- min_len = min(len(x), len(y_used), len(y_cached), len(y_buffered), len(y_free)) x = x[:min_len] y_used = y_used[:min_len] y_cached = y_cached[:min_len] y_buffered = y_buffered[:min_len] y_free = y_free[:min_len] plt.stackplot(x, y_used, y_cached, y_buffered, y_free, colors=[ 'b', 'y', 'g', 'gray', ], labels=[ 'Used', 'Cached', 'Buffered', 'Free', ]) # ---- # Title and labels # ---- plt.set_title(title) plt.set_xlabel("Elapsed Minutes") plt.set_ylabel(unit) plt.legend(loc='upper left') plt.grid() # ---- # Now turn this into an in-memory SVG and return it as requested # (raw or b64-encoded) # ---- buf = io.StringIO() pyplot.savefig(buf, format='svg') if not b64encode: return buf.getvalue() return base64.b64encode(buf.getvalue().encode('utf-8')).decode('utf-8')
def plot_stratigraphy(section, style, ncols=1, linewidth=1, col_spacings=0.5, col_widths=1): """ Initialize a figure and subplots, with the stratigraphic section already plotted on the first axis. This function is intended to act similar to `plt.subplots()` in that it will initialize the figure and axis handles. However, given that controlling the exact width and height of the axes is critical, this function is necessary to initialize the handles correctly. Note that setting the figsize itself is not sufficient to control the width and height of the axes exactly, since the figsize includes the size of the padding around the axes. Parameters ---------- section : Section A Section object. style : Style A Style object. ncols : int The number of axes that will be in the figure (including the axis with the stratigraphic section.) linewidth : float The linewidth when drawing the stratigraphic section. col_spacings : float or array_like The spacing between the axes in inches. If a float, this value will be interpreted as uniform spacing between the axes. If an array, the length of the array must be ncols - 1, and the values will be the spacing between the individual axes. col_widths : float or array_like The width of the axes as a ratio relative to the width of the stratigraphic column. If a float, this value will be interpreted as a uniform width of the axes, excluding the stratigraphic column, for which the width is explicitly set in the Style. If an array, the length of the array must be ncols - 1, and the values will be the widths of the individual axes excluding the stratigraphic column. Returns ------- fig : matplotlib Figure Figure handle. ax : matplotlib Axes Axis handle. """ # get the attributes - implicitly checks if the attributes exist color_attribute = getattr(section, style.color_attribute) width_attribute = getattr(section, style.width_attribute) # initialize fig, ax = plt.subplots(nrows=1, ncols=ncols, sharey=True) # get the first axis if ncols == 1: ax0 = ax else: ax0 = ax[0] # determine the axis height and limits first ax_height = style.height_scaling_factor * section.total_thickness ax0.set_ylim(0, section.total_thickness) # initiate counting of the stratigraphic height strat_height = 0.0 # loop over elements of the data for i in range(section.n_units): # pull out the thickness this_thickness = section.thicknesses[i] # loop over the elements in Style to get the color and width for j in range(style.n_color_labels): if color_attribute[i] == style.color_labels[j]: this_color = style.color_values[j] for j in range(style.n_width_labels): if width_attribute[i] == style.width_labels[j]: this_width = style.width_values[j] # create the rectangle ax0.add_patch( Rectangle((0.0, strat_height), this_width, this_thickness, facecolor=this_color, edgecolor='k', linewidth=linewidth)) # count the stratigraphic height strat_height = strat_height + this_thickness # set the axis dimensions (values below are all in inches) ax0_lower_left_x = 0.5 ax0_lower_left_y = 0.5 ax0_width = style.width_inches h = [Size.Fixed(ax0_lower_left_x), Size.Fixed(ax0_width)] v = [Size.Fixed(ax0_lower_left_y), Size.Fixed(ax_height)] divider = Divider(fig, (0.0, 0.0, 1., 1.), h, v, aspect=False) ax0.set_axes_locator(divider.new_locator(nx=1, ny=1)) # prettify ax0.set_xlim(0, 1) ax0.set_xticks([0, 0.2, 0.4, 0.6, 0.8, 1]) for label in ax0.get_xticklabels(): label.set_rotation(270) label.set_ha('center') label.set_va('top') ax0.set_axisbelow(True) ax0.xaxis.grid(ls='--') ax0.spines['top'].set_visible(False) ax0.spines['right'].set_visible(False) ax0.set_ylabel('stratigraphic height [m]') # turning the spines off creates some clipping mask issues # so just turn the clipping masks off for obj in ax0.findobj(): obj.set_clip_on(False) # check if the col_spacing and col_widths is of the correct format if type(col_spacings) == list or type(col_spacings) == np.ndarray: if len(col_spacings) != ncols - 1: raise Exception('col_spacings must be either a float or ' 'array_like with length ncols-1.') if type(col_widths) == list or type(col_widths) == np.ndarray: if len(col_widths) != ncols - 1: raise Exception('col_widths must be either a float or ' 'array_like with length ncols-1.') # set up the other axes if ncols != 1: # iterate through the axes for i in range(1, ncols): # get the spacing and width values if type(col_spacings) == list or type(col_spacings) == np.ndarray: col_spacing = col_spacings[i - 1] else: col_spacing = col_spacings if type(col_widths) == list or type(col_widths) == np.ndarray: col_width = col_widths[i - 1] * ax0_width else: col_width = col_widths * ax0_width # adjust the axis if i == 1: axn_lower_left_x = ax0_lower_left_x + ax0_width + col_spacing else: axn_lower_left_x = axn_lower_left_x + axn_width + col_spacing axn_lower_left_y = ax0_lower_left_y axn_width = col_width h = [Size.Fixed(axn_lower_left_x), Size.Fixed(axn_width)] v = [Size.Fixed(axn_lower_left_y), Size.Fixed(ax_height)] divider = Divider(fig, (0.0, 0.0, 1., 1.), h, v, aspect=False) ax[i].set_axes_locator(divider.new_locator(nx=1, ny=1)) # set the figsize here too to account for the axis size manipulation if ncols != 1: fig.set_size_inches( ax0_lower_left_x * 2 + np.sum(col_spacings) + np.sum(col_widths) + ax0_width, ax0_lower_left_y * 2 + ax_height) else: fig.set_size_inches(ax0_lower_left_x * 2 + ax0_width, ax0_lower_left_y * 2 + ax_height) return fig, ax
############################################################################## # Fixed axes sizes; fixed paddings. fig = plt.figure(figsize=(6, 6)) fig.suptitle("Fixed axes sizes, fixed paddings") # Sizes are in inches. horiz = [Size.Fixed(1.), Size.Fixed(.5), Size.Fixed(1.5), Size.Fixed(.5)] vert = [Size.Fixed(1.5), Size.Fixed(.5), Size.Fixed(1.)] rect = (0.1, 0.1, 0.8, 0.8) # Divide the axes rectangle into a grid with sizes specified by horiz * vert. div = Divider(fig, rect, horiz, vert, aspect=False) # The rect parameter will actually be ignored and overridden by axes_locator. ax1 = fig.add_axes(rect, axes_locator=div.new_locator(nx=0, ny=0)) label_axes(ax1, "nx=0, ny=0") ax2 = fig.add_axes(rect, axes_locator=div.new_locator(nx=0, ny=2)) label_axes(ax2, "nx=0, ny=2") ax3 = fig.add_axes(rect, axes_locator=div.new_locator(nx=2, ny=2)) label_axes(ax3, "nx=2, ny=2") ax4 = fig.add_axes(rect, axes_locator=div.new_locator(nx=2, nx1=4, ny=0)) label_axes(ax4, "nx=2, nx1=4, ny=0") ############################################################################## # Axes sizes that scale with the figure size; fixed paddings. fig = plt.figure(figsize=(6, 6)) fig.suptitle("Scalable axes sizes, fixed paddings") horiz = [Size.Scaled(1.5), Size.Fixed(.5), Size.Scaled(1.), Size.Scaled(.5)]
Simple Axes Divider 1 ===================== """ from mpl_toolkits.axes_grid1 import Size, Divider import matplotlib.pyplot as plt fig1 = plt.figure(1, (6, 6)) # fixed size in inch horiz = [Size.Fixed(1.), Size.Fixed(.5), Size.Fixed(1.5), Size.Fixed(.5)] vert = [Size.Fixed(1.5), Size.Fixed(.5), Size.Fixed(1.)] rect = (0.1, 0.1, 0.8, 0.8) # divide the axes rectangle into grid whose size is specified by horiz * vert divider = Divider(fig1, rect, horiz, vert, aspect=False) # the rect parameter will be ignore as we will set axes_locator ax1 = fig1.add_axes(rect, label="1") ax2 = fig1.add_axes(rect, label="2") ax3 = fig1.add_axes(rect, label="3") ax4 = fig1.add_axes(rect, label="4") ax1.set_axes_locator(divider.new_locator(nx=0, ny=0)) ax2.set_axes_locator(divider.new_locator(nx=0, ny=2)) ax3.set_axes_locator(divider.new_locator(nx=2, ny=2)) ax4.set_axes_locator(divider.new_locator(nx=2, nx1=4, ny=0)) plt.draw() plt.show()
fig = plt.figure(figsize=(12, 6)) sfs = fig.subfigures(1, 2) sfs[0].suptitle("Fixed axes sizes, fixed paddings") # Sizes are in inches. horiz = [Size.Fixed(1.), Size.Fixed(.5), Size.Fixed(1.5), Size.Fixed(.5)] vert = [Size.Fixed(1.5), Size.Fixed(.5), Size.Fixed(1.)] rect = (0.1, 0.1, 0.8, 0.8) # Divide the axes rectangle into a grid with sizes specified by horiz * vert. div = Divider(sfs[0], rect, horiz, vert, aspect=False) # The rect parameter will actually be ignored and overridden by axes_locator. ax1 = sfs[0].add_axes(rect, axes_locator=div.new_locator(nx=0, ny=0)) label_axes(ax1, "nx=0, ny=0") ax2 = sfs[0].add_axes(rect, axes_locator=div.new_locator(nx=0, ny=2)) label_axes(ax2, "nx=0, ny=2") ax3 = sfs[0].add_axes(rect, axes_locator=div.new_locator(nx=2, ny=2)) label_axes(ax3, "nx=2, ny=2") ax4 = sfs[0].add_axes(rect, axes_locator=div.new_locator(nx=2, nx1=4, ny=0)) label_axes(ax4, "nx=2, nx1=4, ny=0") sfs[1].suptitle("Scalable axes sizes, fixed paddings") # Fixed sizes are in inches, scaled sizes are relative. horiz = [Size.Scaled(1.5), Size.Fixed(.5), Size.Scaled(1.), Size.Scaled(.5)] vert = [Size.Scaled(1.), Size.Fixed(.5), Size.Scaled(1.5)] rect = (0.1, 0.1, 0.8, 0.8)
def setup_axes(df, plates, attrs): from mpl_toolkits.axes_grid1 import Divider from mpl_toolkits.axes_grid1.axes_size import Fixed # These assumptions let us simplify some code, and should always be true. assert len(plates) > 0 assert len(attrs) > 0 # Determine how much data will be shown in the figure: num_plates = len(plates) num_attrs = len(attrs) dims = Dimensions(df) bar_label_width = guess_attr_label_width(df, attrs) # Define the grid on which the axes will live: h_divs = [ LEFT_MARGIN, ] for _ in plates: h_divs += [ CELL_SIZE * dims.num_cols, PAD_WIDTH, ] h_divs[-1:] = [ BAR_PAD_WIDTH, BAR_WIDTH, RIGHT_MARGIN + bar_label_width, ] v_divs = [ TOP_MARGIN, ] for attr in attrs: v_divs += [ max( CELL_SIZE * dims.num_rows, BAR_WIDTH * dims.num_values[attr], ), PAD_HEIGHT, ] v_divs[-1:] = [ BOTTOM_MARGIN, ] # Add up all the divisions to get the width and height of the figure: figsize = sum(h_divs), sum(v_divs) # Make the figure: fig, axes = plt.subplots( num_attrs, num_plates + 1, # +1 for the colorbar axes. figsize=figsize, squeeze=False, ) # Position the axes: rect = 0.0, 0.0, 1, 1 h_divs = [Fixed(x) for x in h_divs] v_divs = [Fixed(x) for x in reversed(v_divs)] divider = Divider(fig, rect, h_divs, v_divs, aspect=False) for i in range(num_attrs): for j in range(num_plates + 1): loc = divider.new_locator(nx=2 * j + 1, ny=2 * (num_attrs - i) - 1) axes[i, j].set_axes_locator(loc) return fig, axes, dims
def segtrends(x, segments=2, charts=True): """ Turn minitrends to iterative process more easily adaptable to implementation in simple trading systems; allows backtesting functionality. :param x: One-dimensional data set :param window: How long the trendlines should be. If window < 1, then it will be taken as a percentage of the size of the data :param charts: Boolean value saying whether to print chart to screen """ import numpy as np y = np.array(x['Close']) # for i in range(len(y),1200): # y = np.append(y, y[len(y)-1]) # Implement trendlines segments = int(segments) maxima = np.ones(segments) minima = np.ones(segments) segsize = int(len(y) / segments) for i in range(1, segments + 1): ind2 = i * segsize ind1 = ind2 - segsize maxima[i - 1] = max(y[ind1:ind2]) minima[i - 1] = min(y[ind1:ind2]) # Find the indexes of these maxima in the data x_maxima = np.ones(segments) x_minima = np.ones(segments) for i in range(0, segments): x_maxima[i] = np.where(y == maxima[i])[0][0] x_minima[i] = np.where(y == minima[i])[0][0] if charts: import matplotlib.pyplot as plt plt.rc('font', size=6) fig = plt.figure(figsize=(8, 6)) h = [Size.Fixed(0.5), Size.Fixed(7.)] v = [Size.Fixed(0.7), Size.Fixed(5.)] divider = Divider(fig, (0.0, 0.0, 0., 0.), h, v, aspect=False) ax = Axes(fig, divider.get_position()) ax.set_axes_locator(divider.new_locator(nx=1, ny=1)) fig.add_axes(ax) plt.plot(y, linewidth=1) plt.grid(True) for i in range(0, segments - 1): maxslope = (maxima[i + 1] - maxima[i]) / (x_maxima[i + 1] - x_maxima[i]) a_max = maxima[i] - (maxslope * x_maxima[i]) b_max = maxima[i] + (maxslope * (len(y) + 300 - x_maxima[i])) maxline = np.linspace(a_max, b_max, len(y) + 300) minslope = (minima[i + 1] - minima[i]) / (x_minima[i + 1] - x_minima[i]) a_min = minima[i] - (minslope * x_minima[i]) b_min = minima[i] + (minslope * (len(y) + 300 - x_minima[i])) minline = np.linspace(a_min, b_min, len(y) + 300) if charts: plt.plot(maxline, 'g', linewidth=0.15) plt.plot(minline, 'r', linewidth=.15) if charts: #plt.show() plt.ylim(min(y[-120:] * .9), max(y[-120:] * 1.1)) plt.rc('xtick', labelsize=6) plt.xticks(range(0, 1200, 4), x.index[range(0, 910, 4)], rotation=90) plt.rc('xtick', labelsize=6) plt.xlim(800, 1000) # plt.xlim(datetime.datetime(2016,1,1),datetime.datetime(2022,1,1)) plt.savefig('C:/git/TRADE/chart.png', dpi=750) plt.close() # OUTPUT return x_maxima, maxima, x_minima, minima
A = np.array([[ndados, sumTE], [sumTE, prodTE]]) B = np.array([[sumFinalAnalysis], [sumFinalAnalysisTE]]) invA = np.linalg.inv(A) P = np.matmul(invA, B) T2[indexValue] = (P[1][0]) for i, t in enumerate(T2): T2[i] = math.inf if t[0] == 0 else 1000 / t[0] T2Star = np.reshape(T2, (400, 400)) fig = plt.figure(figsize=(6, 6)) h = [Size.Fixed(1.0), Size.Fixed(5.)] v = [Size.Fixed(1.0), Size.Fixed(5.)] divider = Divider(fig, (0.0, 0.0, 1., 1.), h, v, aspect=False) ax = Axes(fig, divider.get_position()) ax.set_axes_locator(divider.new_locator(nx=1, ny=1)) fig.add_axes(ax) plt.pcolor(np.flip(T2Star, 0), cmap=jet_combined, vmin=0, vmax=180) toc = time.perf_counter() print(f"Executed in {toc - tic:0.4f} seconds") # toggle_selector.RS = RectangleSelector(ax, line_select_callback, # drawtype='box', useblit=True, # button=[1, 3], # don't use middle button # minspanx=5, minspany=5, # spancoords='pixels', # interactive=True) # plt.connect('key_press_event', toggle_selector) plt.show()
def tpmc_svg(self, b64encode=True): fig = pyplot.figure(figsize=self.FIGSIZE) h = [Size.Fixed(1.2), Size.Scaled(1.), Size.Fixed(.2)] v = [Size.Fixed(0.7), Size.Scaled(1.), Size.Fixed(.5)] divider = Divider(fig, (0.0, 0.0, 1., 1.), h, v, aspect=False) plt = Axes(fig, divider.get_position()) plt.set_axes_locator(divider.new_locator(nx=1, ny=1)) fig.add_axes(plt) result = self.result runinfo = result.runinfo # ---- # The X limits are -rampupMins, runMins # ---- plt.set_xlim(-int(runinfo['rampupMins']), int(runinfo['runMins'])) plt.axvspan(-int(runinfo['rampupMins']), 0, facecolor='0.2', alpha=0.1) # ---- # offset the timestamps by -rampupMins so that the graph # starts with negative minutes elapsed and switches to # positive when the measurement begins. # ---- offset = (int(runinfo['rampupMins'])) * 60.0 # ---- # NEW_ORDER transactions per minute. First get the timestamp # and number of transactions from the result data. # The X vector then is the sorted unique timestamps rounded # to an interval. # ---- interval = 10 data = numpy.array([[(int(tup[0] / interval) * interval - offset) / 60, tup[1] * (60 / interval)] for tup in result.result_ttype['NEW_ORDER']]) x = sorted(numpy.unique(data[:, 0])) # ---- # The Y vector is the sums of transactions grouped by X # ---- y = [] for ts in x: tmp = data[numpy.where(data[:, 0] == ts)] y.append(numpy.sum(tmp[:, 1])) # ---- # Plot the NOPM and add all the decorations # ---- plt.plot(x, y, 'b') plt.set_title("NEW_ORDER Transactions per Minute (tpmC)") plt.set_xlabel("Elapsed Minutes") plt.set_ylabel("tpmC") plt.grid() buf = io.StringIO() pyplot.savefig(buf, format='svg') if not b64encode: return buf.getvalue() return base64.b64encode(buf.getvalue().encode('utf-8')).decode('utf-8')
def __init__(self, images, shape): fig = plt.figure(figsize=(10, 6)) # subplot positions h_nav = [Size.Fixed(0.5), Size.Fixed(2.5)] v_nav = [Size.Fixed(0.5), Size.Scaled(1.0), Size.Fixed(0.5)] h_im = [Size.Fixed(0.5), Size.Scaled(1.0), Size.Fixed(0.5)] v_im = [Size.Fixed(0.5), Size.Scaled(1.0), Size.Fixed(0.5)] nav = Divider(fig, (0.0, 0.0, 0.2, 1.), h_nav, v_nav, aspect=False) image = Divider(fig, (0.2, 0.0, 0.8, 1.), h_im, v_im, aspect=True) image.set_anchor('C') # Toolbar menu box ax1 = LocatableAxes(fig, nav.get_position()) ax1.set_axes_locator(nav.new_locator(nx=1, ny=1)) ax1.get_xaxis().set_visible(False) ax1.get_yaxis().set_visible(False) fig.add_axes(ax1, label='toolbar') ax1.text(0.05, 0.45, "Filter", weight='heavy', transform=ax1.transAxes) # Image space ax2 = LocatableAxes(fig, image.get_position()) ax2.set_axes_locator(image.new_locator(nx=1, ny=1)) fig.add_axes(ax2, label='image_space') self.callback = ImageIndex(images, shape, fig) # Navigation ## Go to ax_text_index = plt.axes([0.59, 0.05, 0.1, 0.075]) ip = InsetPosition(ax1, [0.2, 0.84, 0.3, 0.05]) ax_text_index.set_axes_locator(ip) entry_index = TextBox(ax_text_index, 'Go to', initial="0") entry_index.on_submit(self.callback.submit_index) ## Previous ax_prev = plt.axes([0.7, 0.05, 0.075, 0.075]) ip = InsetPosition(ax1, [0.55, 0.84, 0.15, 0.05]) ax_prev.set_axes_locator(ip) bprev = Button(ax_prev, '<<') bprev.on_clicked(self.callback.prev) ## Next ax_next = plt.axes([0.81, 0.05, 0.075, 0.075]) ip = InsetPosition(ax1, [0.75, 0.84, 0.15, 0.05]) ax_next.set_axes_locator(ip) bnext = Button(ax_next, '>>') bnext.on_clicked(self.callback.next) # Bounding Boxes ax_chec = plt.axes([0.1, 0.05, 0.35, 0.075]) ip = InsetPosition(ax1, [0.05, 0.5, 0.9, 0.3]) ax_chec.set_axes_locator(ip) ax_chec.text(0.05, 0.85, "Bounding Boxes", transform=ax_chec.transAxes) check = CheckButtons(ax_chec, ('characters', 'lines'), (False, False)) check.on_clicked(self.callback.update_bboxes) # Filtering ## Image ax_text_image = plt.axes([0.1, 0.1, 0.1, 0.075]) ip = InsetPosition(ax1, [0.26, 0.38, 0.64, 0.05]) ax_text_image.set_axes_locator(ip) entry_image = TextBox(ax_text_image, 'images', initial="image_id,image_id") entry_image.on_submit(self.callback.submit_images) ## Characters ax_text_char = plt.axes([0.1, 0.2, 0.1, 0.075]) ip = InsetPosition(ax1, [0.21, 0.3, 0.69, 0.05]) ax_text_char.set_axes_locator(ip) entry_char = TextBox(ax_text_char, 'chars', initial="U+3055,U+3056") entry_char.on_submit(self.callback.submit_chars) ## Reset ax_reset = plt.axes([0., 0., 1., 1.]) ip = InsetPosition(ax1, [0.05, 0.2, 0.2, 0.05]) ax_reset.set_axes_locator(ip) breset = Button(ax_reset, 'Reset') breset.on_clicked(self.callback.reset) plt.show()
def plot_legend(self, legend_unit_height=0.25): """ Plot a legend for this Style object. If the color and width labels are the same, a single legend will be created. Otherwise, two legends will be created - one with the color labels, and the other with the width labels. Parameters ---------- legend_unit_height : float A scaling factor to modify the height of each unit in the legend only. Returns ------- fig : matplotlib Figure Figure handle. ax : matplotlib Axes Axis handle. """ # print some plotting values print('stratigraphic height scaling : 1 distance unit = 1 inch * {}'. format(self.height_scaling_factor)) print('width value of 1 will be : {} inches'.format( self.width_inches)) # extract attributes color_labels = self.color_labels width_labels = self.width_labels color_values = self.color_values width_values = self.width_values # if the color and width labels are different if np.any(~(color_labels == width_labels)): # sort the widths width_sort_inds = np.argsort(width_values) width_labels = width_labels[width_sort_inds] width_values = width_values[width_sort_inds] # initialize the figure fig, ax = plt.subplots(nrows=1, ncols=2, sharey=True) # determine the axis height and limits first if self.n_color_labels > self.n_width_labels: ax_height = legend_unit_height * self.n_color_labels ax[0].set_ylim(0, self.n_color_labels) ax[1].set_ylim(0, self.n_color_labels) else: ax_height = legend_unit_height * self.n_width_labels ax[0].set_ylim(0, self.n_width_labels) ax[1].set_ylim(0, self.n_width_labels) # plot the colors strat_height_colors = 0 for i in range(len(color_labels)): # create the rectangle - with thickness of 1 ax[0].add_patch( Rectangle((0.0, strat_height_colors), 1, 1, facecolor=color_values[i], edgecolor='k')) # label the unit ax[0].text(1.2, strat_height_colors + 0.5, color_labels[i], horizontalalignment='left', verticalalignment='center') # count the height strat_height_colors = strat_height_colors + 1 # set the axis dimensions (values below are all in inches) ax0_lower_left_x = 0.5 ax0_lower_left_y = 0.5 ax0_width = 0.5 h = [Size.Fixed(ax0_lower_left_x), Size.Fixed(ax0_width)] v = [Size.Fixed(ax0_lower_left_y), Size.Fixed(ax_height)] divider = Divider(fig, (0.0, 0.0, 1., 1.), h, v, aspect=False) ax[0].set_axes_locator(divider.new_locator(nx=1, ny=1)) # set the limits ax[0].set_xlim(0, 1) # prettify ax[0].set_xticks([]) ax[0].set_yticklabels([]) ax[0].set_yticks([]) # plot the widths strat_height_widths = 0 for i in range(len(width_labels)): # create the rectangle ax[1].add_patch( Rectangle((0.0, strat_height_widths), width_values[i], 1, facecolor='grey', edgecolor='k')) # the label ax[1].text(1.1, strat_height_widths + 0.5, width_labels[i], horizontalalignment='left', verticalalignment='center') # count the height strat_height_widths = strat_height_widths + 1 # set the axis dimensions (values below are all in inches) ax1_lower_left_x = ax0_lower_left_x + ax0_width + 2 ax1_lower_left_y = ax0_lower_left_y ax1_width = self.width_inches h = [Size.Fixed(ax1_lower_left_x), Size.Fixed(ax1_width)] v = [Size.Fixed(ax1_lower_left_y), Size.Fixed(ax_height)] divider = Divider(fig, (0.0, 0.0, 1., 1.), h, v, aspect=False) ax[1].set_axes_locator(divider.new_locator(nx=1, ny=1)) # prettify ax[1].set_xlim(0, 1) ax[1].set_xticks([0, 0.2, 0.4, 0.6, 0.8, 1]) for label in ax[1].get_xticklabels(): label.set_rotation(270) label.set_ha('center') label.set_va('top') ax[1].set_axisbelow(True) ax[1].xaxis.grid(ls='--') ax[1].set_yticklabels([]) ax[1].set_yticks([]) ax[1].spines['top'].set_visible(False) ax[1].spines['right'].set_visible(False) # turning the spines off creates some clipping mask issues # so just turn the clipping masks off for obj in fig.findobj(): obj.set_clip_on(False) # not really necessary since the axis sizes are already # forced, but we may as well set the figsize here too fig.set_size_inches( ax1_lower_left_x + ax1_width + ax0_lower_left_x, ax1_lower_left_y * 2 + ax_height) # if the color and width labels are the same else: # sort by width width_sort_inds = np.argsort(width_values) color_labels = color_labels[width_sort_inds] width_labels = width_labels[width_sort_inds] color_values = color_values[width_sort_inds] width_values = width_values[width_sort_inds] # initiate fig and ax fig, ax = plt.subplots() # determine the axis height and limits first ax_height = legend_unit_height * self.n_color_labels ax.set_ylim(0, self.n_color_labels) # initiate counting of the stratigraphic height strat_height = 0 # loop over each item for i in range(len(color_labels)): # create the rectangle - with thickness of 1 ax.add_patch( Rectangle((0.0, strat_height), width_values[i], 1, facecolor=color_values[i], edgecolor='k')) # label the unit ax.text(1.1, strat_height + 0.5, color_labels[i], horizontalalignment='left', verticalalignment='center') # count the stratigraphic height strat_height = strat_height + 1 # set the axis dimensions (values below are all in inches) ax_lower_left_x = 0.5 ax_lower_left_y = 0.5 ax_width = self.width_inches h = [Size.Fixed(ax_lower_left_x), Size.Fixed(ax_width)] v = [Size.Fixed(ax_lower_left_y), Size.Fixed(ax_height)] divider = Divider(fig, (0.0, 0.0, 1., 1.), h, v, aspect=False) ax.set_axes_locator(divider.new_locator(nx=1, ny=1)) # prettify ax.set_xlim(0, 1) ax.set_xticks([0, 0.2, 0.4, 0.6, 0.8, 1]) for label in ax.get_xticklabels(): label.set_rotation(270) label.set_ha('center') label.set_va('top') ax.set_axisbelow(True) ax.xaxis.grid(ls='--') ax.set_yticklabels([]) ax.set_yticks([]) ax.spines['top'].set_visible(False) ax.spines['right'].set_visible(False) # turning the spines off creates some clipping mask issues # so just turn the clipping masks off for obj in fig.findobj(): obj.set_clip_on(False) # not really necessary since the axis sizes are already # forced, but we may as well set the figsize here too fig.set_size_inches(ax_lower_left_x * 2 + ax_width, ax_lower_left_y * 2 + ax_height) return fig, ax
def delay_avg_svg(self, ttype, b64encode=True): fig = pyplot.figure(figsize=self.FIGSIZE) h = [Size.Fixed(1.2), Size.Scaled(1.), Size.Fixed(.2)] v = [Size.Fixed(0.7), Size.Scaled(1.), Size.Fixed(.5)] divider = Divider(fig, (0.0, 0.0, 1., 1.), h, v, aspect=False) plt = Axes(fig, divider.get_position()) plt.set_axes_locator(divider.new_locator(nx=1, ny=1)) fig.add_axes(plt) result = self.result runinfo = result.runinfo # ---- # The X limits are -rampupMins, runMins # ---- plt.set_xlim(-int(runinfo['rampupMins']), int(runinfo['runMins'])) plt.axvspan(-int(runinfo['rampupMins']), 0, facecolor='0.2', alpha=0.1) # ---- # offset the timestamps by -rampupMins so that the graph # starts with negative minutes elapsed and switches to # positive when the measurement begins. # ---- offset = (int(runinfo['rampupMins'])) * 60.0 # ---- # ttype transaction delay. First get the timestamp # and delay numbers from the result data. # The X vector then is the sorted unique timestamps rounded # to an interval. # ---- interval = 10 data = numpy.array([[(int(tup[0] / interval) * interval - offset) / 60, tup[1], tup[5]] for tup in result.result_ttype[ttype]]) x = sorted(numpy.unique(data[:, 0])) # ---- # The Y vector is the sums of transactions delay divided by # the sums of the count, grouped by X. # ---- y = [] for ts in x: tmp = data[numpy.where(data[:, 0] == ts)] y.append(numpy.sum(tmp[:, 2]) / (numpy.sum(tmp[:, 1]) + 0.000001)) # ---- # Plot the ttype delay and add all the decorations # ---- plt.plot(x, y, 'r', label='Delay') # ---- # Now do the same aggregation for the latency # ---- data = numpy.array([[(int(tup[0] / interval) * interval - offset) / 60, tup[1], tup[2]] for tup in result.result_ttype[ttype]]) # ---- # The Y vector is similar by based on latency # ---- y = [] for ts in x: tmp = data[numpy.where(data[:, 0] == ts)] y.append(numpy.sum(tmp[:, 2]) / (numpy.sum(tmp[:, 1]) + 0.000001)) plt.plot(x, y, 'b', label='Latency') plt.set_title("{} Average Latency and Delay".format(ttype)) plt.set_xlabel("Elapsed Minutes") plt.set_ylabel("Latency/Delay in ms") plt.legend(loc='upper left') plt.grid() buf = io.StringIO() pyplot.savefig(buf, format='svg') if not b64encode: return buf.getvalue() return base64.b64encode(buf.getvalue().encode('utf-8')).decode('utf-8')
def cpu_svg(self, host=None, title="CPU Usage", ylabel="Percent", b64encode=True): fig = pyplot.figure(figsize=self.FIGSIZE) h = [Size.Fixed(1.2), Size.Scaled(1.), Size.Fixed(.2)] v = [Size.Fixed(0.7), Size.Scaled(1.), Size.Fixed(.5)] divider = Divider(fig, (0.0, 0.0, 1., 1.), h, v, aspect=False) plt = Axes(fig, divider.get_position()) plt.set_axes_locator(divider.new_locator(nx=1, ny=1)) fig.add_axes(plt) result = self.result runinfo = result.runinfo # ---- # The X limits are -rampupMins, runMins, Y limits are 0..100 # ---- plt.set_xlim(-int(runinfo['rampupMins']), int(runinfo['runMins'])) plt.set_ylim(0, 100) plt.axvspan(-int(runinfo['rampupMins']), 0, facecolor='0.2', alpha=0.1) # ---- # Gather all the relevant data # ---- x, y_user = self._get_metric_xy({ 'host': host, 'metric': 'cpu.percent-user', }) _, y_sys = self._get_metric_xy( { 'host': host, 'metric': 'cpu.percent-system', }, x) _, y_wait = self._get_metric_xy( { 'host': host, 'metric': 'cpu.percent-wait', }, x) _, y_intr = self._get_metric_xy( { 'host': host, 'metric': 'cpu.percent-interrupt', }, x) _, y_softirq = self._get_metric_xy( { 'host': host, 'metric': 'cpu.percent-softirq', }, x) _, y_idle = self._get_metric_xy( { 'host': host, 'metric': 'cpu.percent-idle', }, x) # ---- # It is possible that the mqtt based metric collector produces # CSV files with different numbers of lines. We cut all of them # to a combined minimum length. # ---- min_len = min(len(x), len(y_user), len(y_sys), len(y_wait), len(y_intr), len(y_softirq), len(y_idle)) x = x[:min_len] y_user = y_user[:min_len] y_sys = y_sys[:min_len] y_wait = y_wait[:min_len] y_intr = y_intr[:min_len] y_softirq = y_softirq[:min_len] y_idle = y_idle[:min_len] # ---- # Plot the CPU usage # ---- plt.stackplot(x, y_user, y_sys, y_wait, y_intr, y_softirq, y_idle, colors=[ 'g', 'b', 'r', 'c', 'm', 'y', ], labels=[ 'User', 'System', 'Wait', 'Interrupt', 'SoftIrq', 'Idle', ]) # ---- # Title and labels # ---- plt.set_title(title) plt.set_xlabel("Elapsed Minutes") plt.set_ylabel(ylabel) plt.legend(loc='upper left') plt.grid() # ---- # Now turn this into an in-memory SVG and return it as requested # (raw or b64-encoded) # ---- buf = io.StringIO() pyplot.savefig(buf, format='svg') if not b64encode: return buf.getvalue() return base64.b64encode(buf.getvalue().encode('utf-8')).decode('utf-8')
# rgba = np.dstack([rgba, alpha]) # # else: # hsv[:, :, 2] = alpha.clip(min=0.2, max=value) # rgba_l = colors.hsv_to_rgb(hsv) # alpha_l = np.abs(1 - alpha).clip(min=value, max=1) # hsv[:, :, 2] = alpha_l # rgba_lr = colors.hsv_to_rgb(hsv) cmap = colors.ListedColormap(cmap, name='test1') fig = plt.figure(1, figsize=(12, 8)) h = [Size.Fixed(0.), Size.Fixed(6.5)] v = [Size.Fixed(0.5), Size.Fixed(3.25)] win = Divider(fig, (0.1, 0.1, 0.8, 0.8), h, v, aspect=False) ax = Axes(fig, win.get_position()) ax.set_axes_locator(win.new_locator(nx=1, ny=1)) fig.add_axes(ax) # fig = plt.gcf() for ii in range(1, 2): if ii == 0: to_plot = rgb title = 'Model' elif ii == 1: to_plot = rgba title = 'Model + Resolution (Transparency)' elif ii == 2: to_plot = rgba_l title = 'Model + Resolution (Lightness)' else: to_plot = rgba_lr title = 'Model + Resolution (Reverse Lightness)'
def plot_variance_multi(savefile, data, labels, colors, ylabel, ylim, ylim_unit=1, ylim_scale=5, colors2=None, hline=None, vline=None, locator=-1, draw_dist=True, subsample=1): plt.clf() plt.rcParams["font.size"] = 14 colors2 = colors if colors2 is None else colors2 m = len(data) #fig, ax = plt.subplots(1, 1) fig = plt.figure(1, figsize=(4, 4)) # The first items are for padding and the second items are for the axes. # sizes are in inch. h = [Size.Fixed(0.65), Size.Fixed(5.5)] v = [Size.Fixed(0.7), Size.Fixed(4.)] divider = Divider(fig, (0.0, 0.0, 1., 1.), h, v, aspect=False) # the width and height of the rectangle is ignored. ax = LocatableAxes(fig, divider.get_position()) ax.set_axes_locator(divider.new_locator(nx=1, ny=1)) fig.add_axes(ax) if not hasattr(draw_dist, '__getitem__'): v = draw_dist draw_dist = [v for i in range(m)] print(draw_dist) for k in range(m)[::-1]: plot_m = numpy.median(data[k], 0) sorted = numpy.sort(data[k], 0) n = data[k].shape[0] T = data[k].shape[1] t = numpy.arange(0, T) fin = plot_m[-1] best = sorted[0][-1] alpha = 1.0 / (n // 2) * 0.4 if subsample > 1: t = subsample_data(t, subsample) plot_m = subsample_data(plot_m, subsample) sorted = subsample_data(sorted, subsample) if k == 0: if ylim is None: ymax = min([fin * ylim_scale, sorted[-1, 0], 90]) ymin = numpy.floor(numpy.max(best / ylim_unit - 0.5, 0)) * ylim_unit ymin = 0 ylim = [ymin, numpy.ceil(ymax / ylim_unit) * ylim_unit] else: ylim = ylim # 3: 0 if draw_dist[k]: print('k', k) for i in range(n // 2): ax.fill_between(t, sorted[-1 - i], sorted[i], facecolor=colors2[k], alpha=alpha) for k in range(m)[::-1]: plot_m = numpy.median(data[k], 0) t = numpy.arange(0, T) if subsample > 1: t = subsample_data(t, subsample) plot_m = subsample_data(plot_m, subsample) ax.plot(t, plot_m, lw=1, color=colors[k], ls='-', label=labels[k]) if hline is not None: ax.plot((0, T), (hline, hline), color='gray', ls=':') if vline is not None: ax.plot((vline, vline), (ylim[0], ylim[1]), color='gray', ls=':') ax.legend(loc='upper right') ax.set_xlabel('Iterations') ax.set_ylabel(ylabel) ax.set_xlim([0, T]) ax.set_ylim(ylim) if locator >= 0: ax.yaxis.set_major_locator(MultipleLocator(locator)) ax.grid() plt.savefig(savefile + '.png') plt.savefig(savefile + '.pdf')
# Filters the level 4 data to CD and UC IBD_level_4 = level_4.loc[level_4['dx'].isin(["CD", "UC"])] IBD_level_4 = IBD_level_4.drop(columns=metadata_columns) IBD_level_4 = IBD_level_4.set_index('index') # Normalise the data around 0 standardised = (IBD_level_4 - IBD_level_4.mean()) / IBD_level_4.std() # sets the sizing so as much of the label can be shown as possible fig = plt.figure(figsize=(11.7, 8.27)) h = [Size.Fixed(6.), Size.Scaled(.5), Size.Fixed(.2)] v = [Size.Fixed(0.7), Size.Scaled(.5), Size.Fixed(.5)] divider = Divider(fig, (0, 0, 1, 1), h, v, aspect=False) ax = fig.add_axes(divider.get_position(), axes_locator=divider.new_locator(nx=1, ny=1)) # Plots the relative frequency sns.boxplot(y="variable", x="value", data=pd.melt(standardised), showfliers=False, width=.6, ax=ax) ax.xaxis.grid(True) ax.set(ylabel="Bacteria", xlabel="Relative Abundance", title="Relative Abundance for IBD for taxa at level 4") sns.despine(trim=True, left=True) plt.savefig(out_individual_boxplot) this_experiment = { "_id": experiment_id, "parent": parent_name, "stage": CURRENT_STAGE, "output": { "visuals": [out_id_freq_table,out_otu_freq_table,out_id_rel_freq_table, out_otu_rel_freq_table, out_stacked_frequency,
class MatPlotLibBase(QWidget): def __init__(self, parent, file_dialog_service, h_margin=(0.8, 0.1), v_margin=(0.5, 0.15), h_axes=[Size.Scaled(1.0)], v_axes=[Size.Scaled(1.0)], nx_default=1, ny_default=1): QWidget.__init__(self, parent) self._file_dialog_service = file_dialog_service self._figure = Figure() self._canvas = FigureCanvas(self._figure) h = [Size.Fixed(h_margin[0]), *h_axes, Size.Fixed(h_margin[1])] v = [Size.Fixed(v_margin[0]), *v_axes, Size.Fixed(v_margin[1])] self._divider = Divider(self._figure, (0.0, 0.0, 1.0, 1.0), h, v, aspect=False) self._axes = LocatableAxes(self._figure, self._divider.get_position()) self._axes.set_axes_locator( self._divider.new_locator(nx=nx_default, ny=ny_default)) self._axes.set_zorder(2) self._axes.patch.set_visible(False) for spine in ['top', 'right']: self._axes.spines[spine].set_visible(False) self._figure.add_axes(self._axes) self._canvas.setParent(self) self._layout = QVBoxLayout(self) self._layout.setContentsMargins(0, 0, 0, 0) self._layout.addWidget(self._canvas) self.setLayout(self._layout) self._figure.canvas.mpl_connect('scroll_event', self._on_scroll) self._xy_extents = None self._background_cache = None self._decoration_artists = [] self._is_panning = False self._zoom_selector = _RectangleSelector(self._axes, self._zoom_selected) self._zoom_selector.set_active(False) self._x_extent_padding = 0.01 self._y_extent_padding = 0.01 self._axes.ticklabel_format(style='sci', axis='x', scilimits=(-4, 4)) self._axes.ticklabel_format(style='sci', axis='y', scilimits=(-4, 4)) self._active_tools = {} self._span = _SpanSeletor(self._axes, self._handle_span_select, 'horizontal', rectprops=dict(alpha=0.2, facecolor='red', edgecolor='k'), span_stays=True) self._span.set_on_select_none(self._handle_span_select_none) self.span = self._previous_span = None self._span_center_mouse_event = None self._span_left_mouse_event = None self._span_right_mouse_event = None self._figure.canvas.mpl_connect('button_press_event', self._handle_press) self._figure.canvas.mpl_connect('motion_notify_event', self._handle_move) self._figure.canvas.mpl_connect('button_release_event', self._handle_release) self._figure.canvas.mpl_connect('resize_event', self._handle_resize) self.activateTool(ToolType.span, self.isActiveDefault(ToolType.span)) self._pan_event = None self._pending_draw = None self._pending_artists_draw = None self._other_draw_events = [] self._draw_timer = QTimer(self) self._draw_timer.timeout.connect(self._do_draw_events) self._draw_timer.start(20) self._zoom_skew = None self._menu = QMenu(self) self._copy_image_action = QAction(self.tr('Copy To Clipboard'), self) self._copy_image_action.triggered.connect(self.copyToClipboard) self._copy_image_action.setShortcuts(QKeySequence.Copy) self._save_image_action = QAction(self.tr('Save As Image'), self) self._save_image_action.triggered.connect(self.saveAsImage) self._show_table_action = QAction(self.tr('Show Table'), self) self._show_table_action.triggered.connect(self.showTable) self._menu.addAction(self._copy_image_action) self._menu.addAction(self._save_image_action) self._menu.addAction(self._show_table_action) self.addAction(self._copy_image_action) self._table_view = None self._single_axis_zoom_enabled = True self._cached_label_width_height = None if hasattr(type(self), 'dataChanged'): self.dataChanged.connect(self._on_data_changed) self._options_view = None self._secondary_axes = self._secondary_y_extent = self._secondary_x_extent = None self._legend = None self._draggable_legend = None self._setting_axis_limits = False self.hasHiddenSeries = False enabledToolsChanged = pyqtSignal() spanChanged = pyqtSignal(SpanModel) hasHiddenSeriesChanged = pyqtSignal(bool) span = AutoProperty(SpanModel) hasHiddenSeries = AutoProperty(bool) def setOptionsView(self, options_view): self._options_view = options_view self._options_view.setSecondaryYLimitsEnabled( self._secondary_y_enabled()) self._options_view.setSecondaryXLimitsEnabled( self._secondary_x_enabled()) self._options_view.showGridLinesChanged.connect( self._update_grid_lines) self._options_view.xAxisLowerLimitChanged.connect( self._handle_options_view_limit_changed(x_min_changed=True)) self._options_view.xAxisUpperLimitChanged.connect( self._handle_options_view_limit_changed(x_max_changed=True)) self._options_view.yAxisLowerLimitChanged.connect( self._handle_options_view_limit_changed(y_min_changed=True)) self._options_view.yAxisUpperLimitChanged.connect( self._handle_options_view_limit_changed(y_max_changed=True)) self._options_view.xAxisLimitsChanged.connect( self._handle_options_view_limit_changed(x_min_changed=True, x_max_changed=True)) self._options_view.yAxisLimitsChanged.connect( self._handle_options_view_limit_changed(y_min_changed=True, y_max_changed=True)) self._options_view.secondaryXAxisLowerLimitChanged.connect( self._handle_options_view_secondary_limit_changed( x_min_changed=True)) self._options_view.secondaryXAxisUpperLimitChanged.connect( self._handle_options_view_secondary_limit_changed( x_max_changed=True)) self._options_view.secondaryYAxisLowerLimitChanged.connect( self._handle_options_view_secondary_limit_changed( y_min_changed=True)) self._options_view.secondaryYAxisUpperLimitChanged.connect( self._handle_options_view_secondary_limit_changed( y_max_changed=True)) self._options_view.secondaryXAxisLimitsChanged.connect( self._handle_options_view_secondary_limit_changed( x_min_changed=True, x_max_changed=True)) self._options_view.secondaryYAxisLimitsChanged.connect( self._handle_options_view_secondary_limit_changed( y_min_changed=True, y_max_changed=True)) def setLegendControl(self, legend_control): self._legend_control = legend_control self._legend_control.seriesUpdated.connect(self._legend_series_updated) self._legend_control.showLegendChanged.connect(self._show_legend) self._legend_control.seriesNameChanged.connect( self._handle_series_name_changed) self._legend_control.showSeriesChanged.connect( self._handle_show_series_changed) bind(self._legend_control, self, 'hasHiddenSeries', two_way=False) def _legend_series_updated(self): if self._legend is not None: self._show_legend(self._legend_control.showLegend) def _show_legend(self, show): if self._legend and not show: self._legend.remove() self._legend = None self.draw() elif show: if self._legend: self._legend.remove() show_series = self._legend_control.showSeries handles = [ h for h, s in zip(self._legend_control.seriesHandles, show_series) if s ] names = [ n for n, s in zip(self._legend_control.seriesNames, show_series) if s ] axes = (self._secondary_axes if self._secondary_axes and self._secondary_axes.get_visible() and self._secondary_axes.get_zorder() > self._axes.get_zorder() else self._axes) self._legend = self._create_legend( axes, handles, names, markerscale=self._get_legend_markerscale()) if self._get_legend_text_color() is not None: for text in self._legend.texts: text.set_color(self._get_legend_text_color()) self._draggable_legend = DraggableLegend(self._legend) self.draw() def _get_legend_markerscale(self): return 5 def _create_legend(self, axes, handles, names, **kwargs): return axes.legend(handles, names, **kwargs) def _get_legend_text_color(self): return None def _handle_series_name_changed(self, index, series_name): if self._legend is not None and index < len( self._legend_control.seriesHandles): visible_handles = [ h for h, s in zip(self._legend_control.seriesHandles, self._legend_control.showSeries) if s and h is not None ] try: legend_index = visible_handles.index( self._legend_control.seriesHandles[index]) except ValueError: return if legend_index < len(self._legend.texts): self._legend.texts[legend_index].set_text(series_name) self.draw() def _handle_show_series_changed(self, index, show_series): if index < len(self._legend_control.seriesHandles): self._set_series_visibility( self._legend_control.seriesHandles[index], show_series) if self._legend is not None: self._show_legend(self._legend_control.showLegend) else: self.draw() def _set_series_visibility(self, handle, visible): if not handle: return if hasattr(handle, 'set_visible'): handle.set_visible(visible) elif hasattr(handle, 'get_children'): for child in handle.get_children(): self._set_series_visibility(child, visible) def _update_grid_lines(self): show_grid_lines = False if self._options_view is None else self._options_view.showGridLines gridline_color = self._axes.spines['bottom'].get_edgecolor() gridline_color = gridline_color[0], gridline_color[1], gridline_color[ 2], 0.5 kwargs = dict(color=gridline_color, alpha=0.5) if show_grid_lines else {} self._axes.grid(show_grid_lines, **kwargs) self.draw() def _handle_options_view_limit_changed(self, x_min_changed=False, x_max_changed=False, y_min_changed=False, y_max_changed=False): def _(): if self._options_view is None or self._setting_axis_limits: return (x_min, x_max), (y_min, y_max) = (new_x_min, new_x_max), ( new_y_min, new_y_max) = self._get_xy_extents() (x_opt_min, x_opt_max), (y_opt_min, y_opt_max) = self._get_options_view_xy_extents() if x_min_changed: new_x_min = x_opt_min if x_max_changed: new_x_max = x_opt_max if y_min_changed: new_y_min = y_opt_min if y_max_changed: new_y_max = y_opt_max if [new_x_min, new_x_max, new_y_min, new_y_max ] != [x_min, x_max, y_min, y_max]: self._xy_extents = (new_x_min, new_x_max), (new_y_min, new_y_max) self._set_axes_limits() self.draw() return _ def _get_options_view_xy_extents(self): (x_data_min, x_data_max), (y_data_min, y_data_max) = self._get_data_xy_extents() x_min = x_data_min if np.isnan( self._options_view.xAxisLowerLimit ) else self._options_view.xAxisLowerLimit x_max = x_data_max if np.isnan( self._options_view.xAxisUpperLimit ) else self._options_view.xAxisUpperLimit y_min = y_data_min if np.isnan( self._options_view.yAxisLowerLimit ) else self._options_view.yAxisLowerLimit y_max = y_data_max if np.isnan( self._options_view.yAxisUpperLimit ) else self._options_view.yAxisUpperLimit return (x_min, x_max), (y_min, y_max) def _handle_options_view_secondary_limit_changed(self, x_min_changed=False, x_max_changed=False, y_min_changed=False, y_max_changed=False): def _(): if self._options_view is None or self._setting_axis_limits: return updated = False (x_opt_min, x_opt_max), ( y_opt_min, y_opt_max) = self._get_options_view_secondary_xy_extents() if self._has_secondary_y_extent() and (y_min_changed or y_max_changed): y_min, y_max = new_y_min, new_y_max = self._get_secondary_y_extent( ) if y_min_changed: new_y_min = y_opt_min if y_max_changed: new_y_max = y_opt_max if [new_y_min, new_y_max] != [y_min, y_max]: self._secondary_y_extent = (new_y_min, new_y_max) updated = True if self._has_secondary_x_extent() and (x_min_changed or x_max_changed): x_min, x_max = new_x_min, new_x_max = self._get_secondary_x_extent( ) if x_min_changed: new_x_min = x_opt_min if x_max_changed: new_x_max = x_opt_max if [new_x_min, new_x_max] != [x_min, x_max]: self._secondary_x_extent = (new_x_min, new_x_max) updated = True if updated: self._set_axes_limits() self.draw() return _ def _get_options_view_secondary_xy_extents(self): x_data_min, x_data_max = self._get_data_secondary_x_extent() y_data_min, y_data_max = self._get_data_secondary_y_extent() x_min = x_data_min if np.isnan( self._options_view.secondaryXAxisLowerLimit ) else self._options_view.secondaryXAxisLowerLimit x_max = x_data_max if np.isnan( self._options_view.secondaryXAxisUpperLimit ) else self._options_view.secondaryXAxisUpperLimit y_min = y_data_min if np.isnan( self._options_view.secondaryYAxisLowerLimit ) else self._options_view.secondaryYAxisLowerLimit y_max = y_data_max if np.isnan( self._options_view.secondaryYAxisUpperLimit ) else self._options_view.secondaryYAxisUpperLimit return (x_min, x_max), (y_min, y_max) def _on_data_changed(self): self._cached_label_width_height = None def closeEvent(self, event): QWidget.closeEvent(self, event) if event.isAccepted(): self._zoom_selector.onselect = self._span.onselect = self._span._select_none_handler = None def set_divider_h_margin(self, h_margin): h = [ Size.Fixed(h_margin[0]), Size.Scaled(1.0), Size.Fixed(h_margin[1]) ] self._divider.set_horizontal(h) def set_divider_v_margin(self, v_margin): v = [ Size.Fixed(v_margin[0]), Size.Scaled(1.0), Size.Fixed(v_margin[1]) ] self._divider.set_vertical(v) @property def x_extent_padding(self): return self._x_extent_padding @x_extent_padding.setter def x_extent_padding(self, value): self._x_extent_padding = value @property def y_extent_padding(self): return self._y_extent_padding @y_extent_padding.setter def y_extent_padding(self, value): self._y_extent_padding = value def _in_interval(self, value, interval): return interval[0] <= value <= interval[1] def _interval_skew(self, value, interval): return (value - interval[0]) / (interval[1] - interval[0]) def _in_x_scroll_zone(self, event): return self._in_interval(event.x, self._axes.bbox.intervalx ) and event.y <= self._axes.bbox.intervaly[1] def _in_y_scroll_zone(self, event): return self._in_interval(event.y, self._axes.bbox.intervaly ) and event.x <= self._axes.bbox.intervalx[1] def _on_scroll(self, event): if self._secondary_axes is not None: self._handle_scroll_secondary(event) in_x = self._in_x_scroll_zone(event) in_y = self._in_y_scroll_zone(event) if in_x or in_y and event.button in ['up', 'down']: (x_min, x_max), (y_min, y_max) = self._get_actual_xy_extents() if (in_x and self._single_axis_zoom_enabled) or (in_x and in_y): skew = self._zoom_skew and self._zoom_skew[0] skew = self._interval_skew( event.x, self._axes.bbox.intervalx) if skew is None else skew x_min, x_max = self._zoom(x_min, x_max, skew, event.button) if (in_y and self._single_axis_zoom_enabled) or (in_x and in_y): skew = self._zoom_skew and self._zoom_skew[1] skew = self._interval_skew( event.y, self._axes.bbox.intervaly) if skew is None else skew y_min, y_max = self._zoom(y_min, y_max, skew, event.button) self._xy_extents = (x_min, x_max), (y_min, y_max) self._set_axes_limits() self.draw() def _in_secondary_y_scroll_zone(self, event): return self._in_interval(event.y, self._axes.bbox.intervaly) and \ event.x >= self._axes.bbox.intervalx[1] def _in_secondary_x_scroll_zone(self, event): return self._in_interval(event.x, self._axes.bbox.intervalx) and \ event.y >= self._axes.bbox.intervaly[1] def _handle_scroll_secondary(self, event): if self._has_secondary_y_extent(): in_secondary_y = self._in_secondary_y_scroll_zone(event) if in_secondary_y and event.button in ['up', 'down']: self._secondary_y_extent = self._zoom( *self._get_secondary_y_extent(), self._interval_skew(event.y, self._axes.bbox.intervaly), event.button) if self._has_secondary_x_extent(): in_secondary_x = self._in_secondary_x_scroll_zone(event) if in_secondary_x and event.button in ['up', 'down']: self._secondary_x_extent = self._zoom( *self._get_secondary_x_extent(), self._interval_skew(event.x, self._axes.bbox.intervalx), event.button) def _get_zoom_multiplier(self): return 20 / 19 def _zoom(self, min_, max_, skew, direction): zoom_multiplier = self._get_zoom_multiplier( ) if direction == 'up' else 1 / self._get_zoom_multiplier() range_ = max_ - min_ diff = (range_ * (1 / zoom_multiplier)) - range_ max_ += diff * (1 - skew) min_ -= diff * skew return min_, max_ def _set_axes_limits(self): try: self._setting_axis_limits = True if self._secondary_axes is not None: self._set_secondary_axes_limits() self._update_ticks() (x_min, x_max), (y_min, y_max) = self._get_xy_extents() if self._options_view is not None: if self._options_view.x_limits: self._options_view.setXLimits(float(x_min), float(x_max)) if self._options_view.y_limits: self._options_view.setYLimits(float(y_min), float(y_max)) self._axes.set_xlim(*_safe_limits(x_min, x_max)) self._axes.set_ylim(*_safe_limits(y_min, y_max)) finally: self._setting_axis_limits = False def _set_secondary_axes_limits(self): if self._options_view is not None: if self._options_view.secondary_y_limits: enabled = self._secondary_y_enabled() secondary_y_min, secondary_y_max = self._get_secondary_y_extent( ) if enabled else (float('nan'), float('nan')) self._options_view.setSecondaryYLimitsEnabled(enabled) self._options_view.setSecondaryYLimits(float(secondary_y_min), float(secondary_y_max)) if self._options_view.secondary_x_limits: enabled = self._secondary_x_enabled() secondary_x_min, secondary_x_max = self._get_secondary_x_extent( ) if enabled else (float('nan'), float('nan')) self._options_view.setSecondaryXLimitsEnabled(enabled) self._options_view.setSecondaryXLimits(float(secondary_x_min), float(secondary_x_max)) if self._has_secondary_y_extent(): self._secondary_axes.set_ylim(*_safe_limits( *self._get_secondary_y_extent())) if self._has_secondary_x_extent(): self._secondary_axes.set_xlim(*_safe_limits( *self._get_secondary_x_extent())) def _secondary_y_enabled(self): return True if self._secondary_axes and self._secondary_axes.get_visible( ) and self._has_secondary_y_extent() else False def _secondary_x_enabled(self): return True if self._secondary_axes and self._secondary_axes.get_visible( ) and self._has_secondary_x_extent() else False def _set_axes_labels(self): self._axes.set_xlabel(self.data.xAxisTitle) self._axes.set_ylabel(self.data.yAxisTitle) def _set_center(self, center): if not all(c is not None for c in center): center = (0, 0) x_extent, y_extent = self._get_xy_extents() span = x_extent[1] - x_extent[0], y_extent[1] - y_extent[0] x_extent = center[0] - span[0] / 2, center[0] + span[0] / 2 y_extent = center[1] - span[1] / 2, center[1] + span[1] / 2 self._xy_extents = x_extent, y_extent def _get_xy_extents(self): if self.data is None: return (0, 0), (0, 0) if self._xy_extents is None: return self._get_data_xy_extents() return self._xy_extents def _get_data_xy_extents(self): if self.data is None: return (0, 0), (0, 0) (x_min, x_max), (y_min, y_max) = self.data.get_xy_extents() return self._pad_extent(x_min, x_max, self.x_extent_padding), self._pad_extent( y_min, y_max, self.y_extent_padding) def _has_secondary_y_extent(self): return hasattr(self.data, 'get_secondary_y_extent') def _get_secondary_y_extent(self): if self._secondary_y_extent is not None: return self._secondary_y_extent if self.data is not None: return self._get_data_secondary_y_extent() return (0, 0) def _get_data_secondary_y_extent(self): if self.data is None: return (0, 0) return self._pad_extent(*self.data.get_secondary_y_extent(), self.y_extent_padding) def _has_secondary_x_extent(self): return hasattr(self.data, 'get_secondary_x_extent') def _get_secondary_x_extent(self): if self._secondary_x_extent is not None: return self._secondary_x_extent if self.data is not None: return self._get_data_secondary_x_extent() return (0, 0) def _get_data_secondary_x_extent(self): if self.data is None or not hasattr(self.data, 'get_secondary_x_extent'): return (0, 0) return self._pad_extent(*self.data.get_secondary_x_extent(), self.x_extent_padding) def _get_actual_xy_extents(self): return self._axes.get_xlim(), self._axes.get_ylim() def _pad_extent(self, min_, max_, padding): min_, max_ = self._zero_if_nan(min_), self._zero_if_nan(max_) range_ = max_ - min_ return min_ - padding * range_, max_ + padding * range_ def _zoom_selected(self, start_pos, end_pos): x_min, x_max = min(start_pos.xdata, end_pos.xdata), max(start_pos.xdata, end_pos.xdata) y_min, y_max = min(start_pos.ydata, end_pos.ydata), max(start_pos.ydata, end_pos.ydata) self._xy_extents = (x_min, x_max), (y_min, y_max) self._set_axes_limits() self.draw() def _handle_span_select(self, x_min, x_max): x_min, x_max = self._round_to_bin_width(x_min, x_max) self._update_span_rect(x_min, x_max) self.span = SpanModel(self, x_min, x_max) self.draw() def _handle_span_select_none(self): self.span = None def _handle_press(self, event): if event.button == 1: if self._is_panning: self._pan_event = event elif self._span.active: self._handle_span_press(event) def _handle_move(self, event): if event.xdata and self._pan_event: self._handle_pan_move(event) elif event.xdata and any(self._span_events()): self._handle_span_move(event) def _handle_release(self, event): if self._pan_event: self._pan_event = None elif any(self._span_events()): self._handle_span_release(event) def _handle_pan_move(self, event): from_x, from_y = self._axes.transData.inverted().transform( (self._pan_event.x, self._pan_event.y)) to_x, to_y = self._axes.transData.inverted().transform( (event.x, event.y)) self._pan(from_x - to_x, from_y - to_y) self._pan_event = event def _pan(self, delta_x, delta_y): (x_min, x_max), (y_min, y_max) = self._get_xy_extents() self._xy_extents = (x_min + delta_x, x_max + delta_x), (y_min + delta_y, y_max + delta_y) self._set_axes_limits() self.draw() def _span_events(self): return self._span_center_mouse_event, self._span_left_mouse_event, self._span_right_mouse_event def _handle_span_press(self, event): if not event.xdata: return span_min, span_max = (self.span.left, self.span.right) if self.span else (0, 0) edge_tolerance = self._span_tolerance() if abs(span_min - event.xdata) < edge_tolerance: self._span.active = False self._span_left_mouse_event = event elif abs(span_max - event.xdata) < edge_tolerance: self._span.active = False self._span_right_mouse_event = event elif span_min < event.xdata < span_max: self._span.active = False self._span_center_mouse_event = event def _handle_span_move(self, event): if not self.span: return x_min, x_max = self.span.left, self.span.right last_event = next(x for x in self._span_events() if x) diff_x = event.xdata - last_event.xdata if self._span_center_mouse_event is not None: self._update_span_rect(x_min + diff_x) elif self._span_left_mouse_event is not None: self._update_span_rect(x_min + diff_x, x_max) elif self._span_right_mouse_event is not None: self._update_span_rect(x_min, x_max + diff_x) self.draw([self._span.rect]) def _handle_span_release(self, _event): x_min = self._span.rect.get_x() x_max = x_min + self._span.rect.get_width() x_min, x_max = self._round_to_bin_width(x_min, x_max) self._update_span_rect(x_min, x_max) self.span = SpanModel(self, x_min, x_max) self.draw() self._span.active = True self._span_center_mouse_event = self._span_left_mouse_event = self._span_right_mouse_event = None def _update_span_rect(self, x_min, x_max=None): self._span.rect.set_x(x_min) self._span.stay_rect.set_x(x_min) if x_max: self._span.rect.set_width(x_max - x_min) self._span.stay_rect.set_width(x_max - x_min) def _round_to_bin_width(self, x_min, x_max): return x_min, x_max def _span_tolerance(self): return 5 def toolEnabled(self, _tool_type): return False def toolAvailable(self, _tool_type): return False def activateTool(self, tool_type, active): if tool_type == ToolType.zoom: self._zoom_selector.set_active(active) elif tool_type == ToolType.span: if self._span.active and not active: self._previous_span = self.span self.span = None for r in [self._span.rect, self._span.stay_rect]: self._remove_artist(r) elif not self._span.active and active: self.span = self._previous_span for r in [self._span.rect, self._span.stay_rect]: self._add_artist(r) self._span.active = active self.draw() elif tool_type == ToolType.pan: self._is_panning = active self._active_tools[tool_type] = active def toolActive(self, tool_type): return self._active_tools.get(tool_type, False) def isActiveDefault(self, _tool_type): return False def _add_artist(self, artist): self._axes.add_artist(artist) self._decoration_artists.append(artist) def _remove_artist(self, artist): artist.remove() if artist in self._decoration_artists: self._decoration_artists.remove(artist) def _handle_resize(self, _event): self._update_ticks() return self.draw() def draw(self, artists=None): if artists is None: def _update(): for a in self._decoration_artists: a.remove() self._canvas.draw() self._background_cache = self._canvas.copy_from_bbox( self._figure.bbox) for a in self._decoration_artists: self._axes.add_artist(a) self._axes.draw_artist(a) self._canvas.update() self._pending_draw = _update else: def _update(): if self._background_cache is None: raise RuntimeError('Must run draw before drawing artists!') self._canvas.restore_region(self._background_cache) for a in artists: self._axes.draw_artist(a) self._canvas.update() self._pending_artists_draw = _update def _do_draw_events(self): if self._pending_draw is not None: self._pending_draw() self._pending_draw = None if self._pending_artists_draw is not None: self._pending_artists_draw() self._pending_artists_draw = None if self._other_draw_events: for draw_event in self._other_draw_events: draw_event() self._other_draw_events = [] def addDrawEvent(self, draw_event): self._other_draw_events.append(draw_event) def resetZoom(self): self._secondary_y_extent = self._secondary_x_extent = None self._xy_extents = None self._set_axes_limits() self.draw() def _twinx(self, ylabel): axes = self._axes.twinx() for spine in ['top', 'left']: axes.spines[spine].set_visible(False) axes.set_ylabel(ylabel) axes.set_zorder(1) return axes @property def axes(self): return self._axes @property def secondary_axes(self): if self._secondary_axes is None: self._set_secondary_axes(self._twinx('')) return self._secondary_axes def _set_secondary_axes(self, axes): self._secondary_axes = axes @staticmethod def sizeHint(): """function::sizeHint() Override the default sizeHint to ensure the plot has an initial size """ return QSize(600, 400) def minimumSizeHint(self): """function::sizeHint() Override the default sizeHint to ensure the plot does not shrink below minimum size """ return self.sizeHint() @staticmethod def _zero_if_nan(value): return value if not isinstance(value, float) or not np.isnan(value) else 0 def canShowTable(self): return hasattr(self, 'data') and self.data is not None and hasattr( self.data, 'table') def contextMenuEvent(self, event): self._show_table_action.setEnabled(self.canShowTable()) self._menu.exec_(event.globalPos()) def copyToClipboard(self): with BytesIO() as buffer: self._figure.savefig(buffer, facecolor=self._figure.get_facecolor()) QApplication.clipboard().setImage( QImage.fromData(buffer.getvalue())) def saveAsImage(self): filename = self._file_dialog_service.get_save_filename( self, self.tr('Portable Network Graphics (*.png)')) if filename: self._figure.savefig(filename, facecolor=self._figure.get_facecolor()) def showTable(self): if self.canShowTable(): self._table_view = TableView(None) self._table_view.pasteEnabled = False self._table_view.setModel(self.data.table) self._table_view.setMinimumSize(800, 600) self._table_view.show() def _update_ticks(self): if not self.data: return if hasattr(self.data, 'x_labels'): step = self.data.x_tick_interval if hasattr( self.data, 'x_tick_interval') else None x_ticks, x_labels = self._get_labels(self.data.x_labels, step, horizontal=True) self._axes.set_xticks(x_ticks) self._axes.set_xticklabels(x_labels) if hasattr(self.data, 'y_labels'): step = self.data.y_tick_interval if hasattr( self.data, 'y_tick_interval') else None y_ticks, y_labels = self._get_labels(self.data.y_labels, step, horizontal=False) self._axes.set_yticks(y_ticks) self._axes.set_yticklabels(y_labels) def _get_labels(self, labels, step, horizontal=True): (x0, x1), (y0, y1) = self._get_xy_extents() start, end = (int(x0), int(x1)) if horizontal else (int(y0), int(y1)) visible_points = end - start if not (step and step > 0): width, height = self._get_label_width_height(labels) axes_bbox = self._axes.get_window_extent( self._figure.canvas.get_renderer()).transformed( self._figure.dpi_scale_trans.inverted()) plot_size = (axes_bbox.width if horizontal else axes_bbox.height) * self._figure.dpi size = (width if horizontal else height) if plot_size == 0 or size == 0: n_labels = 16 else: n_labels = int(plot_size / size) if n_labels == 0: n_labels = 16 step = int(visible_points / n_labels) + 1 else: step = int(step) indexes = list(range(len(labels))) display_labels = list(labels) for i in indexes: if i % step: display_labels[i] = '' return indexes, display_labels def _get_label_width_height(self, labels): if not self._cached_label_width_height: font = MatPlotLibFont.default() width = 0 height = 0 for label in labels: next_width, next_height = font.get_size( str(label), matplotlib.rcParams['font.size'], self._figure.dpi) width = max(width, next_width) height = max(height, next_height) self._cached_label_width_height = width, height return self._cached_label_width_height def _create_new_axes(self, nx=1, ny=1) -> LocatableAxes: axes = LocatableAxes(self._figure, self._divider.get_position()) axes.set_axes_locator(self._divider.new_locator(nx=nx, ny=ny)) self._figure.add_axes(axes) return axes @staticmethod def _create_secondary_xy_axes(figure, divider, nx=1, ny=1, visible=False, z_order=1): axes = LocatableAxes(figure, divider.get_position()) axes.set_axes_locator(divider.new_locator(nx=nx, ny=ny)) axes.xaxis.tick_top() axes.xaxis.set_label_position('top') axes.yaxis.tick_right() axes.yaxis.set_label_position('right') axes.patch.set_visible(visible) axes.set_zorder(z_order) figure.add_axes(axes) axes.ticklabel_format(style='sci', axis='x', scilimits=(-4, 4)) axes.ticklabel_format(style='sci', axis='y', scilimits=(-4, 4)) return axes @staticmethod def _create_shared_axes(figure, divider, shared_axes, nx=1, ny=1, visible=False, z_order=1): axes = LocatableAxes(figure, divider.get_position(), sharex=shared_axes, sharey=shared_axes, frameon=False) axes.set_axes_locator(divider.new_locator(nx=nx, ny=ny)) for spine in axes.spines.values(): spine.set_visible(False) for axis in axes.axis.values(): axis.set_visible(False) axes.patch.set_visible(False) axes.set_visible(False) axes.set_zorder(z_order) figure.add_axes(axes) return axes