def signal_set_xlim(axes, tmin=None, tmax=None, **kwargs): ''' This set_xlim function replaces the usual matplotlib axes set_xlim function. It will redraw the signals after having downsampled them. ''' # don't do anything if locked. if axes._are_axes_locked: return axes.lock_axes() # parse inputs if tmax is None and is_iterable(tmin): tmin, tmax = tmin if hasattr(axes, '_signal_times'): for s_id in axes._signal_draw_order: # don't replot if bounds didn't actually change. xmin, xmax = axes.get_xlim() if xmin == tmin and xmax == tmax and\ s_id in axes._signal_lines.keys(): continue # delete existing lines if s_id in axes._signal_lines.keys(): axes._signal_lines[s_id].remove() del axes._signal_lines[s_id] # downsample new_signal, new_times = downsample_for_plot( axes._signals[s_id], axes._signal_times[s_id], tmin, tmax, axes._signal_num_samples) line = axes.plot(new_times, new_signal, *axes._signal_args[s_id], **axes._signal_kwargs[s_id])[0] # save this line so we can remove it later. axes._signal_lines[s_id] = line axes.unlock_axes() # actually change the xlimits axes._pre_signal_set_xlim(tmin, tmax, **kwargs)
def make_into_publication_axes( axes, axis="both", base_unit=("s", "V"), base_unit_prefix=("m", "m"), plot_to_base_factor=(1.0, 1.0), target_size_frac=(0.2, 0.2), scale_bar_origin_frac=(0.7, 0.7), live_update=True, chunks=[1, 2, 5, 10, 20, 25, 30, 50, 100, 200, 500], y_label_rotation="horizontal", color="black", ): """ Makes the axes look like trace plots in publications. That is, the frame is not drawn, and a scale bar for x and y is displayed instead. Inputs: axes: The axes you wish to format this way. axis: 'x', 'y', or 'both' base_unit: The base SI unit, for example: 'V', 'Hz', 'F', 'C'... base_unit_prefix: The prefix needed to get to the plotted units. plot_to_base_factor: The factor which converts plotted units to base units. (i.e. pixels_to_um for an image) target_size_frac: The desired size of the scale bar, this may be off by a bit, depending on the choice of <chunks>. (kwarg) scale_bar_origin_frac : The position of the origin of the scale bar in fractional axes units. live_update: If True, the scale bars will update when ylim changes. chunks : Passed on to get_scale_bar_info. y_label_rotation: the angle of the y label. Anything that a matplotlib Text object accepts as a rotation= kwarg. color: The color of the lines and labels. Returns: None : It just alters the axes. """ if live_update: if not hasattr(axes, "_is_signal_axes"): make_into_signal_axes(axes) axes._live_updating_scalebars = True axes.set_frame_on(False) axes.set_xticks([]) axes.set_yticks([]) # parse inputs if is_iterable(base_unit): base_unit_x, base_unit_y = base_unit else: base_unit_x, base_unit_y = (base_unit, base_unit) if is_iterable(base_unit_prefix): base_unit_prefix_x, base_unit_prefix_y = base_unit_prefix else: base_unit_prefix_x, base_unit_prefix_y = (base_unit_prefix, base_unit_prefix) if is_iterable(plot_to_base_factor): plot_to_base_factor_x, plot_to_base_factor_y = plot_to_base_factor else: plot_to_base_factor_x, plot_to_base_factor_y = (plot_to_base_factor, plot_to_base_factor) if is_iterable(target_size_frac): target_size_frac_x, target_size_frac_y = target_size_frac else: target_size_frac_x, target_size_frac_y = (target_size_frac, target_size_frac) def create_x_scale_bar(axes): # clear old if hasattr(axes, "_x_scale_bar"): for line in axes._x_scale_bar: line.remove() del axes._x_scale_bar if hasattr(axes, "_x_scale_text"): axes._x_scale_text.remove() del axes._x_scale_text x_min = numpy.min(axes.get_xlim()) x_max = numpy.max(axes.get_xlim()) x_range = x_max - x_min y_min = numpy.min(axes.get_ylim()) y_max = numpy.max(axes.get_ylim()) y_range = y_max - y_min scale_bar_info = get_scale_bar_info( target_size_frac_x, x_range * plot_to_base_factor_x, base_unit_prefix=base_unit_prefix_x, chunks=chunks ) bar_min = x_min + scale_bar_origin_frac[0] * x_range bar_max = bar_min + scale_bar_info["scale_base"] / plot_to_base_factor_x bar_y = scale_bar_origin_frac[1] * y_range + y_min axes._x_scale_bar = axes.plot((bar_min, bar_max), (bar_y, bar_y), linewidth=2, color=color, clip_on=False) bar_range = bar_max - bar_min bar_mid = bar_min + bar_range / 2.0 text = "%s %s%s" % (scale_bar_info["best_chunk"], scale_bar_info["scale_unit_prefix"], base_unit_x) f = axes.figure canvas_size_in_pixels = (f.get_figwidth() * f.get_dpi(), f.get_figheight() * f.get_dpi()) y_pix = as_fraction_axes(y=8, axes=axes, canvas_size_in_pixels=canvas_size_in_pixels) * y_range axes._x_scale_text = axes.text( bar_mid, bar_y - y_pix, text, horizontalalignment="center", verticalalignment="top", color=color ) def create_y_scale_bar(axes): # clear old if hasattr(axes, "_y_scale_bar"): for line in axes._y_scale_bar: line.remove() del axes._y_scale_bar if hasattr(axes, "_y_scale_text"): axes._y_scale_text.remove() del axes._y_scale_text x_min = numpy.min(axes.get_xlim()) x_max = numpy.max(axes.get_xlim()) x_range = x_max - x_min y_min = numpy.min(axes.get_ylim()) y_max = numpy.max(axes.get_ylim()) y_range = y_max - y_min scale_bar_info = get_scale_bar_info( target_size_frac_y, y_range * plot_to_base_factor_y, base_unit_prefix=base_unit_prefix_y, chunks=chunks ) bar_min = scale_bar_origin_frac[1] * y_range + y_min bar_max = bar_min + scale_bar_info["scale_base"] / plot_to_base_factor_y bar_x = scale_bar_origin_frac[0] * x_range + x_min axes._y_scale_bar = axes.plot((bar_x, bar_x), (bar_min, bar_max), linewidth=2, color=color, clip_on=False) bar_range = bar_max - bar_min bar_mid = bar_min + bar_range / 2.0 text = "%s %s%s" % (scale_bar_info["best_chunk"], scale_bar_info["scale_unit_prefix"], base_unit_y) f = axes.figure canvas_size_in_pixels = (f.get_figwidth() * f.get_dpi(), f.get_figheight() * f.get_dpi()) x_pix = as_fraction_axes(x=8, axes=axes, canvas_size_in_pixels=canvas_size_in_pixels) * x_range axes._y_scale_text = axes.text( bar_x - x_pix, bar_mid, text, horizontalalignment="right", verticalalignment="center", rotation=y_label_rotation, color=color, ) if axis in ["both", "x"]: axes._create_x_scale_bar = create_x_scale_bar else: axes._create_x_scale_bar = lambda axes: None if axis in ["both", "y"]: axes._create_y_scale_bar = create_y_scale_bar else: axes._create_y_scale_bar = lambda axes: None