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))
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
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)
Ejemplo n.º 5
0
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
Ejemplo n.º 6
0
    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
Ejemplo n.º 7
0
    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)
Ejemplo n.º 8
0
    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)
Ejemplo n.º 9
0
    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)
Ejemplo n.º 10
0
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
Ejemplo n.º 11
0
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
Ejemplo n.º 12
0
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)
Ejemplo n.º 13
0
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()
Ejemplo n.º 14
0
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)
Ejemplo n.º 15
0
    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