def plot_single_decomposition_runtime( self, decomposition_runtime_metric_specification, decomposition_runtime_axes_specification): base_filename = "{}__by__{}".format( decomposition_runtime_metric_specification["filename"], decomposition_runtime_axes_specification["filename"]) output_path, filename = self._construct_output_path_and_filename( base_filename) logger.debug("output_path is {};\t filename is {}".format( output_path, filename)) if not self.overwrite_existing_files and os.path.exists(filename): logger.info( "Skipping generation of {} as this file already exists".format( filename)) return values_dict = self._get_values_dict( base_filename, decomposition_runtime_axes_specification, decomposition_runtime_metric_specification) fig, ax = plt.subplots(figsize=(FIGSIZE[0] - 0.75, FIGSIZE[1])) if self.paper_mode: print decomposition_runtime_axes_specification ax.set_title( decomposition_runtime_axes_specification['plot_title'], fontsize=PLOT_TITLE_FONT_SIZE) else: title = decomposition_runtime_metric_specification['name'] + "\n" title += self._get_sol_count_string(values_dict) ax.set_title(title, fontsize=PLOT_TITLE_FONT_SIZE) sorted_keys = sorted(values_dict.keys()) percentiles = decomposition_runtime_metric_specification["percentiles"] linewidths = decomposition_runtime_metric_specification.get( "linewidths", [0.5] * len(percentiles)) color_values = decomposition_runtime_metric_specification.get( "color_values") lines = np.zeros((len(percentiles), len(sorted_keys))) for i, key in enumerate(sorted_keys): lines[:, i] = np.percentile(values_dict[key], percentiles) t_start = time() handles = [] median_legend_handle = None for i, p in enumerate(percentiles): sorted_keys = sorted(values_dict.keys()) if p == 50: sorted_keys[0] += 0.15 sorted_keys[-1] -= 0.15 line = ax.plot(sorted_keys, lines[i][:], linewidth=linewidths[i], color="k", label="median" if p == 50 else None, solid_capstyle='round') line[0].set_path_effects([ path_effects.Stroke(linewidth=linewidths[i] + 0.5, foreground='w'), path_effects.Normal() ]) if i < len(percentiles) - 1: if color_values: c = plt.cm.inferno(color_values[i]) else: c = plt.cm.inferno(0.01 * p) if p == 50: median_legend_handle = line[0] handles[-1].set_label("{}% - {}%".format( percentiles[i - 1], percentiles[i + 1])) else: handles.append( mpatches.Patch(color=c, label="{}% - {}%".format( p, percentiles[i + 1]))) ax.fill_between( sorted_keys, lines[i][:], lines[i + 1][:], facecolor=matplotlib.colors.to_rgba( c, 0.8), # apply alpha only to facecolor ) handles.reverse() #if median_legend_handle: # handles.append(median_legend_handle) leg = ax.legend(handles=handles, fontsize=LEGEND_LABEL_FONT_SIZE - 2, loc=2, title="percentiles", handletextpad=.35, borderaxespad=0.175, borderpad=0.2, handlelength=1.75) plt.setp(leg.get_title(), fontsize=LEGEND_TITLE_FONT_SIZE - 1) plt.gca().add_artist(leg) sec_leg = ax.legend(handles=[median_legend_handle], fontsize=LEGEND_LABEL_FONT_SIZE - 1, loc=1, title="", handletextpad=.35, borderaxespad=0.175, borderpad=0.2, handlelength=1.75, frameon=True) print "Plotting:", time() - t_start, "seconds" if "x_axis_ticks" in decomposition_runtime_axes_specification: ax.set_xticks( decomposition_runtime_axes_specification["x_axis_ticks"]) ax.set_xticklabels( map(str, decomposition_runtime_axes_specification["x_axis_ticks"])) if decomposition_runtime_metric_specification.get( "use_log_scale", False): plt.yscale('log') plt.autoscale(True) if "xlim" in decomposition_runtime_axes_specification: ax.set_xlim(decomposition_runtime_axes_specification['xlim'][0], decomposition_runtime_axes_specification['xlim'][1]) ax.tick_params(axis="x", **DEFAULT_MAJOR_TICK_PARAMS) ax.tick_params(axis="y", **DEFAULT_MAJOR_TICK_PARAMS) ax.tick_params(axis="x", **DEFAULT_MINOR_TICK_PARAMS) ax.tick_params(axis="y", **DEFAULT_MINOR_TICK_PARAMS) for tick in ax.xaxis.get_major_ticks(): tick.label.set_fontsize(TICK_LABEL_FONT_SIZE) for tick in ax.yaxis.get_major_ticks(): tick.label.set_fontsize(TICK_LABEL_FONT_SIZE) #plt.xlim(-5,41) ax.grid( ) # to change grid style parameters, modify the BOXPLOT_..._TICK_PARAMS dicts defined at the top of the file ax.set_xlabel(decomposition_runtime_axes_specification['x_axis_title'], fontsize=X_AXIS_LABEL_FONT_SIZE) ax.set_ylabel( decomposition_runtime_metric_specification['y_axis_title'], fontsize=Y_AXIS_LABEL_FONT_SIZE) self._show_and_or_save_plots(output_path, filename)
def plot_img_boxes(img, boxes, classes, extras=None, plt_ax=None, figsize=None, class_names=None, real_pixels=False, box_centered=True): if not plt_ax: _, plt_ax = plt.subplots(figsize=figsize) colors = np.array([[1, 0, 1], [0, 0, 1], [0, 1, 1], [0, 1, 0], [1, 1, 0], [1, 0, 0]]) if type(img) == PIL.Image.Image: width = img.width height = img.height elif type(img) in [torch.Tensor, np.ndarray]: # if len(img.shape)>3: img = img[0] if type(img) == torch.Tensor: img = img.clone().cpu().numpy() width = img.shape[2] height = img.shape[1] img = img.transpose(1, 2, 0) if (img < 1.01).all() and (img >= 0).all(): img = img.clip( 0, 1 ) # avoid "Clipping input data to the valid range" warning after tensor roundings else: raise (f"Unkown type for image: {type(img)}") if len(boxes) > 0 and not real_pixels: boxes[:, 0] *= width boxes[:, 2] *= width boxes[:, 1] *= height boxes[:, 3] *= height for i in range(len(boxes)): b, class_id = boxes[i], classes[i] if b[0] == 0: break color = colors[class_id % len(colors)] if box_centered: x, y = (b[0] - b[2] / 2, b[1] - b[3] / 2) w, h = (b[2], b[3]) else: x, y = b[0], b[1] w, h = b[2], b[3] patch = plt_ax.add_patch( patches.Rectangle([x, y], w, h, fill=False, edgecolor=color, lw=2)) patch.set_path_effects([ patheffects.Stroke(linewidth=1, foreground='black', alpha=0.5), patheffects.Normal() ]) s = class_names[class_id] if class_names else str(class_id) if extras: s += "\n" + str(extras[i]) patch = plt_ax.text(x + 2, y, s, verticalalignment='top', color=color, fontsize=12, weight='bold') patch.set_path_effects([ patheffects.Stroke(linewidth=1, foreground='black', alpha=0.5), patheffects.Normal() ]) _ = plt_ax.imshow(img) plt.show()
def main(): myhero = Heuro(email, password) # Small dictionary to convert API output to a readable format mygender = { 0: "female", 1: "male" } # mypipe = myhero.make_pipeline(pipeline="test_pipe") # print(mypipe) # upload = myhero.ingest_file('../data/images/test_faces_2.jpg', pipeline_id) """ file_to_ingest = '../data/audio/man-woman.mp3' file_to_ingest = '../data/images/four-in-car.jpeg' file_to_ingest = '../data/images/family1.jpeg' image_to_ingest = "../data/images/thb1.jpg" audio_to_ingest = '../data/audio/man-woman.mp3' audio_to_ingest = '../data/video/tagueule.mp3' image_to_ingest = '../data/video/tagueule.png' image_to_ingest = '../data/images/four-in-car.jpeg' image_to_ingest = '../data/images/mp1.jpeg' audio_to_ingest = "../data/audio/baby-talk.mp3" image_to_ingest = '../data/images/girls.jpg' audio_to_ingest = "../data/audio/tom_scott_trim.mp3" """ # Image first, just because audio_to_ingest = "../data/audio/ambianceinsidecar.mp3" image_to_ingest = '../data/images/4.jpg' files_to_ingest = [image_to_ingest, audio_to_ingest] if image_to_ingest[-3:] != "png" and \ image_to_ingest[-3:] != "jpg" and \ image_to_ingest[-4:] != "jpeg" and \ audio_to_ingest[-3:] != "mp3": sys.exit(" Sorry. File format is not recognized.") is_jpeg = detect_jpeg(file_to_ingest=image_to_ingest) results = analyse_file_api(files_to_ingest, target_api=myhero, pipeline_id=pipeline_id) # print(results) # r1 = analyse_file_api(image_to_ingest, target_api=myhero, pipeline_id=pipeline_id) r1 = results[0] watch_json = True # False if watch_json: import json with open('jsonwatch_image.txt', 'w') as outf: json.dump(r1, outf, sort_keys = True, indent = 4, separators=(',', ':')) # Audio second if audio_to_ingest[-3:] != "mp3": sys.exit(" Sorry. Image file format is not recognized.") # r2 = analyse_file_api(audio_to_ingest, target_api=myhero, pipeline_id=pipeline_id) r2 = results[1] # Distinguish between image and audio (different output formats) # inference_audio = {} # inference_image = {} r_video = r1['result']['output']['classification'] # for x, y in zip(r_output.keys(), r_output.values()): # print(str(x)+": "+str(np.array(y).shape)+str(y)) people = r_video.get('objects') # Test if we got anything at all out if not people: sys.exit("Error: the API did not detect any people.") n_people = len(people) gender_image = [] age_image = [] face_xy = [] for person in people: gender_image.append(person['gender']) age_image.append(person['ageGroup']) face_xy.append((person['face']['X'], person['face']['Y'])) r_audio = r2['result']['output'] # for x, y in zip(r_output.keys(), r_output.values()): # print(str(x)+": "+str(y)) gender_audio = r_audio['gender'] age_audio = r_audio['age'] language = r_audio['language'] # if file_to_ingest[-3:] == "mp3": # with open('jsonwatch_audio.txt', 'w') as outf: # json.dump(r, outf, sort_keys = True, indent = 4, separators=(',', ':')) # elif file_to_ingest[-3:] == "png" or\ # file_to_ingest[-3:] == "jpg" or\ # file_to_ingest[-4:] == "jpeg": print("=== Audio evaluation ===") print("gender_audio: ", gender_audio) print("age_audio: ", age_audio) print("language: ", language) print("=== Video evaluation ===") print("n_people: ", n_people) print("gender_image: ", [mygender[gen] for gen in gender_image]) print("age_image: ", age_image) print("faces: ", face_xy) children = False if "Child" in age_image: children = True n_male = gender_image.count(1) n_female = gender_image.count(0) n_child = age_image.count("Child") n_adult = age_image.count("Adult") if n_female > n_male: maj_sex = "female" elif n_female < n_male: maj_sex = "male" else: maj_sex = None if n_child > n_adult: maj_age = "Child" else: maj_age = "Adult" # if n_male==0 or n_female==0: # mix_sex = False # else: # mix_sex = True print() print("=== Overall mood ===") print("Children: ", children) print("Gender Majority: ", maj_sex) print("Age Majority: ", maj_age) if gender_audio == maj_sex: print("Audio agrees with video on gender.") else: print("AI cannot determine gender using audio.") # print("Sex Mix: ", mix_sex) if is_jpeg: from PIL import Image # with open(image_to_ingest, 'r') as im_input: # im = Image.open(im_input) im = Image.open(image_to_ingest, 'r') im.save("Foto.png") #, 'w') # with open("Foto.png", 'w') as foto: # im.save(foto) img = mpimage.imread('Foto.png', 'r') else: img = mpimage.imread(image_to_ingest) plt.imshow(img) for age, gend, face in zip(age_image, gender_image, face_xy): plt.text(face[0], face[1], str(age)+"\n"+str(mygender[gend]), color='white', fontsize=24).set_path_effects([path_effects.Stroke(linewidth=4, foreground='black'), path_effects.Normal()]) plt.xticks([]) plt.yticks([]) plt.show() outfile = "../data/output/output.jpg" with open(outfile, 'w') as outf: plt.savefig(outf) # Remove png file, only needed for visualization if is_jpeg: os.remove('Foto.png')
def plot_values(self, lons, lats, vals, fmt='%s', valmask=None, color='#000000', textsize=14, labels=None, labeltextsize=10, labelcolor='#000000', showmarker=False, labelbuffer=25, outlinecolor='#FFFFFF'): """Plot values onto the map Args: lons (list): longitude values to use for placing `vals` lats (list): latitude values to use for placing `vals` vals (list): actual values to place on the map fmt (str, optional): Format specification to use for representing the values. For example, the default is '%s'. valmask (list, optional): Boolean list to use as masking of the `vals` while adding to the map. color (str, list, optional): Color to use while plotting the `vals`. This can be a list to specify each color to use with each value. textsize (str, optional): Font size to draw text. labels (list, optional): Optional list of labels to place below the plotting of `vals` labeltextsize (int, optional): Size of the label text labelcolor (str, optional): Color to use for drawing labels showmarker (bool, optional): Place a marker on the map for the label labelbuffer (int): pixel buffer around labels outlinecolor (color): color to use for text outlines """ if valmask is None: valmask = [True] * len(lons) if labels is None: labels = [''] * len(lons) if isinstance(color, str): color = [color] * len(lons) bbox = self.fig.get_window_extent().transformed( self.fig.dpi_scale_trans.inverted()) axbbox = self.ax.get_window_extent().transformed( self.fig.dpi_scale_trans.inverted()) axx0 = axbbox.x0 * self.fig.dpi axx1 = (axbbox.x0 + axbbox.width) * self.fig.dpi axy0 = axbbox.y0 * self.fig.dpi axy1 = (axbbox.y0 + axbbox.height) * self.fig.dpi figwidth = bbox.width * self.fig.dpi figheight = bbox.height * self.fig.dpi if self.textmask is None: self.textmask = np.zeros((int(figwidth), int(figheight)), bool) thisax = self.ax # Create a fake label, to test out our scaling t0 = self.fig.text(0.5, 0.5, "ABCDEFGHIJ", transform=thisax.transAxes, color='None', size=textsize) bbox = t0.get_window_extent(self.fig.canvas.get_renderer()) xpixels_per_char = bbox.width / 10. ypixels = bbox.height for o, a, v, m, c, label in zip(lons, lats, vals, valmask, color, labels): if not m: continue ha = 'center' mystr = fmt % (v,) max_mystr_len = max([len(s) for s in mystr.split("\n")]) mystr_lines = len(mystr.split("\n")) # compute the pixel coordinate of this data point (x, y) = thisax.projection.transform_point(o, a, ccrs.Geodetic()) (imgx, imgy) = thisax.transData.transform([x, y]) imgx0 = int(imgx - (max_mystr_len * xpixels_per_char / 2.0)) if imgx0 < axx0: ha = 'left' imgx0 = imgx imgx1 = imgx0 + max_mystr_len * xpixels_per_char if imgx1 > axx1: imgx1 = imgx imgx0 = imgx1 - max_mystr_len * xpixels_per_char ha = 'right' imgy0 = int(imgy) imgy1 = imgy0 + mystr_lines * ypixels # Now we buffer imgx0 = max([0, imgx0 - labelbuffer]) imgx1 = min([figwidth, (imgx0 + 2 * labelbuffer + max_mystr_len * xpixels_per_char)]) imgy0 = max([0, imgy0 - labelbuffer * 0.75]) imgy1 = min([figheight, (imgy0 + mystr_lines * ypixels + 2 * labelbuffer * 0.75)]) _cnt = np.sum(np.where(self.textmask[int(imgx0):int(imgx1), int(imgy0):int(imgy1)], 1, 0)) # If we have more than 15 pixels of overlap, don't plot this! if _cnt > 15: if self.debug: print("culling |%s| due to overlap, %s" % (repr(mystr), _cnt)) continue if self.debug: rec = plt.Rectangle([imgx0, imgy0], (imgx1 - imgx0), (imgy1 - imgy0), facecolor='None', edgecolor='r') self.fig.patches.append(rec) # Useful for debugging this algo if self.debug: print(("label: %s imgx: %s/%s-%s imgy: %s/%s-%s " "x:%s-%s y:%s-%s _cnt:%s" ) % (repr(mystr), imgx, axx0, axx1, imgy, axy0, axy1, imgx0, imgx1, imgy0, imgy1, _cnt)) self.textmask[int(imgx0):int(imgx1), int(imgy0):int(imgy1)] = True t0 = thisax.text(o, a, mystr, color=c, size=textsize, zorder=Z_OVERLAY+2, va='center' if not showmarker else 'bottom', ha=ha, transform=ccrs.PlateCarree()) bbox = t0.get_window_extent(self.fig.canvas.get_renderer()) if self.debug: rec = plt.Rectangle([bbox.x0, bbox.y0], bbox.width, bbox.height, facecolor='None', edgecolor='k') self.fig.patches.append(rec) if showmarker: thisax.scatter(o, a, marker='+', zorder=Z_OVERLAY+2, color='k', transform=ccrs.PlateCarree()) t0.set_clip_on(True) t0.set_path_effects([PathEffects.Stroke(linewidth=3, foreground=outlinecolor), PathEffects.Normal()]) if label and label != '': thisax.annotate("%s" % (label, ), xy=(x, y), ha='center', va='top', xytext=(0, 0 - textsize/2), color=labelcolor, textcoords="offset points", zorder=Z_OVERLAY+1, clip_on=True, fontsize=labeltextsize)
def plot_online_prediction(preds_dict, new_inputs_dict, online_stg, t_predict, robot_future, dt, max_speed, color_dict=None, data_id=0, focus_on=None, focus_window_height=6, line_alpha=0.7, line_width=0.2, edge_width=2, circle_edge_width=0.5, only_predict=None, edge_line_width=1.0, dpi=300, fig_height=4, xlim=(0, 100), ylim=(0, 50), figsize=None, return_frame=False, return_fig=False, printing=False, robot_circle=False, add_legend=True, title=None, flip_axes=False, omit_names=False, plot_edges=True, axes_labels=True, rotate_axes_text=0, save_at=None): if color_dict is None: # This changes colors per run. color_dict = defaultdict(dict) if dt is None: raise ValueError( 'You must supply a time delta, the argument dt cannot be None!') robot_node = online_stg.robot_node if figsize is None: aspect_ratio = float(xlim[1] - xlim[0]) / (ylim[1] - ylim[0]) figsize = (fig_height * aspect_ratio, fig_height) predict_horizon = robot_future.shape[0] if t_predict < online_stg.hyperparams['minimum_history_length']: return ################### ### Predictions ### ################### outputs = {k: v.cpu().numpy() for k, v in preds_dict.items()} ######################## ### Data Preparation ### ######################## output_pos = dict() sampled_zs = dict() for node in online_stg.nodes: if robot_node == node: continue key = str(node) + '/y' z_key = str(node) + '/z' output_pos[node] = integrate_trajectory(outputs[key], [0, 1], new_inputs_dict[node][0], [0, 1], dt, output_limit=max_speed, velocity_in=True) sampled_zs[node] = outputs[z_key] ###################### ### Visualizations ### ###################### fig, ax = plt.subplots(figsize=figsize) not_added_samples = True for node_name in online_stg.nodes: if focus_on is not None and node_name != focus_on: continue predictions = output_pos[node_name][:, 0] z_values = sampled_zs[node_name][:, 0] # Predicted trails if only_predict is None or (only_predict is not None and node_name == only_predict): if not_added_samples: # plt.plot([] , [], 'r', label='Sampled Futures') not_added_samples = False for sample_num in range(output_pos[node_name].shape[0]): z_value = tuple(z_values[sample_num]) if z_value not in color_dict[node_name]: color_dict[node_name][z_value] = "#%06x" % random.randint( 0, 0xFFFFFF) ax.plot(predictions[sample_num, :, 0], predictions[sample_num, :, 1], color=color_dict[node_name][z_value], linewidth=line_width, alpha=line_alpha, zorder=2) # Current Node Position circle = plt.Circle( (new_inputs_dict[node_name][0, 0], new_inputs_dict[node_name][0, 1]), 0.3, facecolor='b' if 'Home' in node_name.type else 'g', edgecolor='k', lw=circle_edge_width, zorder=3) ax.add_artist(circle) # if focus_on: # ax.set_title(node_name) # else: # ax.text(prefix[-1, 0] + 0.4, prefix[-1, 1], node_name, zorder=4) if not omit_names: ax.text(new_inputs_dict[node_name][0, 0] + 0.4, new_inputs_dict[node_name][0, 1], node_name, zorder=4) # Robot Node if focus_on is None: robot_future = robot_future[:, 0:2] future_all_zeros = not np.any(robot_future) if not future_all_zeros and robot_node in new_inputs_dict: ax.plot(robot_future[:, 0], robot_future[:, 1], 'w--', path_effects=[ pe.Stroke(linewidth=edge_width, foreground='k'), pe.Normal() ]) circle = plt.Circle( (new_inputs_dict[robot_node][0, 0], new_inputs_dict[robot_node][0, 1]), 0.3, facecolor='b' if 'Home' in robot_node.type else 'g', edgecolor='k', lw=circle_edge_width, zorder=3) ax.add_artist(circle) # Radius of influence if robot_circle: circle = plt.Circle((new_inputs_dict[robot_node][0, 0], new_inputs_dict[robot_node][0, 1]), online_stg.hyperparams['edge_radius'], fill=False, color='r', linestyle='--', zorder=3) ax.plot([], [], 'r--', label='Edge Radius') ax.add_artist(circle) if not omit_names: ax.text(new_inputs_dict[robot_node][0, 0] + 0.4, new_inputs_dict[robot_node][0, 1], robot_node, zorder=4) if plot_edges: already_seen_pairs = list() for node_A, egdes_and_neighbors in online_stg.scene_graph.node_edges_and_neighbors.items( ): for edge_type, neigbors in egdes_and_neighbors.items(): for node_B in neigbors: if (node_A, node_B) in already_seen_pairs: continue already_seen_pairs.append((node_B, node_A)) if robot_node not in [node_A, node_B]: edge_age = min([ online_stg.node_models_dict[str( node_A)].get_mask_for_edge_to(node_B).item(), online_stg.node_models_dict[str( node_B)].get_mask_for_edge_to(node_A).item() ]) else: edge_age = 1 plt.plot([ new_inputs_dict[node_A][0, 0], new_inputs_dict[node_B][0, 0] ], [ new_inputs_dict[node_A][0, 1], new_inputs_dict[node_B][0, 1] ], color='k', lw=edge_line_width, dashes=[edge_age, 1 - edge_age], zorder=-1) if focus_on is not None: y_radius = focus_window_height x_radius = aspect_ratio * y_radius ax.set_ylim((prefix[-1, 1] - y_radius, prefix[-1, 1] + y_radius)) ax.set_xlim((prefix[-1, 0] - x_radius, prefix[-1, 0] + x_radius)) if ylim is not None: ax.set_ylim(ylim) if xlim is not None: ax.set_xlim(xlim) if add_legend and robot_circle and not future_all_zeros: ax.legend(loc='best') if title is not None: ax.set_title(title) if axes_labels: ax.set_xlabel('$x$ Position (m)') ax.set_ylabel('$y$ Position (m)') if rotate_axes_text != 0: plt.xticks(rotation=rotate_axes_text) plt.yticks(rotation=rotate_axes_text) fig.tight_layout() if return_fig: return fig if return_frame: buffer_ = StringIO() plt.savefig(buffer_, format="png", transparent=True, dpi=dpi) buffer_.seek(0) data = np.asarray(Image.open(buffer_)) plt.close(fig) return data if save_at is not None: plt.savefig(save_at, dpi=dpi, transparent=True) plt.show() plt.close(fig)
def cell_wise_velocity(adata, genes, x=0, y=1, basis='trimap', n_columns=1, color=None, label_on_embedding=True, cmap=None, s_kwargs_dict={}, layer='X', cell_ind='all', quiver_scale=None, figsize=None, **q_kwargs): """Plot the velocity vector of each cell. Parameters ---------- adata: :class:`~anndata.AnnData` an Annodata object. genes: `list` The gene names whose gene expression will be faceted. x: `int` (default: `0`) The column index of the low dimensional embedding for the x-axis y: `int` (default: `1`) The column index of the low dimensional embedding for the y-axis basis: `str` (default: `trimap`) The reduced dimension embedding of cells to visualize. n_columns: `int (default: 1) The number of columns of the resulting plot. color: `list` or None (default: None) A list of attributes of cells (column names in the adata.obs) will be used to color cells. cmap: `plt.cm` or None (default: None) The color map function to use. s_kwargs_dict: `dict` (default: {}) The dictionary of the scatter arguments. layer: `str` (default: X) Which layer of expression value will be used. cell_ind: `str` or `list` (default: all) the cell index that will be chosen to draw velocity vectors. quiver_scale: `float` or None (default: None) scale of quiver plot (default: None). Number of data units per arrow length unit, e.g., m/s per plot width; a smaller scale parameter makes the arrow longer. If None, we will use quiver_autoscaler to calculate the scale. figsize: `None` or `[float, float]` (default: None) The width and height of a figure. q_kwargs: Additional parameters that will be passed to plt.quiver function Returns ------- Nothing but a cell wise quiver plot """ import matplotlib.pyplot as plt import matplotlib.patheffects as PathEffects if cmap is None and color is None: cmap = plt.cm.RdBu_r n_cells, n_genes = adata.shape[0], len(genes) # {"alpha": 0.5, "s": 8, "edgecolor": "0.8", "lw": 0.15} if cell_ind is "all": ix_choice = np.arange(adata.shape[0]) elif cell_ind is 'random': ix_choice = np.random.choice(np.range(adata.shape[0]), size=1000, replace=False) elif type(cell_ind) is int: ix_choice = np.random.choice(np.range(adata.shape[0]), size=cell_ind, replace=False) elif type(cell_ind) is list: ix_choice = cell_ind scatter_kwargs = dict(alpha=0.4, s=8, edgecolor=None, linewidth=0) if s_kwargs_dict is not None: scatter_kwargs.update(s_kwargs_dict) # layer_keys = list(adata.layers.keys()) # layer_keys.extend(['X', 'protein']) if layer is 'X': E_vec = adata[:, adata.var.index.isin(genes)].X.T elif layer in adata.layers.keys(): E_vec = adata[:, adata.var.index.isin(genes)].layers[layer].T elif layer is 'protein': # update subset here E_vec = adata[:, adata.var.index.isin(genes)].obsm[layer].T else: raise Exception(f'The {layer} you passed in is not existed in the adata object.') if color is not None: color = list(set(color).intersection(adata.obs.keys())) n_genes, genes = len(color), color E_vec = adata.obs[color].values.T.flatten() if len(color) > 0 else np.empty((0, 1)) if ('X_' + basis in adata.obsm.keys()) and ('velocity_' + basis in adata.obsm.keys()): X = adata.obsm['X_' + basis][:, [x, y]] V = adata.obsm['velocity_' + basis][:, [x, y]] else: if 'X_' + basis not in adata.obsm.keys(): reduceDimension(adata, velocity_key='velocity_S', reduction_method=basis) if 'kmc' not in adata.uns_keys(): cell_velocities(adata, vkey='pca', basis=basis, method='analytical') X = adata.obsm['X_' + basis][:, [x, y]] V = adata.obsm['velocity_' + basis][:, [x, y]] else: kmc = adata.uns['kmc'] X = adata.obsm['X_' + basis][:, [x, y]] V = kmc.compute_density_corrected_drift(X, kmc.Idx, normalize_vector=True) adata.obsm['velocity_' + basis] = V if 0 in E_vec.shape: raise Exception(f'The gene names {genes} (or cell annotations {color}) provided are not existed in your data.') if quiver_scale is None: quiver_scale = quiver_autoscaler(X, V) quiver_kwargs = {"angles": 'xy', "scale_units": 'xy', 'scale': quiver_scale, "minlength": 1.5, "alpha": 0.4} quiver_kwargs.update(q_kwargs) n_columns, plot_per_gene = n_columns, 1 # we may also add random velocity results nrow, ncol = int(np.ceil(plot_per_gene * n_genes / n_columns)), n_columns if figsize is None: plt.figure(None, (ncol * 3, nrow * 3), dpi=160) else: plt.figure(None, (figsize[0]*ncol, figsize[1]*nrow)) # , dpi=160 E_vec = E_vec.A.flatten() if issparse(E_vec) else E_vec.flatten() V = V.A[:, [x, y]] if issparse(V) else V[:, [x, y]] # iterate over cell first then a different dimension/gene/column df = pd.DataFrame({"x": np.tile(X[:, 0], n_genes), "y": np.tile(X[:, 1], n_genes), "u": np.tile(V[:, 0], n_genes), "v": np.tile(V[:, 1], n_genes), 'gene': np.repeat(np.array(genes), n_cells), "expression": E_vec}, index=range(n_cells * n_genes)) # the following code is inspired by https://github.com/velocyto-team/velocyto-notebooks/blob/master/python/DentateGyrus.ipynb gs = plt.GridSpec(nrow, ncol) for i, gn in enumerate(genes): ax = plt.subplot(gs[i*plot_per_gene]) try: ix=np.where(adata.var.index == gn)[0][0] except: ix = gn in adata.obs.columns if not ix: continue cur_pd = df.loc[df.gene == gn, :] E_vec = cur_pd.loc[:, 'expression'] if color is None: limit = np.max(np.abs(np.percentile(E_vec, [1, 99]))) # upper and lowe limit / saturation E_vec = E_vec + limit # that is: tmp_colorandum - (-limit) E_vec = E_vec / (2 * limit) # that is: tmp_colorandum / (limit - (-limit)) E_vec = np.clip(E_vec, 0, 1) ax.scatter(cur_pd.iloc[:, 0], cur_pd.iloc[:, 1], c=cmap(E_vec), **scatter_kwargs) else: import seaborn as sns # List of RGB triplets color_labels = E_vec.unique() rgb_values = sns.color_palette("Set2", len(color_labels)) # Map label to RGB color_map = pd.DataFrame(zip(color_labels, rgb_values), index=color_labels) ax.scatter(cur_pd.iloc[:, 0], cur_pd.iloc[:, 1], c=color_map.loc[E_vec, 1].values, **scatter_kwargs) if label_on_embedding: for i in color_labels: color_cnt = np.median(cur_pd.iloc[np.where(E_vec == i)[0], :2], 0) txt=ax.text(color_cnt[0], color_cnt[1], str(i), fontsize=13) # , bbox={"facecolor": "w", "alpha": 0.6} txt.set_path_effects([ PathEffects.Stroke(linewidth=5, foreground="w", alpha=0.1), PathEffects.Normal()]) ax.quiver(cur_pd.iloc[ix_choice, 0], cur_pd.iloc[ix_choice, 1], cur_pd.iloc[ix_choice, 2], cur_pd.iloc[ix_choice, 3], **quiver_kwargs) ax.axis("off") plt.show()
def _midiplot(onsets,offsets,pitch): plt.figure(figsize=(20,10)) for i in range(0,len(onsets)): plt.plot([onsets[i],offsets[i]], [pitch[i],pitch[i]], 'k', lw=2, path_effects=[pe.Stroke(linewidth=2, foreground='k'), pe.Normal()], zorder=5) plt.xlabel("Beats") plt.ylabel("Pitch (C4=60)")
def dashboard(prediction, tlm, times, limits, modelname='PSMC', msid='1pdeaat', errorplotlimits=None, yplotlimits=None, fig=None, savefig=True): """ Plot Xija model dashboard. :param prediction: model prediction :param tlm: telemetry :param times: model/telemetry time values :param limits: model limit dict, (e.g. {"units":"C", "caution_high":-12.0, "planning_limit":-14.0}) :param modelname: Name of model (e.g. "ACA") :param msid: msid name (e.g. "aacccdpt") :param errorplotlimits: list or tuple of min and max x axis plot boundaries for both righthand plots Note: prediction, tlm, and times must all have the same number of values. """ # Set some plot characteristic default values # matplotlib.rcParams['xtick.major.pad'] = 10 # matplotlib.rcParams['ytick.major.pad'] = 5 matplotlib.rc('font', family='sans-serif') matplotlib.rc('font', weight='light') error = tlm - prediction stats = calcquantiles(error) # In this case the data is not discretized to a limited number of count values, or has too # many possible values to work with calcquantstats(), such as with tlm_fep1_mong. if len(np.sort(list(set(tlm)))) > 1000: quantized_tlm = digitize_data(tlm) quantstats = calcquantstats(quantized_tlm, error) else: quantstats = calcquantstats(tlm, error) units = limits['units'] cautionhigh = limits.get('caution_high', None) planninglimit = limits.get('planning_limit', None) acisi_limit = limits.get('acisi_limit', None) aciss_limit = limits.get('aciss_limit', None) fp_sens_limit = limits.get('fp_sens_limit', None) startsec = DateTime(times[0]).secs stopsec = DateTime(times[-1]).secs xtick = np.linspace(startsec, stopsec, 10) xlab = [lab[:8] for lab in DateTime(xtick).date] if not fig: # fig = plt.figure(figsize=(16, 10), facecolor=[1, 1, 1]) fig = plt.figure(figsize=(15, 8)) else: fig.clf() # --------------------------------------------------------------------------------------------- # Axis 1 - Model and Telemetry vs Time # # This plot is in the upper lefthand corner and shows predicted temperatures in red and # telemetry in blue vs time. # ax1 = fig.add_axes([0.1, 0.38, 0.44, 0.50], frameon=True) ax1.plot(times, prediction, color='#d92121', linewidth=1, label='Model') ax1.plot(times, tlm, color='#386cb0', linewidth=1.5, label='Telemetry') ax1.set_title('%s Temperature (%s)' % (modelname.replace('_', ' '), msid.upper()), fontsize=18, y=1.00) ax1.set_ylabel('Temperature deg%s' % units, fontsize=18) if yplotlimits is not None: ax1.set_ylim(yplotlimits) ax1.set_yticklabels(ax1.get_yticks(), fontsize=14) ax1.set_xticks(xtick) ax1.set_xticklabels('') ax1.set_xlim(xtick[0] - 10, times[-1]) ax1.grid(True) if cautionhigh: # Draw caution high limit line. ylim1 = ax1.get_ylim() dy = ylim1[1] - ylim1[0] if ylim1[1] - 2 <= cautionhigh: ax1.set_ylim(ylim1[0], cautionhigh + dy / 7.) ax1.set_yticklabels(ax1.get_yticks(), fontsize=14) ylim1 = ax1.get_ylim() yellowlimitline = ax1.plot(ax1.get_xlim(), [cautionhigh, cautionhigh], 'orange', linewidth=1.5) if ylim1[1] <= cautionhigh: ax1.set_ylim(ylim1[0], cautionhigh + 1) # Print caution high limit value (remember plot is 50% of fig height). #chfig = 0.50 * (cautionhigh - ylim1[0]) / (np.diff(ylim1)) + 0.38 #txt = fig.text(0.11, chfig - 0.000, 'Caution High (Yellow) = {:4.1f} {}'.format( # cautionhigh, units), ha="left", va="bottom", size=18) #txt.set_bbox(dict(color='white', alpha=0.8)) xlim1 = ax1.get_xlim() chx = 0.02 * (xlim1[1] - xlim1[0]) + xlim1[0] chy = 0.01 * (ylim1[1] - ylim1[0]) + cautionhigh txt = ax1.text(chx, chy, 'Caution High (Yellow) = {:4.1f} {}'.format( cautionhigh, units), ha="left", va="bottom", fontsize=12) txt.set_path_effects([ path_effects.Stroke(linewidth=3, foreground='white', alpha=0.7), path_effects.Normal() ]) txt.set_bbox(dict(color='white', alpha=0)) if planninglimit: # Draw planning limit line. planninglimitline1 = ax1.plot(ax1.get_xlim(), [planninglimit, planninglimit], 'g--', linewidth=1.5) ylim1 = ax1.get_ylim() # Print planning limit value (remember plot is 50% of fig height). #if (ylim1[-1] - planninglimit) / np.diff(ylim1) < 0.1: # plfig = 0.50 * (planninglimit - ylim1[0]) / (np.diff(ylim1)) + 0.38 #else: # # <-- figure coordinates (plot is 50% of fig height) # plfig = 0.50 * (planninglimit - ylim1[0]) / (np.diff(ylim1)) + 0.38 + 0.01 # #if cautionhigh: # if np.abs(planninglimit - cautionhigh)/np.diff(ylim1) < 0.1: # plfig = plfig + 0.02 #txt = fig.text(0.11, plfig - 0.005, 'Planning Limit = {:4.1f} {}'.format( # planninglimit, units), ha="left", va="top", size=18) #txt.set_bbox(dict(color='white', alpha=0.8)) xlim1 = ax1.get_xlim() plx = 0.02 * (xlim1[1] - xlim1[0]) + xlim1[0] ply = 0.01 * (ylim1[1] - ylim1[0]) + planninglimit txt = ax1.text(plx, ply, 'Planning Limit = {:4.1f} {}'.format( planninglimit, units), ha="left", va="bottom", fontsize=12) txt.set_path_effects([ path_effects.Stroke(linewidth=3, foreground='white', alpha=0.7), path_effects.Normal() ]) # txt.set_bbox(dict(color='white', alpha=0)) if acisi_limit: # Draw ACIS-I limit line. acisilimitline = ax1.plot(ax1.get_xlim(), [acisi_limit, acisi_limit], 'b-.', linewidth=1.5) ylim1 = ax1.get_ylim() xlim1 = ax1.get_xlim() plx = 0.02 * (xlim1[1] - xlim1[0]) + xlim1[0] ply = 0.01 * (ylim1[1] - ylim1[0]) + acisi_limit txt = ax1.text(plx, ply, 'ACIS-I Limit = {:4.1f} {}'.format(acisi_limit, units), ha="left", va="bottom", fontsize=14) txt.set_path_effects([ path_effects.Stroke(linewidth=4, foreground='white', alpha=1.0), path_effects.Normal() ]) if aciss_limit: # Draw ACIS-S limit line. acisslimitline = ax1.plot(ax1.get_xlim(), [aciss_limit, aciss_limit], '-.', color='purple', linewidth=1.5) ylim1 = ax1.get_ylim() xlim1 = ax1.get_xlim() plx = 0.02 * (xlim1[1] - xlim1[0]) + xlim1[0] ply = 0.01 * (ylim1[1] - ylim1[0]) + aciss_limit txt = ax1.text(plx, ply, 'ACIS-S Limit = {:4.1f} {}'.format(aciss_limit, units), ha="left", va="bottom", fontsize=14) txt.set_path_effects([ path_effects.Stroke(linewidth=4, foreground='white', alpha=1.0), path_effects.Normal() ]) if fp_sens_limit: # Draw FP SENS limit line. fpsenslimitline = ax1.plot(ax1.get_xlim(), [fp_sens_limit, fp_sens_limit], '--', color='red', linewidth=1.5) ylim1 = ax1.get_ylim() xlim1 = ax1.get_xlim() plx = 0.02 * (xlim1[1] - xlim1[0]) + xlim1[0] ply = 0.01 * (ylim1[1] - ylim1[0]) + fp_sens_limit txt = ax1.text(plx, ply, 'FP SENS Limit = {:4.1f} {}'.format( fp_sens_limit, units), ha="left", va="bottom", fontsize=14) txt.set_path_effects([ path_effects.Stroke(linewidth=4, foreground='white', alpha=1.0), path_effects.Normal() ]) # --------------------------------------------------------------------------------------------- # Axis 2 - Model Error vs Time # # This plot is in the lower lefthand corner and shows model error (telemetry - model) vs. time. # ax2 = fig.add_axes([0.1, 0.1, 0.44, 0.2], frameon=True) ax2.plot(times, error, color='#386cb0', label='Telemetry') if errorplotlimits: ax2.set_ylim(errorplotlimits) ax2.set_title('%s Model Error (Telemetry - Model)' % modelname.replace('_', ' '), fontsize=18, y=1.00) ax2.set_ylabel('Error deg%s' % units, fontsize=18) ax2.set_yticklabels(ax2.get_yticks(), fontsize=14) # ax2.tick_params(axis='x', which='major', pad=1) ax2.set_xticks(xtick) ax2.set_xticklabels(xlab, fontsize=14, rotation=30, ha='right') ax2.set_xlim(xtick[0] - 10, times[-1]) ax2.grid(True) # --------------------------------------------------------------------------------------------- # Axis 3 - Telemetry vs Model Error # # This plot is in the upper righthand corner of the page and shows telemetry vs. model error. # The code to show model temperature vs model error is commented out but can be used in place # of the current comparison, although the quantile lines plotted will also need to be removed. # # Add some noise to the telemetry (or model) data to make it easier to see the data (less # pile-up). # # band is the mean difference between counts in telemetry (resolution). band = np.abs(np.diff(tlm)) band = np.mean(band[band > 0]) / 2 noise = np.random.uniform(-band, band, len(tlm)) ax3 = fig.add_axes([0.62, 0.38, 0.36, 0.50], frameon=True) ax3.plot(error, tlm + noise, 'o', color='#386cb0', alpha=1, markersize=2, markeredgecolor='#386cb0') #ax3.plot(error, prediction + noise, 'b,', alpha = 0.1) ax3.set_title('%s Telemetry \n vs. Model Error' % modelname.replace('_', ' '), fontsize=18, y=1.00) ax3.set_ylabel('Temperature deg%s' % units, fontsize=18) ax3.grid(True) # This is an option so that the user can tweak the two righthand plots to use a reasonable # set of x axis limits, either because an outlier is expanding the axis range too much, or if # more space is needed at the boundaries of the axis. if errorplotlimits: ax3.set_xlim(errorplotlimits) ax3.set_ylim(ax1.get_ylim()) ax3.set_yticks(ax1.get_yticks()) ax3.set_yticklabels(ax1.get_yticks(), fontsize=14) ylim3 = ax3.get_ylim() ax3.set_xticklabels(ax3.get_xticks(), fontsize=14) xlim3 = ax3.get_xlim() if cautionhigh: # Draw caution high limit line. dt = 0.05 * np.diff(ax1.get_ylim()) yellowlimitline3 = ax3.plot(xlim3, [cautionhigh, cautionhigh], 'orange', linewidth=1.5) if ylim3[1] <= cautionhigh: ax3.set_ylim(ylim3[0], cautionhigh + 1) ax3.set_yticklabels(ax3.get_yticks(), fontsize=18) if planninglimit: # Draw planning limit line. planninglimitline3 = ax3.plot(xlim3, [planninglimit, planninglimit], 'g--', linewidth=1.5) if acisi_limit: # Draw ACIS-I limit line. acisilimitline = ax3.plot(xlim3, [acisi_limit, acisi_limit], 'b-.', linewidth=1.5) if aciss_limit: # Draw ACIS-S limit line. acisslimitline = ax3.plot(xlim3, [aciss_limit, aciss_limit], '-.', color='purple', linewidth=1.5) if fp_sens_limit: # Draw FP SENS limit line. fpsenslimitline = ax3.plot(xlim3, [fp_sens_limit, fp_sens_limit], '--', color='red', linewidth=1.5) # Plot quantile lines for each count value Epoints01, Tpoints01 = getQuantPlotPoints(quantstats, 'q01') Epoints99, Tpoints99 = getQuantPlotPoints(quantstats, 'q99') Epoints50, Tpoints50 = getQuantPlotPoints(quantstats, 'q50') ax3.plot(Epoints01, Tpoints01, color='k', linewidth=4) ax3.plot(Epoints99, Tpoints99, color='k', linewidth=4) ax3.plot(Epoints50, Tpoints50, color=[1, 1, 1], linewidth=4) ax3.plot(Epoints01, Tpoints01, 'k', linewidth=2) ax3.plot(Epoints99, Tpoints99, 'k', linewidth=2) ax3.plot(Epoints50, Tpoints50, 'k', linewidth=1.5) xlim3 = ax3.get_xlim() ylim1 = ax1.get_ylim() # Match axis 1 y scale # --------------------------------------------------------------------------------------------- # Axis 4 - Error Distribution Histogram # # This plot is in the lower righthand corner of the page and shows the error distribution # histogram. # ax4 = fig.add_axes([0.62, 0.1, 0.36, 0.2], frameon=True) n, bins, patches = ax4.hist(error, 40, range=errorplotlimits, facecolor='#386cb0') ax4.set_title('Error Distribution', fontsize=18, y=1.0) ytick4 = ax4.get_yticks() # This is an option so that the user can tweak the two righthand plots to use a reasonable # set of x axis limits, either because an outlier is expanding the axis range too much, or if # more space is needed at the boundaries of the axis. if errorplotlimits: ax4.set_xlim(errorplotlimits) else: xlim_offset = (np.max(error) - np.min(error)) * 0.1 ax4.set_xlim(np.min(error) - xlim_offset, np.max(error) + xlim_offset) # Plot lines for statistical boundaries. ylim4 = ax4.get_ylim() ax4.set_yticklabels( ['%2.0f%%' % (100 * n / len(prediction)) for n in ytick4], fontsize=14) ax4.plot([stats['q01'], stats['q01'] + 1e-6], ylim4, color=[.5, .5, .5], linestyle='--', linewidth=1.5, alpha=1) ax4.plot([stats['q99'], stats['q99'] + 1e-6], ylim4, color=[.5, .5, .5], linestyle='--', linewidth=1.5, alpha=1) ax4.plot([np.min(error), np.min(error) + 1e-6], ylim4, color=[.5, .5, .5], linestyle='--', linewidth=1.5, alpha=1) ax4.plot([np.max(error), np.max(error) + 1e-6], ylim4, color=[.5, .5, .5], linestyle='--', linewidth=1.5, alpha=1) ax4.set_xlabel('Error deg%s' % units, fontsize=18) # Print labels for statistical boundaries. ystart = (ylim4[1] + ylim4[0]) * 0.5 xoffset = -(.2 / 25) * np.abs(np.diff(ax4.get_xlim())) ptext4a = ax4.text(stats['q01'] + xoffset * 1.1, ystart, '1% Quantile', ha="right", va="center", rotation=90, size=14) if np.min(error) > ax4.get_xlim()[0]: ptext4b = ax4.text(np.min(error) + xoffset * 1.1, ystart, 'Minimum Error', ha="right", va="center", rotation=90, size=14) ptext4c = ax4.text(stats['q99'] - xoffset * 0.9, ystart, '99% Quantile', ha="left", va="center", rotation=90, size=14) if np.max(error) < ax4.get_xlim()[1]: ptext4d = ax4.text(np.max(error) - xoffset * 0.9, ystart, 'Maximum Error', ha="left", va="center", rotation=90, size=14) xlim4 = ax4.get_xlim() xlimright = [min(xlim3[0], xlim4[0]), max(xlim3[1], xlim4[1])] ax4.set_ylim(ylim4) ax4.set_xlim(xlimright) ax4.set_xticklabels(ax4.get_xticks(), fontsize=14) # Replot axis 3 using widest right hand side xlim if cautionhigh: # # Draw caution high limit line. yellowlimitline3 = ax3.plot(xlimright, [cautionhigh, cautionhigh], 'orange', linewidth=1.5) # Draw planning limit line. planninglimitline3 = ax3.plot(xlimright, [planninglimit, planninglimit], 'g--', linewidth=1.5) ax3.set_xlim(xlimright) ax3.set_xticklabels(ax3.get_xticks()) # I know the following code looks to be redundant and unnecessary, but for some unholy reason, # Matplotlib REALLY does not want the top two axes to share the same Y scale. The following # code is used to pound Matplotlib into submission. ax3.set_ylim(ax1.get_ylim()) ax3.set_ybound(ax1.get_ylim()) ax3.set_yticks(ax1.get_yticks()) ax3.set_yticklabels(ax1.get_yticks()) ax1.set_ylim(ax1.get_ylim()) ax1.set_ybound(ax1.get_ylim()) ax1.set_yticks(ax1.get_yticks()) ax1.set_yticklabels(ax1.get_yticks()) # --------------------------------------------------------------------------------------------- # Force redraw and save. plt.draw() if savefig: fig.savefig(modelname + '_' + msid.upper() + '_Model_Dashboard.png')
def plot_time_slice(S, processed_st, time_slice=None, label_stations=True, hires=False, dem=None, plot_peak=True, xy_grid=None, cont_int=5, annot_int=50): """ Plot a time slice through :math:`S` to produce a map-view plot. If time is not specified, then the slice corresponds to the maximum of :math:`S` in the time direction. Can also plot the peak of the stack function over time. Args: S (:class:`~xarray.DataArray`): The stack function :math:`S` processed_st (:class:`~obspy.core.stream.Stream`): Pre-processed Stream; output of :func:`~rtm.waveform.process_waveforms` (This is needed because Trace metadata from this Stream are used to plot stations on the map) time_slice (:class:`~obspy.core.utcdatetime.UTCDateTime`): Time of desired time slice. The nearest time in :math:`S` to this specified time will be plotted. If `None`, the time corresponding to :math:`\max(S)` is used (default: `None`) label_stations (bool): Toggle labeling stations with network and station codes (default: `True`) hires (bool): If `True`, use higher-resolution coastlines, which looks better but can be slow (default: `False`) dem (:class:`~xarray.DataArray`): Overlay time slice on a user-supplied DEM from :class:`~rtm.grid.produce_dem` (default: `None`) plot_peak (bool): Plot the peak stack function over time as a subplot (default: `True`) xy_grid (int, float, or None): If not `None`, transforms UTM coordinates such that the grid center is at (0, 0) — the plot extent is then given by (-xy_grid, xy_grid) [meters] for easting and northing. Only valid for projected grids cont_int (int): Contour interval [m] for plots with DEM data annot_int (int): Annotated contour interval [m] for plots with DEM data (these contours are thicker and labeled) Returns: :class:`~matplotlib.figure.Figure`: Output figure """ # Don't plot peak of stack function when length of stack is one if plot_peak and len(S.time) == 1: plot_peak = False warnings.warn('Stack time length = 1, not plotting peak', RTMWarning) st = processed_st.copy() # Get coordinates of stack maximum in (latitude, longitude) time_max, y_max, x_max, peaks, props = get_peak_coordinates( S, unproject=S.UTM) # Gather coordinates of grid center lon_0, lat_0 = S.grid_center if S.UTM: # Don't use cartopy for UTM proj = None transform = None plot_transform = None lon_0, lat_0, _, _ = utm.from_latlon(S.grid_center[1], S.grid_center[0], force_zone_number=S.UTM['zone']) x_max, y_max, _, _ = utm.from_latlon(y_max, x_max, force_zone_number=S.UTM['zone']) for tr in st: tr.stats.longitude, tr.stats.latitude, _, _ = utm.from_latlon( tr.stats.latitude, tr.stats.longitude, force_zone_number=S.UTM['zone']) else: # This is a good projection to use since it preserves area proj = ccrs.AlbersEqualArea(central_longitude=lon_0, central_latitude=lat_0, standard_parallels=(S.y.values.min(), S.y.values.max())) transform = ccrs.PlateCarree() plot_transform = ccrs.PlateCarree() if plot_peak: fig, (ax, ax1) = plt.subplots(figsize=(8, 12), nrows=2, gridspec_kw={'height_ratios': [3, 1]}, subplot_kw=dict(projection=proj)) #axes kluge so the second one can have a different projection ax1.remove() ax1 = fig.add_subplot(414) else: fig, ax = plt.subplots(figsize=(8, 8), subplot_kw=dict(projection=proj)) # In either case, we convert from UTCDateTime to np.datetime64 if time_slice: time_to_plot = np.datetime64(time_slice) else: time_to_plot = np.datetime64(time_max) slice = S.sel(time=time_to_plot, method='nearest') # Convert UTM grid/etc to x/y coordinates with (0,0) as origin if xy_grid: # Make sure this is a projected grid if not S.UTM: raise ValueError('xy_grid can only be used with projected grids!') print(f'Converting to x/y grid, cropping {xy_grid:d} m from center') # Update dataarrays to x/y coordinates from dem x0 = slice.x.data.min() + slice.x_radius y0 = slice.y.data.min() + slice.y_radius slice = slice.assign_coords(x=(slice.x.data - x0)) slice = slice.assign_coords(y=(slice.y.data - y0)) # In case DEM has different extent than slice if dem is not None: x0_dem = dem.x.data.min() + dem.x_radius y0_dem = dem.y.data.min() + dem.y_radius dem = dem.assign_coords(x=(dem.x.data - x0_dem)) dem = dem.assign_coords(y=(dem.y.data - y0_dem)) lon_0 = lon_0 - x0 lat_0 = lat_0 - y0 x_max = x_max - x0 y_max = y_max - y0 for tr in st: tr.stats.longitude = tr.stats.longitude - x0 tr.stats.latitude = tr.stats.latitude - y0 if dem is None: if not S.UTM: _plot_geographic_context(ax=ax, hires=hires) alpha = 0.5 else: alpha = 1 # Can plot slice as opaque for UTM plots w/o DEM, since nothing beneath slice slice_plot_kwargs = dict(ax=ax, alpha=alpha, cmap='viridis', add_colorbar=False, add_labels=False) else: # Rounding to nearest cont_int all_levels = np.arange( np.ceil(dem.min().data / cont_int), np.floor(dem.max().data / cont_int) + 1) * cont_int # Rounding to nearest annot_int annot_levels = np.arange( np.ceil(dem.min().data / annot_int), np.floor(dem.max().data / annot_int) + 1) * annot_int # Ensure we don't draw annotated levels twice cont_levels = [] for level in all_levels: if level not in annot_levels: cont_levels.append(level) dem.plot.contour(ax=ax, colors='k', levels=cont_levels, zorder=-1, linewidths=0.3) # Use thicker lines for annotated contours cs = dem.plot.contour(ax=ax, colors='k', levels=annot_levels, zorder=-1, linewidths=0.7) ax.clabel(cs, fontsize=9, fmt='%d', inline=True) # Actually annotate slice_plot_kwargs = dict(ax=ax, alpha=0.7, cmap='viridis', add_colorbar=False, add_labels=False) # Mask areas outside of DEM extent # Select subset of DEM that slice occupies dem_slice = dem.sel(x=slice.x, y=slice.y, method='nearest') slice.data[np.isnan(dem_slice.data)] = np.nan if S.UTM: # imshow works well here (no gridlines in translucent plot) sm = slice.plot.imshow(zorder=0, **slice_plot_kwargs) plot_transform = ax.transData # Label axes according to choice of xy_grid or not if xy_grid: ax.set_xlabel('X [m]') ax.set_ylabel('Y [m]') else: ax.set_xlabel('UTM easting [m]') ax.set_ylabel('UTM northing [m]') ax.ticklabel_format(style='plain', useOffset=False) else: # imshow performs poorly for Albers equal-area projection - use # pcolormesh instead (gridlines will show in translucent plot) sm = slice.plot.pcolormesh(transform=transform, **slice_plot_kwargs) # Initialize list of handles for legend h = [None, None, None] scatter_zorder = 5 # Plot center of grid h[0] = ax.scatter(lon_0, lat_0, s=50, color='limegreen', edgecolor='black', label='Grid center', transform=plot_transform, zorder=scatter_zorder) # Plot stack maximum if S.UTM: # x/y formatting label = 'Stack max' else: # Lat/lon formatting label = f'Stack max\n({y_max:.4f}, {x_max:.4f})' h[1] = ax.scatter(x_max, y_max, s=100, color='red', marker='*', edgecolor='black', label=label, transform=plot_transform, zorder=scatter_zorder) # Plot stations for tr in st: h[2] = ax.scatter(tr.stats.longitude, tr.stats.latitude, marker='v', color='orange', edgecolor='black', label='Station', transform=plot_transform, zorder=scatter_zorder) if label_stations: ax.text(tr.stats.longitude, tr.stats.latitude, ' {}.{}'.format(tr.stats.network, tr.stats.station), verticalalignment='center_baseline', horizontalalignment='left', fontsize=10, color='white', transform=plot_transform, zorder=scatter_zorder, path_effects=[ pe.Stroke(linewidth=2, foreground='black'), pe.Normal() ], clip_on=True) ax.legend(h, [handle.get_label() for handle in h], loc='best', framealpha=1, borderpad=.3, handletextpad=.3) time_round = np.datetime64(slice.time.values + np.timedelta64(500, 'ms'), 's').astype(datetime) # Nearest second title = 'Time: {}'.format(time_round) if hasattr(S, 'celerity'): title += f'\nCelerity: {S.celerity:g} m/s' # Label global maximum if applicable if slice.time.values == time_max: title = 'GLOBAL MAXIMUM\n\n' + title ax.set_title(title, pad=20) # Show x- and y-axes w/ same scale if this is a Cartesian plot if S.UTM: ax.set_aspect('equal') # Crop plot to show just the slice area if xy_grid: ax.set_xlim(-xy_grid, xy_grid) ax.set_ylim(-xy_grid, xy_grid) ax_pos = ax.get_position() cloc = [ax_pos.x1 + .02, ax_pos.y0, .02, ax_pos.height] cbaxes = fig.add_axes(cloc) cbar = fig.colorbar(sm, cax=cbaxes, label='Stack amplitude') cbar.solids.set_alpha(1) if plot_peak: plot_stack_peak(S, plot_max=True, ax=ax1) fig.show() return fig
modes = ('mean', 'mean_flip', 'pca_flip') tcs = dict() for mode in modes: tcs[mode] = stc.extract_label_time_course(label, src, mode=mode) print("Number of vertices : %d" % len(stc_label.data)) # %% # View source activations # ----------------------- fig, ax = plt.subplots(1) t = 1e3 * stc_label.times ax.plot(t, stc_label.data.T, 'k', linewidth=0.5, alpha=0.5) pe = [ path_effects.Stroke(linewidth=5, foreground='w', alpha=0.5), path_effects.Normal() ] for mode, tc in tcs.items(): ax.plot(t, tc[0], linewidth=3, label=str(mode), path_effects=pe) xlim = t[[0, -1]] ylim = [-27, 22] ax.legend(loc='upper right') ax.set(xlabel='Time (ms)', ylabel='Source amplitude', title='Activations in Label %r' % (label.name), xlim=xlim, ylim=ylim) mne.viz.tight_layout() # %% # Using vector solutions
def draw_outline(patch: patches.Patch, lw: int) -> None: stroke = patheffects.Stroke(linewidth=lw, foreground='black') normal = patheffects.Normal() patch.set_path_effects([stroke, normal])
def draw_total_precipitation(prep, map_extent=(107., 112, 23.2, 26.5), back_image='terrain-background', back_image_zoom=8, title="降水量实况图", draw_station=True, station_info='cities', station_size=22, just_contourf=False): """ 该程序用于显示多日的累积降水量分布特征, 2020/6/7按业务要求制作. Args: ax (matplotlib.axes.Axes): the `Axes` instance used for plotting. prep (dictionary): precipitation, dictionary: {'lon': 1D array, 'lat': 1D array, 'data': 2D array} map_extent (tuple, optional): (lonmin, lonmax, latmin, latmax),. Defaults to (107., 112, 23.2, 26.5). back_image (str, opional): the background image name. Default is stamen 'terrain-background', else is arcgis map server 'World_Physical_Map' (max zoom level is 8) back_image_zoom (int, optional): the zoom level for background image. Defaults to 8. draw_station (bool, optional): draw station name. Defaults to True. station_info (str, optional): station information, 'cities' is 260 city names, or province captial shows. station_size (int, optional): station font size. Defaults to 22. title (str, optional): title string. Defaults to "降水量实况图". Example: import pandas as pd from nmc_met_graphics.plot.precipitation import draw_total_precipitation from nmc_met_io.retrieve_micaps_server import get_model_grids # read data times = pd.date_range(start = pd.to_datetime('2020-06-02 08:00'), end = pd.to_datetime('2020-06-07 08:00'), freq='1H') dataset = get_model_grids("CLDAS/RAIN01_TRI_DATA_SOURCE", times.strftime("%y%m%d%H.000")) data = dataset.sum(dim="time") data['data'].values[data['data'].values > 2400.0] = np.nan prep = {'lon': data['lon'].values, 'lat': data['lat'].values, 'data': data['data'].values} # draw the figure draw_total_precipitation(prep); """ # set figure size fig = plt.figure(figsize=(16, 14.5)) # set map projection datacrs = ccrs.PlateCarree() mapcrs = ccrs.LambertConformal(central_longitude=np.mean(map_extent[0:1]), central_latitude=np.mean(map_extent[2:3]), standard_parallels=(30, 60)) ax = plt.axes((0.1, 0.08, 0.85, 0.92), projection=mapcrs) ax.set_extent(map_extent, crs=datacrs) # add map background add_china_map_2cartopy(ax, name='province', edgecolor='k', lw=1) add_china_map_2cartopy(ax, name='river', edgecolor='cyan', lw=1) if back_image == 'terrain-background': stamen_terrain = cimg.Stamen('terrain-background') ax.add_image(stamen_terrain, back_image_zoom) else: image = cimg.GoogleTiles( url= "https://server.arcgisonline.com/arcgis/rest/services/World_Physical_Map/MapServer/tile/{z}/{y}/{x}.jpg" ) ax.add_image(image, back_image_zoom) # set colors and levels clevs = [50, 100, 200, 300, 400, 500, 600] colors = [ '#6ab4f1', '#0001f6', '#f405ee', '#ffa900', '#fc6408', '#e80000', '#9a0001' ] linewidths = [1, 1, 2, 2, 3, 4, 4] cmap, norm = mpl.colors.from_levels_and_colors(clevs, colors, extend='max') # draw precipitation contour map x, y = np.meshgrid(prep['lon'], prep['lat']) if just_contourf: _ = ax.contourf(x, y, np.squeeze(prep['data']), clevs, norm=norm, cmap=cmap, transform=datacrs, extend='max', alpha=0.5) else: _ = ax.contourf(x, y, np.squeeze(prep['data']), clevs, norm=norm, cmap=cmap, transform=datacrs, extend='max', alpha=0.1) con2 = ax.contour(x, y, np.squeeze(prep['data']), clevs, norm=norm, cmap=cmap, transform=datacrs, linewidths=linewidths) # add path effects plt.setp(con2.collections, path_effects=[ path_effects.SimpleLineShadow(), path_effects.Normal() ]) # add title and legend font = FontProperties(family='Microsoft YaHei', size=32) ax.set_title('降水量实况图(累计降水: 6月02日—6月06日)', loc='center', fontproperties=font) font = FontProperties(family='Microsoft YaHei', size=16) plt.legend([mpatches.Patch(color=b) for b in colors], [ '50~100 毫米', '100~200 毫米', '200-300 毫米', '300~400 毫米', '400~500 毫米', '500~600 毫米', '>=600毫米' ], prop=font) # add city information if draw_station: if station_info == 'cities': cities = pd.read_csv(pkg_resources.resource_filename( 'nmc_met_graphics', "resources/stations/cma_city_station_info.dat"), delimiter=r"\s+") else: cities = pd.read_csv( pkg_resources.resource_filename( 'nmc_met_graphics', "resources/stations/provincial_capital.csv")) font = FontProperties(family='SimHei', size=22, weight='bold') geodetic_transform = ccrs.Geodetic()._as_mpl_transform(ax) for _, row in cities.iterrows(): text_transform = offset_copy(geodetic_transform, units='dots', x=-5) ax.plot(row['lon'], row['lat'], marker='o', color='white', markersize=8, alpha=0.7, transform=datacrs) ax.text(row['lon'], row['lat'], row['city_name'], clip_on=True, verticalalignment='center', horizontalalignment='right', transform=text_transform, fontproperties=font, color='white', path_effects=[ path_effects.Stroke(linewidth=1, foreground='black'), path_effects.Normal() ]) return fig
def single_plot(robot, p, fig, link_plot, joint_plot, eff_plot, cfg_path_plots=None, path_history=None, save_dir=None, ax=None): from copy import copy from matplotlib.lines import Line2D points_traj = robot.fkine(p) points_traj = torch.cat([torch.zeros(len(p), 1, 2), points_traj], dim=1) traj_alpha = 0.3 ends_alpha = 0.5 lw = link_plot.get_lw() link_traj = [ ax.plot(points[:, 0], points[:, 1], color='gray', alpha=traj_alpha, lw=lw, solid_capstyle='round')[0] for points in points_traj ] joint_traj = [ ax.plot(points[:-1, 0], points[:-1, 1], 'o', color='tab:red', alpha=traj_alpha, markersize=lw)[0] for points in points_traj ] eff_traj = [ ax.plot(points[-1:, 0], points[-1:, 1], 'o', color='black', alpha=traj_alpha, markersize=lw)[0] for points in points_traj ] # for link_plot, joint_plot, eff_plot, points in zip(link_traj, joint_traj, eff_traj, points_traj): # link_plot.set_data(points[:, 0], points[:, 1]) # joint_plot.set_data(points[:-1, 0], points[:-1, 1]) # eff_plot.set_data(points[-1:, 0], points[-1:, 1]) for i in [0, -1]: link_traj[i].set_alpha(ends_alpha) link_traj[i].set_path_effects( [path_effects.SimpleLineShadow(), path_effects.Normal()]) joint_traj[i].set_alpha(ends_alpha) eff_traj[i].set_alpha(ends_alpha) link_traj[0].set_color('green') link_traj[-1].set_color('orange') # ax.add_artist(link_traj[2]) # def divide(p): # divide the path into several segments that obeys the wrapping around rule [TODO] # diff = torch.abs(p[:-1]-p[1:]) # div_idx = torch.where(diff.max(1) > np.pi) # div_idx = torch.cat([-1, div_idx]) # segments = [] # for i in range(len(div_idx)-1): # segments.append(p[div_idx[i]+1:div_idx[i+1]+1]) # segments.append(p[div_idx[-1]+1:]) # for i in range(len(segments)-1): # if torch.sum(torch.abs(segments[i]) > np.pi) == 2: offset = torch.FloatTensor([[0, 0], [0, 1], [-1, 1], [-1, 0]]) * np.pi * 2 for i, cfg_path in enumerate(cfg_path_plots): cfg_path.set_data(p[:, 0] + offset[i % 4, 0], p[:, 1] + offset[i % 4, 1])
def create_plots(robot, obstacles, dist_est, checker): from matplotlib.cm import get_cmap cmaps = [get_cmap('Reds'), get_cmap('Blues')] if robot.dof > 2: fig = plt.figure(figsize=(3, 3)) ax = fig.add_subplot(111) #, projection='3d' elif robot.dof == 2: # Show C-space at the same time num_class = getattr(checker, 'num_class', 1) fig = plt.figure(figsize=(3 * (num_class), 3 * (num_class + 1))) plt.rcParams.update({ "text.usetex": True, "font.family": "sans-serif", "font.sans-serif": ["Helvetica"] }) gs = fig.add_gridspec(num_class + 1, num_class) ax = fig.add_subplot( gs[:-1, :] ) #sum([list(range(r*(num_class+1)+1, (r+1)*(num_class+1))) for r in range(num_class)], [])) #, projection='3d' cfg_path_plots = [] size = [400, 400] yy, xx = torch.meshgrid(torch.linspace(-np.pi, np.pi, size[0]), torch.linspace(-np.pi, np.pi, size[1])) grid_points = torch.stack([xx, yy], dim=2).reshape((-1, 2)) grid_points = grid_points.double( ) if checker.support_points.dtype == torch.float64 else grid_points score_spline = dist_est(grid_points).reshape(size + [num_class]) c_axes = [] with sns.axes_style('ticks'): for cat in range(num_class): c_ax = fig.add_subplot(gs[-1, cat]) # score_DiffCo = checker.score(grid_points).reshape(size) # score = (torch.sign(score_DiffCo)+1)/2*(score_spline-score_spline.min()) + (-torch.sign(score_DiffCo)+1)/2*(score_spline-score_spline.max()) score = score_spline[:, :, cat] color_mesh = c_ax.pcolormesh(xx, yy, score, cmap=cmaps[cat], vmin=-torch.abs(score).max(), vmax=torch.abs(score).max()) c_support_points = checker.support_points[ checker.gains[:, cat] != 0] c_ax.scatter(c_support_points[:, 0], c_support_points[:, 1], marker='.', c='black', s=1.5) c_ax.contour( xx, yy, score, levels=[0], linewidths=1, alpha=0.4, ) #-1.5, -0.75, 0, 0.3 # fig.colorbar(color_mesh, ax=c_ax) # sparse_score = score[5:-5:10, 5:-5:10] # score_grad_x = -ndimage.sobel(sparse_score.numpy(), axis=1) # score_grad_y = -ndimage.sobel(sparse_score.numpy(), axis=0) # score_grad = np.stack([score_grad_x, score_grad_y], axis=2) # score_grad /= np.linalg.norm(score_grad, axis=2, keepdims=True) # score_grad_x, score_grad_y = score_grad[:, :, 0], score_grad[:, :, 1] # c_ax.quiver(xx[5:-5:10, 5:-5:10], yy[5:-5:10, 5:-5:10], score_grad_x, score_grad_y, color='red', width=2e-3, headwidth=2, headlength=5) # cfg_point = Circle(collision_cfgs[0], radius=0.05, facecolor='orange', edgecolor='black', path_effects=[path_effects.withSimplePatchShadow()]) # c_ax.add_patch(cfg_point) for _ in range(4): cfg_path, = c_ax.plot([], [], '-o', c='olivedrab', markersize=3) cfg_path_plots.append(cfg_path) c_ax.set_aspect('equal', adjustable='box') # c_ax.axis('equal') c_ax.set_xlim(-np.pi, np.pi) c_ax.set_ylim(-np.pi, np.pi) c_ax.set_xticks([-np.pi, 0, np.pi]) c_ax.set_xticklabels(['$-\pi$', '$0$', '$\pi$']) c_ax.set_yticks([-np.pi, 0, np.pi]) c_ax.set_yticklabels(['$-\pi$', '$0$', '$\pi$']) # c_ax.tick_params(direction='in', reset=True) # c_ax.tick_params(which='both', direction='out', length=6, width=2, colors='r', # grid_color='r', grid_alpha=0.5) # c_ax.set_ticks('') # Plot ostacles # ax.axis('tight') ax.set_xlim(-8, 8) ax.set_ylim(-8, 8) ax.set_aspect('equal', adjustable='box') ax.set_xticks([-4, 0, 4]) ax.set_yticks([-4, 0, 4]) for obs in obstacles: cat = obs[3] if len(obs) >= 4 else 1 if obs[0] == 'circle': ax.add_patch( Circle(obs[1], obs[2], path_effects=[path_effects.withSimplePatchShadow()], color=cmaps[cat](0.5))) elif obs[0] == 'rect': ax.add_patch( Rectangle((obs[1][0] - float(obs[2][0]) / 2, obs[1][1] - float(obs[2][1]) / 2), obs[2][0], obs[2][1], path_effects=[path_effects.withSimplePatchShadow()], color=cmaps[cat](0.5))) # print((obs[1][0]-obs[2][0]/2, obs[1][1]-obs[2][1]/2)) # Placeholder of the robot plot trans = ax.transData.transform lw = ((trans((1, robot.link_width)) - trans( (0, 0))) * 72 / ax.figure.dpi)[1] link_plot, = ax.plot( [], [], color='silver', alpha=0.1, lw=lw, solid_capstyle='round', path_effects=[path_effects.SimpleLineShadow(), path_effects.Normal()]) joint_plot, = ax.plot([], [], 'o', color='tab:red', markersize=lw) eff_plot, = ax.plot([], [], 'o', color='black', markersize=lw) if robot.dof > 2: return fig, ax, link_plot, joint_plot, eff_plot elif robot.dof == 2: return fig, ax, link_plot, joint_plot, eff_plot, cfg_path_plots
def plot_calma_data(self, loudnessValues, features, duration, type, **kwargs): """ Takes CALMA data for a single track as input, and creates a plot. Parameters ---------- loudnessValues : float[] An array of loudness / amplitude values. features : float[] Features information. duration : float The duration of the track. """ # Replace colour map if needed if type == 'segment': self.colourMap = self.get_segment_colour_map(features) if type == 'key': self.colourMap = self.get_colour_map() # Hide placeholder text if visible try: self.placeHolderText.remove() text = self.fig.text(0.5, 0.65, kwargs['title'], horizontalalignment='center', verticalalignment='center', fontsize=16) text.set_path_effects([ path_effects.Stroke(linewidth=2, foreground='white'), path_effects.Normal() ]) except (KeyError, ValueError) as v: self.placeHolderText.set_text('') # Perform pre-processing nploudnessValues, duration, xSpaced, average = self.pre_processing( loudnessValues, duration) # Plot waveform self.canvasGraph.axes.cla() self.canvasGraph.plot(xSpaced, nploudnessValues) for index, key in enumerate(features): # Calculate graph positions lx, ly, rec = self.calculate_graph_element_position( features, key, index, duration, average) # Add annotation to plot self.canvasGraph.annotate(key[1], (lx, ly), weight='bold', color='Black', fontsize=7, ha='center', va='center', rotation=270) self.ax.add_artist(rec) # Set axes labels self.ax.set_yticklabels([]) self.ax.set_xlabel("Time (seconds)") # Add colour legend for keys keysAsSet = list(set([x[1] for x in features])) patches = [] for k in keysAsSet: # Plot rectangle for key changes try: fc = self.colourMap[k] except KeyError as keyerr: fc = 'grey' patch = mpatch.Patch(color=fc, label=k) patches.append(patch) self.canvasGraph.legend(handles=patches, bbox_to_anchor=(1.00, 1), loc=2, borderaxespad=0, fontsize=7, ncol=2) self.fig.subplots_adjust(left=0.00, right=0.85, top=0.95) try: kwargs['release'] except KeyError as v: # Causes crash with multiple plots self.finishDraw() self.fig.patch.set_alpha(1.0) return
def plot_storm_nrl(self, forecast, track=None, image_path=os.getcwd(), track_labels='fhr', cone_days=5, domain="dynamic_forecast", ax=None, return_ax=False, prop={}, map_prop={}): r""" Creates a plot of the operational NRL forecast track along with observed track data. Parameters ---------- forecast : dict Dict entry containing forecast data. track : dict Dict entry containing observed track data. Default is none. track_labels : str Label forecast hours with the following methods: '' = no label 'fhr' = forecast hour 'valid_utc' = UTC valid time 'valid_edt' = EDT valid time cone_days : int Number of days to plot the forecast cone. Default is 5 days. Can select 2, 3, 4 or 5 days. domain : str Domain for the plot. Can be one of the following: "dynamic_forecast" - default. Dynamically focuses the domain on the forecast track. "dynamic" - Dynamically focuses the domain on the combined observed and forecast track. "lonW/lonE/latS/latN" - Custom plot domain ax : axes Instance of axes to plot on. If none, one will be generated. Default is none. return_ax : bool Whether to return axis at the end of the function. If false, plot will be displayed on the screen. Default is false. prop : dict Property of storm track lines. map_prop : dict Property of cartopy map. """ #Determine if forecast is realtime realtime_flag = True if forecast['advisory_num'] == -1 else False #Set default properties default_prop = { 'dots': True, 'fillcolor': 'category', 'linecolor': 'k', 'category_colors': 'default', 'linewidth': 1.0, 'ms': 7.5, 'cone_lw': 1.0, 'cone_alpha': 0.6 } default_map_prop = { 'res': 'm', 'land_color': '#FBF5EA', 'ocean_color': '#EDFBFF', 'linewidth': 0.5, 'linecolor': 'k', 'figsize': (14, 9), 'dpi': 200 } #Initialize plot prop = self.add_prop(prop, default_prop) map_prop = self.add_prop(map_prop, default_map_prop) self.plot_init(ax, map_prop) #-------------------------------------------------------------------------------------- #Keep record of lat/lon coordinate extrema max_lat = None min_lat = None max_lon = None min_lon = None #Add storm or multiple storms if track != "": #Check for storm type, then get data for storm if isinstance(track, dict) == True: storm_data = track else: raise RuntimeError("Error: track must be of type dict.") #Retrieve storm data lats = storm_data['lat'] lons = storm_data['lon'] vmax = storm_data['vmax'] styp = storm_data['type'] sdate = storm_data['date'] #Check if there's enough data points to plot matching_times = [i for i in sdate if i <= forecast['init']] check_length = len(matching_times) if check_length >= 2: #Subset until time of forecast matching_times = [i for i in sdate if i <= forecast['init']] plot_idx = sdate.index(matching_times[-1]) + 1 lats = storm_data['lat'][:plot_idx] lons = storm_data['lon'][:plot_idx] vmax = storm_data['vmax'][:plot_idx] styp = storm_data['type'][:plot_idx] sdate = storm_data['date'][:plot_idx] #Account for cases crossing dateline if self.proj.proj4_params['lon_0'] == 180.0: new_lons = np.array(lons) new_lons[new_lons < 0] = new_lons[new_lons < 0] + 360.0 lons = new_lons.tolist() #Connect to 1st forecast location fcst_hr = np.array(forecast['fhr']) start_slice = 0 if 3 in fcst_hr: start_slice = 3 if realtime_flag == True: start_slice = int(fcst_hr[1]) iter_hr = np.array(forecast['fhr'])[fcst_hr >= start_slice][0] fcst_lon = np.array(forecast['lon'])[fcst_hr >= start_slice][0] fcst_lat = np.array(forecast['lat'])[fcst_hr >= start_slice][0] fcst_type = np.array( forecast['type'])[fcst_hr >= start_slice][0] fcst_vmax = np.array( forecast['vmax'])[fcst_hr >= start_slice][0] if fcst_type == "": fcst_type = get_storm_type(fcst_vmax, False) if self.proj.proj4_params['lon_0'] == 180.0: if fcst_lon < 0: fcst_lon = fcst_lon + 360.0 lons.append(fcst_lon) lats.append(fcst_lat) vmax.append(fcst_vmax) styp.append(fcst_type) sdate.append(sdate[-1] + timedelta(hours=start_slice)) #Add to coordinate extrema if domain != "dynamic_forecast": if max_lat == None: max_lat = max(lats) else: if max(lats) > max_lat: max_lat = max(lats) if min_lat == None: min_lat = min(lats) else: if min(lats) < min_lat: min_lat = min(lats) if max_lon == None: max_lon = max(lons) else: if max(lons) > max_lon: max_lon = max(lons) if min_lon == None: min_lon = min(lons) else: if min(lons) < min_lon: min_lon = min(lons) else: max_lat = lats[-1] + 0.2 min_lat = lats[-2] - 0.2 max_lon = lons[-1] + 0.2 min_lon = lons[-2] - 0.2 #Plot storm line as specified if prop['linecolor'] == 'category': type6 = np.array(styp) for i in (np.arange(len(lats[1:])) + 1): ltype = 'solid' if type6[i] not in ['SS', 'SD', 'TD', 'TS', 'HU']: ltype = 'dotted' self.ax.plot( [lons[i - 1], lons[i]], [lats[i - 1], lats[i]], '-', color=get_colors_sshws(np.nan_to_num(vmax[i])), linewidth=prop['linewidth'], linestyle=ltype, transform=ccrs.PlateCarree(), path_effects=[ path_effects.Stroke( linewidth=prop['linewidth'] * 1.25, foreground='k'), path_effects.Normal() ]) else: self.ax.plot(lons, lats, '-', color=prop['linecolor'], linewidth=prop['linewidth'], transform=ccrs.PlateCarree()) #Plot storm dots as specified if prop['dots'] == True: #filter dots to only 6 hour intervals time_hr = np.array([i.strftime('%H%M') for i in sdate]) #time_idx = np.where((time_hr == '0300') | (time_hr == '0900') | (time_hr == '1500') | (time_hr == '2100')) lat6 = np.array(lats) #[time_idx] lon6 = np.array(lons) #[time_idx] vmax6 = np.array(vmax) #[time_idx] type6 = np.array(styp) #[time_idx] for i, (ilon, ilat, iwnd, itype) in enumerate(zip(lon6, lat6, vmax6, type6)): mtype = '^' if itype in ['SD', 'SS']: mtype = 's' elif itype in ['TD', 'TS', 'HU']: mtype = 'o' if prop['fillcolor'] == 'category': ncol = get_colors_sshws(np.nan_to_num(iwnd)) else: ncol = 'k' self.ax.plot(ilon, ilat, mtype, color=ncol, mec='k', mew=0.5, ms=prop['ms'], transform=ccrs.PlateCarree()) #-------------------------------------------------------------------------------------- #Error check cone days if isinstance(cone_days, int) == False: raise TypeError("Error: cone_days must be of type int") if cone_days not in [5, 4, 3, 2]: raise ValueError( "Error: cone_days must be an int between 2 and 5.") #Error check forecast dict if isinstance(forecast, dict) == False: raise RuntimeError("Error: Forecast must be of type dict") #Determine first forecast index fcst_hr = np.array(forecast['fhr']) start_slice = 0 if 3 in fcst_hr: start_slice = 3 if realtime_flag == True: start_slice = int(fcst_hr[1]) check_duration = fcst_hr[(fcst_hr >= start_slice) & (fcst_hr <= cone_days * 24)] #Check for sufficiently many hours if len(check_duration) > 1: #Generate forecast cone for forecast data dateline = False if self.proj.proj4_params['lon_0'] == 180.0: dateline = True cone = self.generate_nrl_cone(forecast, dateline, cone_days) #Contour fill cone & account for dateline crossing if 'cone' in forecast.keys() and forecast['cone'] == False: pass else: cone_lon = cone['lon'] cone_lat = cone['lat'] cone_lon_2d = cone['lon2d'] cone_lat_2d = cone['lat2d'] if self.proj.proj4_params['lon_0'] == 180.0: new_lons = np.array(cone_lon_2d) new_lons[new_lons < 0] = new_lons[new_lons < 0] + 360.0 cone_lon_2d = new_lons.tolist() new_lons = np.array(cone_lon) new_lons[new_lons < 0] = new_lons[new_lons < 0] + 360.0 cone_lon = new_lons.tolist() cone_2d = cone['cone'] cone_2d = ndimage.gaussian_filter(cone_2d, sigma=0.5, order=0) self.ax.contourf(cone_lon_2d, cone_lat_2d, cone_2d, [0.9, 1.1], colors=['#ffffff', '#ffffff'], alpha=prop['cone_alpha'], zorder=2, transform=ccrs.PlateCarree()) self.ax.contour(cone_lon_2d, cone_lat_2d, cone_2d, [0.9], linewidths=prop['cone_lw'], colors=['k'], zorder=3, transform=ccrs.PlateCarree()) #Plot center line & account for dateline crossing center_lon = cone['center_lon'] center_lat = cone['center_lat'] if self.proj.proj4_params['lon_0'] == 180.0: new_lons = np.array(center_lon) new_lons[new_lons < 0] = new_lons[new_lons < 0] + 360.0 center_lon = new_lons.tolist() self.ax.plot(center_lon, center_lat, color='k', linewidth=2.0, zorder=4, transform=ccrs.PlateCarree()) #Retrieve forecast dots iter_hr = np.array(forecast['fhr'])[(fcst_hr >= start_slice) & (fcst_hr <= cone_days * 24)] fcst_lon = np.array(forecast['lon'])[(fcst_hr >= start_slice) & (fcst_hr <= cone_days * 24)] fcst_lat = np.array(forecast['lat'])[(fcst_hr >= start_slice) & (fcst_hr <= cone_days * 24)] fcst_type = np.array( forecast['type'])[(fcst_hr >= start_slice) & (fcst_hr <= cone_days * 24)] fcst_vmax = np.array( forecast['vmax'])[(fcst_hr >= start_slice) & (fcst_hr <= cone_days * 24)] #Account for cases crossing dateline if self.proj.proj4_params['lon_0'] == 180.0: new_lons = np.array(fcst_lon) new_lons[new_lons < 0] = new_lons[new_lons < 0] + 360.0 fcst_lon = new_lons.tolist() #Plot forecast dots for i, (ilon, ilat, itype, iwnd, ihr) in enumerate( zip(fcst_lon, fcst_lat, fcst_type, fcst_vmax, iter_hr)): mtype = '^' if itype in ['SD', 'SS']: mtype = 's' elif itype in ['TD', 'TS', 'HU', '']: mtype = 'o' if prop['fillcolor'] == 'category': ncol = get_colors_sshws(np.nan_to_num(iwnd)) else: ncol = 'k' #Marker width mew = 0.5 use_zorder = 5 if i == 0: mew = 2.0 use_zorder = 10 self.ax.plot(ilon, ilat, mtype, color=ncol, mec='k', mew=mew, ms=prop['ms'] * 1.3, transform=ccrs.PlateCarree(), zorder=use_zorder) #Label forecast dots if track_labels in [ 'fhr', 'valid_utc', 'valid_edt', 'fhr_wind_kt', 'fhr_wind_mph' ]: valid_dates = [ forecast['init'] + timedelta(hours=int(i)) for i in iter_hr ] if track_labels == 'fhr': labels = [str(i) for i in iter_hr] if track_labels == 'fhr_wind_kt': labels = [ f"Hour {iter_hr[i]}\n{fcst_vmax[i]} kt" for i in range(len(iter_hr)) ] if track_labels == 'fhr_wind_mph': labels = [ f"Hour {iter_hr[i]}\n{knots_to_mph(fcst_vmax[i])} mph" for i in range(len(iter_hr)) ] if track_labels == 'valid_edt': labels = [ str(int(i.strftime('%I'))) + ' ' + i.strftime('%p %a') for i in [j - timedelta(hours=4) for j in valid_dates] ] edt_warning = True if track_labels == 'valid_utc': labels = [ f"{i.strftime('%H UTC')}\n{str(i.month)}/{str(i.day)}" for i in valid_dates ] self.plot_nhc_labels(self.ax, fcst_lon, fcst_lat, labels, k=1.2) #Add cone coordinates to coordinate extrema if 'cone' in forecast.keys() and forecast['cone'] == False: if domain == "dynamic_forecast" or max_lat == None: max_lat = max(center_lat) min_lat = min(center_lat) max_lon = max(center_lon) min_lon = min(center_lon) else: if max(center_lat) > max_lat: max_lat = max(center_lat) if min(center_lat) < min_lat: min_lat = min(center_lat) if max(center_lon) > max_lon: max_lon = max(center_lon) if min(center_lon) < min_lon: min_lon = min(center_lon) else: if domain == "dynamic_forecast" or max_lat == None: max_lat = max(cone_lat) min_lat = min(cone_lat) max_lon = max(cone_lon) min_lon = min(cone_lon) else: if max(cone_lat) > max_lat: max_lat = max(cone_lat) if min(cone_lat) < min_lat: min_lat = min(cone_lat) if max(cone_lon) > max_lon: max_lon = max(cone_lon) if min(cone_lon) < min_lon: min_lon = min(cone_lon) #-------------------------------------------------------------------------------------- #Storm-centered plot domain if domain == "dynamic" or domain == 'dynamic_forecast': bound_w, bound_e, bound_s, bound_n = self.dynamic_map_extent( min_lon, max_lon, min_lat, max_lat) self.ax.set_extent([bound_w, bound_e, bound_s, bound_n], crs=ccrs.PlateCarree()) #Pre-generated or custom domain else: bound_w, bound_e, bound_s, bound_n = self.set_projection(domain) #Plot parallels and meridians #This is currently not supported for all cartopy projections. try: self.plot_lat_lon_lines([bound_w, bound_e, bound_s, bound_n]) except: pass #-------------------------------------------------------------------------------------- #Identify storm type (subtropical, hurricane, etc) first_fcst_wind = np.array(forecast['vmax'])[fcst_hr >= start_slice][0] first_fcst_mslp = np.array(forecast['mslp'])[fcst_hr >= start_slice][0] first_fcst_type = np.array(forecast['type'])[fcst_hr >= start_slice][0] if all_nan(first_fcst_wind) == True: storm_type = 'Unknown' else: subtrop = True if first_fcst_type in ['SD', 'SS'] else False cur_wind = first_fcst_wind + 0 storm_type = get_storm_classification(np.nan_to_num(cur_wind), subtrop, 'north_atlantic') #Identify storm name (and storm type, if post-tropical or potential TC) matching_times = [ i for i in storm_data['date'] if i <= forecast['init'] ] if check_length < 2: if all_nan(first_fcst_wind) == True: storm_name = storm_data['name'] else: storm_name = num_to_text(int(storm_data['id'][2:4])).upper() if first_fcst_wind >= 34 and first_fcst_type in [ 'TD', 'SD', 'SS', 'TS', 'HU' ]: storm_name = storm_data['name'] if first_fcst_type not in ['TD', 'SD', 'SS', 'TS', 'HU']: storm_type = 'Storm' else: storm_name = num_to_text(int(storm_data['id'][2:4])).upper() storm_type = 'Storm' storm_tropical = False if all_nan(vmax) == True: storm_type = 'Unknown' storm_name = storm_data['name'] else: for i, (iwnd, ityp) in enumerate(zip(vmax, styp)): if ityp in ['SD', 'SS', 'TD', 'TS', 'HU']: storm_tropical = True subtrop = True if ityp in ['SD', 'SS'] else False storm_type = get_storm_classification( np.nan_to_num(iwnd), subtrop, 'north_atlantic') if np.isnan(iwnd) == True: storm_type = 'Unknown' else: if storm_tropical == True: storm_type = 'Post Tropical Cyclone' if ityp in ['SS', 'TS', 'HU']: storm_name = storm_data['name'] #Fix storm types for non-NHC basins if 'cone' in forecast.keys(): storm_type = get_storm_classification(first_fcst_wind, False, forecast['basin']) #Add left title self.ax.set_title(f"{storm_type} {storm_name}", loc='left', fontsize=17, fontweight='bold') endash = u"\u2013" dot = u"\u2022" #Get current advisory information first_fcst_wind = "N/A" if np.isnan(first_fcst_wind) == True else int( first_fcst_wind) first_fcst_mslp = "N/A" if np.isnan(first_fcst_mslp) == True else int( first_fcst_mslp) #Get time of advisory fcst_hr = forecast['fhr'] start_slice = 0 if 3 in fcst_hr: start_slice = 1 if realtime_flag == True: start_slice = 1 forecast_date = (forecast['init'] + timedelta( hours=fcst_hr[start_slice])).strftime("%H%M UTC %d %b %Y") forecast_id = forecast['advisory_num'] #Get wind value to display if first_fcst_wind == "N/A": wind_display_value = "N/A" else: wind_display_value = knots_to_mph(first_fcst_wind) if forecast_id == -1: title_text = f"Current Intensity: {wind_display_value} mph {dot} {first_fcst_mslp} hPa" if 'cone' in forecast.keys() and forecast['cone'] == False: title_text += f"\nJTWC Issued: {forecast_date}" else: title_text += f"\nNHC Issued: {forecast_date}" else: title_text = f"Current Intensity: {wind_display_value} mph {dot} {first_fcst_mslp} hPa" title_text += f"\nForecast Issued: {forecast_date}" #Add right title self.ax.set_title(title_text, loc='right', fontsize=13) #-------------------------------------------------------------------------------------- #Add legend if prop['fillcolor'] == 'category' or prop['linecolor'] == 'category': ex = mlines.Line2D([], [], linestyle='None', ms=prop['ms'], mec='k', mew=0.5, label='Non-Tropical', marker='^', color='w') sb = mlines.Line2D([], [], linestyle='None', ms=prop['ms'], mec='k', mew=0.5, label='Subtropical', marker='s', color='w') uk = mlines.Line2D([], [], linestyle='None', ms=prop['ms'], mec='k', mew=0.5, label='Unknown', marker='o', color='w') td = mlines.Line2D([], [], linestyle='None', ms=prop['ms'], mec='k', mew=0.5, label='Tropical Depression', marker='o', color=get_colors_sshws(33)) ts = mlines.Line2D([], [], linestyle='None', ms=prop['ms'], mec='k', mew=0.5, label='Tropical Storm', marker='o', color=get_colors_sshws(34)) c1 = mlines.Line2D([], [], linestyle='None', ms=prop['ms'], mec='k', mew=0.5, label='Category 1', marker='o', color=get_colors_sshws(64)) c2 = mlines.Line2D([], [], linestyle='None', ms=prop['ms'], mec='k', mew=0.5, label='Category 2', marker='o', color=get_colors_sshws(83)) c3 = mlines.Line2D([], [], linestyle='None', ms=prop['ms'], mec='k', mew=0.5, label='Category 3', marker='o', color=get_colors_sshws(96)) c4 = mlines.Line2D([], [], linestyle='None', ms=prop['ms'], mec='k', mew=0.5, label='Category 4', marker='o', color=get_colors_sshws(113)) c5 = mlines.Line2D([], [], linestyle='None', ms=prop['ms'], mec='k', mew=0.5, label='Category 5', marker='o', color=get_colors_sshws(137)) self.ax.legend(handles=[ex, sb, uk, td, ts, c1, c2, c3, c4, c5], prop={'size': 11.5}) #Add forecast label warning try: if edt_warning == True: warning_text = "All times displayed are in EDT\n\n" else: warning_text = "" except: warning_text = "" try: warning_text += f"The cone of uncertainty in this product was generated internally\nusing {cone['year']} derived NRL cone radii.\n\n" except: pass self.ax.text(0.99, 0.01, warning_text, fontsize=9, color='k', alpha=0.7, transform=self.ax.transAxes, ha='right', va='bottom', zorder=10) credit_text = self.plot_credit() self.add_credit(credit_text) #Return axis if specified, otherwise display figure if ax != None or return_ax == True: return self.ax else: plt.savefig( f"{image_path}/{track['id']}_{forecast_date.replace(' ','')}") plt.close()
hts = np.array([extract(m, "Elevation") for m in mountains]) # Histogram plot of mountain heights. with plt.xkcd(): # Cueball: "Why?" Black hat: "Why not?" plt.hist(hts, 20, facecolor='cyan', alpha=0.75) plt.figure(1) print("Histogram of the heights of named mountains.") plt.xlabel("Mountain height") plt.ylabel("Mountain count") plt.show(1) # Ordinary data plot of mountain heights. plt.figure(2) pef = [path_effects.SimpleLineShadow(), path_effects.Normal()] plt.plot(np.sort(hts), '--', path_effects=pef) print("Heights of the mountains of the world.") plt.show(2) with open('countries.json', encoding="utf-8") as data_file: countries = json.load(data_file) pops = np.array([extract(c, "Population") for c in countries]) gdp = np.array([extract(c, "GDP") for c in countries]) gdppc = gdp / pops pops_log = np.log(pops) / np.log(10) # Scatter plot of population against GDP per person. plt.figure(3)
def _draw_outline(o, lw: int): "Outline bounding box onto image `Patch`." o.set_path_effects([ patheffects.Stroke(linewidth=lw, foreground='black'), patheffects.Normal() ])
def stremline_plot(adata, genes, x=0, y=1, method='sparseVFC', basis='trimap', n_columns=1, color=None, label_on_embedding=True, cmap=None, s_kwargs_dict={}, layer='X', xy_grid_nums=[30, 30], density=1, g_kwargs_dict={}, V_threshold=1e-5, figsize=None, show_quiver=True, **streamline_kwargs): """Plot the streamline of vector field based on the sampled cells. Parameters ---------- adata: :class:`~anndata.AnnData` an Annodata object. genes: `list` The gene names whose gene expression will be faceted. x: `int` (default: `0`) The column index of the low dimensional embedding for the x-axis y: `int` (default: `1`) The column index of the low dimensional embedding for the y-axis method: `str` (default: `SparseVFC`) Method to reconstruct the vector field. Currently it supports either SparseVFC (default) or the empirical method Gaussian kernel method from RNA velocity (Gaussian). basis: `str` (default: `trimap`) The reduced dimension embedding of cells to visualize. n_columns: `int (default: 1) The number of columns of the resulting plot. color: `list` or None (default: None) A list of attributes of cells (column names in the adata.obs) will be used to color cells. cmap: `plt.cm` or None (default: None) The color map function to use. s_kwargs_dict: `dict` (default: {}) The dictionary of the scatter arguments. layer: `str` (default: X) Which layer of expression value will be used. xy_grid_nums: `tuple` (default: (5, 5)) the number of grids in either x or y axis. density: `float` or None (default: 1) density of the plt.streamplot function. q_kwargs_dict: `dict` (default: {}) A dictionary of the parameters for the plt.quiver function. V_threshold: `None` or `float` The threshold of velocity value for visualization figsize: `None` or `[float, float]` (default: None) The width and height of a figure. show_quiver: `bool` (default: True) Whether also show the quiver plot in additional to the streamline plot. **streamline_kwargs: Additional parameters that will be passed to plt.streamplot function Returns ------- Nothing but a cell wise quiver plot """ import matplotlib.pyplot as plt import matplotlib.patheffects as PathEffects streamplot_kwargs={"density": density, "linewidth": None, "color": None, "cmap": None, "norm": None, "arrowsize": 1, "arrowstyle": '-|>', "minlength": 0.1, "transform": None, "zorder": None, "start_points": None, "maxlength": 4.0, "integration_direction": 'both'} streamplot_kwargs.update(streamline_kwargs) if cmap is None and color is None: cmap = plt.cm.RdBu_r n_cells, n_genes = adata.shape[0], len(genes) # {"alpha": 0.5, "s": 8, "edgecolor": "0.8", "lw": 0.15} scatter_kwargs = dict(alpha=0.4, s=8, edgecolor=None, linewidth=0) if s_kwargs_dict is not None: scatter_kwargs.update(s_kwargs_dict) if layer is 'X': E_vec = adata[:, adata.var.index.isin(genes)].X.T elif layer in adata.layers.keys(): E_vec = adata[:, adata.var.index.isin(genes)].layers[layer].T elif layer is 'protein': # update subset here E_vec = adata[:, adata.var.index.isin(genes)].obsm[layer].T else: raise Exception(f'The {layer} you passed in is not existed in the adata object.') if color is not None: color = list(set(color).intersection(adata.obs.keys())) n_genes, genes = len(color), color E_vec = adata.obs[color].values.T.flatten() if len(color) > 0 else np.empty((0, 1)) if ('X_' + basis in adata.obsm.keys()) and ('velocity_' + basis in adata.obsm.keys()): X = adata.obsm['X_' + basis][:, [x, y]] V = adata.obsm['velocity_' + basis][:, [x, y]] else: if 'X_' + basis not in adata.obsm.keys(): reduceDimension(adata, velocity_key='velocity_S', reduction_method=basis) if 'kmc' not in adata.uns_keys(): cell_velocities(adata, vkey='pca', basis=basis, method='analytical') X = adata.obsm['X_' + basis][:, [x, y]] V = adata.obsm['velocity_' + basis][:, [x, y]] else: kmc = adata.uns['kmc'] X = adata.obsm['X_' + basis][:, [x, y]] V = kmc.compute_density_corrected_drift(X, kmc.Idx, normalize_vector=True) adata.obsm['velocity_' + basis] = V if 0 in E_vec.shape: raise Exception(f'The gene names {genes} (or cell annotations {color}) provided are not existed in your data.') if method is 'SparseVFC' and adata.obsm['X_' + basis].shape[1] == 2: if 'VecFld_' + basis not in adata.uns.keys(): VectorField(adata, basis=basis) X_grid, V_grid = adata.uns['VecFld_' + basis]['grid'], adata.uns['VecFld_' + basis]['grid_V'] N = int(np.sqrt(V_grid.shape[0])) X_grid, V_grid = np.array([np.unique(X_grid[:, 0]), np.unique(X_grid[:, 1])]), \ np.array([V_grid[:, 0].reshape((N, N)), V_grid[:, 1].reshape((N, N))]) elif 'grid_velocity_' + basis in adata.uns.keys(): X_grid, V_grid, _ = adata.uns['grid_velocity_' + basis]['X_grid'], adata.uns['grid_velocity_' + basis]['V_grid'], \ adata.uns['grid_velocity_' + basis]['D'] else: grid_kwargs_dict = {"density": None, "smooth": None, "n_neighbors": None, "min_mass": None, "autoscale": False, "adjust_for_stream": True, "V_threshold": None} grid_kwargs_dict.update(g_kwargs_dict) X_grid, V_grid, D = velocity_on_grid(X[:, [x, y]], V[:, [x, y]], xy_grid_nums, **grid_kwargs_dict) # if quiver_scale is None: # quiver_scale = quiver_autoscaler(X_grid, V_grid) # quiver_kwargs = {"angles": 'xy', "scale_units": 'xy', 'scale': quiver_scale, "minlength": 1.5} # quiver_kwargs.update(q_kwargs) n_columns, plot_per_gene = n_columns, 1 # we may also add random velocity results nrow, ncol = int(np.ceil(plot_per_gene * n_genes / n_columns)), n_columns if figsize is None: plt.figure(None, (3*ncol, 3*nrow), dpi=160) # else: plt.figure(None, (figsize[0]*ncol, figsize[1]*nrow)) # , dpi=160 E_vec = E_vec.A.flatten() if issparse(E_vec) else E_vec.flatten() V = V.A[:, [x, y]] if issparse(V) else V[:, [x, y]] # iterate over cell first then a different dimension/gene/column df = pd.DataFrame({"x": np.tile(X[:, 0], n_genes), "y": np.tile(X[:, 1], n_genes), "u": np.tile(V[:, 0], n_genes), "v": np.tile(V[:, 1], n_genes), 'gene': np.repeat(np.array(genes), n_cells), "expression": E_vec}, index=range(n_cells * n_genes)) # the following code is inspired by https://github.com/velocyto-team/velocyto-notebooks/blob/master/python/DentateGyrus.ipynb gs = plt.GridSpec(nrow, ncol) for i, gn in enumerate(genes): ax = plt.subplot(gs[i*plot_per_gene]) try: ix=np.where(adata.var.index == gn)[0][0] except: ix = gn in adata.obs.columns if not ix: continue cur_pd = df.loc[df.gene == gn, :] E_vec = cur_pd.loc[:, 'expression'] if color is None: limit = np.max(np.abs(np.percentile(E_vec, [1, 99]))) # upper and lowe limit / saturation E_vec = E_vec + limit # that is: tmp_colorandum - (-limit) E_vec = E_vec / (2 * limit) # that is: tmp_colorandum / (limit - (-limit)) E_vec = np.clip(E_vec, 0, 1) ax.scatter(cur_pd.iloc[:, 0], cur_pd.iloc[:, 1], c=cmap(E_vec), **scatter_kwargs) else: import seaborn as sns # List of RGB triplets color_labels = E_vec.unique() rgb_values = sns.color_palette("Set2", len(color_labels)) # Map label to RGB color_map = pd.DataFrame(zip(color_labels, rgb_values), index=color_labels) ax.scatter(cur_pd.iloc[:, 0], cur_pd.iloc[:, 1], c=color_map.loc[E_vec, 1].values, **scatter_kwargs) if label_on_embedding: for i in color_labels: color_cnt = np.median(cur_pd.iloc[np.where(E_vec == i)[0], :2], 0) txt=ax.text(color_cnt[0], color_cnt[1], str(i), fontsize=13) # , bbox={"facecolor": "w", "alpha": 0.6} txt.set_path_effects([ PathEffects.Stroke(linewidth=5, foreground="w", alpha=0.1), PathEffects.Normal()]) if show_quiver: ax.quiver(X_grid[0], X_grid[1], V_grid[0], V_grid[1], color = 'gray', alpha = 0.7) # , **quiver_kwargs mass = np.sqrt((V_grid ** 2).sum(0)) if V_threshold is not None: if V_threshold is not None: V_grid[0][mass.reshape(V_grid[0].shape) < V_threshold] = np.nan streamplot_kwargs.update({"linewidth": 4 * mass / mass[~np.isnan(mass)].max()}) ax.streamplot(X_grid[0], X_grid[1], V_grid[0], V_grid[1], **streamplot_kwargs) ax.axis("off") plt.show()
def add_mslp_label(ax, proj_ccrs, mslp, lat, lon): """ Add mslp low and high label Args: ax (matplotlib.axes.Axes): the `Axes` instance used for plotting. proj_ccrs (cartopy projection): cartopy projection object. mslp (np.array): numpy array. lat (np.array): latitude lon (np.array): longitdue """ #Label MSLP extrema def _extrema(mat, mode='wrap', window=50): mn = minimum_filter(mat, size=window, mode=mode) mx = maximum_filter(mat, size=window, mode=mode) return np.nonzero(mat == mn), np.nonzero(mat == mx) #Determine an appropriate window given the lat/lon grid resolution res = lat[1] - lat[0] nwindow = int(9.5 / res) mslp = np.ma.masked_invalid(mslp) local_min, local_max = _extrema(mslp, mode='wrap', window=nwindow) #Determine axis boundaries xmin, xmax, ymin, ymax = ax.get_extent() lons2d, lats2d = np.meshgrid(lon, lat) transformed = proj_ccrs.transform_points(proj_ccrs, lons2d, lats2d) x = transformed[..., 0] y = transformed[..., 1] #Get location of extrema on grid xlows = x[local_min]; xhighs = x[local_max] ylows = y[local_min]; yhighs = y[local_max] lowvals = mslp[local_min]; highvals = mslp[local_max] yoffset = 0.022*(ymax-ymin) dmin = yoffset #Plot low pressures xyplotted = [] for x,y,p in zip(xlows, ylows, lowvals): if x < xmax-yoffset and x > xmin+yoffset and y < ymax-yoffset and y > ymin+yoffset: dist = [np.sqrt((x-x0)**2+(y-y0)**2) for x0,y0 in xyplotted] if not dist or min(dist) > dmin: #,fontweight='bold' a = ax.text(x,y,'L',fontsize=28, ha='center',va='center',color='r',fontweight='normal') b = ax.text(x,y-yoffset,repr(int(p)),fontsize=14, ha='center',va='top',color='r',fontweight='normal') a.set_path_effects([mpatheffects.Stroke(linewidth=1.5, foreground='black'), mpatheffects.SimpleLineShadow(),mpatheffects.Normal()]) b.set_path_effects([mpatheffects.Stroke(linewidth=1.0, foreground='black'), mpatheffects.SimpleLineShadow(),mpatheffects.Normal()]) xyplotted.append((x,y)) #Plot high pressures xyplotted = [] for x,y,p in zip(xhighs, yhighs, highvals): if x < xmax-yoffset and x > xmin+yoffset and y < ymax-yoffset and y > ymin+yoffset: dist = [np.sqrt((x-x0)**2+(y-y0)**2) for x0,y0 in xyplotted] if not dist or min(dist) > dmin: a = ax.text(x,y,'H',fontsize=28, ha='center',va='center',color='b',fontweight='normal') b = ax.text(x,y-yoffset,repr(int(p)),fontsize=14, ha='center',va='top',color='b',fontweight='normal') a.set_path_effects([mpatheffects.Stroke(linewidth=1.5, foreground='black'), mpatheffects.SimpleLineShadow(),mpatheffects.Normal()]) b.set_path_effects([mpatheffects.Stroke(linewidth=1.0, foreground='black'), mpatheffects.SimpleLineShadow(),mpatheffects.Normal()]) xyplotted.append((x,y))
def plot_fixed_points( vecfld, marker="o", markersize=200, cmap=None, filltype=["full", "top", "none"], background=None, save_show_or_return='return', save_kwargs={}, ax=None, ): """Plot fixed points stored in the VectorField2D class. Arguments --------- vecfld: :class:`~VectorField2D` An instance of the VectorField2D class which presumably has fixed points computed and stored. marker: `str` (default: `o`) The marker type. Any string supported by matplotlib.markers. markersize: `float` (default: 200) The size of the marker. cmap: string (optional, default 'Blues') The name of a matplotlib colormap to use for coloring or shading the confidence of fixed points. If None, the default color map will set to be viridis (inferno) when the background is white (black). filltype: list The fill type used for stable, saddle, and unstable fixed points. Default is 'full', 'top' and 'none', respectively. background: `str` or None (default: None) The background color of the plot. save_show_or_return: {'show', 'save', 'return'} (default: `return`) Whether to save, show or return the figure. save_kwargs: `dict` (default: `{}`) A dictionary that will passed to the save_fig function. By default it is an empty dictionary and the save_fig function will use the {"path": None, "prefix": 'plot_fixed_points', "dpi": None, "ext": 'pdf', "transparent": True, "close": True, "verbose": True} as its parameters. Otherwise you can provide a dictionary that properly modify those keys according to your needs. ax: :class:`~matplotlib.axes.Axes` The matplotlib axes used for plotting. Default is to use the current axis. """ import matplotlib from matplotlib import rcParams, markers import matplotlib.patheffects as PathEffects from matplotlib.colors import to_hex if background is None: _background = rcParams.get("figure.facecolor") _background = to_hex( _background) if type(_background) is tuple else _background else: _background = background if _background in ["#ffffff", "black"]: _theme_ = ("inferno") else: _theme_ = ("viridis") _cmap = _themes[_theme_]["cmap"] if cmap is None else cmap Xss, ftype = vecfld.get_fixed_points(get_types=True) confidence = vecfld.get_Xss_confidence() if ax is None: ax = plt.gca() cm = matplotlib.cm.get_cmap(_cmap) if type(_cmap) is str else _cmap for i in range(len(Xss)): cur_ftype = ftype[i] marker_ = markers.MarkerStyle(marker=marker, fillstyle=filltype[int(cur_ftype + 1)]) ax.scatter(*Xss[i], marker=marker_, s=markersize, c=np.array(cm(confidence[i])).reshape(1, -1), edgecolor=_select_font_color(_background), linewidths=1, cmap=_cmap, vmin=0, zorder=5) txt = ax.text( *Xss[i], repr(i), c=('black' if cur_ftype == -1 else 'blue' if cur_ftype == 0 else 'red'), horizontalalignment='center', verticalalignment='center', zorder=6, weight='bold', ) txt.set_path_effects([ PathEffects.Stroke(linewidth=1.5, foreground=_background, alpha=0.8), PathEffects.Normal(), ]) if save_show_or_return == "save": s_kwargs = { "path": None, "prefix": 'plot_fixed_points', "dpi": None, "ext": 'pdf', "transparent": True, "close": True, "verbose": True } s_kwargs = update_dict(s_kwargs, save_kwargs) save_fig(**s_kwargs) elif save_show_or_return == "show": plt.tight_layout() plt.show() elif save_show_or_return == "return": return ax
async def ingame_(self, ctx, *, username): ds_type = utils.DSType(ctx.invoked_with.lower()) dsobj = await ds_type.fetch(ctx, username, name=True) queries = [] for num in range(29): table = f"{ds_type.table}{num or ''}" base = f'SELECT * FROM {table} WHERE ' \ f'{table}.world = $1 AND {table}.id = $2' queries.append(base) query = " UNION ALL ".join(queries) async with self.bot.pool.acquire() as conn: records = await conn.fetch(query, ctx.server, dsobj.id) data = [ds_type.Class(rec) for rec in records] data.reverse() rows = [ f"**{dsobj.name}** | {ctx.world.show(clean=True)} {ctx.world.icon}" ] urls = [] for url_type in ["ingame", "guest", "twstats"]: url = getattr(dsobj, f"{url_type}_url") urls.append(f"[{url_type.capitalize()}]({url})") rows.append(" | ".join(urls)) points = f"**Punkte:** `{utils.seperator(dsobj.points)}` | **Rang:** `{dsobj.rank}`" if hasattr(dsobj, 'tribe_id'): tribe = await self.bot.fetch_tribe(ctx.server, dsobj.tribe_id) desc = tribe.mention if tribe else "None" villages = f"**Stamm:** {desc}" else: villages = f"**Mitglieder:** `{dsobj.member}`" villages += f" | **Dörfer:** `{utils.seperator(dsobj.villages)}`" rows.extend(["", points, villages, "", "**Besiegte Gegner:**"]) bash_rows = OrderedDict() for index, stat in enumerate( ['all_bash', 'att_bash', 'def_bash', 'sup_bash']): if index == 3 and isinstance(dsobj, utils.Tribe): value = await dsobj.fetch_supbash(ctx) rank_value = None else: value = getattr(dsobj, stat) rank_stat = f"{stat.split('_')[0]}_rank" rank_value = getattr(dsobj, rank_stat) stat_title = self.bot.msg['statTitle'][stat] represent = f"{stat_title}: `{sep(value)}`" if rank_value: represent += f" | Rang: `{rank_value}`" bash_rows[represent] = value clean = sorted(bash_rows.items(), key=lambda l: l[1], reverse=True) rows.extend([line[0] for line in clean]) profile = discord.Embed(description="\n".join(rows)) profile.colour = discord.Color.blue() image_url = await self.fetch_profile_picture(dsobj) if image_url is not None: profile.set_thumbnail(url=image_url) filled = [0] * (29 - len(data)) + [d.points for d in data] plot_data = pd.DataFrame({'x_coord': range(29), 'y_coord': filled}) config = { 'color': '#3498db', 'linewidth': 5, 'path_effects': [patheffects.SimpleLineShadow(linewidth=8), patheffects.Normal()] } figure = self.create_figure() if not data: plt.ylim(top=50, bottom=-3) figure.plot('x_coord', 'y_coord', data=plot_data, **config) figure.grid(axis='y', zorder=1, alpha=0.3) buf = io.BytesIO() plt.savefig(buf, format='png', dpi=100, transparent=True) buf.seek(0) plt.close() file = discord.File(buf, "example.png") profile.set_image(url="attachment://example.png") await ctx.send(embed=profile, file=file)
def plot_predictions(eval_data_dict, model_registrar, robot_node, hyperparams, device, dt, max_speed, color_dict=None, num_samples=100, data_id=2, t_predict=56, radius_of_influence=3.0, node_circle_size=0.3, focus_on=None, focus_window_height=6, line_alpha=0.7, line_width=0.2, edge_width=2, circle_edge_width=0.5, only_predict=None, dpi=300, fig_height=4, ylim=(0, 50), xlim=(0, 100), figsize=None, tick_fontsize=13, xlabel='$x$ position (m)', ylabel='$y$ position (m)', custom_xticks=None, custom_yticks=None, legend_loc=None, return_frame=False, return_fig=False, printing=False, robot_circle=True, robot_shift_future=0.0, robot_shift='x', add_legend=True, title=None, flip_axes=False, omit_names=False, axes_labels=True, rotate_axes_text=0, save_at=None): from model.dyn_stg import SpatioTemporalGraphCVAEModel from utils.scene_utils import create_batch_scene_graph if color_dict is None: # This changes colors per run. color_dict = defaultdict(dict) if dt is None: raise ValueError( 'You must supply a time delta, the argument dt cannot be None!') if figsize is None: aspect_ratio = float(xlim[1] - xlim[0]) / (ylim[1] - ylim[0]) figsize = (fig_height * aspect_ratio, fig_height) max_time = eval_data_dict['input_dict'][robot_node][data_id, :].shape[0] predict_horizon = hyperparams['prediction_horizon'] if t_predict < hyperparams['minimum_history_length']: raise ValueError('ERROR: t_predict must be >= %d' % hyperparams['minimum_history_length']) elif t_predict + predict_horizon >= max_time: raise ValueError('ERROR: t_predict must be <= %d' % (max_time - predict_horizon - 1)) ################### ### Predictions ### ################### tic = timeit.default_timer() tic0 = timeit.default_timer() hyperparams['state_dim'] = eval_data_dict['input_dict'][robot_node].shape[ 2] hyperparams['pred_dim'] = len(eval_data_dict['pred_indices']) hyperparams['pred_indices'] = eval_data_dict['pred_indices'] hyperparams['nodes_standardization'] = eval_data_dict[ "nodes_standardization"] hyperparams["labels_standardization"] = eval_data_dict[ "labels_standardization"] kwargs_dict = { 'dynamic_edges': hyperparams['dynamic_edges'], 'edge_state_combine_method': hyperparams['edge_state_combine_method'], 'edge_influence_combine_method': hyperparams['edge_influence_combine_method'] } # Create the aggregate scene_graph for all the data, allowing # for batching, just like the old one. Then, for speed tests # we'll show how much faster this method is than keeping the # full version. Can show graphs of forward inference time vs problem size # with two lines (using aggregate graph, using online-computed graph). input_dict = { k: v[[data_id]] for k, v in eval_data_dict['input_dict'].items() } label_dict = {k: v[[data_id]] for k, v in eval_data_dict['labels'].items()} robot_future = eval_data_dict['input_dict'][robot_node][[data_id], t_predict + 1:t_predict + predict_horizon + 1] if robot_shift_future != 0.0: idx = 4 if robot_shift == 'x' else 5 print('Shifting %s by %.2f!' % (robot_shift, robot_shift_future)) robot_future[..., idx] += robot_shift_future robot_future[..., idx - 2] = cumtrapz( robot_future[..., idx], axis=1, initial=0, dx=dt) + robot_future[0, 0, idx - 2] robot_future[..., idx - 4] = cumtrapz( robot_future[..., idx - 2], axis=1, initial=0, dx=dt) + robot_future[0, 0, idx - 4] with torch.no_grad(): test_stg = SpatioTemporalGraphCVAEModel(robot_node, model_registrar, hyperparams, kwargs_dict, None, device) test_agg_scene_graph = create_batch_scene_graph( input_dict, float(hyperparams['edge_radius']), use_old_method=(hyperparams['dynamic_edges'] == 'no')) if hyperparams['dynamic_edges'] == 'yes': test_agg_scene_graph.compute_edge_scaling( hyperparams['edge_addition_filter'], hyperparams['edge_removal_filter']) test_stg.set_scene_graph(test_agg_scene_graph) test_inputs = { k: torch.from_numpy(v).float() for k, v in input_dict.items() if v.size > 0 } test_labels = { k: torch.from_numpy(v).float() for k, v in label_dict.items() } test_inputs[str(robot_node) + "_future"] = torch.from_numpy(robot_future).float() test_inputs['traj_lengths'] = torch.tensor([t_predict]) if hyperparams['dynamic_edges'] == 'yes': test_inputs['edge_scaling_mask'] = torch.from_numpy( test_agg_scene_graph.edge_scaling_mask).float() toc0 = timeit.default_timer() if printing: print("constructing feed_dict took: ", toc0 - tic0, " (s), running pytorch!") tic0 = timeit.default_timer() outputs = test_stg.predict(test_inputs, hyperparams['prediction_horizon'], num_samples) toc0 = timeit.default_timer() outputs = {k: v.cpu().numpy() for k, v in outputs.items()} if printing: print("done running pytorch!, took (s): ", toc0 - tic0) toc = timeit.default_timer() if printing: print("total time taken (s): ", toc - tic) ######################## ### Data Preparation ### ######################## prefixes_dict = dict() futures_dict = dict() nodes = test_agg_scene_graph.nodes prefix_earliest_idx = max(0, t_predict - predict_horizon) for node in nodes: if robot_node == node: continue node_data = input_dict[node] if printing: print('node', node) print('node_data.shape', node_data.shape) prefixes_dict[node] = node_data[[0], prefix_earliest_idx:t_predict + 1, 0:2] futures_dict[node] = node_data[[0], t_predict + 1:t_predict + predict_horizon + 1] if printing: print('node', node) print('prefixes_dict[node].shape', prefixes_dict[node].shape) print('futures_dict[node].shape', futures_dict[node].shape) # 44.72 km/h = 40.76 ft/s (ie. that's the max value that a coordinate can be) output_pos = dict() sampled_zs = dict() for node in nodes: if robot_node == node: continue key = str(node) + '/y' z_key = str(node) + '/z' output_pos[node] = integrate_trajectory(outputs[key], [0, 1], futures_dict[node][0, 0], [0, 1], dt, output_limit=max_speed, velocity_in=True) sampled_zs[node] = outputs[z_key] if printing: print('prefixes_dict[node].shape', prefixes_dict[node].shape) print('futures_dict[node].shape', futures_dict[node].shape) print('output_pos[node].shape', output_pos[node].shape) print('sampled_zs[node].shape', sampled_zs[node].shape) ###################### ### Visualizations ### ###################### fig, ax = plt.subplots(figsize=figsize) not_added_prefix = True not_added_future = True not_added_samples = True for node_name in prefixes_dict: if focus_on is not None and node_name != focus_on: continue prefix = prefixes_dict[node_name][0] future = futures_dict[node_name][0] predictions = output_pos[node_name][:, 0] z_values = sampled_zs[node_name][:, 0] prefix_all_zeros = not np.any(prefix) future_all_zeros = not np.any(future) if prefix_all_zeros and future_all_zeros: continue if not (xlim[0] <= prefix[-1, 0] <= xlim[1]) or not (ylim[0] <= prefix[-1, 1] <= ylim[1]): continue if np.any([prefix[-1, 0], prefix[-1, 1]]): # Prefix trails prefix_start_idx = first_nonzero(np.sum(prefix, axis=1), axis=0, invalid_val=-1) if not_added_prefix: ax.plot(prefix[prefix_start_idx:, 0], prefix[prefix_start_idx:, 1], 'k--', label='History') not_added_prefix = False else: ax.plot(prefix[prefix_start_idx:, 0], prefix[prefix_start_idx:, 1], 'k--') # Predicted trails if only_predict is None or (only_predict is not None and node_name == only_predict): if not_added_samples: # plt.plot([] , [], 'r', label='Sampled Futures') not_added_samples = False for sample_num in range(output_pos[node_name].shape[0]): z_value = tuple(z_values[sample_num]) if z_value not in color_dict[node_name]: color_dict[node_name][ z_value] = "#%06x" % random.randint(0, 0xFFFFFF) ax.plot(predictions[sample_num, :, 0], predictions[sample_num, :, 1], color=color_dict[node_name][z_value], linewidth=line_width, alpha=line_alpha) # Future trails future_start_idx = first_nonzero(np.sum(future, axis=1), axis=0, invalid_val=-1) future_end_idx = future.shape[0] - first_nonzero( np.sum(future, axis=1)[::-1], axis=0, invalid_val=-1) if not_added_future: ax.plot(future[future_start_idx:future_end_idx, 0], future[future_start_idx:future_end_idx, 1], 'w--', path_effects=[ pe.Stroke(linewidth=edge_width, foreground='k'), pe.Normal() ], label='Actual Future') not_added_future = False else: ax.plot(future[future_start_idx:future_end_idx, 0], future[future_start_idx:future_end_idx, 1], 'w--', path_effects=[ pe.Stroke(linewidth=edge_width, foreground='k'), pe.Normal() ]) # Current Node Position circle = plt.Circle( (prefix[-1, 0], prefix[-1, 1]), node_circle_size, facecolor='b' if 'Home' in node_name.type else 'g', edgecolor='k', lw=circle_edge_width, zorder=3) ax.add_artist(circle) # if focus_on: # ax.set_title(node_name) # else: # ax.text(prefix[-1, 0] + 0.4, prefix[-1, 1], node_name, zorder=4) if not omit_names: ax.text(prefix[-1, 0] + 0.4, prefix[-1, 1], node_name, zorder=4) # Robot Node if focus_on is None: prefix_earliest_idx = max(0, t_predict - predict_horizon) robot_prefix = eval_data_dict['input_dict'][robot_node][ data_id, prefix_earliest_idx:t_predict + 1, 0:2] prefix_start_idx = first_nonzero(np.sum(robot_prefix, axis=1), axis=0, invalid_val=-1) # robot_future = eval_data_dict[robot_node][data_id, t_predict + 1 : t_predict + predict_horizon + 1, 0:2] robot_future = robot_future[0, :, 0:2].copy() prefix_all_zeros = not np.any(robot_prefix) future_all_zeros = not np.any(robot_future) if not (prefix_all_zeros and future_all_zeros) and ( (xlim[0] <= robot_prefix[-1, 0] <= xlim[1]) and (ylim[0] <= robot_prefix[-1, 1] <= ylim[1])): ax.plot(robot_prefix[prefix_start_idx:, 0], robot_prefix[prefix_start_idx:, 1], 'k--') ax.plot(robot_future[:, 0], robot_future[:, 1], 'w--', path_effects=[ pe.Stroke(linewidth=edge_width, foreground='k'), pe.Normal() ]) circle = plt.Circle( (robot_prefix[-1, 0], robot_prefix[-1, 1]), node_circle_size, facecolor='b' if 'Home' in robot_node.type else 'g', edgecolor='k', lw=circle_edge_width, zorder=3) ax.add_artist(circle) # Radius of influence if robot_circle: circle = plt.Circle((robot_prefix[-1, 0], robot_prefix[-1, 1]), radius_of_influence, fill=False, color='r', linestyle='--', zorder=3) ax.plot([], [], 'r--', label='Edge Radius') ax.add_artist(circle) if not omit_names: ax.text(robot_prefix[-1, 0] + 0.4, robot_prefix[-1, 1], robot_node, zorder=4) if focus_on is None: ax.set_ylim(ylim) ax.set_xlim(xlim) else: y_radius = focus_window_height x_radius = aspect_ratio * y_radius ax.set_ylim((prefix[-1, 1] - y_radius, prefix[-1, 1] + y_radius)) ax.set_xlim((prefix[-1, 0] - x_radius, prefix[-1, 0] + x_radius)) if add_legend: if legend_loc is not None: leg = ax.legend(loc=legend_loc, handlelength=4) else: leg = ax.legend(loc='best', handlelength=4) for line in leg.get_lines(): line.set_linewidth(2.25) for text in leg.get_texts(): text.set_fontsize(14) if title is not None: ax.set_title(title) if axes_labels: ax.set_xlabel(xlabel, fontsize=tick_fontsize) ax.set_ylabel(ylabel, fontsize=tick_fontsize) if rotate_axes_text != 0: if custom_xticks is not None: plt.xticks(custom_xticks, rotation=rotate_axes_text, fontsize=tick_fontsize) else: plt.xticks(rotation=rotate_axes_text, fontsize=tick_fontsize) if custom_yticks is not None: plt.yticks(custom_yticks, rotation=rotate_axes_text, fontsize=tick_fontsize) else: plt.yticks(rotation=rotate_axes_text, fontsize=tick_fontsize) else: if custom_xticks is not None: plt.xticks(custom_xticks, fontsize=tick_fontsize) else: plt.xticks(fontsize=tick_fontsize) if custom_yticks is not None: plt.yticks(custom_yticks, fontsize=tick_fontsize) else: plt.yticks(fontsize=tick_fontsize) fig.tight_layout() if return_fig: return fig if return_frame: buffer_ = StringIO() plt.savefig(buffer_, format="png", transparent=True, dpi=dpi) buffer_.seek(0) data = np.asarray(Image.open(buffer_)) plt.close(fig) return data if save_at is not None: plt.savefig(save_at, dpi=300, transparent=True) plt.show() plt.close(fig)
def create_figure(self, frameno=0, binning=1, dpi=None, stretch='log', vmin=1, vmax=5000, cmap='gray', data_col='FLUX', annotate=True, time_format='ut', show_flags=False, label=None): """Returns a matplotlib Figure object that visualizes a frame. Parameters ---------- frameno : int Image number in the target pixel file. binning : int Number of frames around `frameno` to co-add. (default: 1). dpi : float, optional [dots per inch] Resolution of the output in dots per Kepler CCD pixel. By default the dpi is chosen such that the image is 440px wide. vmin : float, optional Minimum cut level (default: 1). vmax : float, optional Maximum cut level (default: 5000). cmap : str, optional The matplotlib color map name. The default is 'gray', can also be e.g. 'gist_heat'. raw : boolean, optional If `True`, show the raw pixel counts rather than the calibrated flux. Default: `False`. annotate : boolean, optional Annotate the Figure with a timestamp and target name? (Default: `True`.) show_flags : boolean, optional Show the quality flags? (Default: `False`.) label : str Label text to show in the bottom left corner of the movie. Returns ------- image : array An array of unisgned integers of shape (x, y, 3), representing an RBG colour image x px wide and y px high. """ # Get the flux data to visualize flx = self.flux_binned(frameno=frameno, binning=binning, data_col=data_col) # Determine the figsize and dpi shape = list(flx.shape) shape = [shape[1], shape[0]] if dpi is None: # Twitter timeline requires dimensions between 440x220 and 1024x512 # so we make 440 the default dpi = 440 / float(shape[0]) # libx264 require the height to be divisible by 2, we ensure this here: shape[0] -= ((shape[0] * dpi) % 2) / dpi # Create the figureand display the flux image using matshow fig = pl.figure(figsize=shape, dpi=dpi) # Display the image using matshow ax = fig.add_subplot(1, 1, 1) if self.verbose: print('{} vmin/vmax = {}/{} (median={})'.format( data_col, vmin, vmax, np.nanmedian(flx))) if stretch == 'linear': stretch_fn = visualization.LinearStretch() elif stretch == 'sqrt': stretch_fn = visualization.SqrtStretch() elif stretch == 'power': stretch_fn = visualization.PowerStretch(1.0) elif stretch == 'log': stretch_fn = visualization.LogStretch() elif stretch == 'asinh': stretch_fn = visualization.AsinhStretch(0.1) else: raise ValueError('Unknown stretch: {0}.'.format(stretch)) transform = (stretch_fn + visualization.ManualInterval(vmin=vmin, vmax=vmax)) flx_transform = 255 * transform(flx) # Make sure to remove all NaNs! flx_transform[~np.isfinite(flx_transform)] = 0 ax.imshow(flx_transform.astype(int), aspect='auto', origin='lower', interpolation='nearest', cmap=cmap, norm=NoNorm()) if annotate: # Annotate the frame with a timestamp and target name? fontsize = 3. * shape[0] margin = 0.03 # Print target name in lower left corner if label is None: label = self.objectname txt = ax.text(margin, margin, label, family="monospace", fontsize=fontsize, color='white', transform=ax.transAxes) txt.set_path_effects([ path_effects.Stroke(linewidth=fontsize / 6., foreground='black'), path_effects.Normal() ]) # Print a timestring in the lower right corner txt2 = ax.text(1 - margin, margin, self.timestamp(frameno, time_format=time_format), family="monospace", fontsize=fontsize, color='white', ha='right', transform=ax.transAxes) txt2.set_path_effects([ path_effects.Stroke(linewidth=fontsize / 6., foreground='black'), path_effects.Normal() ]) # Print quality flags in upper right corner if show_flags: flags = self.quality_flags(frameno) if len(flags) > 0: txt3 = ax.text(margin, 1 - margin, '\n'.join(flags), family="monospace", fontsize=fontsize * 1.3, color='white', ha='left', va='top', transform=ax.transAxes, linespacing=1.5, backgroundcolor='red') txt3.set_path_effects([ path_effects.Stroke(linewidth=fontsize / 6., foreground='black'), path_effects.Normal() ]) ax.set_xticks([]) ax.set_yticks([]) ax.axis('off') fig.subplots_adjust(left=0.0, right=1.0, top=1.0, bottom=0.0) fig.canvas.draw() return fig
def plot_predictions_during_training(test_stg, inputs, num_predicted_timesteps, num_samples, dt, max_speed, color_dict=None, data_id=None, t_predict=56, focus_on=None, node_circle_size=0.3, focus_window_height=6, line_alpha=0.7, line_width=0.2, edge_width=2, circle_edge_width=0.5, only_predict=None, dpi=300, fig_height=4, return_frame=False, return_fig=True, printing=False, robot_circle=True, add_legend=True, title=None, flip_axes=False, omit_names=False, axes_labels=True, rotate_axes_text=0, save_at=None): if color_dict is None: # This changes colors per run. color_dict = defaultdict(dict) if dt is None: raise ValueError( 'You must supply a time delta, the argument dt cannot be None!') robot_node = test_stg.robot_node figsize = (5, 5) traj_lengths = inputs['traj_lengths'].cpu().numpy().astype(int) predict_horizon = num_predicted_timesteps if data_id is None: data_id = np.random.choice([ idx for idx, traj_len in enumerate(traj_lengths) if t_predict + predict_horizon < traj_len ]) max_time = inputs[robot_node][data_id, :].shape[0] traj_length = traj_lengths[data_id] if t_predict < test_stg.hyperparams['minimum_history_length']: raise ValueError('ERROR: t_predict must be >= %d' % test_stg.hyperparams['minimum_history_length']) elif t_predict + predict_horizon >= traj_length: raise ValueError('ERROR: t_predict must be <= %d' % (traj_length - predict_horizon - 1)) ################### ### Predictions ### ################### inputs = {k: v[[data_id]] for k, v in inputs.items()} robot_future = inputs[robot_node][[0], t_predict + 1:t_predict + predict_horizon + 1] inputs[str(robot_node) + "_future"] = robot_future inputs['traj_lengths'] = torch.tensor([t_predict]) with torch.no_grad(): tic0 = timeit.default_timer() outputs = test_stg.predict(inputs, num_predicted_timesteps, num_samples) toc0 = timeit.default_timer() outputs = {k: v.cpu().numpy() for k, v in outputs.items()} if printing: print("done running pytorch!, took (s): ", toc0 - tic0) ######################## ### Data Preparation ### ######################## prefixes_dict = dict() futures_dict = dict() nodes = list(test_stg.nodes) prefix_earliest_idx = max(0, t_predict - predict_horizon) for node in nodes: if robot_node == node: continue node_data = inputs[node].cpu().numpy() if printing: print('node', node) print('node_data.shape', node_data.shape) prefixes_dict[node] = node_data[[0], prefix_earliest_idx:t_predict + 1, 0:2] futures_dict[node] = node_data[[0], t_predict + 1:min(t_predict + predict_horizon + 1, traj_length)] if printing: print('node', node) print('prefixes_dict[node].shape', prefixes_dict[node].shape) print('futures_dict[node].shape', futures_dict[node].shape) # 44.72 km/h = 40.76 ft/s (ie. that's the max value that a coordinate can be) output_pos = dict() sampled_zs = dict() for node in nodes: if robot_node == node: continue key = str(node) + '/y' z_key = str(node) + '/z' output_pos[node] = integrate_trajectory(outputs[key], [0, 1], futures_dict[node][0, 0], [0, 1], dt, output_limit=max_speed, velocity_in=True) sampled_zs[node] = outputs[z_key] if printing: print('prefixes_dict[node].shape', prefixes_dict[node].shape) print('futures_dict[node].shape', futures_dict[node].shape) print('output_pos[node].shape', output_pos[node].shape) print('sampled_zs[node].shape', sampled_zs[node].shape) ###################### ### Visualizations ### ###################### fig, ax = plt.subplots(figsize=figsize) not_added_prefix = True not_added_future = True not_added_samples = True for node_name in prefixes_dict: if focus_on is not None and node_name != focus_on: continue prefix = prefixes_dict[node_name][0] future = futures_dict[node_name][0] predictions = output_pos[node_name][:, 0] z_values = sampled_zs[node_name][:, 0] prefix_all_zeros = not np.any(prefix) future_all_zeros = not np.any(future) if prefix_all_zeros and future_all_zeros: continue if np.any([prefix[-1, 0], prefix[-1, 1]]): # Prefix trails prefix_start_idx = first_nonzero(np.sum(prefix, axis=1), axis=0, invalid_val=-1) if not_added_prefix: ax.plot(prefix[prefix_start_idx:, 0], prefix[prefix_start_idx:, 1], 'k--', label='History') not_added_prefix = False else: ax.plot(prefix[prefix_start_idx:, 0], prefix[prefix_start_idx:, 1], 'k--') # Predicted trails if only_predict is None or (only_predict is not None and node_name == only_predict): if not_added_samples: # plt.plot([] , [], 'r', label='Sampled Futures') not_added_samples = False for sample_num in range(output_pos[node_name].shape[0]): z_value = tuple(z_values[sample_num]) if z_value not in color_dict[node_name]: color_dict[node_name][ z_value] = "#%06x" % random.randint(0, 0xFFFFFF) ax.plot(predictions[sample_num, :, 0], predictions[sample_num, :, 1], color=color_dict[node_name][z_value], linewidth=line_width, alpha=line_alpha) # Future trails future_start_idx = first_nonzero(np.sum(future, axis=1), axis=0, invalid_val=-1) future_end_idx = future.shape[0] - first_nonzero( np.sum(future, axis=1)[::-1], axis=0, invalid_val=-1) if not_added_future: ax.plot(future[future_start_idx:future_end_idx, 0], future[future_start_idx:future_end_idx, 1], 'w--', path_effects=[ pe.Stroke(linewidth=edge_width, foreground='k'), pe.Normal() ], label='Actual Future') not_added_future = False else: ax.plot(future[future_start_idx:future_end_idx, 0], future[future_start_idx:future_end_idx, 1], 'w--', path_effects=[ pe.Stroke(linewidth=edge_width, foreground='k'), pe.Normal() ]) # Current Node Position circle = plt.Circle( (prefix[-1, 0], prefix[-1, 1]), node_circle_size, facecolor='b' if 'Home' in node_name.type else 'g', edgecolor='k', lw=circle_edge_width, zorder=3) ax.add_artist(circle) # if focus_on: # ax.set_title(node_name) # else: # ax.text(prefix[-1, 0] + 0.4, prefix[-1, 1], node_name, zorder=4) if not omit_names: ax.text(prefix[-1, 0] + 0.4, prefix[-1, 1], node_name, zorder=4) # Robot Node if focus_on is None: prefix_earliest_idx = max(0, t_predict - predict_horizon) robot_prefix = inputs[robot_node][0, prefix_earliest_idx:t_predict + 1, 0:2].cpu().numpy() robot_future = inputs[robot_node][ 0, t_predict + 1:min(t_predict + predict_horizon + 1, traj_length), 0:2].cpu().numpy() prefix_all_zeros = not np.any(robot_prefix) future_all_zeros = not np.any(robot_future) if not (prefix_all_zeros and future_all_zeros): ax.plot(robot_prefix[:, 0], robot_prefix[:, 1], 'k--') ax.plot(robot_future[:, 0], robot_future[:, 1], 'w--', path_effects=[ pe.Stroke(linewidth=edge_width, foreground='k'), pe.Normal() ]) circle = plt.Circle( (robot_prefix[-1, 0], robot_prefix[-1, 1]), node_circle_size, facecolor='b' if 'Home' in robot_node.type else 'g', edgecolor='k', lw=circle_edge_width, zorder=3) ax.add_artist(circle) # Radius of influence if robot_circle: circle = plt.Circle((robot_prefix[-1, 0], robot_prefix[-1, 1]), test_stg.hyperparams['edge_radius'], fill=False, color='r', linestyle='--', zorder=3) ax.plot([], [], 'r--', label='Edge Radius') ax.add_artist(circle) if not omit_names: ax.text(robot_prefix[-1, 0] + 0.4, robot_prefix[-1, 1], robot_node, zorder=4) if focus_on is not None: y_radius = focus_window_height x_radius = aspect_ratio * y_radius ax.set_ylim((prefix[-1, 1] - y_radius, prefix[-1, 1] + y_radius)) ax.set_xlim((prefix[-1, 0] - x_radius, prefix[-1, 0] + x_radius)) if add_legend: ax.legend(loc='best') if title is not None: ax.set_title(title) string_splitter = ' ' if omit_names: string_splitter = '\n' if axes_labels: ax.set_xlabel('Longitudinal Court Position ($l$)') ax.set_ylabel('Lateral Court%sPosition ($w$)' % string_splitter) if rotate_axes_text != 0: plt.xticks(rotation=rotate_axes_text) plt.yticks(rotation=rotate_axes_text) fig.tight_layout() if return_fig: return fig if return_frame: buffer_ = StringIO() plt.savefig(buffer_, format="png", transparent=True, dpi=dpi) buffer_.seek(0) data = np.asarray(Image.open(buffer_)) plt.close(fig) return data if save_at is not None: plt.savefig(save_at, dpi=300, transparent=True) plt.show() plt.close(fig)
def plot_spectrum_heatmap(self, plot_spec1=True, frange=[], title="Audio Comparison", cmap="plasma", background_color="white", background_alpha=0.5): """ Plots a heatmap and spectrogram showing the relative hot and cool spots of thw two compared AudioAnalyzer class instances. A number of options are available to customize the appearance of the generated plot. """ # DATAFRAME SETUP if plot_spec1: df = self.original_df else: df = self.modified_df df['ratio_amplitude'] = self.ratio_df.scaled_amplitude df['attenuated_scaled'] = df.scaled_amplitude df['boosted_scaled'] = df.scaled_amplitude if len(frange): plot_df = df.loc[(df.bins >= frange[0] / 1000) & (df.bins <= frange[1] / 1000)] ratio_df = self.ratio_df.loc[ (self.ratio_df.bins >= frange[0] / 1000) & (self.ratio_df.bins <= frange[1] / 1000)] else: plot_df = df ratio_df = self.ratio_df # FIGURE SETUP fig = plt.figure(figsize=(20, 10)) ax1 = fig.add_subplot(211, facecolor="white") # ax1 = plt.subplot2grid((8,1), (0,0), rowspan=5, facecolor="white", fig=fig) ax2 = fig.add_subplot(211, facecolor="#00000000") # ax2 = plt.subplot2grid((8,1), (0,0), rowspan=2, facecolor="#00000000", fig=fig) # fig2 = plt.figure(figsize=(32, 8)) # cbaxes = fig2.add_subplot(32,1,1) cbaxes = plt.subplot2grid((16, 1), (10, 0)) cbaxes.set_title("Scaled Amplitude Ratio", size=14) # HEATMAP PLOT sns.heatmap(data=ratio_df.set_index('bins').transpose(), cbar=True, cbar_ax=cbaxes, cbar_kws={"orientation": "horizontal"}, cmap=cmap, alpha=0.95, zorder=1, ax=ax1, vmin=0.0, vmax=1.0) ax1.set_xlabel("") ax1.set_xticks([]) ax1.set_ylabel("") ax1.set_yticks([]) # FREQUENCY PLOT sns.lineplot(data=plot_df, x="bins", y="scaled_amplitude", color='black', zorder=10, ax=ax2, path_effects=[ path_effects.SimpleLineShadow(), path_effects.Normal() ]) ax2.fill_between(x=plot_df.bins, y1=plot_df.scaled_amplitude, color='white', alpha=0.0) ax2.fill_between(x=plot_df.bins, y1=plot_df.scaled_amplitude, y2=1.0, color=background_color, alpha=background_alpha) ax2.set_xlabel("Frequency (kHz)", size=28) ax2.set_ylabel("Scaled Amplitude", size=28) ax2.margins(0) fig.suptitle(title, size=36, y=0.95)
def solar_corr(data, labels, center, ax=False, moon_orbit=0.25, base_circle_size=50, calc_corr=True, orbits=10, show_window=True, image_path="solar.png", save_png=True, title="Solar Correlation Map", selected=[], show_labels=True): labels = np.array(labels) center_idx, center_idx_bool = label_to_idx(labels, center) plot_idx = 23 all_idx = np.logical_not(center_idx_bool) positive = transform_to_positive_corrs( data, center_idx) if calc_corr else transform_to_positive( data, center_idx) corr_dist = transform_to_correlation_dist(data) if calc_corr else data sun_corr_dist = corr_dist[center_idx] colors = np.linspace(0, 1, num=len(sun_corr_dist)) cordinate_to_correlation = {} step = 1.0 / orbits last_orbit = 0.1 fig = plt.gcf() if not ax: fig.set_size_inches(20, 20) labels_idx = np.array([center_idx]) # matplotlib.rcParams.update({'font.size': 14}) all_labels = [] all_circles = [] color_map = plt.get_cmap("Paired") color_map_circle = plt.get_cmap("Greys", 10) color_map_tab10 = plt.get_cmap("tab20") if not ax: ax = fig.add_subplot(111) ax.xaxis.set_visible(False) ax.yaxis.set_visible(False) if not ax: ax.set_position([0.01, 0.01, 0.98, 0.98]) # set a new position # place sun: all_circles.append( ax.scatter(0, 0, color=color_map_circle(7), s=base_circle_size * 2, label=labels[center_idx], zorder=zorder_planet)) # ax.text(0, 0.25, str(labels[center_idx]), verticalalignment="center", horizontalalignment='center', color=color_map_circle(7), zorder=zorder_label) last_orbit_had_values = False min_orbit = 0 for orbit in range(1, orbits + 1): new_orbit = step * orbit + 0.1 idx = (sun_corr_dist >= (1 - last_orbit)) & (sun_corr_dist > (1 - new_orbit)) & all_idx idx_int = np.where(idx)[0] last_orbit = new_orbit if (sum(idx) == 0 and not last_orbit_had_values): min_orbit = orbit continue else: last_orbit_had_values = True orbit = orbit - min_orbit corr_dists = [] for index in idx_int: corr_dists = np.append(corr_dists, corr_dist[center_idx][index]) sort_args = np.argsort(corr_dists) idx_int = idx_int[sort_args] labels_idx = np.append(labels_idx, idx_int) planets = sum(idx) angles = get_angles(orbit, planets, ax, True) print(orbit) print(angles) print("IDX: " + str(sum(idx)) + " current orbit " + str(new_orbit) + " " + "last orbit: " + str(last_orbit)) last_idx = -1 # place planets while np.any(idx): idx_int = np.where(idx)[0] remaining = sum(idx) # current_planet = planets - remaining current_planet = 0 print(current_planet) # breakpoint() current_idx = idx_int[current_planet] angle = angles[planets - remaining] x = get_x(angle, orbit) y = get_y(angle, orbit) # current_idx = idx_int[current_planet] color = colors[current_idx] # plt.scatter(x, y, color=color_map(color), s=100, label=labels[current_idx]) cordinate_to_correlation[(x, y)] = { "is_planet": True, "corr_sun": corr_dist[center_idx, current_idx] } planet_idx = current_idx planet_corr = corr_dist[planet_idx] # ax.text(x-0.35, y+0.2, "{0:.3f}".format(planet_corr[center_idx])) col = "#03C03C" if positive[planet_idx] else "#FF6961" if orbit == orbits: col = "grey" # ax.text(x + 0.15, y + 0.15, str(labels[planet_idx]), verticalalignment="bottom", horizontalalignment='left', # color=col, fontsize='small') moon_idx = (planet_corr >= 0.65) & idx moon_idx_int = np.where(moon_idx)[0] moons = sum(moon_idx) moon_angles = get_angles(0, moons, ax, False) # add orbit around planet if it has moons if moons > 1: circle = plt.Circle((x, y), moon_orbit, color='lightgrey', alpha=0.8, fill=True, zorder=zorder_moonorbit) ax.add_artist(circle) all_circles.append(circle) else: pointcol = color_map_tab10( 2) if labels[planet_idx] in selected else color_map_tab10( 0) labelcol = color_map_tab10( 2) if labels[planet_idx] in selected else color_map_tab10( 0) idx[planet_idx] = False all_idx[planet_idx] = False all_circles.append( ax.scatter(x, y, color=pointcol, s=base_circle_size, label=labels[current_idx], zorder=zorder_planet)) # all_labels.append(ax.text(x + 0.15 if x > 0 else x - 0.15, y + 0.15 if y > 0 else y - 0.15, str(labels[planet_idx]), verticalalignment="center", horizontalalignment='right' if x < 0 else 'left', # color=col, fontsize='small')) if show_labels: all_labels.append( ax.text(x, y, str(labels[planet_idx]), verticalalignment="center", horizontalalignment='right', color=labelcol, zorder=zorder_label, path_effects=[ path_effects.Stroke(linewidth=3, foreground='white'), path_effects.Normal() ])) continue if (current_idx != last_idx): print(labels[planet_idx]) print("Drawing Moons " + str(current_idx) + " moons " + str(sum(moon_idx))) last_idx = current_idx while np.any(moon_idx): remaining_moons = sum(moon_idx) current_moon = moons - remaining_moons current_moon_idx = moon_idx_int[current_moon] angle = moon_angles[current_moon] m_x = get_x(angle, moon_orbit) + x m_y = get_y(angle, moon_orbit) + y pointcol = color_map_tab10(2) if labels[ current_moon_idx] in selected else color_map_tab10(0) labelcol = color_map_tab10( 2) if labels[planet_idx] in selected else color_map_tab10( 0) all_circles.append( ax.scatter(m_x, m_y, color=pointcol, s=base_circle_size, label=labels[current_moon_idx], zorder=zorder_planet)) cordinate_to_correlation[(m_x, m_y)] = { "is_planet": False, "corr_sun": corr_dist[center_idx][current_moon_idx] } col = "#03C03C" if positive[current_moon_idx] else "#FF6961" if orbit == orbits: col = "grey" #all_labels.append(ax.text(m_x + 0.1 if m_x > x else m_x - 0.1, m_y + 0.1 if m_y > y else m_y - 0.1, str(labels[current_moon_idx]), verticalalignment="center", # horizontalalignment='right' if m_x < x else 'left', fontsize='small', color=col)) if show_labels: all_labels.append( ax.text( m_x, m_y, str(labels[current_moon_idx]), verticalalignment="center", horizontalalignment='right' if m_x < x else 'left', color=labelcol, zorder=zorder_label, path_effects=[ path_effects.Stroke(linewidth=3, foreground='white'), path_effects.Normal() ])) moon_idx[current_moon_idx] = False idx[current_moon_idx] = False all_idx[current_moon_idx] = False # last_orbit = new_orbit print("Drawing circle") circlecol = color_map_circle((1 - ((orbit - 1) * step)) / 2) circle = plt.Circle((0, 0), orbit, color=circlecol, fill=False, zorder=zorder_orbit) ax.add_artist(circle) if 1 - float(orbit + min_orbit) / 10 > 0: orbit_t = ax.text(0, -orbit + 0.1, "{0:.1f}".format(1 - float(orbit + min_orbit) / 10), verticalalignment="bottom", horizontalalignment="center", color=circlecol, zorder=zorder_orbit) all_circles.append(orbit_t) labels_pos = np.array(labels)[labels_idx] recs = [] # ax = plt.gca() if not ax: ax.axis("equal") # ax.margins(x=-0.3, y=-0.3) # ax.axis([-5, 5, -5, 5]) # plt.axis([-10, 10, -10, 10]) legend_elements = [ Line2D([0], [0], linestyle='none', marker='o', color=color_map_tab10(0), label='candidate', markersize=10), Line2D([0], [0], linestyle='none', marker='o', color=color_map_circle(7), label='document', markersize=10) ] if len(selected) > 0: legend_elements.append( Line2D([0], [0], linestyle='none', marker='o', color=color_map_tab10(2), label='selected candidate', markersize=10)) ax.legend(handles=legend_elements, loc='upper left').set_zorder(102) # plt.subplots_adjust(top=0.95) if save_png: plt.savefig(image_path) if show_window: # only require mplcursors if we need an interactive plot # import mplcursors # cooordinate_to_correlation[(sel.target.x, sel.target.y)]["corr_sun"]) # cursors = mplcursors.cursor(hover=True) # @cursors.connect("add") def _(sel): sel.annotation.set(position=(15, -15)) # Note: Needs to be set separately due to matplotlib/matplotlib#8956. sel.annotation.get_bbox_patch().set(fc="lightgrey") sel.annotation.arrow_patch.set(arrowstyle="simple", fc="white", alpha=0) sel.annotation.set_text("Correlation to sun \n{}".format( cordinate_to_correlation[(sel.target[0], sel.target[1])]["corr_sun"])) if show_labels: adjust_text(all_labels, add_objects=all_circles, va="center", ha="left", ax=ax, zorder=zorder_annotations, horizontalalignment='left', verticalalignment='center', arrowprops=dict(connectionstyle="angle3", arrowstyle='-', color='darkgrey')) # for item in all_labels: # item.set_fontsize(10) if not ax: plt.show()
def plot_animations(animations, joint_parents, scale_max, scale_min, save=False, save_overlayed=False, dataset_name=None, subset_name=None, fill=6, overwrite=False): if save: if not os.path.exists('videos'): os.makedirs('videos') dir_name = os.path.join('videos', dataset_name) if not os.path.exists(dir_name): os.makedirs(dir_name) if subset_name is not None: dir_name = os.path.join(dir_name, subset_name) if not os.path.exists(dir_name): os.makedirs(dir_name) total_animations = len(animations) joint_colors = list(sorted(colors.cnames.keys()))[::-1] total_colors = len(joint_colors) num_frames = len(animations[0]) for ai, anim in enumerate(animations): if save: save_file_name = os.path.join(dir_name, str(ai).zfill(fill) + '.mp4') if not overwrite and os.path.exists(save_file_name): continue fig = plt.figure(figsize=(12, 8)) ax = p3.Axes3D(fig) ax.set_xlim3d(scale_min[0], scale_max[0]) ax.set_zlim3d(scale_min[1], scale_max[1]) ax.set_ylim3d(scale_min[2], scale_max[2]) ax.set_xticks([], False) ax.set_yticks([], False) ax.set_zticks([], False) ax.patch.set_alpha(0.) lines = [ax.plot([0, 0], [0, 0], [0, 0], color=joint_colors[ai % total_colors], lw=2, path_effects=[pe.Stroke(linewidth=3, foreground='black'), pe.Normal()])[0] for _ in range(anim.shape[1])] # ani = animation.FuncAnimation(fig, animate_joints, frames=num_frames, # fargs=(lines, animations[ai], parents), # interval=100, blit=True, repeat=True) if save: animation.FuncAnimation(fig, animate_joints, frames=num_frames, fargs=(lines, animations[ai], joint_parents), interval=100, blit=True, repeat=True).save(save_file_name) print('\rGenerating animations: {0:d}/{1:d} done ({2:.2f}%).' .format(ai + 1, total_animations, 100. * (ai + 1) / total_animations), end='') plt.cla() plt.close() if save_overlayed: save_file_name = os.path.join(dir_name, 'overlayed.mp4') if overwrite or not os.path.exists(save_file_name): lines = [] fig = plt.figure(figsize=(12, 8)) ax = p3.Axes3D(fig) ax.set_xlim3d(scale_min[0], scale_max[0]) ax.set_zlim3d(scale_min[1], scale_max[1]) ax.set_ylim3d(scale_min[2], scale_max[2]) ax.set_xticks([], False) ax.set_yticks([], False) ax.set_zticks([], False) for ai, anim in enumerate(animations): lines.extend([ax.plot([0, 0], [0, 0], [0, 0], color=joint_colors[ai % total_colors], lw=2, path_effects=[pe.Stroke(linewidth=3, foreground='black'), pe.Normal()])[0] for _ in range(anim.shape[1])]) animation.FuncAnimation(fig, animate_joints, frames=num_frames, fargs=(lines, animations, joint_parents), interval=100, blit=True, repeat=True).save(save_file_name)
def _draw_outline(o, lw): o.set_path_effects([ patheffects.Stroke(linewidth=lw, foreground='black'), patheffects.Normal() ])
def main(): url = 'https://opendata.ecdc.europa.eu/covid19/casedistribution/csv' # df_ecdc = pd.read_html(url) df_ecdc = pd.read_csv('csv') df_owid = pd.read_csv('owid.csv') days = 14 weeks = 2 for region in ( 'Americas', 'Nordic', 'Europe', 'Asia', 'Oceania', 'Africa', 'G7', 'EU', ): countries = d_regions[region] x = [] y = [] colors = [] l_total_tests_per_thousand = [] sizes = deathsCumulative = [] labels = [] z = [] # print(df_ecdc) # print(df_owid) # print(df_ecdc['countryterritoryCode'].unique()) # exit() for country in df_ecdc['countryterritoryCode'].unique(): if country not in df_owid['iso_code'].unique(): continue # if country not in europe + g7: # continue # if country not in americas: # continue if country not in countries: continue casesTotal = df_ecdc[df_ecdc['countryterritoryCode'] == country]['cases_weekly'].sum() if casesTotal < 100: # Faroe Islands 188, Iceland 1882 print('casesTotal', country, casesTotal) continue cases = df_ecdc[df_ecdc['countryterritoryCode'] == country]['cases_weekly'] deaths = df_ecdc[df_ecdc['countryterritoryCode'] == country]['deaths_weekly'] x2 = cases.head(1 * weeks).sum() x1 = cases.head(2 * weeks).tail(1 * weeks).sum() # if country == 'LTU': # continue # negative values??? # print(cases.to_string()) # exit() # if country in ('CYP',): # continue # no testing? y2 = deaths.head(1 * weeks).sum() y1 = deaths.head(2 * weeks).tail(1 * weeks).sum() # if x1 == 0 or y1 == 0: # continue total_tests_per_thousand = df_owid[df_owid['iso_code'] == country]['total_tests_per_thousand'] if total_tests_per_thousand.max() == 0: continue label = df_owid[df_owid['iso_code'] == country]['location'].iloc[0] # changeCasesWeekly = 100 * (x2 - x1) / x1 # changeDeathsWeekly = 100 * (y2 - y1) / y1 # x1 = cases.sum() - cases.head(7).sum() # x2 = cases.sum() x1 = cases.head(2 * weeks).tail(1 * weeks).sum() x2 = cases.head(1 * weeks).sum() if x1 < 0 or x2 < 0: continue if x1 == 0: changeCasesWeekly = 0 else: changeCasesWeekly = 100 * (x2 - x1) / x1 # Skip outliers. if changeCasesWeekly > 200: # Small absolute change. if y1 < 50 or y2 < 50: changeCasesWeekly = 200 else: pass # print('changeCasesWeekly', country, changeCasesWeekly) # continue # y1 = deaths.sum() - deaths.head(7).sum() # y2 = deaths.sum() x1 = deaths.head(2 * weeks).tail(1 * weeks).sum() x2 = deaths.head(1 * weeks).sum() if y1 == 0: # Faroe Islands have zero deaths changeDeathsWeekly = 0 else: changeDeathsWeekly = 100 * (y2 - y1) / y1 # Skip when deaths are negative: # https://www.theguardian.com/world/2020/aug/12/coronavirus-death-toll-in-england-revised-down-by-more-than-5000 if y1 < 0 or y2 < 0: continue # Skip outliers. if changeDeathsWeekly > 200: # Few absolute changes. if y1 < 50 or y2 < 50: changeDeathsWeekly = 200 else: pass # print('changeDeathsWeekly', country, changeDeathsWeekly) # continue # z2 = total_tests_per_thousand.max() # # Skip if no testing. # if z2 == 0 or np.isnan(z2): # if country in ('FRO',): # change = 0 # else: # continue # else: # for i in range(7, 21): # z1 = total_tests_per_thousand.iloc[-i] # if z1 == z2: # continue # if not np.isnan(z1): # change = 100 * (z2 - z1) / z1 # break # else: # change = 0 # # print(country, z2) # # print(total_tests_per_thousand.to_string()) # # exit() v1 = total_tests_per_thousand.tail(3 * days).head(1 * days).max() v2 = total_tests_per_thousand.tail(2 * days).head(1 * days).max() v3 = total_tests_per_thousand.tail(1 * days).max() z2 = v3 - v2 z1 = v2 - v1 if z1 == 0: change = 0 else: change = 100 * (z2 - z1) / z1 z.append(change) # z.append(100 * (z2 - z1) / z1) l_total_tests_per_thousand.append(total_tests_per_thousand.max()) x.append(changeCasesWeekly) y.append(changeDeathsWeekly) labels.append(label) # sizes.append(5 * math.sqrt(deaths)) deathsTotal = df_ecdc[df_ecdc['countryterritoryCode'] == country]['deaths_weekly'].sum() # size = 10 * deathsTotal ** (1/3) size = max(20, 10 * deathsTotal ** (1/3)) sizes.append(size) # print(country, changeCasesWeekly, changeDeathsWeekly, size) # for _ in l_total_tests_per_thousand: # colors.append(_ / max(l_total_tests_per_thousand)) colors = z fig, ax = plt.subplots() fig.set_size_inches(16 / 2, 9 / 2) for t in reversed(sorted(zip(sizes, x, y, colors, labels))): sizes.append(t[0]) x.append(t[1]) y.append(t[2]) colors.append(t[3]) labels.append(t[4]) sizes = sizes[len(sizes)//2:] x = x[len(x)//2::] y = y[len(y)//2::] colors = colors[len(colors)//2::] labels = labels[len(labels)//2::] paths = ax.scatter( x, y, c = colors, s = sizes, marker = 'o', # label = labels, edgecolor = 'black', linewidth = 0.1, # font = { # # 'family' : 'normal', # # 'weight' : 'bold', # 'size' : 'small', # }, alpha = 0.5, cmap = 'viridis', # vmin = min(l_total_tests_per_thousand), # vmax = max(l_total_tests_per_thousand), vmin = min(0, min(colors)), vmax = max(0, max(colors)), # vmax = 25, ) # ax.axhline(0, color='black', linewidth=0.5, linestyle='--') # ax.axvline(0, color='black', linewidth=0.5, linestyle='--') cbar = fig.colorbar(paths) # cbar.set_label('Total tests per thousand') # cbar.set_label('Weekly change in total tests (%)') # cbar.set_label(f'{days} day change in weekly tests (%)') cbar.set_label('Change in weekly tests (%)') texts = [] for xi, yi, label in zip(x, y, labels): texts.append(ax.text( xi, yi, label, size='xx-small', ## ha='left', va='bottom', ha='center', va='center', color='white', path_effects=[ path_effects.Stroke(linewidth=1, foreground='black'), path_effects.Normal(), ], )) # adjust_text(texts, arrowprops=dict(arrowstyle='->', color='black')) adjust_text(texts) # legend_elements = [] # print(colors) # print(max(colors)) # print(l_total_tests_per_thousand) # print(max(l_total_tests_per_thousand)) # print(min(l_total_tests_per_thousand)) # exit() # for total_tests_per_thousand in [0, ]: # label = forwardPE # if forwardPE == 30: # label = '30+' # legend_elements.append( # Line2D( # [0], [0], marker='o', # color = 'white', # don't show line # label=label, # markerfacecolor=color_forwardPE(forwardPE), # markersize=10, # )) # legend_color = ax.legend( # handles=legend_elements, # loc='upper right', # title=args.color, # # bbox_to_anchor=(0.75, 1), # bbox_to_anchor=(0.95, 1), # ) # # produce a legend with a cross section of sizes from the scatter # handles, labels = scatter.legend_elements( # prop="sizes", alpha=0.5, # func=lambda s: s / 3.01, # ) # labels[-1] = '5.0+' # labels = labels[0::2] # handles = handles[0::2] # legend_size = ax.legend( # handles, labels, loc="upper right", # title=args.size, # # func=lambda s: np.sqrt(s) / 4, # ) # ax.add_artist(legend_size) # ax.set_xlabel('Weekly change in total cases (%)') # ax.set_ylabel('Weekly change in total fatalities (%)') # ax.set_xlabel(f'{weeks} week change in weekly cases (%)') # ax.set_ylabel(f'{weeks} week change in weekly fatalities (%)') ax.set_xlabel(f'Change in weekly cases (%)') ax.set_ylabel(f'Change in weekly fatalities (%)') ax.set_title(region) # ax.set_xlim(0, 75) # El Salvador # ax.set_ylim(0, 65) # Mexico # ax.set_xlim(0, 100) # Ghana # ax.set_ylim(0, 120) # Senegal # ax.set_xlim(0, 5 + 5 * max((25, max(x), max(y))) // 5) # ax.set_ylim(0, 5 + 5 * max((25, max(x), max(y))) // 5) # ax.set_xlim(0, 25) # Canada # ax.set_ylim(0, 30) # Canada # ax.set_xlim(0, min(100, 2 + 2 * max((20, max(x))) // 2)) # ax.set_ylim(0, min(100, 2 + 2 * max((20, max(y))) // 2)) ax.axvline(x=0, ls='--', color='.1', lw=0.5) ax.axhline(y=0, ls='--', color='.1', lw=0.5) path = 'plot_bubble_{}.png'.format(region) fig.savefig(path, dpi=200) print(path) fig.savefig('plot_bubble_{}_{}.png'.format(region, date.today().isoformat()), dpi=200) return