def video(zipname, html=None): fig, ax = plt.subplots() def plot_hour(hour): # data reader = zip_csv_iter(zipname) header = next(reader) cidx = header.index("country") timeidx = header.index("time") counts = defaultdict(int) w = geopandas.read_file( geopandas.datasets.get_path('naturalearth_lowres')) # no Antarctica w = w[w["continent"] != "Antarctica"] w["count"] = 0 # plot the background ax.cla() w.plot(color="0.8", ax=ax) # populate counts for row in reader: if hour != None: if hour != int(row[timeidx].split(":")[0]): continue counts[row[cidx]] += 1 # data with count bigger than 0 for country, count in counts.items(): if country not in list(w["name"]): continue w["count"][w["name"] == country] = count w = w[w["count"] > 0] # plot the hour w.plot(ax=ax, column="count", cmap="Reds", scheme='quantiles') anim = FuncAnimation(fig, plot_hour, frames=24, interval=250) html_code = anim.to_html5_video() plt.close() with open(html, "w") as f: f.write(html_code)
def visual_convolution(image, kernel, debug=False): fig = plt.figure() _image = np.pad(image, ((1, 1), (1, 1)), 'constant') # padd with zeros output_image = np.copy(image) frames = [output_image] convolve(image, kernel, frames=frames) img = plt.imshow(np.copy(output_image), animated=True, cmap="gray", norm=NoNorm()) def update(f): img.set_array(f) return img ani = FuncAnimation(fig, update, frames=frames, interval=50) html = HTML(ani.to_html5_video()) plt.close() display(html)
def animate(self, mode="js"): plt.ioff() heigth, width = self.background.shape ratio = width / heigth figure, ax = plt.subplots(figsize=(3 * ratio, 3)) im = plt.imshow(self.background, cmap=self.cmap, norm=self.norm, animated=True) title = ax.text(0.5, 0.90, "", bbox={ 'facecolor': 'w', 'alpha': 0.5, 'pad': 5 }, transform=ax.transAxes, ha="center") ax.axis('off') def update(i): data = self.frames[i] if isinstance(data, tuple): img, text = data title.set_text(text) else: img = data im.set_array(img) return im, title ani = FuncAnimation(figure, update, frames=len(self.frames), interval=1000 / 60, blit=True, repeat=False) if mode == "html": return HTML(ani.to_html5_video()) elif mode == "js": return HTML(ani.to_jshtml()) elif mode == "plot": plt.show()
def view_game(board_history): """ This is a helper function which takes a board history (i.e., a list of board states) and creates an animation of the game as it progresses. """ fig, ax = plt.subplots() colors = ['black', 'blue', 'pink', 'white', 'red', 'yellow'] cmap = matplotlib.colors.ListedColormap(colors) bounds = np.linspace(0, 5, 6) norm = matplotlib.colors.BoundaryNorm(bounds, cmap.N) matrix = ax.matshow(board_history[0], cmap=cmap, norm=norm) def update(i): matrix.set_array(board_history[i]) return matrix ani = FuncAnimation(fig, update, frames=len(board_history), interval=100) plt.show() return HTML(ani.to_html5_video())
def animate(states, times=None, figsize=None, channel=None, vmin=0, vmax=1): backend = matplotlib.get_backend() matplotlib.use("nbAgg") fig, ax = plt.subplots(1, 1, figsize=figsize) def init(): im = ax.imshow(states[0, channel].squeeze(), animated=True, cmap="magma", vmin=vmin, vmax=vmax) cbar = fig.colorbar(im) cbar.set_label("mV", rotation=0) return [im] def update(iteration): print("Rendering {}\t".format(iteration + 1), end="\r") im = ax.imshow(states[iteration, channel].squeeze(), animated=True, cmap="magma", vmin=vmin, vmax=vmax) if times is not None: ax.set_title("t: %d" % times[iteration]) return [ax] animation = FuncAnimation(fig, update, frames=range(len(states)), init_func=init, blit=True) matplotlib.use(backend) return HTML(animation.to_html5_video())
def animatedLineplot(): fig, ax = plt.subplots() ln1, = ax.plot([], [], 'b-') ln2, = ax.plot([], [], 'r-') data_spain_ccaa = pd.read_csv('/warehouse/serie_historica_acumulados.csv', sep=',') data_spain_ccaa = data_spain_ccaa.drop(len(data_spain_ccaa) - 1) data_spain_ccaa['Casos '] = data_spain_ccaa['Casos '].fillna(0) data_spain_ccaa['Fallecidos'] = data_spain_ccaa['Fallecidos'].fillna(0) data_MD = data_spain_ccaa[data_spain_ccaa['CCAA Codigo ISO'].isin( ['MD'])][['Casos ', 'Fallecidos']].to_numpy().transpose().astype(int) data_AN = data_spain_ccaa[data_spain_ccaa['CCAA Codigo ISO'].isin( ['CT'])][['Casos ', 'Fallecidos']].to_numpy().transpose().astype(int) # GET HEADERS FROM UI, X AND Y. GET THE MAXIMUM VALUE AMONG ALL THE GIVEN HEADERS. CREATE UNA LINE FOR EACH HEADER. def init(): ax.set_xlim(0, 15000) ax.set_ylim(0, 2000) return ln1, ln2, def update(num, data_MD, data_AN, line1, line2): line1.set_data(data_MD[..., :num]) line2.set_data(data_AN[..., :num]) return ln1, ln2, #Writer = animation.writers['ffmpeg'] #writer = Writer(fps=15, metadata=dict(artist='Me'), bitrate=1800) ani = FuncAnimation(fig, update, 50, fargs=(data_MD, data_AN, ln1, ln2), interval=100, init_func=init, blit=True) return ani.to_html5_video()
def make_animation(self): def init_func(): self.plot_bars(0) interval = self.period_length / self.steps_per_period anim = FuncAnimation(self.fig, self.anim_func, range(len(self.df_values)), init_func, interval=interval) try: if self.html: ret_val = anim.to_html5_video() try: from IPython.display import HTML ret_val = HTML(ret_val) except ImportError: pass else: ret_val = anim.save(self.filename, fps=self.fps, writer=self.writer) except Exception as e: message = str(e) # if self.extension != 'gif': # message = f'''You do not have ffmpeg installed on your machine. Download # ffmpeg from here: https://www.ffmpeg.org/download.html. # Matplotlib's original error message below:\n # {str(e)} # ''' # else: # message = str(e) raise Exception(message) finally: plt.rcParams = self.orig_rcParams return ret_val
def make_animation(self): def init_func(): self.plot_bars(0) interval = self.period_length / self.steps_per_period anim = FuncAnimation(self.fig, self.anim_func, range(len(self.df_values)), init_func, interval=interval) if self.html: html = anim.to_html5_video() plt.rcParams = self.orig_rcParams return html extension = self.filename.split('.')[-1] if extension == 'gif': anim.save(self.filename, fps=self.fps, writer='imagemagick') else: anim.save(self.filename, fps=self.fps) plt.rcParams = self.orig_rcParams
def render(episode, env, filename): fig = plt.figure() img = plt.imshow(env.render(mode='rgb_array')) env.close() plt.axis('off') def animate(i): img.set_data(episode[i]) return img, anim = FuncAnimation(fig, animate, frames=len(episode), interval=24, blit=True) vid = HTML(anim.to_html5_video()) anim.save(filename + '.mp4') plt.close(fig) #!rm None0000000.png return vid
def video_from_images(image_files, fps=5, callback=None, reverse=False, dpi=72, interpolation=None, repeat_first=0, repeat_last=0, save=None, repetitions=None, crop=None, snap_first=False): r"""Display a movie from a sequence of images. This renders the given images into a video to view inside the Jupyter notebook and/or save into a file. @param image_files Images to render into a video. @param fps Frames/images per second to show. Default is `5`. @param callback Optional callback called for each frame with the signature `callback(i, ax, ctrl)`, where `i` runs from `0` through the frame numbers, `ax` is the axes object, and `ctrl` the image control created by `ax.imshow()`. @param reverse If `True`, play the images in reverse order. @param dpi Dots per inch of the stored image. When set correctly, the image will be shown in its native resolution (i.e. without resizing). @param interpolation Pixel interpolation in case the rendered size is not exactly the image size. Default is `None`. @param repeat_first Number of extra repetitions of the first image. This adds additional time at the start. Default is `0`. @param repeat_last Number of extra repetitions of the last image. This adds additional time at the end, so that the result can be inspected a little longer. Default is `0`. @param save Optional filename for storing the resulting video. @param repetitions How often to repeat individual images. Should be a sequence of integers corresponding to the individual images. Missing elements are taken to be 1. @param crop 4-tuple with the amount of cropping (in pixel) in order (left, botton, right, top). @param snap_first If `True`, save a snapshot of the first frame. """ from IPython.display import HTML from matplotlib.animation import FuncAnimation if not image_files: raise ValueError("No images specified.") if reverse: image_files = list(reversed(image_files)) if repetitions is not None: repeated = [] for img, rep in zip_longest(image_files, repetitions, fillvalue=1): if img == 1: break repeated.extend([img] * rep) image_files = repeated ax, image_ctrl = plot_image(image_files[0], dpi=dpi, show=False, animated=True, interpolation=interpolation, crop=crop) if snap_first and save: fname = op.expanduser(save) if fname.endswith(".mp4"): fname = "%s.png" % fname[:-4] os.makedirs(op.normpath(op.dirname(fname)), exist_ok=True) ax.figure.savefig(fname) def update(i): idx = clip(i - repeat_first, 0, len(image_files) - 1) image = plt.imread(image_files[idx]) if crop: image = _crop(image, *crop) image_ctrl.set_array(image) if callback: callback(i, ax, image_ctrl) a = FuncAnimation(ax.figure, update, frames=len(image_files) + repeat_first + repeat_last, interval=1000 / fps) v = a.to_html5_video() if save is not None: if "." not in op.basename(save): save += ".mp4" fname = op.expanduser(save) os.makedirs(op.normpath(op.dirname(fname)), exist_ok=True) a.save(fname) plt.close(ax.figure) return HTML(v)
import matplotlib.pyplot as plt import numpy as np from matplotlib.animation import FuncAnimation from IPython import display ## Khusus Jupyter nootbook # Review Figure fig = plt.figure() plt.xlim(0, 4) plt.ylim(-2, 2) # Animasi line = plt.plot([])[0] def animated(i): x = np.linspace(0, 4, 1000) y = np.sin(2 * np.pi * (x - .1 * i)) line.set_data(x, y) return line anim = FuncAnimation(fig, animated, frames=200, interval=20) video = anim.to_html5_video() html = display.HTML(video) display.display(html) plt.close()
def render_animation(data, skeleton, fps, output='interactive', bitrate=1000): """ Render or show an animation. The supported output modes are: -- 'interactive': display an interactive figure (also works on notebooks if associated with %matplotlib inline) -- 'html': render the animation as HTML5 video. Can be displayed in a notebook using HTML(...). -- 'filename.mp4': render and export the animation as an h264 video (requires ffmpeg). -- 'filename.gif': render and export the animation a gif file (requires imagemagick). """ x = 0 y = 1 z = 2 radius = torch.max(skeleton.offsets()).item( ) * 5 # Heuristic that works well with many skeletons skeleton_parents = skeleton.parents() plt.ioff() fig = plt.figure(figsize=(4, 4)) ax = fig.add_subplot(1, 1, 1, projection='3d') ax.view_init(elev=20., azim=30) ax.set_xlim3d([-radius / 2, radius / 2]) ax.set_zlim3d([0, radius]) ax.set_ylim3d([-radius / 2, radius / 2]) ax.set_aspect('auto') ax.set_xticklabels([]) ax.set_yticklabels([]) ax.set_zticklabels([]) ax.dist = 7.5 lines = [] initialized = False trajectory = data[:, 0, [0, 2]] avg_segment_length = np.mean( np.linalg.norm(np.diff(trajectory, axis=0), axis=1)) + 1e-3 draw_offset = int(25 / avg_segment_length) spline_line, = ax.plot(*trajectory.T) camera_pos = trajectory height_offset = np.min(data[:, :, 1]) # Min height data = data.copy() data[:, :, 1] -= height_offset def update(frame): nonlocal initialized ax.set_xlim3d([ -radius / 2 + camera_pos[frame, 0], radius / 2 + camera_pos[frame, 0] ]) ax.set_ylim3d([ -radius / 2 + camera_pos[frame, 1], radius / 2 + camera_pos[frame, 1] ]) positions_world = data[frame] for i in range(positions_world.shape[0]): if skeleton_parents[i] == -1: continue if not initialized: col = 'red' if i in skeleton.joints_right( ) else 'black' # As in audio cables :) lines.append( ax.plot([ positions_world[i, x], positions_world[skeleton_parents[i], x] ], [ positions_world[i, y], positions_world[skeleton_parents[i], y] ], [ positions_world[i, z], positions_world[skeleton_parents[i], z] ], zdir='y', c=col)) else: lines[i - 1][0].set_xdata( np.array([ positions_world[i, x], positions_world[skeleton_parents[i], x] ])) lines[i - 1][0].set_ydata( np.array([ positions_world[i, y], positions_world[skeleton_parents[i], y] ])) lines[i - 1][0].set_3d_properties([ positions_world[i, z], positions_world[skeleton_parents[i], z] ], zdir='y') l = max(frame - draw_offset, 0) r = min(frame + draw_offset, trajectory.shape[0]) spline_line.set_xdata(trajectory[l:r, 0]) spline_line.set_ydata(np.zeros_like(trajectory[l:r, 0])) spline_line.set_3d_properties(trajectory[l:r, 1], zdir='y') initialized = True if output == 'interactive' and frame == data.shape[0] - 1: plt.close('all') fig.tight_layout() anim = FuncAnimation(fig, update, frames=np.arange(0, data.shape[0]), interval=1000 / fps, repeat=True) if output == 'interactive': plt.show() return anim elif output == 'html': return anim.to_html5_video() elif output.endswith('.mp4'): Writer = writers['ffmpeg'] writer = Writer(fps=fps, metadata={}, bitrate=bitrate) anim.save(output, writer=writer) elif output.endswith('.gif'): anim.save(output, dpi=80, writer='imagemagick') else: raise ValueError( 'Unsupported output format (only html, .mp4, and .gif are supported)' ) plt.close()
def show( self, t, cmap="plasma", res=300, interval=75, file=None, figsize=(3, 3), html5_video=True, window_pad=1.0, ): """Visualize the Keplerian system. Args: t (scalar or vector): The time(s) at which to evaluate the orbit and the map in units of :py:attr:`time_unit`. cmap (string or colormap instance, optional): The matplotlib colormap to use. Defaults to ``plasma``. res (int, optional): The resolution of the map in pixels on a side. Defaults to 300. figsize (tuple, optional): Figure size in inches. Default is (3, 3) for orthographic maps and (7, 3.5) for rectangular maps. interval (int, optional): Interval between frames in milliseconds (animated maps only). Defaults to 75. file (string, optional): The file name (including the extension) to save the animation to (animated maps only). Defaults to None. html5_video (bool, optional): If rendering in a Jupyter notebook, display as an HTML5 video? Default is True. If False, displays the animation using Javascript (file size will be larger.) window_pad (float, optional): Padding around the primary in units of the primary radius. Bodies outside of this window will be cropped. Default is 1.0. """ # Not yet implemented if self._primary._map.nw is not None: # pragma: no cover raise NotImplementedError( "Method not implemented for spectral maps.") # Render the maps & get the orbital positions if self._rv: self._primary.map._set_RV_filter() for sec in self._secondaries: sec.map._set_RV_filter() img_pri, img_sec, x, y, z = self.ops.render( math.reshape(math.to_array_or_tensor(t), [-1]) * self._time_factor, res, self._primary._r, self._primary._m, self._primary._prot, self._primary._t0, self._primary._theta0, self._primary._map._amp, self._primary._map._inc, self._primary._map._obl, self._primary._map._y, self._primary._map._u, self._primary._map._f, self._primary._map._alpha, math.to_array_or_tensor([sec._r for sec in self._secondaries]), math.to_array_or_tensor([sec._m for sec in self._secondaries]), math.to_array_or_tensor([sec._prot for sec in self._secondaries]), math.to_array_or_tensor([sec._t0 for sec in self._secondaries]), math.to_array_or_tensor([sec._theta0 for sec in self._secondaries]), self._get_periods(), math.to_array_or_tensor([sec._ecc for sec in self._secondaries]), math.to_array_or_tensor([sec._w for sec in self._secondaries]), math.to_array_or_tensor([sec._Omega for sec in self._secondaries]), math.to_array_or_tensor([sec._inc for sec in self._secondaries]), math.to_array_or_tensor( [sec._map._amp for sec in self._secondaries]), math.to_array_or_tensor( [sec._map._inc for sec in self._secondaries]), math.to_array_or_tensor( [sec._map._obl for sec in self._secondaries]), math.to_array_or_tensor([sec._map._y for sec in self._secondaries]), math.to_array_or_tensor([sec._map._u for sec in self._secondaries]), math.to_array_or_tensor([sec._map._f for sec in self._secondaries]), math.to_array_or_tensor( [sec._map._alpha for sec in self._secondaries]), ) # Convert to units of the primary radius fac = np.reshape([sec._length_factor for sec in self._secondaries], [-1, 1]) fac = fac * self._primary._r x, y, z = x / fac, y / fac, z / fac r = math.to_array_or_tensor([sec._r for sec in self._secondaries]) r = r / self._primary._r # Evaluate if needed if config.lazy: img_pri = img_pri.eval() img_sec = img_sec.eval() x = x.eval() y = y.eval() z = z.eval() r = r.eval() # We need this to be of shape (nplanet, nframe) x = x.T y = y.T z = z.T # Ensure we have an array of frames if len(img_pri.shape) == 3: nframes = img_pri.shape[0] else: # pragma: no cover nframes = 1 img_pri = np.reshape(img_pri, (1, ) + img_pri.shape) img_sec = np.reshape(img_sec, (1, ) + img_sec.shape) animated = nframes > 1 # Set up the plot fig, ax = plt.subplots(1, figsize=figsize) ax.axis("off") ax.set_xlim(-1.0 - window_pad, 1.0 + window_pad) ax.set_ylim(-1.0 - window_pad, 1.0 + window_pad) # Render the first frame img = [None for n in range(1 + len(self._secondaries))] circ = [None for n in range(1 + len(self._secondaries))] extent = np.array([-1.0, 1.0, -1.0, 1.0]) img[0] = ax.imshow( img_pri[0], origin="lower", extent=extent, cmap=cmap, interpolation="none", vmin=np.nanmin(img_pri), vmax=np.nanmax(img_pri), animated=animated, zorder=0.0, ) circ[0] = plt.Circle((0, 0), 1, color="k", fill=False, zorder=1e-3, lw=2) ax.add_artist(circ[0]) for i, _ in enumerate(self._secondaries): extent = np.array([x[i, 0], x[i, 0], y[i, 0], y[i, 0] ]) + (r[i] * np.array([-1.0, 1.0, -1.0, 1.0])) img[i + 1] = ax.imshow( img_sec[i, 0], origin="lower", extent=extent, cmap=cmap, interpolation="none", vmin=np.nanmin(img_sec), vmax=np.nanmax(img_sec), animated=animated, zorder=z[i, 0], ) circ[i] = plt.Circle( (x[i, 0], y[i, 0]), r[i], color="k", fill=False, zorder=z[i, 0] + 1e-3, lw=2, ) ax.add_artist(circ[i]) # Animation if animated: def updatefig(k): # Update Primary map img[0].set_array(img_pri[k]) # Update Secondary maps & positions for i, _ in enumerate(self._secondaries): extent = np.array([x[i, k], x[i, k], y[i, k], y[i, k]]) + ( r[i] * np.array([-1.0, 1.0, -1.0, 1.0])) if np.any(np.abs(extent) < 1.0 + window_pad): img[i + 1].set_array(img_sec[i, k]) img[i + 1].set_extent(extent) img[i + 1].set_zorder(z[i, k]) circ[i].center = (x[i, k], y[i, k]) circ[i].set_zorder(z[i, k] + 1e-3) return img + circ ani = FuncAnimation(fig, updatefig, interval=interval, blit=False, frames=nframes) # Business as usual if (file is not None) and (file != ""): if file.endswith(".mp4"): ani.save(file, writer="ffmpeg") elif file.endswith(".gif"): ani.save(file, writer="imagemagick") else: # pragma: no cover # Try and see what happens! ani.save(file) plt.close() else: # pragma: no cover try: if "zmqshell" in str(type(get_ipython())): plt.close() if html5_video: display(HTML(ani.to_html5_video())) else: display(HTML(ani.to_jshtml())) else: raise NameError("") except NameError: plt.show() plt.close() # Matplotlib generates an annoying empty # file when producing an animation. Delete it. try: os.remove("None0000000.png") except FileNotFoundError: pass else: if (file is not None) and (file != ""): fig.savefig(file) plt.close() else: # pragma: no cover plt.show() if self._rv: self._primary.map._unset_RV_filter() for sec in self._secondaries: sec.map._unset_RV_filter()
def get_html_video(animation: FuncAnimation): import matplotlib.pyplot as plt plt.rcParams['animation.ffmpeg_path'] = 'C:/FFmpeg/bin/ffmpeg.exe' return animation.to_html5_video()
def visualize_path(M, p): # p is the path from IPython.display import HTML from matplotlib.animation import FuncAnimation from matplotlib.patches import Rectangle import matplotlib.pyplot as plt import numpy as np n = 2 T = 5 D = 0.4 def interpolate(init, final): return np.tile(init, (1, T)) + (final - init) * np.linspace(0, 1, T) m, n = M.shape def ids(l): return [l // n, l % n] def flip(t): return [t[1], t[0]] ps = np.zeros((2, T * (len(p)-1))) for i in range(len(p)-1): u, v = p[i], p[i+1] ucoords = np.array(flip(ids(u))).reshape((2, 1)) vcoords = np.array(flip(ids(v))).reshape((2, 1)) ps[:, i*T:T*(i+1)] = interpolate(ucoords, vcoords) # from http://python4econ.blogspot.com/2013/03/matlabs-cylinder-command-in-python.html def cylinder(r, n): """ Returns the unit cylinder that corresponds to the curve r. INPUTS: r - a vector of radii n - number of coordinates to return for each element in r OUTPUTS: x,y,z - coordinates of points """ # ensure that r is a column vector r = np.atleast_2d(r) r_rows, r_cols = r.shape if r_cols > r_rows: r = r.T # find points along x and y axes points = np.linspace(0, 2 * np.pi, n + 1) x = np.cos(points) * r y = np.sin(points) * r # find points along z axis rpoints = np.atleast_2d(np.linspace(0, 1, len(r))) z = np.ones((1, n + 1)) * rpoints.T return x, y, z x, y, z = cylinder(D / 2, 100) x = x.squeeze() y = y.squeeze() z = z.squeeze() fig, ax = plt.subplots(figsize=(10, 10)) plt.close(fig) ax.axis("equal") #ax.axis([-1.5, 1.5, -1.5, 1.5]) p_data = ax.plot(ps[0, :], ps[1, :], color="C0")[0] ax.scatter(ps[0, :], ps[1, :], color="C0", marker=".") ax.imshow(colored(M, default_cmap)) def update(i): p_data.set_data(ps[0, i] + x, ps[1, i] + y) ax.set_title(f"i = {i}") ani = FuncAnimation(fig, update, interval=100, frames=T*(len(p) - 1)) return HTML(ani.to_html5_video())
miny = 25 maxx = -60 maxy = 52 covid_map_data = select_data_within_bounds(covid_data, minx, miny, maxx, maxy) map_bounded = True mpl.rcParams['animation.embed_limit'] = 200 plot_dates = sorted(list(set(covid_data[covid_data.index.get_level_values("date") > start_date].index.get_level_values("date")))) #dates = plot_dates[plot_dates.index("2020-03-17"):] dates = plot_dates[31*3*-1 -1::3] keys.append("Daily Cases per Million MA") keys.append("Daily Deaths per Million MA") for key in keys: val = covid_map_data vmax = val[key][val.index.get_level_values("date").isin(dates)].max() val[key] = val[key].astype(float) fig, ax = plt.subplots(figsize=(18,8), subplot_kw = {'aspect': 'equal'}) plt.rcParams.update({"font.size": 30}) plt.xticks(fontsize = 25) plt.yticks(fontsize = 25) frames=[i for i in range(len(dates))] anim = FuncAnimation(fig, plot_map, frames = frames, blit = False, init_func = init, interval=300, fargs = (ax, val, vmax, key)) with open(key.replace("/", "-")+ ".html", "w") as f: print(anim.to_html5_video(), file=f) plt.close()
def create_playback_animation( telemetry, filename="playback.html", labels=True, disable_labels_after=None, label_players=[], dead_players=True, dead_player_labels=False, zoom=False, zoom_edge_buffer=0.5, use_hi_res=False, color_teams=True, highlight_teams=[], highlight_players=[], highlight_color="#FFFF00", highlight_winner=False, label_highlights=True, care_packages=True, damage=True, end_frames=20, size=5, dpi=100, interpolate=True, interval=1, fps=30, ): """Create a playback animation from telemetry data. Using matplotlib's animation library, create an HTML5 animation saved to disk relying on external ``ffmpeg`` library to create the video. To view the animation, open the resulting file in your browser. :param telemetry: an Telemetry instance :param filename: a file to generate for the animation (default "playback.html") :param bool labels: whether to label players by name :param int disable_labels_after: if passed, turns off player labels after number of seconds elapsed in game :param list label_players: a list of strings of player names that should be labeled :param bool dead_players: whether to mark dead players :param list dead_player_labels: a list of strings of players that should be labeled when dead :param bool zoom: whether to zoom with the circles through the playback :param float zoom_edge_buffer: how much to buffer the blue circle edge when zooming :param bool use_hi_res: whether to use the hi-res image, best to be set to True when using zoom :param bool color_teams: whether to color code different teams :param list highlight_teams: a list of strings of player names whose teams should be highlighted :param list highlight_players: a list of strings of player names who should be highlighted :param str highlight_color: a color to use for highlights :param bool highlight_winner: whether to highlight the winner(s) :param bool label_highlights: whether to label the highlights :param bool care_packages: whether to show care packages :param bool damage: whether to show PvP damage :param int end_frames: the number of extra end frames after game has been completed :param int size: the size of the resulting animation frame :param int dpi: the dpi to use when processing the animation :param bool interpolate: use linear interpolation to get frames with second-interval granularity :param int interval: interval between gameplay frames in seconds :param int fps: the frames per second for the animation """ # Extract data positions = telemetry.player_positions() circles = telemetry.circle_positions() rankings = telemetry.rankings() winner = telemetry.winner() killed = telemetry.killed() rosters = telemetry.rosters() damages = telemetry.player_damages() package_spawns = telemetry.care_package_positions(land=False) package_lands = telemetry.care_package_positions(land=True) map_id = telemetry.map_id() mapx, mapy = map_dimensions[map_id] all_times = [] for player, pos in positions.items(): for p in pos: all_times.append(int(p[0])) all_times = sorted(list(set(all_times))) if highlight_winner: for player in winner: highlight_players.append(player) highlight_players = list(set(highlight_players)) if highlight_teams is not None: for team_player in highlight_teams: for team_id, roster in rosters.items(): if team_player in roster: for player in roster: highlight_players.append(player) break highlight_players = list(set(highlight_players)) if label_highlights: for player in highlight_players: label_players.append(player) label_players = list(set(label_players)) team_colors = None if color_teams: # Randomly select colors from the pre-defined palette colors = COLORS idx = list(range(len(colors))) random.shuffle(idx) team_colors = {} count = 0 for team_id, roster in rosters.items(): for player in roster: team_colors[player] = colors[idx[count]] count += 1 # Get the max "frame number" maxlength = 0 for player, pos in positions.items(): try: if pos[-1][0] > maxlength: maxlength = pos[-1][0] except IndexError: continue if interpolate: maxlength = max(all_times) else: maxlength = max([maxlength, len(circles)]) # Initialize the plot and artist objects fig = plt.figure(frameon=False, dpi=dpi) ax = fig.add_axes([0, 0, 1, 1]) ax.axis("off") if use_hi_res: if map_id == "Savage_Main": map_image = map_id + ".png" else: map_image = map_id + ".jpg" else: map_image = map_id + "_lowres.jpg" img_path = os.path.join(MAP_ASSET_PATH, map_image) try: img = mpimg.imread(img_path) except FileNotFoundError: raise FileNotFoundError( "High resolution images not included in package.\n" "Download images from https://github.com/pubg/api-assets/tree/master/Assets/Maps\n" "and place in folder: " + MAP_ASSET_PATH) ax.imshow(img, extent=[0, mapx, 0, mapy]) players = ax.scatter(-10000, -10000, marker="o", c="w", edgecolor="k", s=60, linewidths=1, zorder=20) deaths = ax.scatter(-10000, -10000, marker="X", c="r", edgecolor="k", s=60, linewidths=1, alpha=0.5, zorder=10) if highlight_players or highlight_teams: highlights = ax.scatter(-10000, -10000, marker="*", c=highlight_color, edgecolor="k", s=180, linewidths=1, zorder=25) highlights_deaths = ax.scatter(-10000, -10000, marker="X", c=highlight_color, edgecolor="k", s=60, linewidths=1, zorder=15) if labels: if label_players is not None: name_labels = { player_name: ax.text(0, 0, player_name, size=8, zorder=19) for player_name in positions if player_name in label_players } else: name_labels = { player_name: ax.text(0, 0, player_name, size=8, zorder=19) for player_name in positions } for label in name_labels.values(): label.set_path_effects( [patheffects.withStroke(linewidth=2, foreground="w")]) blue_circle = plt.Circle((0, 0), 0, edgecolor="b", linewidth=2, fill=False, zorder=5) white_circle = plt.Circle((0, 0), 0, edgecolor="w", linewidth=2, fill=False, zorder=6) red_circle = plt.Circle((0, 0), 0, color="r", edgecolor=None, lw=0, fill=True, alpha=0.3, zorder=7) care_package_spawns, = ax.plot(-10000, -10000, marker="s", c="w", markerfacecoloralt="w", fillstyle="bottom", mec="k", markeredgewidth=0.5, markersize=10, lw=0, zorder=8) care_package_lands, = ax.plot(-10000, -10000, marker="s", c="r", markerfacecoloralt="b", fillstyle="bottom", mec="k", markeredgewidth=0.5, markersize=10, lw=0, zorder=9) damage_slots = 50 damage_lines = [] for k in range(damage_slots): dline, = ax.plot(-10000, -10000, marker="x", c="r", mec="r", markeredgewidth=5, markersize=10, lw=2, markevery=[1], alpha=0.5, zorder=50) damage_lines.append(dline) ax.add_patch(blue_circle) ax.add_patch(white_circle) ax.add_patch(red_circle) fig.subplots_adjust(left=0, right=1, bottom=0, top=1) fig.set_size_inches((size, size)) ax.set_xlim([0, mapx]) ax.set_ylim([0, mapy]) # Frame init function def init(): if labels: if highlight_players or highlight_teams: updates = players, deaths, highlights, highlights_deaths, blue_circle, red_circle, white_circle, *tuple( name_labels.values()) else: updates = players, deaths, blue_circle, red_circle, white_circle, *tuple( name_labels.values()) else: if highlight_players or highlight_teams: updates = players, deaths, highlights, highlights_deaths, blue_circle, red_circle, white_circle else: updates = players, deaths, blue_circle, red_circle, white_circle if care_packages: updates = *updates, care_package_lands, care_package_spawns if damage: updates = *updates, *damage_lines return updates def interpolate_coords(t, coords, tidx, vidx, step=False): inter = False for idx, coord in enumerate(coords): if coord[tidx] > t: inter = True break if not inter: return coords[-1][vidx] if idx == 0: return coords[0][vidx] else: v0 = coords[idx - 1][vidx] t0 = coords[idx - 1][tidx] v1 = coords[idx][vidx] t1 = coords[idx][tidx] if step: return v1 else: return v0 + (t - t0) * (v1 - v0) / (t1 - t0) # Frame update function def update(frame): logging.info("Processing frame {frame}".format(frame=frame)) try: if interpolate: blue_circle.center = ( interpolate_coords(frame, circles["blue"], 0, 1), mapy - interpolate_coords(frame, circles["blue"], 0, 2)) red_circle.center = ( interpolate_coords(frame, circles["red"], 0, 1, True), mapy - interpolate_coords(frame, circles["red"], 0, 2, True)) white_circle.center = ( interpolate_coords(frame, circles["white"], 0, 1, True), mapy - interpolate_coords(frame, circles["white"], 0, 2, True)) blue_circle.set_radius( interpolate_coords(frame, circles["blue"], 0, 4)) red_circle.set_radius( interpolate_coords(frame, circles["red"], 0, 4, True)) white_circle.set_radius( interpolate_coords(frame, circles["white"], 0, 4, True)) else: blue_circle.center = circles["blue"][frame][ 1], mapy - circles["blue"][frame][2] red_circle.center = circles["red"][frame][ 1], mapy - circles["red"][frame][2] white_circle.center = circles["white"][frame][ 1], mapy - circles["white"][frame][2] blue_circle.set_radius(circles["blue"][frame][4]) red_circle.set_radius(circles["red"][frame][4]) white_circle.set_radius(circles["white"][frame][4]) except IndexError: pass xlim = ax.get_xlim() ylim = ax.get_ylim() xwidth = xlim[1] - xlim[0] ywidth = ylim[1] - ylim[0] if zoom: try: if interpolate: margin_offset = (1 + zoom_edge_buffer) * interpolate_coords( frame, circles["blue"], 0, 4) xmin = max([ 0, interpolate_coords(frame, circles["blue"], 0, 1) - margin_offset ]) xmax = min([ mapx, interpolate_coords(frame, circles["blue"], 0, 1) + margin_offset ]) ymin = max([ 0, mapy - interpolate_coords(frame, circles["blue"], 0, 2) - margin_offset ]) ymax = min([ mapy, mapy - interpolate_coords(frame, circles["blue"], 0, 2) + margin_offset ]) else: margin_offset = ( 1 + zoom_edge_buffer) * circles["blue"][frame][4] xmin = max([0, circles["blue"][frame][1] - margin_offset]) xmax = min( [mapx, circles["blue"][frame][1] + margin_offset]) ymin = max( [0, mapy - circles["blue"][frame][2] - margin_offset]) ymax = min([ mapy, mapy - circles["blue"][frame][2] + margin_offset ]) # ensure full space taken by map if xmax - xmin >= ymax - ymin: if ymin == 0: ymax = ymin + (xmax - xmin) elif ymax == mapy: ymin = ymax - (xmax - xmin) else: if xmin == 0: xmax = xmin + (ymax - ymin) elif xmax == mapx: xmin = xmax - (ymax - ymin) ax.set_xlim([xmin, xmax]) ax.set_ylim([ymin, ymax]) xwidth = xmax - xmin ywidth = ymax - ymin except IndexError: pass positions_x = [] positions_y = [] highlights_x = [] highlights_y = [] deaths_x = [] deaths_y = [] highlights_deaths_x = [] highlights_deaths_y = [] care_package_lands_x = [] care_package_lands_y = [] care_package_spawns_x = [] care_package_spawns_y = [] if color_teams: marker_colors = [] death_marker_colors = [] else: marker_colors = "w" death_marker_colors = "r" t = 0 damage_count = 0 for player, pos in positions.items(): try: player_max = pos[-1][0] # This ensures the alive winner(s) stay on the map at the end. if frame >= player_max and player not in winner: raise IndexError elif frame >= player_max and player not in killed: fidx = frame if interpolate else -1 else: fidx = frame if interpolate: t = max([t, fidx]) else: t = max([t, pos[fidx][0]]) for package in package_spawns: if package[0] < t and package[0] > t - 60: care_package_spawns_x.append(package[1]) care_package_spawns_y.append(mapy - package[2]) for package in package_lands: if package[0] < t: care_package_lands_x.append(package[1]) care_package_lands_y.append(mapy - package[2]) # Update player positions if interpolate: if fidx >= pos[-1][0] and player in killed: raise IndexError x = interpolate_coords(fidx, pos, 0, 1) y = mapy - interpolate_coords(fidx, pos, 0, 2) else: x = pos[fidx][1] y = mapy - pos[fidx][2] # Update player highlights if player in highlight_players: highlights_x.append(x) highlights_y.append(y) else: positions_x.append(x) positions_y.append(y) # Set colors if color_teams: marker_colors.append(team_colors[player]) # Update labels if labels and player in label_players: if disable_labels_after is not None and frame >= disable_labels_after: name_labels[player].set_position((-100000, -100000)) else: name_labels[player].set_position( (x + 10000 * xwidth / mapx, y - 10000 * ywidth / mapy)) # Update player damages if damage: try: for attack in damages[player]: damage_frame = int(attack[0]) if damage_frame >= fidx + interval: break elif damage_frame >= fidx and damage_frame < fidx + interval: damage_line_x = [attack[1], attack[4]] damage_line_y = [ mapy - attack[2], mapy - attack[5] ] damage_lines[damage_count].set_data( damage_line_x, damage_line_y) damage_count += 1 except KeyError: pass except IndexError as exc: # Set death markers if player in highlight_players: highlights_deaths_x.append(pos[-1][1]) highlights_deaths_y.append(mapy - pos[-1][2]) else: deaths_x.append(pos[-1][1]) deaths_y.append(mapy - pos[-1][2]) # Set death marker colors if color_teams: death_marker_colors.append(team_colors[player]) # Draw dead players names if labels and dead_player_labels and player in label_players: name_labels[player].set_position( (pos[-1][1] + 10000 * xwidth / mapx, mapy - pos[-1][2] - 10000 * ywidth / mapy)) name_labels[player].set_path_effects([ patheffects.withStroke(linewidth=1, foreground="gray") ]) # Offscreen if labels are off elif labels and player in label_players: name_labels[player].set_position((-100000, -100000)) player_offsets = [(x, y) for x, y in zip(positions_x, positions_y)] if len(player_offsets) > 0: players.set_offsets(player_offsets) else: players.set_offsets([(-100000, -100000)]) if color_teams: players.set_facecolors(marker_colors) death_offsets = [(x, y) for x, y in zip(deaths_x, deaths_y)] if len(death_offsets) > 0: deaths.set_offsets(death_offsets) if color_teams: deaths.set_facecolors(death_marker_colors) if highlight_players is not None: highlight_offsets = [(x, y) for x, y in zip(highlights_x, highlights_y)] if len(highlight_offsets) > 0: highlights.set_offsets(highlight_offsets) else: highlights.set_offsets([(-100000, -100000)]) highlight_death_offsets = [ (x, y) for x, y in zip(highlights_deaths_x, highlights_deaths_y) ] if len(highlight_death_offsets) > 0: highlights_deaths.set_offsets(highlight_death_offsets) if len(care_package_lands_x) > 0: care_package_lands.set_data(care_package_lands_x, care_package_lands_y) if len(care_package_spawns_x) > 0: care_package_spawns.set_data(care_package_spawns_x, care_package_spawns_y) # Remove the remaining slots for k in range(damage_count, damage_slots): damage_lines[k].set_data([], []) if labels: if highlight_players or highlight_teams: updates = players, deaths, highlights, highlights_deaths, blue_circle, red_circle, white_circle, *tuple( name_labels.values()) else: updates = players, deaths, blue_circle, red_circle, white_circle, *tuple( name_labels.values()) else: if highlight_players or highlight_teams: updates = players, deaths, highlights, highlights_deaths, blue_circle, red_circle, white_circle else: updates = players, deaths, blue_circle, red_circle, white_circle if care_packages: updates = *updates, care_package_lands, care_package_spawns if damage: updates = *updates, *damage_lines return updates # Create the animation animation = FuncAnimation( fig, update, frames=range(0, maxlength + end_frames, interval), interval=int(1000 / fps), init_func=init, blit=True, ) # Write the html5 to buffer h5 = animation.to_html5_video() # Save to disk logging.info("Saving file: {file}".format(file=filename)) with open(filename, "w") as f: f.write(h5) logging.info("Saved file.") return True
def render_animation(figures, skeleton, fps, num_frames, output='out.mp4', bitrate=1000, audios=[], start_time=0, figsize=(4, 4), userStudy=0, history=0, history_offset=1, suptitle=''): """ Render or show an animation. The supported output modes are: figures:: [[kind, pos, datas, (elev, azim)]] kind:: graph, skeleton, highlight pos:: (1,2,2) datas:: [data1, data2 ...] -- 'interactive': display an interactive figure (also works on notebooks if associated with %matplotlib inline) -- 'html': render the animation as HTML5 video. Can be displayed in a notebook using HTML(...). -- 'filename.mp4': render and export the animation as an h264 video (requires ffmpeg). -- 'filename.gif': render and export the animation a gif file (requires imagemagick). """ initialized = [False for _ in figures] liness = [] for figure in figures: kind, pos, datas, title, axes_label, view_point = figure if kind == 'skeleton': liness.append([[[] for _ in range(history + 1)] for _ in datas]) else: liness.append([]) plt.ioff() fig = plt.figure(figsize=figsize) if userStudy: txt1 = """SCALE: 1 - 2 - 3 - 4 - 5 - 6 - 7 Disagree Somewhat Somewhat Agree Disagree Agree """ txt2 = """ 1. There is enough conversation to comment on the quality of the interactions of Person A. 2. The motion of person A looks natural and match his/her speech 3. “Person A” behaves as herself / himself (recall the reference video) 4. “Person A” reacts realistically to person B (in terms of person B’s speech and motion)'""" plt.figtext(0.5, 0.2, txt1, ha='center', fontsize=16) plt.figtext(0.25, 0.01, txt2, ha='left', fontsize=16) plt.suptitle("Person A is black and red", ha='center', fontsize=16) if suptitle: plt.suptitle(suptitle, ha='center', fontsize=12) def init_func(fig, figures, skeleton, figsize, fps): x = 0 y = 1 z = 2 radius = torch.max(skeleton.offsets()).item( ) * 10 # Heuristic that works well with many skeletons skeleton_parents = skeleton.parents() axes = [] skel_fig_num = 0 for fig_num, values in enumerate(figures): kind, pos, datas, title, axes_label, view_point = values elev, azim = view_point if kind == 'skeleton': ax = fig.add_subplot(pos[0], pos[1], pos[2], projection='3d') if title: ax.set_title(title) if axes_label: ax.set_xlabel(axes_label[0]) ax.set_ylabel(axes_label[1]) ax.view_init(elev=elev, azim=azim) ax.set_xlim3d([-radius / 2, radius / 2]) ax.set_ylim3d([0, radius]) ax.set_zlim3d([0, radius]) #ax.set_aspect('equal') ## plot xzplane MINS = datas[0].min(axis=0).min(axis=0) MAXES = datas[0].max(axis=0).max(axis=0) ax = plot_xzPlane(ax, MINS[0], MAXES[0], MINS[2], MAXES[2], 0) ax.grid(b=False) #ax.grid(b=True, axis='y') ## remove grid lines Hardcoded TODO, can be made a parameter plt.axis('off') ax.set_xticklabels([]) ax.set_yticklabels([]) ax.set_zticklabels([]) ax.dist = 7.5 trajectory = sum([data[:, 0, [0, 2]] for data in datas]) / len(datas) avg_segment_length = np.mean( np.linalg.norm(np.diff(trajectory, axis=0), axis=1)) + 1e-3 draw_offset = int(25 / avg_segment_length) spline_line, = ax.plot(*trajectory.T) camera_pos = trajectory height_offset = np.min( [np.min(data[:, :, 1]) for data in datas]) # Min height #data = data.copy() for i, data in enumerate(datas): figures[fig_num][2][i][:, :, 1] -= height_offset axes.append(ax) skel_fig_num = fig_num # min_x = np.min([np.min(data[:, :, 0]) for data in datas]) # Min height # max_x = np.max([np.max(data[:, :, 0]) for data in datas]) # Min height # min_y = np.min([np.min(data[:, :, 1]) for data in datas]) # Min height # max_y = np.max([np.max(data[:, :, 1]) for data in datas]) # Min height # min_z = np.min([np.min(data[:, :, 2]) for data in datas]) # Min height # max_z = np.max([np.max(data[:, :, 2]) for data in datas]) # Min height #ax.set_xlim3d([min_x, max_x]) #ax.set_ylim3d([min_y, max_y]) #ax.set_zlim3d([min_z, max_z]) if kind == 'graph': ax = fig.add_subplot(pos[0], pos[1], pos[2]) ax.set_xlim([0, fps]) ax.set_ylim([np.min(datas), np.max(datas)]) if title: ax.set_title(title) if axes_label: ax.set_xlabel(axes_label[0]) ax.set_ylabel(axes_label[1]) ln = ax.plot([], [], color='red') liness[fig_num].append(ln[0]) axes.append(ax) if kind == 'highlight': axes.append(axes[skel_fig_num]) ax = axes[-1] ln = ax.plot([], [], [], color='g', ls='', marker='.') liness[fig_num].append(ln[0]) return fig, figures, skeleton, skeleton_parents, radius, camera_pos, trajectory, draw_offset, spline_line, x, y, z, axes def update(frame, fig, figures, skeleton, skeleton_parents, radius, camera_pos, trajectory, draw_offset, spline_line, x, y, z, axes): nonlocal initialized nonlocal liness nonlocal fps nonlocal history nonlocal history_offset nonlocal output for fig_num, values in enumerate( zip(initialized, figures, axes, liness)): Initialized, (kind, pos, datas, title, axes_label, view_point), ax, lines = values if kind == 'skeleton': #orange and purple respectively['#d95f02', '#7570b3']] #color_list = [['red', 'black'], ['orange', 'purple']] color_list = [['black', 'red'], ['black', 'purple']] #ax = fig.add_subplot(pos[0], pos[1], pos[2], projection='3d') ax.set_xlim3d([ -radius / 2 + camera_pos[frame, 0], radius / 2 + camera_pos[frame, 0] ]) ax.set_ylim3d([ -radius / 2 + camera_pos[frame, 1], radius / 2 + camera_pos[frame, 1] ]) positions_world = [[ data[fr] for fr in range(frame, frame - history * history_offset - 1, -history_offset) ] for data in datas] for i in range(positions_world[0][0].shape[0]): if skeleton_parents[i] == -1: ## assuming 0 is body_world continue if not Initialized: for count in range(len(datas)): alpha_range = np.arange(1, 0, -1. / (history + 1)) for hist, alpha in zip(range(history + 1), alpha_range): col = color_list[count][ 0] if i in skeleton.joints_right( ) else color_list[count][ 1] # As in audio cables :) #col = color_list[count][0] if hist == 0 else color_list[count][1] liness[fig_num][count][hist].append( ax.plot([ positions_world[count][hist][i, x], positions_world[count][hist][ skeleton_parents[i], x] ], [ positions_world[count][hist][i, y], positions_world[count][hist][ skeleton_parents[i], y] ], [ positions_world[count][hist][i, z], positions_world[count][hist][ skeleton_parents[i], z] ], zdir='y', c=col, alpha=alpha, marker='.')) else: for count in range(len(datas)): for hist in range(history, -1, -1): try: liness[fig_num][count][hist][ i - 1][0].set_xdata([ positions_world[count][hist][i, x], positions_world[count][hist][ skeleton_parents[i], x] ]) except: pdb.set_trace() liness[fig_num][count][hist][ i - 1][0].set_ydata([ positions_world[count][hist][i, y], positions_world[count][hist][ skeleton_parents[i], y] ]) liness[fig_num][count][hist][ i - 1][0].set_3d_properties([ positions_world[count][hist][i, z], positions_world[count][hist][ skeleton_parents[i], z] ], zdir='y') l = max(frame - draw_offset, 0) r = min(frame + draw_offset, trajectory.shape[0]) spline_line.set_xdata(trajectory[l:r, 0]) spline_line.set_ydata(np.zeros_like(trajectory[l:r, 0])) spline_line.set_3d_properties(trajectory[l:r, 1], zdir='y') initialized[fig_num] = True if kind == 'graph': if frame <= fps / 2: ax.set_xlim([0, fps]) liness[fig_num][0].set_data(range(0, frame), datas[0:frame]) else: ax.set_xlim([frame - fps / 2, frame + fps / 2]) liness[fig_num][0].set_data( range(int(frame - fps / 2), frame), datas[int(frame - fps / 2):frame]) if kind == 'highlight': outputs, mask = datas inv_mask = 1 - mask ln = liness[fig_num][0] non_zero_indices = [ idx for idx in range(outputs[0].shape[1]) if not mask[frame, idx] == 0 ] ln.set_xdata(outputs[0][frame, non_zero_indices, x]) ln.set_ydata(outputs[0][frame, non_zero_indices, y]) ln.set_3d_properties(outputs[0][0, non_zero_indices, z], zdir='y') ## save as images as well #filename = '.'.join(Path(output).name.split('.')[:-1]) #out_folder = '.'.join(output.split('.')[:-1]) #os.makedirs(out_folder, exist_ok=True) #plt.savefig(out_folder + '/{}_{:05d}.png'.format(filename, frame)) fig.tight_layout() anim = FuncAnimation(fig, update, frames=np.arange(history * history_offset, num_frames), interval=1000 / fps, repeat=False, fargs=init_func(fig, figures, skeleton, figsize, fps)) if output == 'interactive': plt.show() return anim elif output == 'html': return anim.to_html5_video() elif output.endswith('.mp4'): Writer = writers['ffmpeg'] writer = Writer(fps=fps, metadata={}, bitrate=bitrate) if audios: temp_output = output + '_temp.mp4' anim.save(temp_output, writer=writer) ## add audio to the output command_inputs = [] for audio in reversed(audios): command_inputs.append('-ss') command_inputs.append('{}'.format(start_time)) command_inputs.append('-i') command_inputs.append('{}'.format(audio)) command = ['ffmpeg', '-y'] command += command_inputs command.append('-i') command.append('{}'.format(temp_output)) command.append('-filter_complex') command.append('[0:a][1:a]amerge=inputs=2[aout]') command.append('-map') command.append('[aout]') command.append('-map') command.append('0:a') command.append('-map') command.append('1:a') command.append('-map') command.append('2:v') command.append('-acodec') command.append('ac3') command.append('-shortest') command.append('{}'.format(output)) FNULL = open(os.devnull, 'w') subprocess.call(command, stderr=FNULL, stdout=FNULL) delete_command = ['rm', '{}'.format(temp_output)] subprocess.call(delete_command, stderr=FNULL, stdout=FNULL) else: anim.save(output, writer=writer) elif output.endswith('.gif'): anim.save(output, dpi=80, writer='imagemagick') else: raise ValueError( 'Unsupported output format (only html, .mp4, and .gif are supported)' ) plt.close()
def visualize(image, **kwargs): # Get kwargs cmap = kwargs.pop("cmap", "plasma") grid = kwargs.pop("grid", True) interval = kwargs.pop("interval", 75) file = kwargs.pop("file", None) html5_video = kwargs.pop("html5_video", True) vmin = kwargs.pop("vmin", None) vmax = kwargs.pop("vmax", None) dpi = kwargs.pop("dpi", None) figsize = kwargs.pop("figsize", None) bitrate = kwargs.pop("bitrate", None) colorbar = kwargs.pop("colorbar", False) shrink = kwargs.pop("shrink", 0.01) ax = kwargs.pop("ax", None) if ax is None: custom_ax = False else: custom_ax = True # Animation nframes = image.shape[0] animated = nframes > 1 borders = [] latlines = [] lonlines = [] # Set up the plot if figsize is None: figsize = (7, 3.75) if ax is None: fig, ax = plt.subplots(1, figsize=figsize) else: fig = ax.figure # Mollweide dx = 2.0 / image.shape[1] extent = (1 + shrink) * np.array([ -(1 + dx) * 2 * np.sqrt(2), 2 * np.sqrt(2), -(1 + dx) * np.sqrt(2), np.sqrt(2), ]) ax.axis("off") ax.set_xlim(-2 * np.sqrt(2) - 0.05, 2 * np.sqrt(2) + 0.05) ax.set_ylim(-np.sqrt(2) - 0.05, np.sqrt(2) + 0.05) # Anti-aliasing at the edges x = np.linspace(-2 * np.sqrt(2), 2 * np.sqrt(2), 10000) y = np.sqrt(2) * np.sqrt(1 - (x / (2 * np.sqrt(2)))**2) borders += [ax.fill_between(x, 1.1 * y, y, color="w", zorder=-1)] borders += [ ax.fill_betweenx(0.5 * x, 2.2 * y, 2 * y, color="w", zorder=-1) ] borders += [ax.fill_between(x, -1.1 * y, -y, color="w", zorder=-1)] borders += [ ax.fill_betweenx(0.5 * x, -2.2 * y, -2 * y, color="w", zorder=-1) ] if grid: x = np.linspace(-2 * np.sqrt(2), 2 * np.sqrt(2), 10000) a = np.sqrt(2) b = 2 * np.sqrt(2) y = a * np.sqrt(1 - (x / b)**2) borders += ax.plot(x, y, "k-", alpha=1, lw=1.5, zorder=0) borders += ax.plot(x, -y, "k-", alpha=1, lw=1.5, zorder=0) lats = get_moll_latitude_lines() latlines = [None for n in lats] for n, l in enumerate(lats): (latlines[n], ) = ax.plot(l[0], l[1], "k-", lw=0.5, alpha=0.5, zorder=0) lons = get_moll_longitude_lines() lonlines = [None for n in lons] for n, l in enumerate(lons): (lonlines[n], ) = ax.plot(l[0], l[1], "k-", lw=0.5, alpha=0.5, zorder=0) # Plot the first frame of the image if vmin is None: vmin = np.nanmin(image) if vmax is None: vmax = np.nanmax(image) # Set a minimum contrast if np.abs(vmin - vmax) < 1e-12: vmin -= 1e-12 vmax += 1e-12 img = ax.imshow( image[0], origin="lower", extent=extent, cmap=cmap, vmin=vmin, vmax=vmax, interpolation="none", animated=animated, zorder=-3, ) # Add a colorbar if colorbar: if not custom_ax: fig.subplots_adjust(right=0.85) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) fig.colorbar(img, cax=cax, orientation="vertical") # Display or save the image / animation if animated: def updatefig(i): img.set_array(image[i]) return (img, *borders, *latlines, *lonlines) ani = FuncAnimation(fig, updatefig, interval=interval, blit=True, frames=image.shape[0]) # Business as usual if (file is not None) and (file != ""): if file.endswith(".mp4"): ani.save(file, writer="ffmpeg", dpi=dpi, bitrate=bitrate) elif file.endswith(".gif"): ani.save(file, writer="imagemagick", dpi=dpi, bitrate=bitrate) else: # Try and see what happens! ani.save(file, dpi=dpi, bitrate=bitrate) if not custom_ax: if not plt.isinteractive(): plt.close() else: # if not custom_ax: try: if "zmqshell" in str(type(get_ipython())): plt.close() with matplotlib.rc_context({ "savefig.dpi": dpi if dpi is not None else "figure", "animation.bitrate": bitrate if bitrate is not None else -1, }): if html5_video: display(HTML(ani.to_html5_video())) else: display(HTML(ani.to_jshtml())) else: raise NameError("") except NameError: plt.show() if not plt.isinteractive(): plt.close() # Matplotlib generates an annoying empty # file when producing an animation. Delete it. try: os.remove("None0000000.png") except FileNotFoundError: pass else: if (file is not None) and (file != ""): fig.savefig(file, bbox_inches="tight") if not custom_ax: if not plt.isinteractive(): plt.close() elif not custom_ax: plt.show()
def from_2json_plot( json_file1='./json_data/hip/openpose/output.json', json_file2='./json_data/Std1-openpose.mp4#-20210131T074012Z-001/Std1-openpose.mp4#', save_path='./test_hip.html', video='html'): '''同上,但画两个图''' # TODO: 范围, -y, ect _, _, filenames1 = next(os.walk(json_file1)) filenames1 = [ os.path.join(json_file1, i) for i in filenames1 if i[-4:] == 'json' ] pose_list_all1 = [] for filename in filenames1: pose_list = from_path_get_poseList(filename) if pose_list is not None: pose_list_all1.append(pose_list) _, _, filenames2 = next(os.walk(json_file2)) filenames2 = [ os.path.join(json_file2, i) for i in filenames2 if i[-4:] == 'json' ] pose_list_all2 = [] for filename in filenames2: pose_list = from_path_get_poseList(filename) if pose_list is not None: pose_list_all2.append(pose_list) pose_list_all1 = np.array(pose_list_all1) pose_list_all2 = np.array(pose_list_all2) slices = split(pose_list_all1) # 在这里调试中断,查看slices,手动判断选取哪两个index作为分割帧 slice1_fir = slices[0] slice1_end = slices[-1] slice2 = split(pose_list_all2) slice2_fir = slices[0] slice2_end = slices[-1] # 抽出动图可以看出,确实都是两个俯卧撑周期,而且时间帧数完全一样,效果较好,但openpose结果抖动太大 pose_list_all1 = pose_list_all1[slice1_fir:slice1_end] pose_list_all2 = pose_list_all2[slice2_fir:slice2_end] fig = plt.figure(figsize=(15, 12)) ax = fig.add_subplot(111, autoscale_on=False, xlim=(0, 2000), ylim=(0, 1000)) def animate(i): global Body_25_Pairs global colors ax.cla() ax.set_xlim(0, 2000) ax.set_ylim(0, 1000) pose_list1 = pose_list_all1[i] pose_list2 = pose_list_all2[i] # 每一帧的所有pose for pose_part in Body_25_Pairs: # 每一个关节连接点 pose_list = pose_list1 x1, y1 = pose_list[pose_part[0] * 3], pose_list[pose_part[0] * 3 + 1] x2, y2 = pose_list[pose_part[1] * 3], pose_list[pose_part[1] * 3 + 1] if (x1 and x2 and y1 and y2): ax.plot([x1, x2], [y1, y2], 'o-', lw=2, color='red') # color=colors[pose_part[0]]) for pose_part in Body_25_Pairs: pose_list = pose_list2 x1, y1 = pose_list[pose_part[0] * 3], pose_list[pose_part[0] * 3 + 1] x2, y2 = pose_list[pose_part[1] * 3], pose_list[pose_part[1] * 3 + 1] if (x1 and x2 and y1 and y2): ax.plot([x1, x2], [y1, y2], 'o-', lw=2, color='blue') # colors[pose_part[0]]) frame_num = min(len(pose_list_all1), len(pose_list_all2)) ani = FuncAnimation(fig, animate, frames=range(frame_num), interval=250) if video != 'html': print('Begin saving gif') ani.save('test.gif', writer='imagemagick', fps=None) print('Finished.') else: with open(save_path, 'w') as f: # f.write('<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Test</title> </head> <body> ') f.write(ani.to_html5_video()) return ani
for j in range(1,xx-2): mat_A[j,j+1] = mat_A[j,j+1]/(mat_A[j,j] - mat_A[j,j-1]*mat_A[j-1,j]) #ai = ai / di - bi*ai-1 for j in range(1,xx-1): mat_r[j] = (mat_r[j] - mat_A[j,j-1]*mat_r[j-1]) / (mat_A[j,j] - mat_A[j,j-1]*mat_A[j-1,j]) #ri = (ri - bi*ri-1)/(di - bi*ai-1) grid2[-2,n] = mat_r[-1] #xn = rn for i in range(1,xx-1): grid2[-i-2,n] = mat_r[-i-1] - mat_A[-i-1,-i]*grid2[-i-1,n] #xi = ri - ai*xi+1 from n-1 to 1 #%% plot fig = plt.figure(figsize=(8,6)) ax = plt.axes(xlim=(0, 1), ylim=(0, 1)) line, = ax.plot([], []) def update(i): line.set_data(np.linspace(0, 1, int(1./dx)+1), grid2[:,i]) plt.title('t= %5.3F' %(i*dt)) return line, ani = FuncAnimation(fig, update, frames=200, interval=50) HTML(ani.to_html5_video()) ani.save('sin_plus_cos.gif', writer='imagemagick')
ax.set_xlim(-2, 16) ax.set_ylim(-0.1, 18) lines[0].set_data([],[]) lines[1].set_data([],[]) lines[2].set_data([],[]) return lines def update(frame): tau_data.append(frame) xdata = [x2(i, frame) for i in t_range] hdata = [h_func(i) for i in t_range] ydata.append(np.sum(np.multiply(xdata, hdata)*(t_range[1] - t_range[0]))) lines[0].set_data(t_range, xdata) lines[1].set_data(t_range, hdata) lines[2].set_data(tau_data, ydata) return lines ani = FuncAnimation(fig, update, frames=t_range, init_func=init, blit=True, interval=200) lol = ani.to_html5_video() with open('k.html', 'w') as f: f.write(lol) plt.show()
class SolutionAnimation: def __init__( self, solutions, velocity=False, figsize=None, interval=10, notebook=True, ): plt.style.use("dark_background") self.fig = plt.figure(figsize=figsize) if len(solutions) == 1: self.plotter = SingleSolutionPlotter(solutions[0], self.fig, velocity=velocity) else: self.plotter = SolutionComparePlotter(solutions, self.fig, velocity=velocity) self.interval = interval self.paused = False self.notebook = notebook def init(self): return self.plotter.init() def update(self, i): return self.plotter.update(i) def on_click(self, event): """Toggle play/pause with space bar. Handy for non-jupyter runs.""" if event.key != " ": return if self.paused: self.ani.event_source.start() self.paused = False else: self.ani.event_source.stop() self.paused = True def run(self): self.fig.canvas.mpl_connect("key_press_event", self.on_click) self.ani = FuncAnimation( self.fig, self.update, frames=len(self.plotter), init_func=self.init, interval=self.interval, repeat=False, blit=True, ) if not self.notebook: plt.show() else: plt.close(self.fig) mpl.rcParams.update(mpl.rcParamsDefault) return self def to_html(self): return HTML(self.ani.to_html5_video())
lines = ax.scatter(x, y, marker='o', s=50, c='green', alpha=0.8) plt.close() def animate(i): lines.set_sizes(np.array(AmpSize1[i:i + 9]) * 5) lines.set_color(Color4[i:i + 9]) ax.set_ylabel(df['Time'][i][:10]) if i == len(df) - 9: sd.play((panner(longsines[0], np.radians(-50)) + panner(longsines[1], np.radians(0)) + panner(longsines[2], np.radians(50)) + panner(longsines[3], np.radians(10)) + panner(longsines[4], np.radians(20)) + panner(longsines[5], np.radians(-20)) + panner(longsines[6], np.radians(-30)) + panner(longsines[7], np.radians(5)) + panner(longsines[8], np.radians(-5))) * 0.25, sr) return lines, animation = FuncAnimation(fig, func=animate, frames=np.arange(27, len(df), 9), interval=(dur / splits) * 1000, blit=False, repeat=False) HTML(animation.to_html5_video())
def animate_quadcopter_3d(traj, x_star, t_span, path='quadcopter_animation.gif', html_embed=False): ''' Animate drone and save gif Args traj: drone trajectory x_star: target position t_span: time vector corresponding to each trajectory path: save path for html_embed: embed mp4 video in the page ''' fig = plt.figure(figsize=(10, 10)) ax = plt.axes(projection='3d') # For visualization scale = 1.5 s = 50 dxm = scale * 0.16 # arm length (m) dym = scale * 0.16 # arm length (m) dzm = scale * 0.05 # motor height (m) s_drone = scale * 10 # drone body dimension lw = scale drone_size = [dxm / 2, dym / 2, dzm] drone_color = ["royalblue"] lim = [0, x_star[2] * 1.2] ax.set_xlim3d(lim[0], lim[1]) ax.set_ylim3d(lim[0], lim[1]) ax.set_zlim3d(lim[0], lim[1]) ax.set_xlabel('x[m]') ax.set_ylabel('y[m]') ax.set_zlabel('z[m]') lines1, lines2 = [], [] l1, = ax.plot([], [], [], lw=2, color='red') l2, = ax.plot([], [], [], lw=2, color='green') body, = ax.plot([], [], [], marker='o', markersize=s_drone, color='black', markerfacecolor='black') initial = traj[0] tr = traj # Single frame plotting def get_frame(i): del ax.collections[:] # remove previous 3D elements init = ax.scatter(initial[0], initial[1], initial[2], marker='^', color='blue', label='Initial Position', s=s) fin = ax.scatter(x_star[0], x_star[1], x_star[2], marker='*', color='red', label='Target', s=s) # set linestyle to none ax.plot(tr[:i, 0], tr[:i, 1], tr[:i, 2], alpha=0.1, linestyle='-.', color='tab:blue') time = t_span[i] pos = tr[i] x = pos[0] y = pos[1] z = pos[2] x_from0 = tr[0:i, 0] y_from0 = tr[0:i, 1] z_from0 = tr[0:i, 2] # Trick to reuse the same function R = euler_matrix(torch.Tensor([pos[3]]), torch.Tensor([pos[4]]), torch.Tensor([pos[5]])).numpy().squeeze(0) motorPoints = np.array([[dxm, -dym, dzm], [0, 0, 0], [dxm, dym, dzm], [-dxm, dym, dzm], [0, 0, 0], [-dxm, -dym, dzm], [-dxm, -dym, -dzm]]) motorPoints = np.dot(R, np.transpose(motorPoints)) motorPoints[0, :] += x motorPoints[1, :] += y motorPoints[2, :] += z # Motors l1.set_data(motorPoints[0, 0:3], motorPoints[1, 0:3]) l1.set_3d_properties(motorPoints[2, 0:3]) l2.set_data(motorPoints[0, 3:6], motorPoints[1, 3:6]) l2.set_3d_properties(motorPoints[2, 3:6]) # Body pos = ((motorPoints[:, 6] + 2 * motorPoints[:, 1]) / 3) body = plot_cube(pos, drone_size, rotation=R, edgecolor="k") ax.add_collection3d(body) ax.set_title("Quadcopter Trajectory, t = {:.2f} s".format(time)) # Unused for now def anim_callback(i, get_world_frame): frame = get_world_frame(i) set_frame(frame) # Frame setting def set_frame(frame): # convert 3x6 world_frame matrix into three line_data objects which is 3x2 (row:point index, column:x,y,z) lines_data = [frame[:, [0, 2]], frame[:, [1, 3]], frame[:, [4, 5]]] ax = plt.gca() lines = ax.get_lines() for line, line_data in zip(lines[:3], lines_data): x, y, z = line_data line.set_data(x, y) line.set_3d_properties(z) an = FuncAnimation(fig, get_frame, init_func=None, frames=len(t_span) - 1, interval=20, blit=False) an.save(path, dpi=80, writer='imagemagick', fps=20) if html_embed: HTML(an.to_html5_video())
def generateSimulationFertilized(s_tracker, z_tracker, iteration=None, lcm=f_lcm, norm=f_norm): fig, axes = plt.subplots(1, 2, figsize=(12, 5)) s_iter = s_tracker.iteration z_iter = z_tracker.iteration iteration = max(s_iter, z_iter) if (iteration == None) else iteration plt.subplots_adjust(wspace=0.3) nplots, bplots = ([], []) for ax in axes: plt.setp(ax, xticks=[], yticks=[]) nplot, = ax.plot([], [], 'o', color='blue') bplot, = ax.plot([], [], 'o', color='red') nplots.append(nplot) bplots.append(bplot) splot = axes[0].imshow(s_tracker.tm_tracks[0], cmap=lcm, norm=norm, vmin=0, vmax=1) generateColorbar(axes[0], splot, [0, 1]) zplot = axes[1].imshow(z_tracker.tm_tracks[0], cmap=lcm, norm=norm, vmin=0, vmax=1) generateColorbar(axes[1], zplot, [0, 1]) def animate(i): print("Working on iteration...{}".format(i)) its = min(i, s_iter) itz = min(i, z_iter) (sny, snx), (sby, sbx) = s_tracker.getAgentLocations(its) nplots[0].set_data(snx, sny) bplots[0].set_data(sbx, sby) (zny, znx), (zby, zbx) = z_tracker.getAgentLocations(itz) nplots[1].set_data(znx, zny) bplots[1].set_data(zbx, zby) s_srate = (s_tracker.s_tracks[its] / s_tracker.size) * 100 s_frate = (s_tracker.f_tracks[its] / s_tracker.nt) * 100 axes[0].set_title( ("Iterasi: {}\nSurveillance:{:6.2f}%. Pemupukan: {:6.2f}%").format( i, s_srate, s_frate), {'fontsize': 12}, loc='left') z_srate = (z_tracker.s_tracks[itz] / z_tracker.size) * 100 z_frate = (z_tracker.f_tracks[itz] / z_tracker.nt) * 100 axes[1].set_title( ("Surveillance:{:6.2f}%. Pemupukan: {:6.2f}%").format( z_srate, z_frate), {'fontsize': 12}, loc='left') splot = axes[0].imshow(s_tracker.tm_tracks[its], cmap=lcm, norm=norm, vmin=0, vmax=1) zplot = axes[1].imshow(z_tracker.tm_tracks[itz], cmap=lcm, norm=norm, vmin=0, vmax=1) return splot, zplot # Menampilkan Animasi frames = np.arange(0, iteration, 1) anim = FuncAnimation(fig, animate, frames=frames, interval=100) plt.close(anim._fig) return HTML(anim.to_html5_video())
label2 = ax.text(600, 100, 'angle = 0', fontsize=12) def animate(i): _, c = sess.run([optimiser_op, loss], feed_dict={x : np.array(x_input).reshape(-1, 1), y: np.array(y_output).reshape(-1, 1)}) a,f = sess.run([angle_constant.value(), force_constant.value()]) traj_path = traj(np.arange(1000), f, a, 9.8) label.set_text(traf_equ(int(a), int(f))) label2.set_text('angle = {}°'.format(int(a))) line.set_ydata(traj_path) anim = FuncAnimation( fig, animate, interval=50, frames=130) HTML(anim.to_html5_video()) sess.run(angle_constant.value()) HTML(anim.to_html5_video()) a,f = sess.run([angle_constant.value(), force_constant.value()]) a,f
def animate(self, outputType="screen", color="random", speed=10, outDir="out", type="line"): if not os.path.exists(outDir): os.mkdir(outDir) fname = os.path.join( outDir, "knightPath-{}-{}".format(self.kn.shape[0], self.kn.shape[1])) knightAnimation = FuncAnimation(self.fig, self._genLine, fargs=(speed, color, type), repeat=False, frames=range( -speed, len(self.kn.history), speed, ), blit=False, interval=10, cache_frame_data=False) if outputType == "screen": plt.show() elif outputType == "avi": knightAnimation.save( fname + ".avi", writer=FFMpegFileWriter(fps=1, bitrate=100000, extra_args=['-vcodec', 'libx264']), ) print("video file written to", fname + ".avi") elif outputType == "mp4": knightAnimation.save( fname + ".mp4", writer=FFMpegFileWriter(fps=1, bitrate=100000, extra_args=['-vcodec', 'libx264']), ) print("MP4 video file written to", fname + ".mp4") elif outputType == "gif": knightPathAnim = FuncAnimation(self.fig, self._genAllLines, repeat=False, frames=range(1), blit=False, interval=10, cache_frame_data=False) knightPathAnim.save(fname + '.gif', writer=ImageMagickFileWriter(fps=1)) print("Image written to", fname + ".gif") elif outputType == "animgif": knightAnimation.save(fname + '.anim.gif', writer=ImageMagickFileWriter(fps=1)) print("Animated gif written to", fname + ".anim.gif") elif outputType == "html": open(fname + ".html", "w").write( self._genHtmlFrame(knightAnimation.to_html5_video(50.0))) print("HTML file written to", fname + ".html") else: print("Unknown outputType '" + outputType + "'") return
def animate(map, time, phase0=0.0, res=75, interval=75): """ """ # Load the SPICE data ephemFiles = glob.glob('../data/TESS_EPH_PRE_LONG_2018*.bsp') tlsFile = '../data/tess2018338154046-41240_naif0012.tls' solarSysFile = '../data/tess2018338154429-41241_de430.bsp' #print(spice.tkvrsn('TOOLKIT')) for ephFil in ephemFiles: spice.furnsh(ephFil) spice.furnsh(tlsFile) spice.furnsh(solarSysFile) # JD time range allTJD = time + TJD0 nT = len(allTJD) allET = np.zeros((nT, ), dtype=np.float) for i, t in enumerate(allTJD): allET[i] = spice.unitim(t, 'JDTDB', 'ET') # Calculate positions of TESS, the Earth, and the Sun tess = np.zeros((3, len(allET))) sun = np.zeros((3, len(allET))) for i, et in enumerate(allET): outTuple = spice.spkezr('Mgs Simulation', et, 'J2000', 'NONE', 'Earth') tess[0, i] = outTuple[0][0] * REARTH tess[1, i] = outTuple[0][1] * REARTH tess[2, i] = outTuple[0][2] * REARTH outTuple = spice.spkezr('Sun', et, 'J2000', 'NONE', 'Earth') sun[0, i] = outTuple[0][0] * REARTH sun[1, i] = outTuple[0][1] * REARTH sun[2, i] = outTuple[0][2] * REARTH # Figure setup fig = plt.figure(figsize=(8, 8)) ax = np.zeros((2, 2), dtype=object) ax[0, 0] = plt.subplot(221) ax[0, 1] = plt.subplot(222) ax[1, 0] = plt.subplot(223, sharex=ax[0, 0], sharey=ax[0, 0]) ax[1, 1] = plt.subplot(224, sharex=ax[0, 0], sharey=ax[0, 0]) for axis in [ax[0, 0], ax[1, 0], ax[1, 1]]: axis.set_aspect(1) axis.set_xlim(-65, 65) axis.set_ylim(-65, 65) for tick in axis.xaxis.get_major_ticks() + axis.yaxis.get_major_ticks( ): tick.label.set_fontsize(10) i = 0 # Orbit xz ax[0, 0].plot(tess[0], tess[2], "k.", ms=1, alpha=0.025) txz, = ax[0, 0].plot(tess[0, i], tess[2, i], 'o', color="C0", ms=4) norm = 1. / np.sqrt(sun[0, i]**2 + sun[2, i]**2) x = sun[0, i] * norm y = sun[2, i] * norm theta = 180. / np.pi * np.arctan2(y, x) dayxz = Wedge((0, 0), 5, theta - 90, theta + 90, color=cmap(0.8)) nightxz = Wedge((0, 0), 5, theta + 90, theta + 270, color=cmap(0.0)) ax[0, 0].add_artist(dayxz) ax[0, 0].add_artist(nightxz) ax[0, 0].set_ylabel("z", fontsize=16) # Orbit xy ax[1, 0].plot(tess[0], tess[1], "k.", ms=1, alpha=0.025) txy, = ax[1, 0].plot(tess[0, i], tess[1, i], 'o', color="C0", ms=4) norm = 1. / np.sqrt(sun[0, i]**2 + sun[1, i]**2) x = sun[0, i] * norm y = sun[1, i] * norm theta = 180. / np.pi * np.arctan2(y, x) dayxy = Wedge((0, 0), 5, theta - 90, theta + 90, color=cmap(0.8)) nightxy = Wedge((0, 0), 5, theta + 90, theta + 270, color=cmap(0.0)) ax[1, 0].add_artist(dayxy) ax[1, 0].add_artist(nightxy) ax[1, 0].set_xlabel("x", fontsize=16) ax[1, 0].set_ylabel("y", fontsize=16) # Orbit zy ax[1, 1].plot(tess[2], tess[1], "k.", ms=1, alpha=0.025) tzy, = ax[1, 1].plot(tess[2, i], tess[1, i], 'o', color="C0", ms=4) norm = 1. / np.sqrt(sun[2, i]**2 + sun[1, i]**2) x = sun[2, i] * norm y = sun[1, i] * norm theta = 180. / np.pi * np.arctan2(y, x) dayzy = Wedge((0, 0), 5, theta - 90, theta + 90, color=cmap(0.8)) nightzy = Wedge((0, 0), 5, theta + 90, theta + 270, color=cmap(0.0)) ax[1, 1].add_artist(dayzy) ax[1, 1].add_artist(nightzy) ax[1, 1].set_xlabel("z", fontsize=16) # Render the image t = (time - time[0]) / (time[-1] - time[0]) t = 2 * (t - 0.5) Z = np.empty((len(time), res, res)) north_pole = np.empty((len(time), 3)) y = np.array(map[:, :, :]) for i in tqdm(range(len(time))): # Reset the map and rotate it to the correct phase # in the mean equatorial (J2000) frame map[:, :, :] = y ''' map.axis = [0, 1, 0] phase = (360. * time[i]) % 360. + phase0 map.rotate(phase) ''' # Rotate so that TESS is along the +z axis r = np.sqrt(np.sum(tess[:, i]**2)) costheta = np.dot(tess[:, i], [0, 0, r]) axis = np.cross(tess[:, i], [0, 0, r]) sintheta = np.sqrt(np.sum(axis**2)) axis /= sintheta theta = 180. / np.pi * np.arctan2(sintheta, costheta) R = starry.RAxisAngle(axis, theta) north_pole[i] = np.dot(R, [0, 0, 1]) source = np.dot(R, sun[:, i]) source /= np.sqrt(np.sum(source**2, axis=0)) ''' map.axis = axis map.rotate(theta) ''' # Align the pole of the Earth with the "north" direction costheta = np.dot([0, 1, 0], north_pole[i]) axis = np.cross([0, 1, 0], north_pole[i]) sintheta = np.sqrt(np.sum(axis**2)) axis /= sintheta theta = 180. / np.pi * np.arctan2(sintheta, costheta) map.axis = axis map.rotate(theta) # Rotate to the correct phase map.axis = north_pole[i] phase = (360. * time[i]) % 360. + phase0 map.rotate(phase) # Finally, rotate the image so that north always points up # This doesn't actually change the integrated flux! map.axis = [0, 0, 1] theta = 180. / np.pi * np.arctan2(north_pole[i, 0], north_pole[i, 1]) map.rotate(theta) R = starry.RAxisAngle([0, 0, 1], theta) north_pole[i] = np.dot(R, north_pole[i]) source = np.dot(R, source) # Render the image Z[i] = map.render(t=t[i], source=source, res=res)[0] # Reset the map map[:, :, :] = y map.axis = [0, 1, 0] # Image vmin = 0.0 vmax = np.nanmax(Z) cmap.set_under(cmap(vmin)) image = ax[0, 1].imshow(Z[0], extent=(-1, 1, -1, 1), origin="lower", cmap=cmap, vmin=vmin, vmax=vmax) npl, = ax[0, 1].plot(north_pole[0, 0], north_pole[0, 1], marker=r"$N$", color="r") spl, = ax[0, 1].plot(-north_pole[0, 0], -north_pole[0, 1], marker=r"$S$", color="b") if north_pole[0, 2] > 0: npl.set_visible(True) spl.set_visible(False) else: npl.set_visible(False) spl.set_visible(True) ax[0, 1].axis("off") ax[0, 1].set_xlim(-1.1, 1.1) ax[0, 1].set_ylim(-1.1, 1.1) # Function to animate each frame def update(i): # Update orbit txz.set_xdata(tess[0, i]) txz.set_ydata(tess[2, i]) norm = 1. / np.sqrt(sun[0, i]**2 + sun[2, i]**2) x = sun[0, i] * norm y = sun[2, i] * norm theta = 180. / np.pi * np.arctan2(y, x) dayxz.set_theta1(theta - 90) dayxz.set_theta2(theta + 90) nightxz.set_theta1(theta + 90) nightxz.set_theta2(theta + 270) txy.set_xdata(tess[0, i]) txy.set_ydata(tess[1, i]) norm = 1. / np.sqrt(sun[0, i]**2 + sun[1, i]**2) x = sun[0, i] * norm y = sun[1, i] * norm theta = 180. / np.pi * np.arctan2(y, x) dayxy.set_theta1(theta - 90) dayxy.set_theta2(theta + 90) nightxy.set_theta1(theta + 90) nightxy.set_theta2(theta + 270) tzy.set_xdata(tess[2, i]) tzy.set_ydata(tess[1, i]) norm = 1. / np.sqrt(sun[2, i]**2 + sun[1, i]**2) x = sun[2, i] * norm y = sun[1, i] * norm theta = 180. / np.pi * np.arctan2(y, x) dayzy.set_theta1(theta - 90) dayzy.set_theta2(theta + 90) nightzy.set_theta1(theta + 90) nightzy.set_theta2(theta + 270) image.set_data(Z[i]) npl.set_xdata(north_pole[i, 0]) npl.set_ydata(north_pole[i, 1]) spl.set_xdata(-north_pole[i, 0]) spl.set_ydata(-north_pole[i, 1]) if north_pole[i, 2] > 0: npl.set_visible(True) spl.set_visible(False) else: npl.set_visible(False) spl.set_visible(True) return txz, dayxz, nightxz, txy, dayxy, nightxy, \ tzy, dayzy, nightzy, image, npl, spl # Generate the animation ani = FuncAnimation(fig, update, frames=len(time), interval=interval, blit=False) try: if 'zmqshell' in str(type(get_ipython())): plt.close() display(HTML(ani.to_html5_video())) else: raise NameError("") except NameError: plt.show() plt.close() return np.nansum(Z, axis=(1, 2))
def animate(self): df = self.slice_data() dates = df.columns merged = self.us_map.set_index('NAME').join(df) fig, ax = plt.subplots(figsize=(15, 7)) def draw_frame(frame_num, dates=dates, fig=fig, ax=ax): ax.clear() if len(fig.axes) > 1: fig.delaxes(fig.axes[1]) date = dates[frame_num] bins = merged[date].quantile([0, 0.1, 0.25, 0.5, 0.75, 0.9, 1]) vmin, vmax = merged[date].min(), merged[date].max() med = merged[date].median() merged.plot(column=date, cmap='Reds', linewidth=0.8, ax=ax, edgecolor='0.8', classification_kwds={'bins': bins}) ax.set_xlim([-125, -65]) ax.set_ylim([25, 50]) ax.axis('off') ax.set_title('# of Confirmed Cases of Covid-19', fontdict={ 'fontsize': '18', 'fontweight': '3' }) ax.annotate(date, xy=(0.1, .225), xycoords='figure fraction', ha='left', va='top', fontsize=16) ax.annotate(f'Median: {med}', xy=(0.1, .175), xycoords='figure fraction', ha='left', va='top', fontsize=16) ax.annotate(f'Max: {vmax}', xy=(0.1, .125), xycoords='figure fraction', ha='left', va='top', fontsize=16) sm = plt.cm.ScalarMappable(cmap='Reds', norm=plt.Normalize(vmin=vmin, vmax=vmax)) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) cbar = fig.colorbar(sm, cax=cax) fig.tight_layout() writervideo = animation.FFMpegWriter(fps=60) anim = FuncAnimation(fig, draw_frame, frames=len(dates), interval=400, repeat=False) anim.save('pages/animation.mp4', writer=writervideo) html = anim.to_html5_video() plt.close(fig) return HTML(html)