def __init__(self, fig, ax, labels_and_handlers): self.fig = fig self.ax = ax self.labels_and_handlers = labels_and_handlers self.car_box = Box(-self.LENGHT/2.0, -self.WIDHT/2.0, self.LENGHT/2.0, self.WIDHT/2.0) centerx, centery = 0, 0 radius = self.FOV_DISTANCE start_angle, end_angle = -self.FOV_WIDE/2.0, +self.FOV_WIDE/2.0 # In degrees # We do not really need that many, do we? numsegments = 10 # The coordinates of the arc theta = np.radians(np.linspace(start_angle, end_angle, numsegments)) x = centerx + radius * np.cos(theta) x = np.insert(x, 0, 0.0) y = centery + radius * np.sin(theta) y = np.insert(y, 0, 0.0) arc = LineString(np.column_stack([x, y])) self.fov = Polygon(list(arc.coords))
def clipped_voronoi(points, bbox): vor = scipy.spatial.Voronoi(points) regions, vertices = voronoi_finite_polygons_2d(vor) clip = Box(*bbox) clipped = [clip.intersection(poly) for poly in (Polygon(p) for p in (vertices[region] for region in regions))] regions = [np.array(polygon.exterior.coords) for polygon in clipped] vor.clipped_vertices = vertices vor.clipped_regions = regions return vor
def compare_tile_segment(coordinates, tile, image_dir, tile_images_directory): """ Compares whether the box bounded by the tile's original coordinates intersects the tumor segment indicated in the xml file. Saves all tiles images. Arguments: coordinates: a list of tumor segments coordinates from xml annotations tile: the tile being investigated image_dir: directory of original WSI files tile_images_directory: directory to which images of tiles will be saved Returns: Depending on the positivity of the tile: - if positive tumor: returns the coordinates on that tile image of the tumor region(s) - if negative: returns None, None values """ box = Box(tile.o_c_s, tile.o_r_s, tile.o_c_e, tile.o_r_e) for i in range(len(coordinates)): # We disregard coordinates with less than 2 xy values if len(coordinates[i]) < 3: continue if not os.path.exists(tile_images_directory + tile.file_title + "_" + str(tile.tile_num) + '.png'): save_tile_image(tile, image_dir, tile_images_directory) print(tile.file_title + "_", str(tile.tile_num) + ".png image saved") segment = Polygon(coordinates[i]) if segment.intersects(box): segment = transform(reflection(1), segment) box = transform(reflection(1), box) try: overlap = segment.intersection(box) except: print("Error in ", tile.file_title, " num: ", tile.tile_num, " coord index: ", i) continue if isinstance(overlap, MultiPolygon): x_overlap_shifted_list = [] y_overlap_shifted_list = [] for element in overlap: x_overlap_shifted, y_overlap_shifted = get_xy(tile, element) x_overlap_shifted_list.append(x_overlap_shifted) y_overlap_shifted_list.append(y_overlap_shifted) return x_overlap_shifted_list, y_overlap_shifted_list else: x_overlap_shifted, y_overlap_shifted = get_xy(tile, overlap) return x_overlap_shifted, y_overlap_shifted else: continue return None, None
def main(req: func.HttpRequest) -> func.HttpResponse: try: trace = parse_trace(req) db = CountryDatabase.load() result = ({ "name": country["name"], "continent": country["continent"] } for country in db.query_by_box(trace.bounds) if country["shape"].intersects(Box(*trace.bounds))) return func.HttpResponse(json.dumps(list(result))) except ParseException as e: return func.HttpResponse(e.message, status_code=400)
def intersect_disks_on_globe(xs, ys, rads): """Return the intersection of many DiskOnGlobe objects, constructed from three arrays of longitudes (xs), latitudes (ys), and radii (rads). """ assert len(xs) == len(ys) == len(rads) result = Box(-180, -90, 180, 90) for x, y, rad in zip(xs, ys, rads): d = DiskOnGlobe(x, y, rad) result = result.intersection(d) return result
def area(self): """Weighted area of the nonzero region of the probability matrix.""" if self._area is None: # Notionally, each grid point should be treated as a # rectangle of parallels and meridians _centered_ on the # point. The area of such a rectangle, however, only # depends on its latitude and its breadth; the actual # longitude values don't matter. Since the grid is # equally spaced, we can use [0],[1] always, and then we # do not have to worry about crossing the discontinuity at ±180. west = self.longitudes[0] east = self.longitudes[1] # For latitude, the actual values do matter, but the map # never goes all the way to the poles, and the grid is # equally spaced, so we can precompute the north-south # delta from any pair of latitudes and not have to worry # about running off the ends of the array. d_lat = (self.latitudes[1] - self.latitudes[0]) / 2 # We don't need X, so throw it away immediately. (We # don't use iter_csr_nonzero here because we need to # modify V.) X, Y, V = sparse.find(self.probability) X = None # The value vector is supposed to be normalized, but make # sure it is, and then adjust from 1-overall to 1-per-cell # normalization. assert len(V.shape) == 1 S = V.sum() if S == 0: return 0 if S != 1: V /= S V *= V.shape[0] area = 0 for y, v in zip(Y, V): north = self.latitudes[y] + d_lat south = self.latitudes[y] - d_lat if not (-90 <= south < north <= 90): raise AssertionError( "expected -90 <= {} < {} <= 90".format(south, north)) tile = sh_transform(wgs_to_cea, Box(west, south, east, north)) area += v * tile.area self._area = area return self._area
def _extract_polygons(self, data): # This method should return a dictionary with key-value pairs of # polygon_center : shapely polygon for i in range(data.shape[0]): north, east, alt, d_north, d_east, d_alt = data[i, :] # Extract the min & max extents of the obstacle and create a box shaped # polygon p = Box(north - d_north, east - d_east, north + d_north, east + d_east) # Compute the height of the polygon height = alt + d_alt center = (north, east) self._poly_dict[center] = (p, height) self._poly_center.append(center)
def __init__(self, mapfile): with tables.open_file(mapfile, 'r') as f: M = f.root.baseline if M.shape[0] == len(M.attrs.longitudes): baseline = sparse.csr_matrix(M) elif M.shape[1] == len(M.attrs.longitudes): baseline = sparse.csr_matrix(M).T else: raise RuntimeError( "mapfile matrix shape {!r} is inconsistent with " "lon/lat vectors ({},{})".format(M.shape, len(M.attrs.longitudes), len(M.attrs.latitudes))) # The probabilities stored in the file are not normalized. s = baseline.sum() assert s > 0 baseline /= s # Note: this bound may not be tight, but it should be # good enough. It's not obvious to me how to extract # a tight bounding rectangle from a scipy sparse matrix. bounds = Box(M.attrs.west, M.attrs.south, M.attrs.east, M.attrs.north) if not bounds.is_valid: bounds = bounds.buffer(0) assert bounds.is_valid Location.__init__(self, resolution=M.attrs.resolution, fuzz=M.attrs.fuzz, north=M.attrs.north, south=M.attrs.south, east=M.attrs.east, west=M.attrs.west, lon_spacing=M.attrs.lon_spacing, lat_spacing=M.attrs.lat_spacing, longitudes=M.attrs.longitudes, latitudes=M.attrs.latitudes, probability=baseline, vacuity=False, bounds=bounds)
def _lazy_load_pmatrix(self): assert self._loaded_from is not None with tables.open_file(self._loaded_from, "r") as f: t = f.root.location M = sparse.dok_matrix((t.attrs.lon_count, t.attrs.lat_count), dtype=np.float32) vacuous = True negative_warning = False for row in t.iterrows(): pmass = row['prob_mass'] # The occasional zero is normal, but negative numbers # should never occur. if pmass > 0: M[row['grid_x'], row['grid_y']] = pmass vacuous = False elif pmass < 0: if not negative_warning: sys.stderr.write(fname + ": warning: negative pmass\n") negative_warning = True M = M.tocsr() if vacuous: wb = 0 eb = 0 sb = 0 nb = 0 else: i, j = M.nonzero() wb = self.longitudes[i.min()] eb = self.longitudes[i.max()] sb = self.latitudes[j.min()] nb = self.latitudes[j.max()] self._probability = M self._vacuous = vacuous self._bounds = Box(wb, sb, eb, nb)
def extract_patches(image, polygons, shape, stride=None, threshold=0.5): """Extract patches from a geocoded image Args: image: Filename of geocoded image or rasterio.Dataset polygons: GeoDataFrame with labelled polygons. shape: Desired shape of the extracted patches. Is also used to calculate the number of extracted patches. stride: threshold: How many points of the extracted rectangle should be covered by the labelled polygon? Must be a float be 0 and 1. Yields: A tuple of two elements: the index of the polygon and the corresponding patch. """ if stride is None: stride = shape image_bounds = Box(*image.bounds) BoundingBox = namedtuple( 'BoundingBox', ['col_start', 'col_end', 'row_start', 'row_end', 'height', 'width']) # We want to extract as many rectangles from the labelled polygons as possible. # We are working with two coordinate systems: the index system (row, column) to # extract the pixel values from the image matrix and the geo-referenced # coordinates (x,y) to find the patches corresponding to the labelled polygons. for idx, polygon in polygons.iterrows(): if not polygon.geometry.is_valid: print('Polygon {} is not valid!'.format(idx)) continue if not polygon.geometry.intersects(image_bounds): continue # Extract the bounding box of the polygon, so we can divide it easily # into sub-rectangles: row1, col1 = image.index(polygon.geometry.bounds[0], polygon.geometry.bounds[1]) row2, col2 = image.index(polygon.geometry.bounds[2], polygon.geometry.bounds[3]) polygon_bbox = BoundingBox(col_start=min([col1, col2]), col_end=max([col1, col2]), row_start=min([row1, row2]), row_end=max([row1, row2]), height=abs(row2 - row1), width=abs(col2 - col1)) for column in range((polygon_bbox.width // stride[0]) + 1): for row in range((polygon_bbox.height // stride[1]) + 1): # Transform the patch bounding box indices to coordinates to # calculate the percentage that is covered by the labelled # polygon: x1, y1 = image.xy(polygon_bbox.row_start + row * stride[1], polygon_bbox.col_start + column * stride[0]) x2, y2 = image.xy( polygon_bbox.row_start + row * stride[1] + shape[1], polygon_bbox.col_start + column * stride[0] + shape[1]) patch_bounds = Box(x1, y1, x2, y2) # We check first whether the threshold condition is fullfilled # and then we extract the patch from the image: overlapping_area = \ polygon.geometry.intersection(patch_bounds).area if overlapping_area / patch_bounds.area < threshold: # The labelled polygon covers less than $threshold$ of the # whole patch, i.e. we reject it: continue # rasterio returns data in CxHxW format, so we have to transpose # it: patch = image.read( window=Window(polygon_bbox.col_start + column * stride[0], polygon_bbox.row_start + row * stride[1], shape[1], shape[0])).T # The fourth channel shows the alpha (transparency) value. We do not # allow patch with transparent pixels: if not patch.size or (patch.shape[-1] == 4 and 0 in patch[..., 3]): continue yield idx, patch
def DiskOnGlobe(x, y, radius): """Return a shapely polygon which is a circle centered at longitude X, latitude Y, with radius RADIUS (meters), projected onto the surface of the Earth. """ # Make sure the radius is at least 1km to prevent underflow. radius = max(radius, 1000) # If the radius is too close to half the circumference of the # Earth, the projection operation below will produce an invalid # polygon. We don't get much use out of a region that includes # the whole planet but for a tiny disk (which will probably be # somewhere in the ocean anyway) so just give up and say that the # region is the entire planet. if radius > 19975000: return Box(-180, -90, 180, 90) # To find all points on the Earth within a certain distance of # a reference latitude and longitude, back-project onto the # Earth from an azimuthal-equidistant map with its zero point # at the reference latitude and longitude. aeqd = pyproj.Proj(proj='aeqd', ellps='WGS84', datum='WGS84', lat_0=y, lon_0=x) disk = sh_transform( functools.partial(pyproj.transform, aeqd, wgs_proj), Point(0, 0).buffer(radius, resolution=64)) # Two special cases must be manually dealt with. First, if any # side of the "disk" (really a many-sided polygon) crosses the # coordinate singularity at longitude ±180, we must replace that # side with a diversion to either the north or south pole # (whichever is closer) to ensure the diskstill encloses all of # the area it should. boundary = np.array(disk.boundary) i = 0 while i < boundary.shape[0] - 1: if abs(boundary[i+1,0] - boundary[i,0]) > 180: pole = -90 if boundary[i,1] < 0 else 90 west = -180 if boundary[i,0] < 0 else 180 east = 180 if boundary[i,0] < 0 else -180 boundary = np.insert(boundary, i+1, [ [west, boundary[i,1]], [west, pole], [east, pole], [east, boundary[i+1,1]] ], axis=0) i += 5 else: i += 1 # If there were two sides that crossed the singularity and they # were both on the same side of the equator, the excursions will # coincide and shapely will be unhappy. buffer(0) corrects this. disk = Polygon(boundary).buffer(0) # Second, if the radius is very large, the projected disk might # enclose the complement of the region that it ought to enclose. # If it doesn't contain the reference point, we must subtract it # from the entire map. origin = Point(x, y) if not disk.contains(origin): disk = Box(-180, -90, 180, 90).difference(disk) assert disk.is_valid assert disk.contains(origin) return disk
def tx_geojson(responses): from itertools import takewhile from shapely.geometry import Point, GeometryCollection, Polygon, box as Box transformed = [] xs = [] ys = [] labels = [] arr3d = [] polygons = [] colors = ["royalblue", "crimson", "lightseagreen", "orange"] my_traces = [] buffer = 0.05 for i, obj in enumerate(responses): color = colors[i % len(colors)] label = f"Name: {obj['display_name']}<br>Centroid: {obj['lat']},{obj['lon']}" points = [] geojson = obj["geojson"] points = [] print(json.dumps(obj)) if geojson["type"] == "Polygon": for shape in geojson["coordinates"]: print(f"shape: {shape}") for point in shape: print(f"Point: {point}") points.append(point) poly = Polygon([point for point in points]) buffered = poly.buffer(buffer) elif geojson["type"] == "Point": x1, x2, y1, y2 = [float(x) for x in obj["boundingbox"]] xy = sorted([x1, x2]) + sorted([y1, y2]) minx, maxx, miny, maxy = xy box = Box(minx, miny, maxx, maxy) buffered = box.buffer(buffer) else: print(geojson) print(f"Weird type: {geojson['type']}") continue hull = list(buffered.convex_hull.exterior.coords) simplex = [] for g in grouper(4, hull, fillvalue=hull[-1]): print(f"Next group is: {g}") print(f"Appending {g[0]}") simplex.append(list(reversed(g[0]))) poly = Polygon(simplex) polygons.append(poly) coords = list(poly.exterior.coords) center = list(poly.centroid.coords) print(f"Coords are: {coords}") arr2d = [] _xs = [] _ys = [] _lab = [] for x, y in coords: x, y = list(sorted([x, y])) print(f"x:{x}, y:{y}") arr2d.append([x, y]) _xs.append(x) _ys.append(y) _lab.append(label) arr3d.append(arr2d) labels.extend(_lab + [None]) xs.extend(_xs + [None]) ys.extend(_ys + [None]) _tx = copy(obj) _tx["geojson"] = {"type": "Polygon", "coordinates": [arr2d]} trace = { "fill": "toself", "hoverinfo": "all", "mode": "lines+text", "text": _lab, "lon": _xs, "lat": _ys, "selected": { "marker": { "opacity": 1 / (len(responses) + 1) * i } }, "name": obj["display_name"], "marker": { "size": 10, "color": color }, } print(json.dumps(trace)) transformed.append(_tx) my_traces.append(trace) print(my_traces) arr2d = list(flatten_list(arr3d)) polygons = GeometryCollection(polygons) # area = {} # for trace, poly in zip(my_traces, polygons): # area[trace['name']] = poly.area # my_traces = list(sorted(my_traces, key=lambda trace: area[trace['name']])) centroids = sorted(list(polygons.centroid.coords)) centroid = ( sum([x for x, y in centroids]) / (1 + len(centroids)), sum([y for x, y in centroids]) / (1 + len(centroids)), ) for trace in my_traces: print(json.dumps(trace, indent=4)) out = { "traces": my_traces, "centroids": centroid, "centroid": centroid, "lats": xs, "longs": ys, "geom": polygons, "labels": labels, "points": arr2d, "polygons": arr3d, "data": transformed, } return Munch(out)
def plotproj(plotdef, data, outdir): ''' Plot map. ''' axes = plt.axes() box = Box( plotdef['lonmin'], plotdef['latmin'], plotdef['lonmax'], plotdef['latmax']) for feat in data["features"]: geom = shape(feat["geometry"]) if not geom.intersects(box): continue temp_pol = geom.intersection(box) if plotdef['type'] == 'poly': if isinstance(temp_pol, MultiPolygon): polys = [resample_polygon(polygon) for polygon in temp_pol.geoms] pol = MultiPolygon(polys) else: pol = resample_polygon(temp_pol) else: pol = temp_pol trans = functools.partial(project_xy, proj_string=plotdef['projstring']) proj_geom = transform(trans, pol) if plotdef['type'] == 'poly': try: patch = PolygonPatch(proj_geom, fc=COLOR_LAND, zorder=0) axes.add_patch(patch) except TypeError: pass else: x, y = proj_geom.xy axes.plot(x, y, color=COLOR_COAST, linewidth=0.5) # Plot frame frame = [ parallel(plotdef['latmin'], plotdef['lonmin'], plotdef['lonmax']), parallel(plotdef['latmax'], plotdef['lonmin'], plotdef['lonmax']), ] for line in frame: line = project(line, plotdef['projstring']) x = line[:, 0] y = line[:, 1] axes.plot(x, y, '-k') graticule = build_graticule( plotdef['lonmin'], plotdef['lonmax'], plotdef['latmin'], plotdef['latmax'], ) # Plot graticule for feature in graticule: feature = project(feature, plotdef['projstring']) x = feature[:, 0] y = feature[:, 1] axes.plot(x, y, color=COLOR_GRAT, linewidth=0.4) # Switch off the axis lines... plt.axis('off') # ... and additionally switch off the visibility of the axis lines and # labels so they can be removed by "bbox_inches='tight'" when saving axes.get_xaxis().set_visible(False) axes.get_yaxis().set_visible(False) font = { 'family': 'serif', 'color': 'black', 'style': 'italic', 'size': 12 } # Make sure the plot is not stretched axes.set_aspect('equal') outdir = Path(outdir) if not outdir.exists(): outdir.mkdir(parents=True) if not outdir.is_dir(): raise OSError("outdir is not a directory") plt.savefig(outdir / plotdef['filename'], dpi=400, bbox_inches='tight') # Clean up axes = None del axes plt.close()
def to_box(box: typ.Tuple[int, int, int, int]) -> Box: """Converts box [top, left, right, bottom] to shapely.Box""" x, y, w, h = box return Box(x, y, x + w, y + h)
def compute_bounding_region_now(self): if self._bounds is not None: return distance_bound = self.range_fn.distance_bound() # If the distance bound is too close to half the circumference # of the Earth, the projection operation below will produce an # invalid polygon. We don't get much use out of a bounding # region that includes the whole planet but for a tiny disk # (which will probably be somewhere in the ocean anyway) so # just give up and say that the bound is the entire planet. # Similarly, if the distance bound is zero, give up. if distance_bound > 19975000 or distance_bound == 0: self._bounds = Box(self.west, self.south, self.east, self.north) return # To find all points on the Earth within a certain distance of # a reference latitude and longitude, back-project onto the # Earth from an azimuthal-equidistant map with its zero point # at the reference latitude and longitude. aeqd = pyproj.Proj(proj='aeqd', ellps='WGS84', datum='WGS84', lat_0=self.ref_lat, lon_0=self.ref_lon) try: disk = sh_transform( functools.partial(pyproj.transform, aeqd, wgs_proj), Disk(0, 0, distance_bound)) # Two special cases must be manually dealt with. First, if # any side of the "circle" (really a many-sided polygon) # crosses the coordinate singularity at longitude ±180, we # must replace it with a diversion to either the north or # south pole (whichever is closer) to ensure that it still # encloses all of the area it should. boundary = np.array(disk.boundary) i = 0 while i < boundary.shape[0] - 1: if abs(boundary[i + 1, 0] - boundary[i, 0]) > 180: pole = self.south if boundary[i, 1] < 0 else self.north west = self.west if boundary[i, 0] < 0 else self.east east = self.east if boundary[i, 0] < 0 else self.west boundary = np.insert( boundary, i + 1, [[west, boundary[i, 1]], [west, pole], [east, pole], [east, boundary[i + 1, 1]]], axis=0) i += 5 else: i += 1 # If there were two edges that crossed the singularity and they # were both on the same side of the equator, the excursions will # coincide and shapely will be unhappy. buffer(0) corrects this. disk = Polygon(boundary).buffer(0) # Second, if the disk is very large, the projected disk might # enclose the complement of the region that it ought to enclose. # If it doesn't contain the reference point, we must subtract it # from the entire map. origin = Point(self.ref_lon, self.ref_lat) if not disk.contains(origin): disk = (Box(self.west, self.south, self.east, self.north).difference(disk)) assert disk.is_valid assert disk.contains(origin) self._bounds = disk except Exception as e: setattr(e, 'offending_disk', disk) setattr(e, 'offending_obs', self) raise