def draw_learning_curve_axes( topo_axes_dims: List[float], learning_curve_axes_dims: List[float], epoch: np.ndarray, error: np.ndarray, figure: figure.Figure, lines: np.ndarray, colors: np.ndarray, line_widths: np.ndarray, frame: int, ): """ Render the mock logistic regression and learning curve to their respective axes :param topo_axes_dims: logistic regression axes :param learning_curve_axes_dims: learning curve plot axes :param epoch: array of values for learning curve epoch :param error: array of error values for learning curve :param figure: figure to render the axes to :param lines: Lines in the logistic regression topology :param colors: Colors of the lines in the logistic regression :param line_widths: Widths of the lines in the logistic regression :param frame: frame number of the animation """ lc = mc.LineCollection(lines, colors=colors, linewidths=line_widths) topo_ax = figure.add_axes(topo_axes_dims) topo_ax.set_xlim((0, 960)) topo_ax.set_ylim((-420, 420)) topo_ax.axis("off") topo_ax.add_collection(lc) topo_ax.text(310, -20, r"$\sum_{j=1}^n x_jw_j$", fontsize=30) topo_ax.text(604, -10, r"$\frac{\mathrm{1} }{\mathrm{1} + e^{-net}}$", fontsize=30) for i in range(41): topo_ax.text(0, -425 + i * 21, f"{np.random.randint(0,2)}", fontsize=10, color="green") topo_ax.text(880, -10, f"{np.random.random():0.3f}", fontsize=20, color="green") learning_curve_ax = figure.add_axes(learning_curve_axes_dims) learning_curve_ax.set_xlim(-1, 21) learning_curve_ax.set_ylim(0.01, 1.01) learning_curve_ax.set_xlabel("Epochs", fontsize=18) learning_curve_ax.set_ylabel("Error", fontsize=18) learning_curve_ax.get_xaxis().set_ticks([]) learning_curve_ax.get_yaxis().set_ticks([]) learning_curve_ax.spines["right"].set_visible(False) learning_curve_ax.spines["top"].set_visible(False) learning_curve_ax.spines["left"].set_linewidth(2) learning_curve_ax.spines["bottom"].set_linewidth(2) learning_curve_ax.plot(epoch[:frame], error[:frame], linewidth=3)
def draw_otf_spectrum(cube, figure=None, subplot=111, title='', grid=True, font_family=None, tick_labels_size=9, xlim=None, ylim=None, show=True, *args, **kwargs): import time import numpy import analyse import analyse.plotter import matplotlib.figure import matplotlib.colors import pylab t0 = time.time() print('[%f] -- %f'%(time.time(), time.time()-t0)) if not isinstance(figure, matplotlib.figure.Figure): if figure is None: figure = pylab.figure() else: figure = pylab.figure(figsize=figure) else: show = False if type(subplot) is int: subplot = analyse.plotter.get_subplot(subplot) elif type(subplot) in [list, tuple]: if len(subplot) == 3: subplot = analyse.plotter.get_subplot(subplot) nz, ny, nx = cube.data.shape spectra = cube.data.T.reshape(nx*ny, nz) v = analyse.generate_axis(cube, axis=3) / 1000. ax = figure.add_axes(subplot) #[ax.plot(v, s, '.b', ms=1, mew=0, alpha=0.1) for s in spectra] xd = numpy.array(list(v) * len(spectra)) yd = spectra.ravel() yd[numpy.isnan(yd)] = 0 histmap, histx, histy = pylab.histogram2d(xd, yd, bins=501) histmap = histmap.T histmap[numpy.where(histmap==0)] = 0.3 histmap = numpy.log10(histmap) histX, histY = numpy.meshgrid(histx, histy) ax.pcolormesh(histX, histY, histmap, vmax=3.3) ax.grid(grid) ax.set_title(title, size=tick_labels_size+1) if xlim is not None: ax.set_xlim(*xlim) else: ax.set_xlim(xd.min(), xd.max()) if ylim is not None: ax.set_ylim(*ylim) else: ax.set_ylim(yd.min(), yd.max()) tx = ax.get_xticks() ty = ax.get_yticks() ax.set_xticklabels(tx, size=tick_labels_size) ax.set_yticklabels(ty, size=tick_labels_size) if show: pylab.show() print('[%f] -- %f'%(time.time(), time.time()-t0)) return figure
def run_ui(): figure = plt.figure() ax = figure.add_axes([.05, .05, .9, .9]) x = np.linspace(0, np.pi * 8) ax.plot(x, np.sin(x)) canvas = figure.canvas frame = canvas.component.getTopLevelAncestor() toolbar = plt.get_current_fig_manager().frame.toolbar toolbar.add_button(lambda event: popup_script_dlg(canvas), "hand") plt.show() return frame, canvas, toolbar
def draw_smiley(pos_x: float, pos_y: float, fade_in_frames: int) -> Generator[Image.Image, None, None]: """ Generator method for rendering an emoji style smiley face :param pos_x: x axes offset for the center of the smiley face :param pos_y: y axes offset for the center of the smiley face :param fade_in_frames: Number of frames to fade in the smiley face :return: generator to produce the PIL Image frames """ figure = plt.figure(figsize=(19.2, 10.8)) fade_in_alpha = np.power(np.linspace(0, 1, fade_in_frames), 2) for alpha in fade_in_alpha: figure.clear() ax = figure.add_axes([0, 0, 1, 1]) ax.set_xlim(-960, 960) ax.set_ylim(-540, 540) face_circle = Circle((pos_x, pos_y), 200, color="yellow", alpha=alpha) face_circle.set_facecolor("yellow") ax.add_patch(face_circle) left_eye_circle = Circle((pos_x - 80, pos_y + 50), 50, color="black", alpha=alpha) ax.add_patch(left_eye_circle) right_eye_circle = Circle((pos_x + 80, pos_y + 50), 50, color="black", alpha=alpha) ax.add_patch(right_eye_circle) smile = Wedge((pos_x, pos_y - 50), 100, 180, 0, color="black", alpha=alpha) ax.add_patch(smile) figure.set_facecolor("None") ax.axis("off") im = convert_plot_to_image(figure) yield im while True: yield im
) figure.linewidth = 10 # 创建坐标系Axes:图中可以有多个坐标系(同时显示,需要指定位置大小) # |- Axis坐标轴(XAxis, YAxis) # |- 刻度, 标签,格式化器 # Figure.add_axes(axes对象| 参数) # 使用函数构建Figure ax = plt.Axes( figure, rect=[0.1, 0.5, 0.8, 0.3], label='坐标系2', facecolor=(0, 0, 1, 1), frameon=True, xscale='log', # log是对数坐标 yscale='linear') figure.add_axes(ax) figure.add_axes( [0, 1, 0.1, 0.8, 0.3], projection='polar', label='坐标系1', facecolor=(0, 1, 0, 1), frameon=True, sharex=ax, sharey=ax, xscale='linear', yscale='log', ) # 绘制图形Artist(分成很多类型:线条,矩形,文本,图像)
def plot_spectrum(wavelength, flux, filename="spectrum.png", lambda_limits=None, flux_limits=None, title=None, label=None, figsize=None, step=False, stagger=0.2, features=None, axis_labels=None): """ Plot a spectrum or a collection of spectra and save to disk. This function wraps some Matplotlib plotting functionality for plotting spectra generated with the :class:`~trident.SpectrumGenerator`. In its simplest form, it accepts a wavelength array consisting of wavelength values and a corresponding flux array consisting of relative flux values, and it plots them and saves to disk. In addition, it can plot several spectra on the same axes simultaneously by passing a list of arrays to the ``wavelength``, ``flux`` arguments (and optionally to the ``label`` and ``step`` keywords). Returns the Matplotlib Figure object for further processing. **Parameters** :wavelength: array of floats or list of arrays of floats Wavelength values in angstroms. Either as an array of floats in the case of plotting a single spectrum, or as a list of arrays of floats in the case of plotting several spectra on the same axes. :flux: array of floats or list of arrays of floats Relative flux values (from 0 to 1) corresponding to wavelength array. Either as an array of floats in the case of plotting a single spectrum, or as a list of arrays of floats in the case of plotting several spectra on the same axes. :filename: string, optional Output filename of the plotted spectrum. Will be a png file. Default: 'spectrum.png' :lambda_limits: tuple or list of floats, optional The minimum and maximum of the wavelength range (x-axis) for the plot in angstroms. If specified as None, will use whole lambda range of spectrum. Example: (1200, 1400) for 1200-1400 Angstroms Default: None :flux_limits: tuple or list of floats, optional The minimum and maximum of the flux range (y-axis) for the plot. If specified as None, limits are automatically from [0, 1.1*max(flux)]. Example: (0, 1) for normal flux range before postprocessing. Default: None :step: boolean or list of booleans, optional Plot the spectrum as a series of step functions. Appropriate for plotting processed and noisy data. Use a list of booleans when plotting multiple spectra, where each boolean corresponds to the entry in the ``wavelength`` and ``flux`` lists. :title: string, optional Optional title for plot Default: None :label: string or list of strings, optional Label for each spectrum to be plotted. Useful if plotting multiple spectra simultaneously. Will automatically trigger a legend to be generated. Default: None :stagger: float, optional If plotting multiple spectra on the same axes, do we offset them in the y direction? If set to None, no. If set to a float, stagger them by the flux value specified by this parameter. :features: dict, optional Include vertical lines with labels to represent certain spectral features. Each entry in the dictionary consists of a key string to be overplot and the value float as to where in wavelength space it will be plot as a vertical line with the corresponding label. Example: features={'Ly a' : 1216, 'Ly b' : 1026} Default: None :axis_labels: tuple of strings, optional Optionally set the axis labels directly. If set to None, defaults to ('Wavelength [$\\rm\\AA$]', 'Relative Flux'). Default: None **Returns** Matplotlib Figure object for further processing **Example** Plot a flat spectrum >>> import numpy as np >>> import trident >>> wavelength = np.arange(1200, 1400) >>> flux = np.ones(len(wavelength)) >>> trident.plot_spectrum(wavelength, flux) Generate a one-zone ray, create a Lyman alpha spectrum from it, and add gaussian noise to it. Plot both the raw spectrum and the noisy spectrum on top of each other. >>> import trident >>> ray = trident.make_onezone_ray(column_densities={'H_p0_number_density':1e21}) >>> sg_final = trident.SpectrumGenerator(lambda_min=1200, lambda_max=1300, dlambda=0.5) >>> sg_final.make_spectrum(ray, lines=['Ly a']) >>> sg_final.save_spectrum('spec_raw.h5') >>> sg_final.add_gaussian_noise(10) >>> sg_raw = trident.load_spectrum('spec_raw.h5') >>> trident.plot_spectrum([sg_raw.lambda_field, sg_final.lambda_field], ... [sg_raw.flux_field, sg_final.flux_field], stagger=0, step=[False, True], ... label=['Raw', 'Noisy'], filename='raw_and_noise.png') """ # number of rows and columns n_rows = 1 n_columns = 1 # blank space between edge of figure and active plot area top_buffer = 0.07 bottom_buffer = 0.15 left_buffer = 0.06 right_buffer = 0.03 # blank space between plots hor_buffer = 0.05 vert_buffer = 0.05 # calculate the height and width of each panel panel_width = ((1.0 - left_buffer - right_buffer - ((n_columns - 1) * hor_buffer)) / n_columns) panel_height = ((1.0 - top_buffer - bottom_buffer - ((n_rows - 1) * vert_buffer)) / n_rows) # create a figure (figsize is in inches) if figsize is None: figsize = (12, 4) figure = matplotlib.figure.Figure(figsize=figsize, frameon=True) # get the row and column number my_row = 0 my_column = 0 # calculate the position of the bottom, left corner of this plot left_side = left_buffer + (my_column * panel_width) + \ my_column * hor_buffer top_side = 1.0 - (top_buffer + (my_row * panel_height) + \ my_row * vert_buffer) bottom_side = top_side - panel_height # create an axes object on which we will make the plot my_axes = figure.add_axes( (left_side, bottom_side, panel_width, panel_height)) # Are we overplotting several spectra? or just one? if isinstance(flux, list): fluxs = flux else: fluxs = [flux] if isinstance(wavelength, list): wavelengths = wavelength else: wavelengths = [wavelength] * len(fluxs) if isinstance(step, list): steps = step else: steps = [step] * len(fluxs) if isinstance(label, list): labels = label else: labels = [label] * len(fluxs) # A running maximum of flux for use in ylim scaling in final plot max_flux = 0. if isinstance(wavelength, list): key = wavelength[0] else: key = wavelength xlabel = _xlabels.get(str(key.units)) for i, (wavelength, flux) in enumerate(zip(wavelengths, fluxs)): # Do we stagger the fluxes? if stagger is not None: flux -= stagger * i # Do we include labels and a legend? if steps[i]: my_axes.step(wavelength, flux, label=labels[i]) else: my_axes.plot(wavelength, flux, label=labels[i]) new_max_flux = np.max(flux) if new_max_flux > max_flux: max_flux = new_max_flux # Return the fluxes to their normal values # if they've been staggered if stagger is not None: flux += stagger * i # Do we include a title? if title is not None: my_axes.set_title(title) if lambda_limits is None: lambda_limits = (wavelength.min(), wavelength.max()) my_axes.set_xlim(lambda_limits[0], lambda_limits[1]) if flux_limits is None: flux_limits = (0, 1.1 * max_flux) my_axes.set_ylim(flux_limits[0], flux_limits[1]) if axis_labels is None: axis_labels = (xlabel, 'Relative Flux') my_axes.xaxis.set_label_text(axis_labels[0]) my_axes.yaxis.set_label_text(axis_labels[1]) # Don't let the x-axis switch to offset values for tick labels my_axes.get_xaxis().get_major_formatter().set_useOffset(False) if label is not None: my_axes.legend() # Overplot the relevant features on the plot if features is not None: for feature in features: label = feature wavelength = features[feature] # Draw line my_axes.plot([wavelength, wavelength], flux_limits, '--', color='k') # Write text text_location = flux_limits[1] - 0.05 * (flux_limits[1] - flux_limits[0]) my_axes.text(wavelength, text_location, label, horizontalalignment='right', verticalalignment='top', rotation='vertical') mylog.info("Writing spectrum plot to png file: %s" % filename) canvas = FigureCanvasAgg(figure) canvas.print_figure(filename) return figure
def __init__(self, figure, left = 0.2, bottom = 0.2, width = 0.6, height = 0.6, axes = None, polar = None, autoscale_both_on = None, autoscale_x_on = None, autoscale_y_on = None, colorbar=None, locator_x=None, locator_y=None): """FIGURE is the matplotlib.figure.Figure instance where to act on. AXES is optionally an existing axes instance. If AXES is not given, a new axes instance will be created, either a cartesian, or a polar if POLAR is True. The initial autoscaling is controled by AUTOSCALING_BOTH, AUTOSCALING_X, and AUTOSCALING_Y. If AUTOSCALING_BOTH is given, it overrides AUTOSCALING_X and AUTOSCALING_Y. If the autoscaling for some axis isn't given (either by AUTOSCALING_BOTH or by the other arguments), it defaults to True. If COLORBAR isn't None, but 'vertical' or 'horizontal', the Axes will be initialised by setting the label and ticks position to the appropriate position. This is useful if the Stack is intended to be used for a LayerColorbar, since the LayerColorbar cannot draw a Colorbar until it has received data, and therefore there would be nothing updating the ticks and label positions. LOCATOR_X and LOCATOR_Y are optional and are the major locator to be used for the respective axes.""" # Define the default values for AUTOSCALING_X/Y. May be overridden # by AUTOSCALING_BOTH if that is given ... if autoscale_x_on is None: autoscale_x_on = True if autoscale_y_on is None: autoscale_y_on = True # Initialise attributes ... if axes is None: # Create a new axes instance. axes = figure.add_axes( (left, bottom, width, height), polar = polar) axes.hold(True) # Take over the axes. self.axes = axes # Initialise the title etc. to some values. self.title = self.axes.get_title() self.title_kwargs = {} self.xlabel = self.axes.get_xlabel() self.ylabel = self.axes.get_ylabel() # Apply the autoscaling ... # # This will also store the correct values for .xlim and .ylim. self.set_autoscale_on( both_on = autoscale_both_on, x_on = autoscale_x_on, y_on = autoscale_y_on) # Store the locators ... self.set_locators(locator_x=locator_x, locator_y=locator_y) # Prepare for use as a colorbar ... # # Do this after setting the locators and not before. Because # set_colorbar() sets also the xticks, but set_locators overrides # this by setting the xlocator to AutoLocator(), when done in the # wrong order. self.set_colorbar(colorbar) # The layers present. self._layers = [] # The layers rendered to the FigureAxes. self._layers_drawn = [] # Whether a reset of the FigureAxes is needed before rendering. This # may occur because: # 1. Layers drawn have changed data. # 2. Layers have been removed. self._needs_reset = False
def main(): """ Entry point for rendering the plot """ anim_file_path = Path("./test.mp4") figure = plt.figure(figsize=(19.2, 10.8)) file_writer = FFMpegFileWriter(fps=FRAME_RATE) with file_writer.saving(figure, anim_file_path, dpi=100): intro_text = Scene( 0, 169, 1, draw_text( sentence="I've seen things you people wouldn't believe", text_pos_list=[16, 44], alpha_transitions=60, persist_frames=0, fade_out_frames=24, font_size=48, left_offset=0.12, bottom_offset=0.0, ), ) eye = Scene( intro_text.start_frame, intro_text.end_frame, 0, draw_eye(axes_dims=[0, 0.22, 1.0, 0.8], persist_frames=24, fade_out_frames=24), ) heatmap = Scene( intro_text.end_frame - 47, intro_text.end_frame + 145, 2, draw_fire_automata( axes_dims=[0.2, 0.35, 0.6, 0.6], fade_in_frames=24, update_frames=144, fade_out_frames=24, ), ) gaussian = Scene( intro_text.end_frame + 1, intro_text.end_frame + 145, 1, draw_gaussian( axes_dims=[0.05, 0.1, 0.9, 0.25], fade_in_frames=24, update_frames=72, persist_frames=24, fade_out_frames=24, ), ) heatmaps_text = Scene( 145, 313, 1, draw_text( sentence="Heat maps on fire off the shoulder of a Gaussian", text_pos_list=[17, 48], alpha_transitions=60, persist_frames=24, fade_out_frames=24, font_size=48, left_offset=0.08, bottom_offset=0.0, ), ) learning_curve = Scene( heatmaps_text.end_frame + 1, heatmaps_text.end_frame + 277, 1, draw_learning_curve( topo_axes_dims=[0.01, 0.15, 0.5, 0.8], learning_curve_axes_dims=[0.54, 0.15, 0.44, 0.8], fade_in_frames=24, update_frames=156, persist_frames=72, fade_out_frames=24, ), ) residuals_text = Scene( heatmaps_text.end_frame + 1, heatmaps_text.end_frame + 277, 2, draw_text( sentence= "I watched residuals diminish down the arc of ten thousand weights", text_pos_list=[10, 41, 65], alpha_transitions=60, persist_frames=72, fade_out_frames=24, font_size=40, left_offset=0.015, bottom_offset=0.0, ), ) fade_text_1 = Scene( residuals_text.end_frame + 1, residuals_text.end_frame + 193, 2, draw_text( sentence="All these visuals", text_pos_list=[17], alpha_transitions=60, persist_frames=84, fade_out_frames=48, font_size=100, left_offset=0.2, bottom_offset=0.53, ), ) fade_text_2 = Scene( residuals_text.end_frame + 60, residuals_text.end_frame + 193, 2, draw_text( sentence="will fade in time", text_pos_list=[17], alpha_transitions=60, persist_frames=24, fade_out_frames=48, font_size=100, left_offset=0.2, bottom_offset=0.37, ), ) terrain = Scene( fade_text_2.end_frame + 49, fade_text_2.end_frame + 169, 1, draw_terrain( axes_dims=[0.05, 0.2, 0.9, 0.8], fade_in_frames=24, update_frames=72, fade_out_frames=24, frame_jiggle=0.01, ), ) tears_text = Scene( fade_text_2.end_frame + 1, fade_text_2.end_frame + 169, 2, draw_text( sentence="Like tears in terrain", text_pos_list=[11, 21], alpha_transitions=48, persist_frames=48, fade_out_frames=24, font_size=60, left_offset=0.3, bottom_offset=0, ), ) pi_text_1 = Scene( tears_text.end_frame + 1, tears_text.end_frame + 217, 2, draw_text( sentence="Time to pi", text_pos_list=[4, 10], alpha_transitions=72, persist_frames=72, fade_out_frames=0, font_size=80, left_offset=0.08, bottom_offset=0.8, ), ) pi_text_2 = Scene( tears_text.end_frame + 169, tears_text.end_frame + 217, 1, draw_text( sentence="Time to pip install matplotlib", text_pos_list=[30], alpha_transitions=24, persist_frames=100, fade_out_frames=0, font_size=80, left_offset=0.08, bottom_offset=0.8, ), ) smiley = Scene( tears_text.end_frame + 169, tears_text.end_frame + 217, 2, draw_smiley(fade_in_frames=24, pos_x=0, pos_y=0), ) active_scenes_list: List[Scene] = [ intro_text, eye, heatmap, gaussian, heatmaps_text, learning_curve, residuals_text, fade_text_1, fade_text_2, terrain, tears_text, pi_text_1, pi_text_2, smiley, ] active_scenes_list.sort(key=lambda scene: scene.zorder, reverse=True) for frame_number in itertools.count(): figure.clear() render_axes = figure.add_axes([0.0, 0.0, 1.0, 1.0]) render_axes.axis("off") active_scene_count = len(active_scenes_list) if active_scene_count <= 0: break rendered_scene: bool = False for scene_index in range(active_scene_count - 1, -1, -1): scene = active_scenes_list[scene_index] if frame_number >= scene.start_frame: if frame_number > scene.end_frame: del active_scenes_list[scene_index] else: render_axes.imshow(next(scene.render_frame)) rendered_scene = True if rendered_scene is True: file_writer.grab_frame(facecolor=BACKGROUND_COLOUR)
def draw_terrain( axes_dims: List[float], fade_in_frames: int, update_frames: int, fade_out_frames: int, frame_jiggle: float, ) -> Generator[Image.Image, None, None]: """ Generator method to draw California area, large cities and faults :param axes_dims: matplotlib offset and dimensions :param fade_in_frames: Number of frames to fade in graphic :param update_frames: Number of frames to animate for :param fade_out_frames: Number of frames to fade out the graphic :param frame_jiggle: Random offset to apply to the axes each animation :return: generator to produce the PIL Image frames """ # Downloaded http://naciscdn.org/naturalearth/packages/natural_earth_vector.zip and # unzipped into project directory coastlines_gdf = gpd.read_file( "./natural_earth_vector/10m_physical/ne_10m_land_scale_rank2.shp") populated_gdf = gpd.read_file( "./natural_earth_vector/10m_cultural/ne_10m_populated_places.dbf") # Downloaded https://earthquake.usgs.gov/static/lfs/nshm/qfaults/Qfaults_GIS.zip and # unzipped into project directory faults_gdf = gpd.read_file("./GIS Files/Shapefile/QFaults.shp") area = Polygon([(-124, 33.5), (-124, 38), (-115, 38), (-115, 33.5)]) pop_mask = populated_gdf.within(area) california_gdf = populated_gdf.loc[pop_mask] california_highpop_gdf = california_gdf[california_gdf["SCALERANK"] < 3] fault_mask = faults_gdf.intersects(area) im: Image.Image = Image.fromarray(np.zeros((1, 1, 4), dtype=np.uint8)) figure = plt.figure(figsize=(19.2, 10.8)) fade_in_alpha = np.power(np.linspace(0, 1, fade_in_frames), 2) for alpha in fade_in_alpha: figure.clear() with plt.style.context("dark_background"): ax = figure.add_axes(axes_dims) california_highpop_gdf.plot(ax=ax, zorder=2, color="blue", markersize=100) coastlines_gdf.plot(ax=ax, zorder=1, color="forestgreen") for x, y, label in zip( california_highpop_gdf.geometry.x, california_highpop_gdf.geometry.y, california_highpop_gdf["NAME"], ): ax.annotate( label, xy=(x, y), xytext=(15, -5), textcoords="offset points", zorder=3, fontsize=30, ) ax.set_xlim(-125, -116.111) ax.set_ylim(33.5, 38) fault_mask = faults_gdf.intersects(area) faults_gdf.loc[fault_mask].plot(color="red", ax=ax, zorder=1, alpha=0, linewidth=2) figure.set_facecolor("None") ax.axis("off") im = convert_plot_to_image(figure) pixels = np.array(im) alpha_layer = pixels[:, :, 3] alpha_layer[alpha_layer > 0] = int(255 * alpha) yield Image.fromarray(pixels) for frame_number in range(update_frames): figure.clear() with plt.style.context("dark_background"): jiggled_dims = copy.deepcopy(axes_dims) x_jiggle = np.random.random() x_jiggle = (x_jiggle * 2 - 1) * frame_jiggle y_jiggle = np.random.random() y_jiggle = (y_jiggle * 2 - 1) * frame_jiggle jiggled_dims[0] += x_jiggle jiggled_dims[1] += y_jiggle tear_alpha = (np.sin(frame_number / 4) + 1) / 2 ax = figure.add_axes(jiggled_dims) california_highpop_gdf.plot(ax=ax, zorder=2, color="blue", markersize=100) coastlines_gdf.plot(ax=ax, zorder=1, color="forestgreen") for x, y, label in zip( california_highpop_gdf.geometry.x, california_highpop_gdf.geometry.y, california_highpop_gdf["NAME"], ): ax.annotate( label, xy=(x, y), xytext=(15, -5), textcoords="offset points", zorder=3, fontsize=30, ) ax.set_xlim(-125, -116.111) ax.set_ylim(33.5, 38) faults_gdf.loc[fault_mask].plot(color="red", ax=ax, zorder=1, alpha=tear_alpha, linewidth=2) figure.set_facecolor("None") ax.axis("off") im = convert_plot_to_image(figure) yield im fade_out_alpha = np.power(np.linspace(1, 0, fade_out_frames), 2) for frame_number in range(fade_out_frames): alpha = fade_out_alpha[frame_number] figure.clear() with plt.style.context("dark_background"): jiggled_dims = copy.deepcopy(axes_dims) x_jiggle = np.random.random() x_jiggle = (x_jiggle * 2 - 1) * frame_jiggle y_jiggle = np.random.random() y_jiggle = (y_jiggle * 2 - 1) * frame_jiggle jiggled_dims[0] += x_jiggle jiggled_dims[1] += y_jiggle tear_alpha = (np.sin((update_frames + frame_number) / 4) + 1) / 2 ax = figure.add_axes(jiggled_dims) california_highpop_gdf.plot(ax=ax, zorder=2, color="blue", markersize=100) coastlines_gdf.plot(ax=ax, zorder=1, color="forestgreen") for x, y, label in zip( california_highpop_gdf.geometry.x, california_highpop_gdf.geometry.y, california_highpop_gdf["NAME"], ): ax.annotate( label, xy=(x, y), xytext=(15, -5), textcoords="offset points", zorder=3, fontsize=30, ) ax.set_xlim(-125, -116.111) ax.set_ylim(33.5, 38) faults_gdf.loc[fault_mask].plot(color="red", ax=ax, zorder=1, alpha=tear_alpha, linewidth=2) figure.set_facecolor("None") ax.axis("off") im = convert_plot_to_image(figure) pixels = np.array(im) alpha_layer = pixels[:, :, 3] alpha_layer[alpha_layer > 0] = int(255 * alpha) yield Image.fromarray(pixels) # Stay black for the remainder black_screen = np.array(im) black_screen[:, :, :] = 0 im = Image.fromarray(black_screen) while True: yield im
def draw_eye(axes_dims: List[float], persist_frames: int, fade_out_frames: int) -> Generator[Image.Image, None, None]: """ Generator method for rendering a stylized eye :param axes_dims: offset and dimensions of the axes to render to :param persist_frames: Number of frames to persist the frames to :param fade_out_frames: Number of frames to fade out the eye :return: Generator for producing PIL Image frames """ interval_count = 361 angle = np.linspace(0, np.pi * 2.0, interval_count) radius = np.array([num % 2 for num in range(0, interval_count)]) * 2.5 + 1.5 x = radius * np.cos(angle) y = radius * np.sin(angle) iris = np.vstack([x.reshape(1, -1), y.reshape(1, -1)]) intervals = np.linspace(-7.05, 7.05, interval_count) positive_curve = 0.075 * intervals**2 - 3.75 negative_curve = -0.075 * (intervals**2) + 3.75 im: Image.Image = Image.fromarray(np.zeros((1, 1, 4), dtype=np.uint8)) figure = plt.figure(figsize=(19.2, 10.8)) for i in range(1, interval_count + 3, 3): figure.clear() # Draw Iris ax = figure.add_axes(axes_dims) ax.fill_between( intervals[interval_count - i:], positive_curve[interval_count - i:], negative_curve[interval_count - i:], color="white", zorder=1, ) ax.plot(iris[0, 0:i], iris[1, 0:i], linewidth=5, color="steelblue", zorder=3) ax.fill_between( intervals, np.ones(interval_count) * 5, negative_curve, color="black", alpha=1.0, zorder=4, ) ax.fill_between( intervals, -np.ones(interval_count) * 5, positive_curve, color="black", alpha=1.0, zorder=4, ) ax.set_xlim(-9.6, 9.6) ax.set_ylim(-4.32, 4.32) ax.axis("off") patch = patches.Circle((0, 0), radius=4.02, color="black", zorder=2) ax.add_patch(patch) im = convert_plot_to_image(figure) yield im # Keep the image for this many frames for i in range(persist_frames): yield im # Fade out the image over this many frames fade_out_alpha = np.power(np.linspace(1, 0, fade_out_frames), 2) for alpha in fade_out_alpha: pixels = np.array(im) alpha_layer = pixels[:, :, 3] alpha_layer[alpha_layer > 0] = int(255 * alpha) yield Image.fromarray(pixels) # Stay black for the remainder black_screen = np.array(im) black_screen[:, :, :] = 0 im = Image.fromarray(black_screen) while True: yield im
def draw_gaussian( axes_dims: List[float], fade_in_frames: int, update_frames: int, persist_frames: int, fade_out_frames: int, ) -> Generator[Image.Image, None, None]: """ Generator method for drawing Gaussian :param axes_dims: Offset and dimensions of the plot axes :param fade_in_frames: Number of frames to fade in the graphic :param update_frames: Number of frames to update the graphic :param persist_frames: Number of frames to persist the graphic :param fade_out_frames: Number of frames to fade out the graphic :return: generator for producing the PIL Image frames """ figure = plt.figure(figsize=(19.2, 10.8)) with plt.style.context("dark_background"): ax = figure.add_axes(axes_dims) ax.spines["right"].set_visible(False) ax.spines["top"].set_visible(False) ax.spines["left"].set_linewidth(2) ax.spines["bottom"].set_linewidth(2) ax.set_xlim((-8.8, 8.8)) ax.set_ylim((-0.02, 0.42)) im = convert_plot_to_image(figure) # [0.05, 0.1, 0.9, 0.25] # Fade in the axes over this many frames fade_in_alpha = np.power(np.linspace(0, 1, fade_in_frames), 2) for alpha in fade_in_alpha: pixels = np.array(im) alpha_layer = pixels[:, :, 3] alpha_layer[alpha_layer > 0] = int(255 * alpha) yield Image.fromarray(pixels) # Animate the Guassian mu = 0 variance = 1 sigma = np.sqrt(variance) for frame in range(0, update_frames * 4, 4): figure.clear() with plt.style.context("dark_background"): ax = figure.add_axes(axes_dims) x = np.linspace(mu - 8 * sigma, mu + 8 * sigma, update_frames * 4) ax.plot( x[:frame], stats.norm.pdf(x[:frame], mu, sigma), linewidth=3, color="skyblue", ) ax.spines["right"].set_visible(False) ax.spines["top"].set_visible(False) ax.spines["left"].set_linewidth(2) ax.spines["bottom"].set_linewidth(2) ax.set_xlim((-8.8, 8.8)) ax.set_ylim((-0.02, 0.42)) im = convert_plot_to_image(figure) yield im for frame in range(persist_frames): yield im # Fade out the image over this many frames fade_out_alpha = np.power(np.linspace(1, 0, fade_out_frames), 2) for alpha in fade_out_alpha: pixels = np.array(im) alpha_layer = pixels[:, :, 3] alpha_layer[alpha_layer > 0] = int(255 * alpha) yield Image.fromarray(pixels) # Stay black for the remainder black_screen = np.array(im) black_screen[:, :, :] = 0 im = Image.fromarray(black_screen) while True: yield im
def draw_fire_automata( axes_dims: List[float], fade_in_frames: int, update_frames: int, fade_out_frames: int, ) -> Generator[Image.Image, None, None]: """ Generator method for rendering the fire automata :param axes_dims: Offset and dimensions of the axes :param fade_in_frames: Number of frames to fade in the graphic :param update_frames: Number of frames to update the graphic :param fade_out_frames: Number of frames to fade out the graphic :return: Generator for producing PIL Image frames """ im: Image.Image = Image.fromarray(np.zeros((1, 1, 4), dtype=np.uint8)) fire_automata = FireAutomata(height=65, width=64, decay=0.95, spawn_points=20) figure = plt.figure(figsize=(19.2, 10.8)) fade_in_alpha = np.power(np.linspace(0, 1, fade_in_frames), 2) for alpha in fade_in_alpha: figure.clear() render_axes = figure.add_axes(axes_dims) fire_automata.update_heatmap() render_axes.imshow( fire_automata.heatmap[:-1, :], cmap="hot", interpolation="nearest", alpha=alpha, ) render_axes.axis("off") im = convert_plot_to_image(figure) yield im for frame_number in range(update_frames): figure.clear() render_axes = figure.add_axes(axes_dims) fire_automata.update_heatmap() render_axes.imshow(fire_automata.heatmap[:-1, :], cmap="hot", interpolation="nearest") render_axes.axis("off") im = convert_plot_to_image(figure) yield im fade_out_alpha = np.power(np.linspace(1, 0, fade_out_frames), 2) for alpha in fade_out_alpha: figure.clear() render_axes = figure.add_axes(axes_dims) fire_automata.update_heatmap() render_axes.imshow( fire_automata.heatmap[:-1, :], cmap="hot", interpolation="nearest", alpha=alpha, ) render_axes.axis("off") im = convert_plot_to_image(figure) yield im # Stay black for the remainder black_screen = np.array(im) black_screen[:, :, :] = 0 im = Image.fromarray(black_screen) while True: yield im
def draw_text( sentence: str, text_pos_list: List[int], alpha_transitions: int, persist_frames: int, fade_out_frames: int, font_size: int, left_offset: float, bottom_offset: float, ) -> Generator[Image.Image, None, None]: """ Renders a sentence with configurable phrase boundaries :param sentence: Full text to render :param text_pos_list: Character offsets in the sentence to fade in :param alpha_transitions: Number of alpha increments to fade in each phrase :param persist_frames: Number of frames to persist the sentence once drawn :param fade_out_frames: Number of frames to fade out the sentence :param font_size: Size of the font to render the sentence with :param left_offset: axes offset for the text from the left boundary :param bottom_offset: axes offset for the text from the bottom boundary :return: Generator for producing PIL Image frames """ im: Image.Image = Image.fromarray(np.zeros((1, 1, 4), dtype=np.uint8)) figure = plt.figure(figsize=(19.2, 10.8)) alpha_array = np.power(np.linspace(0, 1, alpha_transitions), 2) for idx, text_pos in enumerate(text_pos_list): for alpha in alpha_array: figure.clear() text_axes = figure.add_axes([0.0, 0.0, 1.0, 1.0]) text_axes.axis("off") if idx > 0: text_axes.text( left_offset, bottom_offset, s=sentence[:text_pos_list[idx - 1]], fontsize=font_size, style="oblique", ha="left", va="bottom", color="white", alpha=1.0, ) text_axes.text( left_offset, bottom_offset, s=sentence[:text_pos], fontsize=font_size, style="oblique", ha="left", va="bottom", color="white", alpha=alpha, ) im = convert_plot_to_image(figure) yield im # Keep the image for this many frames for i in range(persist_frames): yield im # Fade out the image over this many frames fade_out_alpha = np.power(np.linspace(1, 0, fade_out_frames), 2) for alpha in fade_out_alpha: figure.clear() text_axes = figure.add_axes([0.0, 0.0, 1.0, 1.0]) text_axes.axis("off") text_axes.text( left_offset, bottom_offset, s=sentence, fontsize=font_size, style="oblique", ha="left", va="bottom", color="white", alpha=alpha, ) im = convert_plot_to_image(figure) yield im # Stay black for the remainder black_screen = np.array(im) black_screen[:, :, :] = 0 im = Image.fromarray(black_screen) while True: yield im