def plot_image_grid(img_grid, grid_shape, file_name, normalize=False, header=None): plt.ioff() figure = Figure(figsize=(10, 10)) canvas = FigureCanvas(figure) for y in range(grid_shape[0]): for x in range(grid_shape[1]): img = img_grid[y][x] if normalize: min_ = np.min(img) max_ = np.max(img) img = (img - min_) / (max_ - min_) ax = figure.add_subplot(grid_shape[0], grid_shape[1], (y * grid_shape[1]) + x + 1) ax.set_axis_off() ax.imshow(img, interpolation='nearest') if y == 0 and header is not None: ax.set_title(header[x]) canvas.print_figure(os.path.join('../results/', file_name))
cols = len(detectors) + 2 for im_i in range(len(imgs)): im = imgs[im_i] ax = figure.add_subplot(nimages, cols, (im_i * cols) + 1) ax.set_axis_off() ax.imshow(im.original, interpolation='nearest') ax = figure.add_subplot(nimages, cols, (im_i * cols) + 2) ax.set_axis_off() ax.imshow(im.gray, interpolation='nearest') for detector_idx in range(len(detectors)): detector = detectors[detector_idx][1] detector_name = detectors[detector_idx][0] try: img_eq = im.gray # cv2.equalizeHist(im.gray) kp = detector.detect(img_eq, None) im_with_kp = drawKeyPoints(im.original, img_eq, kp) ax = figure.add_subplot(nimages, cols, (im_i * cols) + detector_idx + 3) ax.set_axis_off() ax.imshow(im_with_kp, interpolation='nearest') if im_i == 0: ax.set_title(detector_name) except: print "Unexpected error with detector: ", detector_name, sys.exc_info( )[0] canvas.print_figure('../results/feature_extraction_compare.png')
def plot(self, features, output_path): """ Plots the features: International SIGMETs, US SIGMETs, US AIRMETs and METARS on the map with which this class was instantiated. :param features: Feature object containing the parsed GEOJSON data :param output_path: Path to where the plot will be saved. Only PNG supported for now! :return: """ self._log.debug("Plotting features onto axis") # Storage of return values texts = [] plotting_failed = [] info = {} ax = self._plot_definition.ax data_crs = ccrs.PlateCarree() def plot_features(features, label_property, text_property): """ Plots a collection of features onto the map. :param features: The list of GEOJSON features :param label_property: Field in features[i]["properties"] which contains the label to be plotted onto the map :param text_property: Field in features[i]["properties"] which will be added to the infos. :return: Information dictionary { idx: info_text, ... } """ patches = [] patches_unkown = [] for feat in features: try: plot_one_feature(feat, label_property, patches, patches_unkown, text_property) except ValueError: plotting_failed.append(feat['properties'][text_property]) self._log.warning("Plotting of feature=%s failed", feat) ax.add_collection( PatchCollection(patches, facecolor=self._color_scheme.SIGMET_COLOR, edgecolor=self._color_scheme.SIGMET_COLOR, linewidths=1.5, alpha=self._color_scheme.SIGMET_ALPHA, zorder=40, transform=data_crs)) ax.add_collection( PatchCollection( patches_unkown, facecolor=self._color_scheme.SIGMET_UNKNOWN_COLOR, linestyle='dashed', edgecolor=self._color_scheme.SIGMET_UNKNOWN_COLOR, hatch="/", linewidths=1.5, alpha=self._color_scheme.SIGMET_UNKNOWN_ALPHA, zorder=39, transform=data_crs)) def plot_one_feature(feat, label_property, patches, patches_unkown, text_property): """ Plots one feature. If the feature is a point it will be plotted straight onto the map. If it is a polygon it will be added to patches :param feat: Feature to be plotted :param label_property: Field in feat["properties"] which contains the label to be plotted on the map :param patches: Patches collection to which the patch will be appended :param patches_unknown: Patches collection with unkown geometry :param text_property: Field in feat["properties"] which contains the text will be added to the info :return: Information dictionary with one element { idx: info_text } """ if feat["geometry"]["type"] == "Polygon": # convert the geometry to shapely geom_raw = asShape(feat["geometry"]) if len(geom_raw.shell) > 2: geom = geom_raw.buffer(0) label_geometry(geom, feat, label_property, text_property) if feat["properties"].get("geom", "") == "UNK": patches_unkown.append(PolygonPatch(geom)) else: patches.append(PolygonPatch(geom)) else: self._log.warning( "Encountered feature which had less than 2 elements in its shell feature=%s", feat) elif feat["geometry"]["type"] == "Point": geom = Point(feat["geometry"]["coordinates"][0], feat["geometry"]["coordinates"][1]) ax.plot(geom.x, geom.y, 'o', color=self._color_scheme.SIGMET_COLOR, markersize=8, zorder=35, transform=data_crs) label_geometry(geom, feat, label_property, text_property) else: self._log.error( "Encountered geometry which was neither a polygon nor a point. feature=%s", feat) raise ValueError( 'Geometry type was neither Polygon nor Point.') def find_text(x, y): for text in texts: text_x, text_y = text.get_position() if text_x == x and text_y == y: return text return None def label_geometry(geom, feat, label_property, text_property): """ Labels one geometry elements. Usually a SIMGET or AIRMET patch. The label will be placed in the centroid of the visible part of geom. :param geom: Geometry to be labeled. :param feat: GEOJSON Feature :param label_property: Field in feat["properties"] which contains the label to be plotted on the map :param text_property: Field in feat["properties"] which contains the text will be added to the info :return: Information dictionary with one element { idx: info_text } """ centroid = geom.intersection( self._plot_definition.region_box).centroid if geom.intersects(self._plot_definition.region_box): idx = len(info) + 1 label = feat["properties"][label_property] label = self._color_scheme.TEXT_REPLACEMENT.get(label, label) text = label + "\n" + str(idx) + "." text_x, text_y = self._plot_definition.projection.transform_point( centroid.x, centroid.y, data_crs) conflicting_text = find_text(text_x, text_y) if conflicting_text: self._log.debug("Resolving conflicting text") r = get_renderer(self._plot_definition.ax.get_figure()) bbox = get_bboxes([conflicting_text], r, (1.0, 1.0), ax) text_x = text_x - bbox[0].width / 10 text_y = text_y - bbox[0].height / 10 new_text = ax.text(text_x, text_y, text, horizontalalignment='center', verticalalignment='center', zorder=50, fontweight="heavy", fontsize=8) texts.append(new_text) info[idx] = feat["properties"][text_property] def plot_metars(metar_features): """ Plots metars on the map. :param metar_features: GEOJSON METAR feature list :return: """ self._log.debug("Plotting METARs") for index, feat in metar_features.iterrows(): geom = Point(feat['longitude'], feat['latitude']) if self._plot_definition.region_box.contains(geom): label = feat['flight_category'] color = self._color_scheme.METAR_FLIGHT_CATEGORY_COLORS.get( label, self._color_scheme.METAR_COLOR_UNKOWN) age = datetime.now(timezone.utc) - dateutil.parser.parse( feat['observation_time']) age_m = age.total_seconds() / 60 alpha_age_factor = min(1, -1 / 90 * age_m + 4 / 3) alpha = self._color_scheme.METAR_ALPHA * alpha_age_factor ax.plot(geom.x, geom.y, 'o', color=color, markersize=4, zorder=30, alpha=alpha, transform=data_crs) plot_features(features.sigmets_international["features"], "hazard", "rawSigmet") plot_features(features.sigmets_us["features"], "hazard", "rawAirSigmet") plot_features(features.cwa_us["features"], "hazard", "cwaText") plot_metars(features.metars) adjust_text(texts, ha='center', va='center', expand_text=(0.9, 0.9), autoalign=False, on_basemap=True, text_from_points=False, arrowprops=dict(arrowstyle='->', color='0.15', shrinkA=3, shrinkB=3, connectionstyle="arc3,rad=0."), force_text=(0.8, 0.8)) self._plot_legend(ax, plotting_failed) canvas = FigureCanvas(self._plot_definition.fig) canvas.print_figure(output_path, format="png", pad_inches=0.2, bbox_inches="tight", bbox_extra_artists=[], dpi=90) return PlotResult(output_path, info, plotting_failed)