예제 #1
0
def tiles_for_trail(trail_code, trail_section, alternates, trail_buffer,
                    town_buffer, min_zoom, max_zoom, tms):
    """Get map tile coordinates for trail
    """
    # Load geometries
    trail = Trail(trail_code=trail_code)
    track = trail.track(trail_section=trail_section, alternates=alternates)
    towns = trail.towns(trail_section=trail_section)

    # Create buffers
    if trail_buffer > 0:
        track.geometry = geom.buffer(track, distance=trail_buffer, unit='mile')

    if town_buffer > 0:
        towns.geometry = geom.buffer(towns, distance=town_buffer, unit='mile')

    # Combine into single polygon
    gdf = gpd.GeoDataFrame(pd.concat([track, towns], sort=False, axis=0))
    polygon = gdf.unary_union

    # Find tiles
    scheme = 'tms' if tms else 'xyz'
    zoom_levels = range(min_zoom, max_zoom + 1)
    tiles = tiles_for_polygon(polygon, zoom_levels=zoom_levels, scheme=scheme)

    # Coerce to strings like
    # [x, y, z]
    s = '\n'.join([f'[{t[0]}, {t[1]}, {t[2]}]' for t in tiles])
    click.echo(s)
예제 #2
0
    def get_campsites_near_trail(self, trail):
        section_name, trail = next(Halfmile().trail_iter())
        trail_buf = geom.buffer(trail, distance=2, unit='mile')
        trail_buf = gpd.GeoDataFrame(geometry=trail_buf)
        buf = geom.buffer(trail, distance=2, unit='mile').unary_union

        local_path = self.raw_dir / 'RIDBFullExport_V1_CSV.zip'
        z = ZipFile(local_path)
        z.namelist()
        df = pd.read_csv(BytesIO(z.read('Facilities_API_v1.csv')))
        gdf = gpd.GeoDataFrame(
            df,
            geometry=df.apply(lambda row: Point(row['FacilityLongitude'], row[
                'FacilityLatitude']),
                              axis=1))
예제 #3
0
    def download(self,
                 trail: gpd.GeoDataFrame,
                 buffer_dist=None,
                 buffer_unit='mile',
                 overwrite=False):
        """Download polygon shapefile and intersect with PCT track

        Args:
            - trail: gdf of trail to use to find polygons that intersect
            - buffer_dist: distance to use for trail buffer when intersecting with polygons. By default is None, so no buffer will be used.
            - buffer_unit: unit to use for buffer
            - overwrite: whether to overwrite existing data
        """
        assert self.save_dir is not None, 'self.save_dir must be set'
        assert self.url is not None, 'self.url must be set'
        assert self.filename is not None, 'self.filename must be set'

        # Cache original download in self.raw_dir
        parsed_url = urlparse(self.url)
        raw_fname = Path(parsed_url.path).name
        raw_path = self.raw_dir / raw_fname
        if overwrite or (not raw_path.exists()):
            urlretrieve(self.url, raw_path)

        # Now load the saved file as a GeoDataFrame
        with open(raw_path, 'rb') as f:
            with fiona.BytesCollection(f.read()) as fcol:
                crs = fcol.crs
                gdf = gpd.GeoDataFrame.from_features(fcol, crs=crs)

        # Reproject to WGS84
        gdf = gdf.to_crs(epsg=4326)

        # Use provided `trail` object
        trail = trail.to_crs(epsg=4326)

        # Intersect with the trail
        if buffer_dist is not None:
            buf = geom.buffer(trail, distance=buffer_dist, unit=buffer_unit)
            # Returned as GeoSeries; coerce to GDF
            if not isinstance(buf, gpd.GeoDataFrame):
                buf = gpd.GeoDataFrame(geometry=buf)
                buf = buf.to_crs(epsg=4326)

            intersection = sjoin(gdf, buf, how='inner')
        else:
            intersection = sjoin(gdf, trail, how='inner')

        # Make sure I have valid geometries
        intersection = geom.validate_geom_gdf(intersection)

        # Do any specific steps, to be overloaded in subclasses
        intersection = self._post_download(intersection)

        # Save to GeoJSON
        self.save_dir.mkdir(exist_ok=True, parents=True)
        intersection.to_file(self.save_dir / self.filename, driver='GeoJSON')
예제 #4
0
    def _create_buffer(self, distance: float = 20):
        """Create buffer around USFS pct track

        Args:
            distance: buffer radius in miles
        """
        trail = self.trail()
        buffer = geom.buffer(trail, distance=20, unit='mile')

        save_dir = self.data_dir / 'pct' / 'polygon' / 'usfs'
        save_dir.mkdir(parents=True, exist_ok=True)

        buffer.to_file(save_dir / f'buffer{distance}mi.geojson',
                       driver='GeoJSON')
예제 #5
0
    def handle_sections(self, use_cache: bool = True):
        sections = VALID_TRAIL_SECTIONS[self.trail_code]
        for section_name in sections:
            hm_sections = TRAIL_HM_XW[section_name]
            track = self.hm.trail_section(hm_sections, alternates=True)
            wpt = self.hm.wpt_section(hm_sections)

            buf = geom.buffer(track, distance=2, unit='mile').unary_union

            # section =
            # track

            self = TrailSection(buffer=buf,
                                section_name=section_name,
                                use_cache=use_cache)
            self.main(wpt=wpt)
예제 #6
0
파일: network.py 프로젝트: nst-guide/data
    def get_osm_network(self, buffer_dist, buffer_unit, use_cache=True):
        """Use osmnx to get network of roads/trails around trail geometry
        """
        # Take buffer of approximate trail
        approx_trail_buffer_gdf = geom.buffer(self.approx_trail_gdf,
                                              distance=buffer_dist,
                                              unit=buffer_unit,
                                              crs=self.crs)

        # Consolidate GeoDataFrame to shapely geometry
        approx_trail_buffer = approx_trail_buffer_gdf.unary_union

        # Get graph
        G = self.osm.get_ways_for_polygon(polygon=approx_trail_buffer,
                                          section_name=self.trail_section,
                                          source='geofabrik',
                                          use_cache=use_cache)

        # Get way ids that are part of the trail
        trail_way_ids = self._get_osm_way_ids_for_trail()
        trail_way_ids = list(map(int, trail_way_ids))

        # Set attribute on each edge and node if it's part of the trail
        # trail_nodes is
        trail_nodes = set()
        trail_edges = []
        for u, v, k, way_id in G.edges(keys=True, data='osmid'):
            if way_id not in trail_way_ids:
                continue

            trail_nodes.add(u)
            trail_nodes.add(v)
            trail_edges.append((u, v, k))

        # Add _trail=True for these nodes and edges
        nx.set_node_attributes(G,
                               name='_trail',
                               values={k: True
                                       for k in trail_nodes})
        nx.set_edge_attributes(G,
                               name='_trail',
                               values={(u, v, k): True
                                       for u, v, k in trail_edges})

        return G
예제 #7
0
def get_tile_indices(gdf, buffer_dists, max_zoom):
    """Generate nested tile indices

    For a given GeoDataFrame, generate tile coordinates for each buffer
    distance. These tile coordinates should include include the difference
    between the current buffer distance and the smaller buffer distance, so that
    the tile coordinates can nest.
    """
    # Generate buffers around geometry and generate tile indices for that
    # geometry
    tile_indices = {}
    for buffer_dist in buffer_dists:
        if buffer_dist > 0:
            buf = buffer(gdf, distance=buffer_dist, unit='mile').unary_union
        else:
            buf = gdf.unary_union

        tiles = tiles_for_polygon(buf, zoom_levels=range(0, max(max_zoom) + 1))
        tile_indices[buffer_dist] = tiles

    # When multiple buffer distances are provided, change the higher values to
    # be the difference in tiles between it and the next lowest buffer. So if
    # the buffer distances provided are [2, 5, 10], then change tile_indices[5]
    # to contain only the tile coordinates not in tile_indices[2]
    #
    # NOTE: make sure you create a new dict, otherwise, if you start at the
    # bottom, when you're comparing buffer 5 and buffer 10, you might
    # unintentionally take the set difference of 10 and (5 diff 2), which would
    # include the original 2-buffer tiles. Either start at the largest dist, or
    # you have to diff every lower value, or create a new dict...
    buffer_dists = sorted(buffer_dists)
    if len(buffer_dists) > 1:
        tile_indices_new = {}
        tile_indices_new[min(buffer_dists)] = tile_indices[min(buffer_dists)]
        for prev_dist, dist in zip(buffer_dists, buffer_dists[1:]):
            tile_indices_new[dist] = set(tile_indices[dist]).difference(
                tile_indices[prev_dist])

        tile_indices = tile_indices_new

    # tile_indices now has the minimum tile coordinates for each zoom level
    return tile_indices
예제 #8
0
파일: usgs.py 프로젝트: nst-guide/data
    def _download_nhd_for_line(self, line: Union[LineString, GDF], overwrite):
        """Download National Hydrography Dataset for trail

        Downloads NHD files within 2 miles of trail
        """
        if not isinstance(line, gpd.GeoDataFrame):
            line = gpd.GeoDataFrame([], lineetry=[line])
            line.crs = {'init': 'epsg:4326'}

        buf = geom.buffer(line, distance=2, unit='mile').unary_union
        gdfs = self._get_HU8_units_for_geometry(buf)
        hu8_ids = gdfs['HUC8'].unique()

        baseurl = 'https://prd-tnm.s3.amazonaws.com/StagedProducts/Hydrography/'
        baseurl += 'NHD/HU8/HighResolution/GDB/'
        for hu8_id in hu8_ids:
            name = f'NHD_H_{hu8_id}_HU8_GDB.zip'
            url = baseurl + name
            path = self.raw_dir / name
            if overwrite or (not path.exists()):
                urlretrieve(url, path)
예제 #9
0
    def transit(self,
                trail=True,
                town=True,
                trail_buffer_dist=1000,
                trail_buffer_unit='meter'):
        """Get transit information for trail
        """

        transit = data_source.Transit()

        # Get all stops that intersect trail and town geometries
        all_all_stops = {}
        all_nearby_stops = {}
        all_routes = {}
        if trail:
            for section_name, gdf in self.hm.trail_iter():
                trail_buf = geom.buffer(gdf,
                                        distance=trail_buffer_dist,
                                        unit=trail_buffer_unit).unary_union

                _nearby_stops, _all_stops, _routes = transit.download(
                    trail_buf)

                # Add each dict to `all_${dict}`, but set the _trail key to True
                for key, val in _nearby_stops.items():
                    all_nearby_stops[key] = all_nearby_stops.get(key, val)
                    all_nearby_stops[key]['_trail'] = True

                for key, val in _all_stops.items():
                    all_all_stops[key] = all_all_stops.get(key, val)
                    all_all_stops[key]['_trail'] = True

                for key, val in _routes.items():
                    all_routes[key] = all_routes.get(key, val)
                    all_routes[key]['_trail'] = True

        if town:
            for polygon in self.towns().geometry:
                _nearby_stops, _all_stops, _routes = transit.download(polygon)

                # Add each dict to `all_${dict}`, but set the _trail key to True
                for key, val in _nearby_stops.items():
                    all_nearby_stops[key] = all_nearby_stops.get(key, val)
                    all_nearby_stops[key]['_town'] = True

                for key, val in _all_stops.items():
                    all_all_stops[key] = all_all_stops.get(key, val)
                    all_all_stops[key]['_town'] = True

                for key, val in _routes.items():
                    all_routes[key] = all_routes.get(key, val)
                    all_routes[key]['_town'] = True

        # Combine all_all_stops and all_nearby_stops into single dict
        stops = {}
        for key, val in all_nearby_stops.items():
            stops[key] = stops.get(key, val)
            stops[key]['_nearby_stop'] = True

        for key, val in all_all_stops.items():
            stops[key] = stops.get(key, val)

        stops_features = []
        for key, val in stops.items():
            props = {k: v for k, v in val.items() if k != 'geometry'}
            f = geojson.Feature(id=key,
                                geometry=val['geometry'],
                                properties=props)
            stops_features.append(f)

        routes_features = []
        for key, val in all_routes.items():
            props = {k: v for k, v in val.items() if k != 'geometry'}
            f = geojson.Feature(id=key,
                                geometry=val['geometry'],
                                properties=props)
            routes_features.append(f)

        stops_fc = geojson.FeatureCollection(stops_features)
        routes_fc = geojson.FeatureCollection(routes_features)
        return stops_fc, routes_fc
예제 #10
0
    def wikipedia_articles(self,
                           buffer_dist=2,
                           buffer_unit='mile',
                           attrs=['title', 'url']):
        """Get wikipedia articles for trail

        Args:

        - buffer_dist: numerical distance for buffer around trail
        - buffer_unit: units for buffer_dist, can be 'mile', 'meter', 'kilometer'
        - attrs: list of wikipedia page attributes to keep. Geometry is always
          kept. Options are:

            - categories: List of categories of a page. I.e. names of subsections within article
            - content: Plain text content of the page, excluding images, tables, and other data.
            - html: Get full page HTML. Warning: this can be slow for large
              pages.
            - best_image: My attempt to get the single best image url.
            - images: List of URLs of images on the page.
            - links: List of titles of Wikipedia page links on a page.
            - original_title:
            - pageid:
            - parent_id: Revision ID of the parent version of the current revision of this page. See revision_id for more information.
            - references: List of URLs of external links on a page. May include external links within page that aren’t technically cited anywhere.
            - revision_id: Revision ID of the page.

              The revision ID is a number that uniquely identifies the current
              version of the page. It can be used to create the permalink or for
              other direct API calls. See Help:Page history for more
              information.
            - sections: List of section titles from the table of contents on the page.
            - summary: Plain text summary of the page.
            - title: Title of the page
            - url: URL of the page
        """
        # is best_image asked for
        best_image = 'best_image' in attrs
        # Make sure it's not left in attrs list
        attrs = [attr for attr in attrs if attr != 'best_image']

        # Make sure desired attributes are valid
        valid_attrs = [
            'categories', 'content', 'html', 'images', 'links',
            'original_title', 'pageid', 'parent_id', 'references',
            'revision_id', 'sections', 'summary', 'title', 'url'
        ]
        assert (all(attr) in valid_attrs for attr in attrs), 'Invalid attrs'

        # Get trail track as a single geometric line
        trail = self.hm.trail_full(alternates=False)
        buf = geom.buffer(trail, distance=buffer_dist,
                          unit=buffer_unit).unary_union
        wiki = data_source.Wikipedia()
        pages = wiki.find_pages_for_polygon(buf)

        data = []
        for page in pages:
            d = {}
            if best_image:
                d['best_image'] = wiki.best_image_on_page(page)

            for attr in attrs:
                d[attr] = getattr(page, attr)

            # Page coordinates are in lat, lon order
            d['geometry'] = Point(page.coordinates[::-1])

            data.append(d)

        gdf = gpd.GeoDataFrame(data, crs={'init': 'epsg:4326'})
        return gdf
예제 #11
0
 def buffer_iter(self, distance, unit='mile', alternates=True):
     """Get buffer around each section
     """
     for section_name, gdf in self.trail_iter(alternates=alternates):
         buf = geom.buffer(gdf, distance=distance, unit=unit).unary_union
         yield section_name, buf
예제 #12
0
 def buffer_full(self, distance, unit='mile', alternates=True):
     """
     """
     trail = self.trail_full(alternates=alternates)
     buf = geom.buffer(trail, distance=distance, unit=unit).unary_union
     return buf