def geographical_distance(index1: Index, index2: Index) -> float:
    """Calculate the geodesic distance between two hex centers, in meters.

    >>> i = h3.geo_to_h3(
    ...   numpy.random.random() * 180 - 90,
    ...   numpy.random.random() * 360 - 180,
    ...   RESOLUTION
    ...   )
    >>> i_, neighbors = h3.k_ring_distances(i, 1)
    >>> i_ == {i}
    True
    >>> edge = h3.edge_length(RESOLUTION, 'm')
    >>> ex = 3**0.5 * edge
    >>> ex
    14799.349254643997
    >>> for n in neighbors:
    ...   print(0.7*ex < geographical_distance(i, n) < 1.3*ex
    ...     or geographical_distance(i, n))
    True
    True
    True
    True
    True
    True
    """
    lat1, lon1 = h3.h3_to_geo(index1)
    lat2, lon2 = h3.h3_to_geo(index2)
    return numpy.asarray(GEODESIC.inverse(
        (lon1, lat1),
        (lon2, lat2)))[0, 0]
Beispiel #2
0
def display_test(surf):
    ori = h3.h3_to_geo('882a1072cdfffff')
    des = h3.h3_to_geo('882a100d39fffff')

    y1, x1 = ori
    y2, x2 = des

    display_dot(surf, x1, y1, l_color=BLACK)
    display_dot(surf, x2, y2, l_color=BLACK)

    return 0
Beispiel #3
0
def kring_smoothing(df, hex_col, metric_col, k):
    dfk = df[[hex_col]]
    dfk.index = dfk[hex_col]
    dfs = (dfk[hex_col].apply(lambda x: pd.Series(list(h3.k_ring(x, k)))).
           stack().to_frame('hexk').reset_index(
               1, drop=True).reset_index().merge(df[[
                   hex_col, metric_col
               ]]).fillna(0).groupby(['hexk'])[[metric_col]].sum().divide(
                   (1 + 3 * k * (k + 1))).reset_index().rename(
                       index=str, columns={"hexk": hex_col}))
    dfs['lat'] = dfs[hex_col].apply(lambda x: h3.h3_to_geo(x)[0])
    dfs['lng'] = dfs[hex_col].apply(lambda x: h3.h3_to_geo(x)[1])
    return dfs
Beispiel #4
0
def counts_by_hexagon(df, resolution):
    '''Use h3.geo_to_h3 to index each data point into the spatial index of the specified resolution.
      Use h3.h3_to_geo_boundary to obtain the geometries of these hexagons'''

    #df = df[["latitude","longitude"]]
    df = df[latlong]

    #df["hex_id"] = df.apply(lambda row: h3.geo_to_h3(row["latitude"], row["longitude"], resolution), axis = 1)
    df["hex_id"] = df.apply(
        lambda row: h3.geo_to_h3(row[latlong[0]], row[latlong[1]], resolution),
        axis=1,
        meta=('int'))

    df_aggreg = df.groupby(by="hex_id").size().reset_index()
    df_aggreg.columns = ["hex_id", "value"]
    """
    df_aggreg["geometry"] =  df_aggreg.hex_id.apply(lambda x: 
                                                           {    "type" : "Polygon",
                                                                 "coordinates": 
                                                                [h3.h3_to_geo_boundary(h3_address=x,geo_json=True)]
                                                            }
                                                        )
    """

    df_aggreg["center"] = df_aggreg.hex_id.apply(
        lambda x: {
            "type": "Polygon",
            "coordinates": [h3.h3_to_geo(h3_address=x)]
        },
        meta=('tuple'))

    return df_aggreg
def folium_static_hexagons(df,
                           h3_index_str='h3_index',
                           h3_hex_str='h3_hexagon'):
    feature_collection = []
    for index, row in df.iterrows():
        feature = {
            'type': 'Feature',
            'geometry': {
                'type':
                'Polygon',
                'coordinates':
                [[[elem[1], elem[0]]
                  for elem in row[h3_hex_str] + [row[h3_hex_str][0]]]]
            }
        }
        feature_collection.append(feature)

    f_c = FeatureCollection(feature_collection)

    initial_coords = h3.h3_to_geo(df[h3_index_str][0])
    map_ = folium.Map(location=initial_coords,
                      control_scale=True,
                      zoom_start=9)

    f_json = folium.GeoJson(f_c)

    map_.add_child(f_json)
    return map_
Beispiel #6
0
 def search_position(id):
     lat, lng = h3.h3_to_geo(id)
     xpos = int((lng - extent_.min_lng) // lng_width)
     ypos = int((lat - extent_.min_lat) // lat_width)
     # import pdb
     # pdb.set_trace()
     return n * xpos + ypos
def store_ecocount_in_db(ecoregions: numpy.array, transform: rasterio.Affine,
                         engine: sqlalchemy.engine.Connectable,
                         t_eco: sqlalchemy.Table,
                         t_hex: sqlalchemy.Table) -> None:
    for h, eco_count in hex_ecoregions(ecoregions, transform).items():
        lat, lon = h3.h3_to_geo(h)
        try:
            engine.execute(
                t_hex.insert({
                    "hexbin": h,
                    "longitude": lon,
                    "latitude": lat
                }))
        except sqlalchemy.exc.IntegrityError:
            pass
        for id, freq in eco_count.items():
            try:
                engine.execute(
                    t_eco.insert({
                        "hexbin": h,
                        "ecoregion": id,
                        "frequency": freq
                    }))
            except sqlalchemy.exc.IntegrityError:
                elsewhere = engine.execute(
                    sqlalchemy.select([
                        t_eco.c.frequency
                    ]).where((t_eco.c.hexbin == h)
                             & (t_eco.c.ecoregion == id))).fetchone()[0]
                engine.execute(
                    t_eco.update().where((t_eco.c.hexbin == h)
                                         & (t_eco.c.ecoregion == id)).values(
                                             {"frequency": elsewhere + freq}))
Beispiel #8
0
 def test_h3_to_geo(self):
     latlng = h3.h3_to_geo('85283473fffffff')
     self.assertAlmostEqual(
         latlng[0], 37.34579337536848, None, 'lat center is ok'
     )
     self.assertAlmostEqual(
         latlng[1], -121.97637597255124, None, 'lng center is ok'
     )
Beispiel #9
0
def display_crt_taxi_status(surf, taxi_cls):
    fontObj = pygame.font.Font(TEXT_FONT, 16)
    font_score = pygame.font.Font(TEXT_FONT, 14)


    surf.blit(fontObj.render('Call on : ', False, BLACK), (20, 70))
    surf.blit(fontObj.render('Crt Pos(H3) : ', False, BLACK), (20, 88))
    surf.blit(fontObj.render('Des Pos(H3) : ', False, BLACK), (20, 106))
    surf.blit(fontObj.render('Remain Time : ', False, BLACK), (20, 124))
    surf.blit(fontObj.render('Taxi Status : ', False, BLACK), (20, 142))
    surf.blit(fontObj.render('T-Wait Tm : ', False, BLACK), (20, 160))
    surf.blit(fontObj.render('Driver Prone : ', False, BLACK), (20, 178))

    if taxi_cls.crt_des != None : #taxi_cls.call_status == True:

        #bound_list = h3.h3_to_geo_boundary(taxi_cls.crt_des)
        #adj_bound_list = return_adj_coord(bound_list)

        lat, lon = h3.h3_to_geo(taxi_cls.crt_des)  # array of [lat, lng]
        rtn_adj_coord = return_adj_coord([[lat, lon]])

        #pygame.draw.polygon(surf, BRIGHTBLUE, adj_bound_list, 2)

        pygame.draw.circle(surf, BRIGHTBLUE, (int(rtn_adj_coord[0][0]), int(rtn_adj_coord[0][1])), 3)

        #if taxi_cls.out_cell_move == True:
        #    str_taxi_status = 'Out-cell On'
        #else :
        #    str_taxi_status = 'In-cell On'
    #else :

    if taxi_cls.call_status == True:
        str_calls = 'True'
    else :
        str_calls = 'False'

        #if taxi_cls.out_cell_move == True:
        #    str_taxi_status = 'Out-cell off'
        #else :
        #    str_taxi_status = 'In-cell off'

    str_des = str(taxi_cls.crt_des)
    str_time = str(taxi_cls.crt_move_remain_tm)

    surf.blit(font_score.render(str_calls, False, BLUE), (150, 70))
    surf.blit(font_score.render(str(taxi_cls.crt_pos), False, BLUE), (150, 88))
    surf.blit(font_score.render(str_des, False, BLUE), (150, 106))
    surf.blit(font_score.render(str_time, False, BLUE), (150, 124))
    #surf.blit(font_score.render(str_taxi_status, False, BLUE), (150, 124))
    surf.blit(font_score.render(taxi_cls.str_taxi_status, False, BLUE), (150, 142))
    surf.blit(font_score.render(str(taxi_cls.total_wait_tm), False, BLUE), (150, 160))

    surf.blit(font_score.render(str(taxi_cls.taxi_attribute), False, BLUE), (150, 172))

    return 0
Beispiel #10
0
def make_migration(ctx, filename):
    '''
    '''
    now = datetime.now()
    with open(filename, mode="rt") as f:
        while True:
            data = f.readline()
            if data:
                dt, h3_address_from, h3_address_to, people_count = data.split(
                    ",")
                time_offset = datetime.strptime(dt, "%H:%M")
                time_offset = now.replace(hour=time_offset.hour,
                                          minute=time_offset.minute)
                timestamp = round(time_offset.timestamp())
                coords_from = h3.h3_to_geo(h3_address_from)
                coords_to = h3.h3_to_geo(h3_address_to)
                fields = [timestamp, *coords_from, *coords_to, people_count]
                print(",".join([str(f) for f in fields]))
            else:
                break
Beispiel #11
0
def display_taxi_img(surf, img, h3_coord, car_on = False):

    lat, lon = h3.h3_to_geo(h3_coord)  # array of [lat, lng]

    #rect = img.get_rect()

    rtn_adj_coord = return_adj_coord([[lat,lon]])

    rtn_adj_coord[0][0] = rtn_adj_coord[0][0] - 4
    rtn_adj_coord[0][1] = rtn_adj_coord[0][1] - 8

    surf.blit(img, rtn_adj_coord[0])
Beispiel #12
0
def vector_to_h3(vector_path, value_name, resolution, extent=None, layer=None):
    """Load raster values into h3 dggs cells

    Parameters:
    vector_path (string): path to vector file compatible with Geopandas for uploading
    value_name (string): vector attribute name to load into dggs cells
    resolution (integer): h3 cell resolution to use
    extent (list): extent as array of 2 lon lat pairs to get raster values for
    layer (string): vector layer name if geopackage is used

    Returns:
    Pandas dataframe
   """

    # Open vector to geodataframe
    gdf = gpd.read_file(vector_path, layer)

    # Get extent to fill with h3 hexes
    if extent:
        extent = gpd.GeoSeries(box(extent[0], extent[1], extent[2], extent[3])).__geo_interface__
    else:
        extent = gpd.GeoSeries(
            box(gdf['geometry'].total_bounds[0], gdf['geometry'].total_bounds[1], gdf['geometry'].total_bounds[2],
                gdf['geometry'].total_bounds[3])).__geo_interface__

    # Create dataframe with cell_ids from extent with given resolution
    print(f"Start filling raster extent with h3 indexes at resolution {resolution}")
    h3_gdf = gpd.GeoDataFrame({'cell_id': list(h3.polyfill_geojson(extent['features'][0]["geometry"], res=resolution))})

    # Get hex centroids for points
    h3_gdf['geometry'] = h3_gdf['cell_id'].apply(lambda x: Point(h3.h3_to_geo(x)[1], h3.h3_to_geo(x)[0]))
    hex_gdf = h3_gdf.set_crs('epsg:4326')

    # Spatial join hex centroids with gdf
    vector_h3 = gpd.sjoin(hex_gdf, gdf)

    # Drop unnecessary fields
    vector_h3 = vector_h3[['cell_id', value_name]]

    return vector_h3
Beispiel #13
0
def h3_to_point(dataframe, h3_column='h3'):
    """Convert H3 index in pandas dataframe into longitude and latitude.

    :param: dataframe: pandas dataframe with a column of H3 indices
    :type dataframe: pandas.core.frame.DataFrame
    :param h3_column: column name of the column with the H3 indices,
                      defaults to h3.
    :type h3_column: str, optional
    """
    lat_lon = numpy.array(
        [h3.h3_to_geo(h3hexagon) for h3hexagon in dataframe['h3']])
    dataframe['latitude'] = lat_lon[:, 0]
    dataframe['longitude'] = lat_lon[:, 1]
    return dataframe
Beispiel #14
0
def random_location(candidate_hex_addresses, resolution):
    root_hex = random.choice(candidate_hex_addresses)
    root_resolution = h3.h3_get_resolution(root_hex)

    current_resolution = root_resolution
    current_cell = root_hex

    while current_resolution < resolution:
        # Step up one resolution.
        current_resolution += 1
        # Get all the children of the current cell.
        children = h3.h3_to_children(current_cell, current_resolution)
        # Draw a random child and set it to the current cell.
        current_cell = random.choice(list(children))

    return h3.h3_to_geo(current_cell)
Beispiel #15
0
    def decorated(*args, **kwargs):
        geoframe = kwargs.pop('geoframe', None)
        country = kwargs.pop('country', None)
        polygon = kwargs.pop('polygon', None)
        point = kwargs.pop('point', None)

        number_of_parameter = sum(x is not None
                                  for x in (geoframe, country, polygon, point))
        if number_of_parameter > 1:
            return ("'geoframe', 'country', 'polygon' and "
                    "'point' are mutually exclusive", 400)

        # Parse parameter geoframe
        if geoframe is not None:
            try:
                logger.debug('Try parsing geoframe')
                kwargs['wkt'] = bounding_box_to_wkt(*geoframe)
            except ValueError:
                return 'Invalid geoparam', 400
        # parse parameter country
        elif country is not None:
            logger.debug('Try parsing country')
            try:
                kwargs['wkt'] = get_country_wkt(country.upper())
            except CountryNotFound:
                return 'Unknown country code.', 400
        # parse parameter polygon
        elif polygon is not None:
            try:
                logger.debug('Try parsing polygon')
                kwargs['wkt'] = polygon_to_wkt(polygon)
            except RESTParamError as err:
                return str(err), 400
        # parse parameter point
        elif point is not None:
            try:
                logger.debug('Try to parse point')
                point = h3.h3_to_geo(
                    h3.geo_to_h3(point[1], point[0],
                                 emissionsapi.db.resolution))
                kwargs['wkt'] = f'POINT({point[1]} {point[0]})'
                # Take a radius from 0.01 decimal degree which are approx.
                # 1113 meter
                kwargs['distance'] = 0.01
            except KeyError:
                return 'Invalid point', 400
        return f(*args, **kwargs)
Beispiel #16
0
def data2goolemap(hex_res, data, t):
    cur_time_stamp = int(time.time())
    tmp_dict = {
        'o': b'o',
        'oc': b'oc',
        'd': b'd',
    }
    tmp_time_dict = {
        'o': b'o:t',
        'oc': b'oc:t',
        'd': b'd:t',
    }
    tt = tmp_dict[t]
    ttime = tmp_time_dict[t]
    oc_tt = b'oc'
    oc_ttime = b'oc:t'
    tmp_zip_data = zip(hex_res, data)
    tmp_res = []
    for x in tmp_zip_data:
        val = 0
        if x[1] != {}:
            if tt in x[1] and ttime in x[1] and cur_time_stamp - int(
                    x[1][ttime]) <= key_memory_time and int(x[1][tt]) > 0:
                val += int(x[1][tt])
            # vals related to cancel orders give 5 times weight
            if oc_tt in x[1] and oc_ttime in x[1] and cur_time_stamp - int(
                    x[1][oc_ttime]) <= key_memory_time and int(
                        x[1][oc_tt]) > 0:
                val += int(x[1][oc_tt]) * 5
        if val > 0:
            tmp_res.append([x[0], val])
    print(len(tmp_res))
    s = html_part1 + default_max_point
    for x in range(len(tmp_res)):
        tmp_loc = h3.h3_to_geo(tmp_res[x][0])
        s += data_format % (tmp_loc[0], tmp_loc[1], tmp_res[x][1])
    s += html_part2
    return s
def run_on_one_tile(
        lon: float, lat: float,
        db: sqlalchemy.engine.Engine,
        hex: sqlalchemy.Table, t_dist: sqlalchemy.Table
) -> t.Set[ArrayIndex]:
    """Compute pairwise distances and ecoregion composition

    Given a digital elevation model as raster map and a matching ecoregions
    raster map, compute the pairwise distance to its 1-hex and 2-hex neighbors
    for every H3 address hex at standard resolution, as well as the approximate
    cover of that cell in terms of ecoregions, for all cells where that is
    possible.

    Distances are computed in gross hours of travel while navigating off-track,
    following [@irmischer2018measuring].

    Returns
    =======
    d: A mapping. d[h1][h2] is the distance, in hours, from the center of h1 to
        the center of h2.
    e: A mapping. d[h1][b] is the proportion of hex h1 covered by ecoregion b.

    """
    elevation_file = gmted_tile_from_geocoordinates(lon, lat)
    m_trafo = elevation_file.transform
    height, width = elevation_file.shape
    elevation = numpy.full((height + 1000, width + 1000), -100, int)
    ecoregions = numpy.full((height + 1000, width + 1000), 999, int)
    elevation[500:-500, 500:-500] = elevation_file.read(1)
    ecoregions[500:-500, 500:-500] = ecoregion_tile_from_geocoordinates(lon, lat).read(1)
    print("Loading adjacent data…")
    try:
        elevation[:500, :500] = (gmted_tile_from_geocoordinates(lon - 30, lat + 20)).read(1)[-500:, -500:]
        ecoregions[:500, :500] = ecoregion_tile_from_geocoordinates(lon - 30, lat + 20).read(1)[-500:, -500:]
    except rasterio.RasterioIOError:
        pass
    try:
        elevation[:500, 500:-500] = (gmted_tile_from_geocoordinates(lon, lat + 20)).read(1)[-500:, :]
        ecoregions[:500, 500:-500] = ecoregion_tile_from_geocoordinates(lon, lat + 20).read(1)[-500:, :]
    except rasterio.RasterioIOError:
        pass
    try:
        elevation[:500, -500:] = (gmted_tile_from_geocoordinates(lon + 30, lat + 20)).read(1)[-500:, :500]
        ecoregions[:500, -500:] = ecoregion_tile_from_geocoordinates(lon + 30, lat + 20).read(1)[-500:, :500]
    except rasterio.RasterioIOError:
        pass
    try:
        elevation[500:-500, :500] = (gmted_tile_from_geocoordinates(lon - 30, lat)).read(1)[:, -500:]
        ecoregions[500:-500, :500] = ecoregion_tile_from_geocoordinates(lon - 30, lat).read(1)[:, -500:]
    except rasterio.RasterioIOError:
        pass
    try:
        elevation[500:-500, -500:] = (gmted_tile_from_geocoordinates(lon + 30, lat)).read(1)[:, :500]
        ecoregions[500:-500, -500:] = ecoregion_tile_from_geocoordinates(lon + 30, lat).read(1)[:, :500]
    except rasterio.RasterioIOError:
        pass
    try:
        elevation[-500:, :500] = (gmted_tile_from_geocoordinates(lon - 30, lat - 20)).read(1)[:500, -500:]
        ecoregions[-500:, :500] = ecoregion_tile_from_geocoordinates(lon - 30, lat - 20).read(1)[:500, -500:]
    except rasterio.RasterioIOError:
        pass
    try:
        elevation[-500:, 500:-500] = (gmted_tile_from_geocoordinates(lon, lat - 20)).read(1)[:500, :]
        ecoregions[-500:, 500:-500] = ecoregion_tile_from_geocoordinates(lon, lat - 20).read(1)[:500, :]
    except rasterio.RasterioIOError:
        pass
    try:
        elevation[-500:, -500:] = (gmted_tile_from_geocoordinates(lon + 30, lat - 20)).read(1)[:500, :500]
        ecoregions[-500:, -500:] = ecoregion_tile_from_geocoordinates(lon + 30, lat - 20).read(1)[:500, :500]
    except rasterio.RasterioIOError:
        pass

    print("Computing hex extents…")
    transform = rasterio.Affine(m_trafo.a, 0, m_trafo.c - 500 * m_trafo.a,
                                0, m_trafo.e, m_trafo.f - 500 * m_trafo.e)
    def rowcol(latlon):
        lat, lon = latlon
        if lon > 170:
            # FIXME: We can and need to do this because we are working on the
            # Americas and the Americas only. The generic solution is more
            # difficult.
            lon = lon - 360
        col, row = ~transform * (lon, lat)
        return int(row), int(col)

    center: t.Dict[h3.H3Index, t.Tuple[int, int]] = {}
    cs = sqlalchemy.select([hex.c.hexbin, hex.c.vlongitude, hex.c.vlatitude]).where(hex.c.vlongitude != None)
    for h, lon, lat in db.execute(cs).fetchall():
        row, col = rowcol((lat, lon))
        if 500 <= col < width + 500 and 500 < row < height + 500:
            center[h] = (row, col)

    print("Computing terrain coefficients…")
    terrain_coefficient_raster = TC[ecoregions]

    print("Computing distances on the grid…")
    distance_by_direction = all_pairwise_distances(
        elevation, transform, terrain_coefficient_raster)

    failed: t.Set[ArrayIndex] = set()
    finished: t.Set[ArrayIndex] = set()

    for start, (row, col) in center.items():
        print(f"Computing area around {start:}…")
        lon, lat = transform * (col, row)
        hexbin = h3.geo_to_h3(lat, lon, RESOLUTION)
        this, neighbors1, neighbors2, neighbors3 = list(h3.k_ring_distances(hexbin, 3))
        neighbors: t.Set[h3.H3Index] = neighbors1 | neighbors2
        distance_known = sqlalchemy.select([t_dist.c.hexbin2]).where(
            (t_dist.c.hexbin1 == start) & (t_dist.c.source == 0))
        missing = (neighbors - {k[0] for k in db.execute(distance_known).fetchall()}) & set(center)
        if not missing:
            print("Already known.")
            finished.add(start)
            continue
        print("Not found:", missing)
        if start in failed or start in finished:
            continue

        points = []
        for n in neighbors2 | neighbors3:
            try:
                points.append(center[n])
            except KeyError:
                points.append(rowcol(h3.h3_to_geo(n)))
        rmin = min(p[0] for p in points)
        rmax = max(p[0] for p in points)
        cmin = min(p[1] for p in points)
        cmax = max(p[1] for p in points)
        assert rmin >= 0
        assert cmin >= 0

        def rel_rowcol(latlon):
            lat, lon = latlon
            if lon > 170:
                lon = lon - 360
            col, row = ~transform * (lon, lat)
            return int(row) - rmin, int(col) - cmin

        destinations = [(center[n][0] - rmin, center[n][1] - cmin)
                        for n in neighbors
                        if n in center]

        print(f"Looking for {neighbors:}…")
        distances = distances_from_focus(
            (center[start][0] - rmin, center[start][1] - cmin),
            set(destinations),
            {(n, e): d[rmin-min(n, 0):rmax + 1 - max(0, n),
                       cmin-min(e, 0):cmax + 1 - max(0, e)]
             for (n, e), d in distance_by_direction.items()},
            pred=None
        )

        # For debugging: Output the results
        distances_by_center = {}
        for t, d in center.items():
            try:
                dist = distances[d[0] - rmin, d[1] - cmin]
                if numpy.isfinite(dist):
                    distances_by_center[t] = dist
            except IndexError:
                continue

        print(distances_by_center)

        with db.begin() as conn:
            for n, d in distances_by_center.items():
                try:
                    conn.execute(t_dist.insert({
                        "hexbin1": start,
                        "hexbin2": n,
                        "distance": d,
                        "source": 0}).prefix_with('OR IGNORE'))
                except sqlalchemy.exc.IntegrityError:
                    pass
        finished.add(start)

    return failed
def visualize_hexagons(hexagons_df,
                       legends=True,
                       join_muiltiindex_cols=True,
                       polygon_conf_dict={},
                       folium_map=None,
                       folium_map_config={}):
    """
    Creates a Folium map with hexagons and pop-up legend.
    :param hexagons_df: DataFrame with the H3 index has index.
    :param legends: If 'True', each hexagon will have a pop-up with all the values of its row.
    :param join_muiltiindex_cols: Joins the 'hexagons_df' columns in a single columns, if MultiIndex
    :param polygon_conf_dict: a dict to config the folium.Polygon obj. Ex.:
                {
                    # fill color is True by default, it has to be explicit turned off
                    "color": {"col":"lost_tours", "big_is_better": False, "colormap_legend": "legend", "fill_color": True},
                    "color": {"val":"green"}, # Color can also just be a single value
                    "weight": {"col":"n_bookings", "max": 6, "min":1},
                    "opacity": {"val":0.3},
                    "fill_opacity": {"val":0.15}
                }
                default: opacity: 0.3; fill_opacity: 0.15; weight: 0.5; color: green
    :param folium_map: The folium map obj to had the Hexagons to. If None a new map is created
    :param folium_map_config: default = {"zoom_start": 11,"tiles": 'cartodbpositron', "location": avg_hexagon_location}
                location: The initial lat, long to start the map at. If None tha Avg center of the hexagons will be used.
                zoom_start: the 'folium.Map()' zoom_start value. default 11
                tiles: the 'folium.Map()' tiles value. default 'cartodbpositron'
    :return: Folium map obj
    """

    hexagons_df = hexagons_df.copy()

    hexagons = hexagons_df.index.values
    n_hexs = len(hexagons)
    add_color_map_to_map = False

    # Hexagons popup Legends
    if legends is None or legends is False:
        legends = np.array(n_hexs * [None])
    elif legends is True:
        if join_muiltiindex_cols and type(
                hexagons_df.columns) == pd.MultiIndex:
            hexagons_df.columns = ["-".join(c) for c in hexagons_df.columns]
        hexagons_dict = hexagons_df.to_dict("index")
        legends = [f"{idx}: {hexagons_dict[idx]}" for idx in hexagons]

    # processing Polygon Propreties
    # Adding default Polygon configs
    polygon_conf_dict.setdefault("opacity", {"val": 0.3})
    polygon_conf_dict.setdefault("fill_opacity", {"val": 0.15})
    polygon_conf_dict.setdefault("weight", {"val": 0.5})
    polygon_conf_dict.setdefault("color", {"val": "green"})

    all_poly_props_df = pd.DataFrame()
    for col_name, conf in polygon_conf_dict.items():
        if "col" in conf:
            poly_prop_values = hexagons_df[conf["col"]]
            # Normalize
            if set(("min", "max")).issubset(conf):
                poly_prop_values = (conf["min"] + norm_col(poly_prop_values) *
                                    (conf["max"] - conf["min"])).values
        elif "val" in conf:
            poly_prop_values = len(hexagons_df) * [conf["val"]]
        #     else:
        #         raise Exception("No 'col' or 'val' key found! :(")
        # Processing colors
        if col_name == "color":
            if "col" in conf:
                big_is_better = conf[
                    "big_is_better"] if "big_is_better" in conf else True
                cm_legend = conf[
                    "colormap_legend"] if "colormap_legend" in conf else str(
                        conf["col"]).replace("'", "")
                colormap = ColorMap(np.min(poly_prop_values),
                                    np.max(poly_prop_values), cm_legend,
                                    big_is_better)
                poly_prop_values = [colormap(ci) for ci in poly_prop_values]
                add_color_map_to_map = True
            # Adds fill color by default, it has to be explicit turned off
            if ("fill_color" in conf and conf["fill_color"]) or ("fill_color"
                                                                 not in conf):
                all_poly_props_df["fill_color"] = poly_prop_values

        all_poly_props_df[col_name] = poly_prop_values

    polys_config = list(all_poly_props_df.to_dict("index").values())

    # Initial Location
    if "location" not in folium_map_config:
        location = np.mean([h3.h3_to_geo(h3_id) for h3_id in hexagons], axis=0)
        folium_map_config["location"] = location

    # Creates Folium map
    if folium_map is None:
        folium_map_config.setdefault("zoom_start", 11)
        folium_map_config.setdefault("tiles", 'cartodbpositron')
        m = folium.Map(**folium_map_config)
    else:
        m = folium_map

    # adding polygons
    for hex_id, leg, poly_conf in zip(hexagons, legends, polys_config):
        locations = h3.h3_to_geo_boundary(hex_id)
        folium.Polygon(locations, popup=leg, **poly_conf).add_to(m)
    # adds the colormap legend to the map
    if add_color_map_to_map:
        m.add_child(colormap.colormap)
        colormap.colormap.add_to(m)
    return m
Beispiel #19
0
def decode(h3_address):
    """Decode an h3 address to a lat/lon pair"""
    return h3.h3_to_geo(h3_address)
Beispiel #20
0
import pydeck as pdk

from h3 import h3
#h3_key = h3.geo_to_h3(latitude, longitude, level)
#h3.h3_to_geo_boundary(h3_address=h3_key)
#h3.h3_to_geo_boundary(h3_address=h3_key)

# 2014 locations of car accidents in the UK
UK_ACCIDENTS_DATA = (
    'https://raw.githubusercontent.com/uber-common/deck.gl-data/master/examples/3d-heatmap/heatmap-data.csv'
)
data = pd.read_csv(UK_ACCIDENTS_DATA)

h3_address = h3.geo_to_h3(37.3615593, -122.0553238, 5)
hex_center_coordinates = h3.h3_to_geo(h3_address)
boundary = h3.h3_to_geo_boundary(h3_address)


def lat_lng_to_h3(row):
    return h3.geo_to_h3(row['lat'], row['lng'], 11)


data['h3'] = data.apply(lat_lng_to_h3, axis=1)


def map(data, lat, lon, zoom):
    layer = pdk.Layer(
        "HexagonLayer",
        data=data,
        get_position='[lng, lat]',
Beispiel #21
0
unnested_lst = []
for col in df.columns:
    unnested_lst.append(df[col].apply(pd.Series).stack())
df = pd.concat(unnested_lst, axis=1, keys=df.columns)
df = df.reset_index()
df = df.drop('level_1', axis=1)

# add in district/prov names
df = pd.merge(df,
              matching_districts,
              how='left',
              left_on=['level_0'],
              right_on=['level_0'])

# add lat & lng of center of hex
df['centroid_lat'] = df['h3_hexs'].apply(lambda x: h3.h3_to_geo(x)[0])
df['centroid_long'] = df['h3_hexs'].apply(lambda x: h3.h3_to_geo(x)[1])

# turn h3 hexs into geo. boundary
df['geometry'] = df["h3_hexs"].apply(
    lambda x: h3.h3_to_geo_boundary(h=x, geo_json=True))
# turn to Point
df['geometry'] = df['geometry'].apply(lambda x: [Point(x, y) for [x, y] in x])
# turn to Polygon
df['geometry'] = df['geometry'].apply(
    lambda x: Polygon([[poly.x, poly.y] for poly in x]))

# turn to geoDF
df_geo = gpd.GeoDataFrame(df, geometry="geometry")

# plot to see
Beispiel #22
0
def main():
    """
    """

    # APERTURE_SIZE = 7

    filename = DATA_URL_DICT[3]['name']
    DATA_URL = DATA_URL_DICT[3]['URL']

    gdf = load_geopandas_dataset(DATA_URL=DATA_URL,
                                 dirpath='./data/',
                                 filename=filename)

    if gdf is not None:
        #
        assert gdf.crs is not None
        assert gdf.crs != ""

        st.write(f"gdf.crs: {gdf.crs}")
        gdf = gdf.to_crs(epsg='4326').copy()
        #
        h3_level = 8.5
        gdf[f'H3_{h3_level}'] = gdf.apply(
            lambda row: h3.geo_to_h3(row.geometry.y, row.geometry.x, h3_level),
            axis=1)

        # st.write(gdf.plot())
        # lat, lng, hex resolution
        h3_address = h3.geo_to_h3(58.426172, 17.3623063, h3_level)
        hex_center_coordinates = h3.h3_to_geo(h3_address)
        hex_boundary = h3.h3_to_geo_boundary(h3_address)
        m = visualize_hexagons([h3_address])
        tooltip = "Hexagon center"
        folium.Marker(hex_center_coordinates,
                      popup="Hexagon center",
                      tooltip=tooltip).add_to(m)

        # hexagons = polygonize_hexagons(gdf=gdf, APERTURE_SIZE=8, crs='EPSG:3006')

        #st.write(hexagons)

        # st.write(gdf[f'H3_{h3_level}'].head(20))

        # find all points that fall in the grid polygon
        counts = gdf.groupby([
            f'H3_{h3_level}'
        ])[f'H3_{h3_level}'].agg('count').to_frame('count').reset_index()

        # https://spatialthoughts.com/2020/07/01/point-in-polygon-h3-geopandas/
        # To visualize the results or export it to a GIS, we need to convert the H3 cell ids to a geometry.
        # The h3_to_geo_boundary function takes a H3 key and returns a list of coordinates that form the hexagonal cell.
        # Since GeoPandas uses shapely library for constructing geometries, we convert the list of coordinates
        # to a shapely Polygon object. Note the optional second argument to the h3_to_geo_boundary function which
        # we have set to True which returns the coordinates in the(x, y) order compared to default(lat, lon)

        def add_geometry(row):
            points = h3.h3_to_geo_boundary(row[f'H3_{h3_level}'], True)
            return Polygon(points)

        st.write(counts.head(20))
        counts['geometry'] = counts.apply(add_geometry, axis=1)

        counts_gdf = gpd.GeoDataFrame(counts, crs='EPSG:4326')

        # We turn the dataframe to a GeoDataframe with the CRS EPSG:4326
        # (WGS84 Latitude/Longitude) and write it to a geopackage.
        output_filename = f'./data/gridcounts_H3_{h3_level}.gpkg'
        counts_gdf.to_file(driver='GPKG', filename=output_filename)

        #hexs = h3.polyfill(
        #    gdf.geometry[0].__geo_interface__, APERTURE_SIZE, geo_json_conformant=True)
    """
  
    fig, ax = plt.subplots(figsize=(2, 4))

    geojson_result = latlong_to_geojson_string_h3_geometry(
        latitude_dd=lat_centr_point, longitude_dd=lon_centr_point, resolution=APERTURE_SIZE)

    ax = show_map(
        geojson_result=geojson_result, 
        center_location=[lat_centr_point, lon_centr_point],
        zoom_start=5.5,
        tiles="cartodbpositron")

    #ax = hexagons.plot(alpha=0.5, color="xkcd:pale yellow", figsize=(9, 9))

    st.pyplot(fig)

    #fig, ax = plt.subplots(figsize=(2, 4))
    #world = gpd.read_file(
    #    gpd.datasets.get_path('naturalearth_lowres'))
    #sweden = world.query('name == "Sweden"')    
    #sweden.plot(edgecolor='None', facecolor='lightgray', ax=ax)
    #gdf.plot(ax=ax)
    #ax.axis('off')
    #st.pyplot(fig)
    """
    """
    

    m = visualize_hexagons([h3_address])

    m = visualize_hexagons(list(h3.k_ring_distances(
        h3_address, 4)[3]), color="purple")
    m = visualize_hexagons(list(h3.k_ring_distances(
        h3_address, 4)[2]), color="blue", folium_map=m)
    m = visualize_hexagons(list(h3.k_ring_distances(
        h3_address, 4)[1]), color="green", folium_map=m)
    m = visualize_hexagons(list(h3.k_ring_distances(
        h3_address, 4)[0]), color="red", folium_map=m)

    # add marker for center

    # add marker for Liberty Bell
    tooltip = "Hexagon center"
    folium.Marker(
        hex_center_coordinates, popup="Hexagon center", tooltip=tooltip
    ).add_to(m)
    """
    #geoJson = gdf_to_h3_geojson(gdf=gdf)
    #st.write(geoJson)
    #polyline = geoJson['coordinates'][0]
    """
Beispiel #23
0
 def selector(h3id):
     lat, lng = h3.h3_to_geo(h3id)
     return min_lat <= lat <= max_lat and min_lng <= lng <= max_lng
Beispiel #24
0
def draw_folium(df,
                id_col,
                val_col,
                zoom_start=13,
                control_scale=True,
                bins=None,
                fill_color='YlGn',
                fill_opacity=0.7,
                line_opacity=0.2,
                title=None,
                **kwargs):
    """
        ヒートマップを描画する

        Attributes
        ----------
        df : pandas.core.frame.DataFrame
            対象のデータフレーム
        id_col : str
            表示するデータのidのcolumn名
        val_col : str
            表示するデータのvalueのcloumn名
        zoom_start : int
            foliumのズームの初期位置
        control_scale : bool
            縮尺を表示するかどうか
        bins : list
            choroplethの境界値。valueの最大値よりbinの最大値以上の必要があるので注意
            max(df[val_col]) <= bins[-1]
        fill_color : str
            choroplethの色。以下から選択可能
                ‘BuGn’, ‘BuPu’, ‘GnBu’, ‘OrRd’, ‘PuBu’, ‘PuBuGn’, ‘PuRd’, ‘RdPu’, ‘YlGn’, ‘YlGnBu’, ‘YlOrBr’, ‘YlOrRd’
        fill_opacity : float
            [0,1], 透明度(色塗り)
        line_opacity : float
            [0,1], 透明度(境界)
        title : str
            legend title
    """
    df["h3_lat"], df["h3_lng"] = zip(*df[id_col].apply(lambda x: h3.h3_to_geo(
        x)))  # h3.h3_to_geo has a proper (lat, lng) output
    location = [df["h3_lat"].mean(), df["h3_lng"].mean()]  #[lat,lng]

    fmap = folium.Map(location=location,
                      zoom_start=zoom_start,
                      control_scale=control_scale)

    copyright = ' <a href="https://www.datawise.co.jp/">  | © DATAWISE   </a>,'
    folium.raster_layers.TileLayer(
        tiles='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
        name='OpenStreetMap2',
        attr=copyright,
        overlay=True).add_to(fmap)

    df[id_col] = df[id_col].astype('str')
    geojson = {"type": "FeatureCollection", "features": []}

    df["h3_boundary"] = df[id_col].apply(
        lambda x: tuple((lat, lng) for lng, lat in h3.h3_to_geo_boundary(x))
    )  # Switching lat, lng position because h3.h3_to_geo_boundary has a reverted output.

    def _process_tpl(id_col, h3_boundary):
        tpl = {
            "type": "Feature",
            "geometry": {
                "type": "Polygon",
                "coordinates": []
            }
        }
        tpl["geometry"]["coordinates"].append(h3_boundary)
        tpl["id"] = id_col
        return tpl

    df["tpl"] = df[[id_col,
                    "h3_boundary"]].apply(lambda x: _process_tpl(x[0], x[1]),
                                          axis=1)
    geojson["features"].extend(df["tpl"])
    geojson = json.dumps(geojson)

    if bins is None:
        max_ = df.sort_values(val_col,
                              ascending=False).reset_index()[val_col][0]
        bins = [max_ / 5 * i for i in range(6)]
    if title is None:
        title = val_col
    folium.Choropleth(
        geojson,  # GeoJSONデータ
        name='choropleth',
        data=df,  # DataFrameまたはSeriesを指定
        columns=[id_col, val_col],  # 行政区分コードと表示データ
        key_on='feature.id',  # GeoJSONのキー(行政区分コード)
        fill_color=fill_color,  # 色パレットを指定(※)
        bins=bins,  # 境界値を指定
        fill_opacity=fill_opacity,  # 透明度(色塗り)
        line_opacity=line_opacity,  # 透明度(境界)
        legend_name=title,  # 凡例表示名
        highlight=True,
        **kwargs).add_to(fmap)

    return fmap
 def from_h3(cls: t.Type[P], index: Index) -> P:
     lat, lon = h3.h3_to_geo(index)
     return cls(lon, lat)
Beispiel #26
0
 def decode(self, sId):
     """decode a geohash calling the original library"""
     return h3.h3_to_geo(sId)
Beispiel #27
0
def H3ToGeo(h3_id):
    return h3.h3_to_geo(h3_id)
Beispiel #28
0
    def gen_hexagons(self, resolution, city):
        '''
        Converts an input multipolygon layer to H3 hexagons given a resolution.

        Parameters
        ----------

        resolution: int, 0:15
                    Hexagon resolution, higher values create smaller hexagons.

        city: GeoDataFrame
              Input city polygons to transform into hexagons.

        Returns
        -------

        city_hexagons: GeoDataFrame
                       Hexagon geometry GeoDataFrame (hex_id, geom).

        city_centroids: GeoDataFrame
                        Hexagon centroids for the specified city (hex_id, geom).

        Example
        -------

        >> lima = filter_population(pop_lima, poly_lima)
        >> lima_hex = gen_hexagons(8, lima)

        	0	            | geometry
	        888e620e41fffff | POLYGON ((-76.80007 -12.46917, -76.80439 -12.4...
	        888e62c809fffff | POLYGON ((-77.22539 -12.08663, -77.22971 -12.0...
	        888e62c851fffff | POLYGON ((-77.20708 -12.08484, -77.21140 -12.0...
	        888e62c841fffff | POLYGON ((-77.22689 -12.07104, -77.23122 -12.0...
	        888e62c847fffff | POLYGON ((-77.23072 -12.07929, -77.23504 -12.0...

            0	            | geometry
            888e620e41fffff | POINT (-76.79956 -12.47436)
            888e62c809fffff | POINT (-77.22488 -12.09183)
            888e62c851fffff | POINT (-77.20658 -12.09004)
            888e62c841fffff | POINT (-77.22639 -12.07624)
            888e62c847fffff | POINT (-77.23021 -12.08448)

        '''

        # Polyfill the city boundaries
        h3_centroids = list()
        h3_polygons = list()
        h3_indexes = list()

        # Get every polygon in Multipolygon shape
        city_poly = city.explode().reset_index(drop=True)

        for ix, geo in city_poly.iterrows():
            hexagons = h3.polyfill(geo['geometry'].__geo_interface__, res=resolution, \
                                    geo_json_conformant=True)
            for hexagon in hexagons:
                centroid_lat, centroid_lon = h3.h3_to_geo(
                    hexagon)  # format as x,y (lon, lat)
                h3_centroids.append(Point(centroid_lon, centroid_lat))

                h3_geo_boundary = h3.h3_to_geo_boundary(hexagon)
                [bound.reverse()
                 for bound in h3_geo_boundary]  # format as x,y (lon, lat)
                h3_polygons.append(Polygon(h3_geo_boundary))

                h3_indexes.append(hexagon)

        # Create hexagon dataframe
        city_hexagons = gpd.GeoDataFrame(
            h3_indexes, geometry=h3_polygons).drop_duplicates()
        city_hexagons.crs = 'EPSG:4326'
        city_centroids = gpd.GeoDataFrame(
            h3_indexes, geometry=h3_centroids).drop_duplicates()
        city_centroids.crs = 'EPSG:4326'

        return city_hexagons, city_centroids
Beispiel #29
0
def run_on_one_tile(lon: float, lat: float, db: sqlalchemy.engine.Engine,
                    hex: sqlalchemy.Table,
                    t_dist: sqlalchemy.Table) -> t.Set[ArrayIndex]:
    """Compute pairwise distances and ecoregion composition

    Given a digital elevation model as raster map and a matching ecoregions
    raster map, compute the pairwise distance to its 1-hex and 2-hex neighbors
    for every H3 address hex at standard resolution, as well as the approximate
    cover of that cell in terms of ecoregions, for all cells where that is
    possible.

    Distances are computed in gross hours of travel while navigating off-track,
    following [@irmischer2018measuring].

    Returns
    =======
    d: A mapping. d[h1][h2] is the distance, in hours, from the center of h1 to
        the center of h2.
    e: A mapping. d[h1][b] is the proportion of hex h1 covered by ecoregion b.

    """
    print("Working on hex around ({:}, {:}):".format(lon, lat))
    elevation_file = gmted_tile_from_geocoordinates(lon, lat)
    m_trafo = elevation_file.transform
    height, width = elevation_file.shape
    elevation = numpy.full((height + 1000, width + 1000), -100, int)
    ecoregions = numpy.full((height + 1000, width + 1000), 999, int)
    elevation[500:-500, 500:-500] = elevation_file.read(1)
    ecoregions[500:-500,
               500:-500] = ecoregion_tile_from_geocoordinates(lon, lat).read(1)
    print("Loading adjacent data…")
    try:
        elevation[:500, :500] = (gmted_tile_from_geocoordinates(
            lon - 30, lat + 20)).read(1)[-500:, -500:]
        ecoregions[:500, :500] = ecoregion_tile_from_geocoordinates(
            lon - 30, lat + 20).read(1)[-500:, -500:]
    except rasterio.RasterioIOError:
        pass
    try:
        elevation[:500, 500:-500] = (gmted_tile_from_geocoordinates(
            lon, lat + 20)).read(1)[-500:, :]
        ecoregions[:500, 500:-500] = ecoregion_tile_from_geocoordinates(
            lon, lat + 20).read(1)[-500:, :]
    except rasterio.RasterioIOError:
        pass
    try:
        elevation[:500, -500:] = (gmted_tile_from_geocoordinates(
            lon + 30, lat + 20)).read(1)[-500:, :500]
        ecoregions[:500, -500:] = ecoregion_tile_from_geocoordinates(
            lon + 30, lat + 20).read(1)[-500:, :500]
    except rasterio.RasterioIOError:
        pass
    try:
        elevation[500:-500, :500] = (gmted_tile_from_geocoordinates(
            lon - 30, lat)).read(1)[:, -500:]
        ecoregions[500:-500, :500] = ecoregion_tile_from_geocoordinates(
            lon - 30, lat).read(1)[:, -500:]
    except rasterio.RasterioIOError:
        pass
    try:
        elevation[500:-500, -500:] = (gmted_tile_from_geocoordinates(
            lon + 30, lat)).read(1)[:, :500]
        ecoregions[500:-500, -500:] = ecoregion_tile_from_geocoordinates(
            lon + 30, lat).read(1)[:, :500]
    except rasterio.RasterioIOError:
        pass
    try:
        elevation[-500:, :500] = (gmted_tile_from_geocoordinates(
            lon - 30, lat - 20)).read(1)[:500, -500:]
        ecoregions[-500:, :500] = ecoregion_tile_from_geocoordinates(
            lon - 30, lat - 20).read(1)[:500, -500:]
    except rasterio.RasterioIOError:
        pass
    try:
        elevation[-500:, 500:-500] = (gmted_tile_from_geocoordinates(
            lon, lat - 20)).read(1)[:500, :]
        ecoregions[-500:, 500:-500] = ecoregion_tile_from_geocoordinates(
            lon, lat - 20).read(1)[:500, :]
    except rasterio.RasterioIOError:
        pass
    try:
        elevation[-500:, -500:] = (gmted_tile_from_geocoordinates(
            lon + 30, lat - 20)).read(1)[:500, :500]
        ecoregions[-500:, -500:] = ecoregion_tile_from_geocoordinates(
            lon + 30, lat - 20).read(1)[:500, :500]
    except rasterio.RasterioIOError:
        pass

    print("Computing hex extents…")
    transform = rasterio.Affine(m_trafo.a, 0, m_trafo.c - 500 * m_trafo.a, 0,
                                m_trafo.e, m_trafo.f - 500 * m_trafo.e)

    def rowcol(latlon):
        lat, lon = latlon
        if lon > 170:
            # FIXME: We can and need to do this because we are working on the
            # Americas and the Americas only. The generic solution is more
            # difficult.
            lon = lon - 360
        col, row = ~transform * (lon, lat)
        return int(row), int(col)

    starts: t.List[h3.H3Index] = []
    cs = sqlalchemy.select(
        [hex.c.hexbin, hex.c.longitude, hex.c.latitude, hex.c.habitable])
    for h, lon, lat, habitable in db.execute(cs).fetchall():
        if not habitable:
            continue
        row, col = rowcol((lat, lon))
        if 500 <= col < width + 500 and 500 < row < height + 500:
            starts.append(h)

    print("Computing terrain coefficients…")
    terrain_coefficient_raster = TC[ecoregions]

    print("Computing distances on the grid…")
    distance_by_direction = all_pairwise_distances(elevation, transform,
                                                   terrain_coefficient_raster)

    print("Computing central nodes…")
    center = {}
    partial = set()
    belongs = {}
    for row in range(ecoregions.shape[0]):
        incomplete = set()
        for col in range(ecoregions.shape[1]):
            lon, lat = transform * (col, row)
            hexbin = h3.geo_to_h3(lat, lon, RESOLUTION)
            incomplete.add(hexbin)
            if row == 0 or col < 10 or ecoregions.shape[1] - 10 <= col:
                partial.add(hexbin)
                try:
                    del belongs[hexbin]
                except KeyError:
                    pass
            elif hexbin not in partial:
                belongs.setdefault(hexbin, set()).add((row, col))
        for hexbin in set(belongs) - incomplete:
            print(f"Checking {hexbin}…")
            points = belongs.pop(hexbin)
            if hexbin in partial:
                print("Not competely in this tile.")
                continue
            result = engine.execute(
                sqlalchemy.select([
                    hex.c.habitable, hex.c.vlongitude, hex.c.vlatitude,
                    hex.c.longitude, hex.c.latitude
                ]).where(hex.c.hexbin == hexbin)).fetchone()
            if not result:
                center[hexbin] = rowcol(h3.h3_to_geo(hexbin))
                print(
                    "WHAT IS THIS??? THIS HEX ({:}, {:}) IS NOT IN THE DB!!!!".
                    format(*center[hexbin]))
                continue
            h, vlon, vlat, lon, lat = result
            if vlon is not None and vlat is not None:
                print("Known in DB.")
                center[hexbin] = rowcol((vlat, vlon))
                continue
            if lon and lat and not h:
                print("Uninhabitable.")
                center[hexbin] = rowcol((lat, lon))
                continue
            print("Computing centralities…")
            engine.execute(hex.update().where(hex.c.hexbin == hexbin).values({
                "vlatitude":
                0.0,
                "vlongitude":
                0.0
            }))
            rmin = min(p[0] for p in points)
            rmax = max(p[0] for p in points)
            cmin = min(p[1] for p in points)
            cmax = max(p[1] for p in points)
            assert rmin >= 0
            assert cmin >= 0

            dist = {(n, e): d[rmin - min(n, 0):rmax + 1 - max(0, n),
                              cmin - min(e, 0):cmax + 1 - max(0, e)]
                    for (n, e), d in distance_by_direction.items()}

            border = [
                (i - rmin, j - cmin) for (i, j) in points
                if (i - 1, j) not in points or (i + 1, j) not in points or (
                    i, j - 1) not in points or (i, j + 1) not in points
            ]

            c = t.Counter()
            max_dist = 0
            for r0, c0 in border:
                pred = {(r0, c0): None}
                all_dist = distances_from_focus((r0, c0),
                                                set(border),
                                                dist,
                                                pred=pred)
                for b1 in border:
                    n = b1
                    while pred[n]:
                        n = pred[n]
                        c[n] += 1
                max_dist = max(max_dist, all_dist.max())
            (r0, c0), centrality = c.most_common(1)[0]
            center[hexbin] = (r0 + rmin, c0 + cmin)
            print(hexbin, center[hexbin], centrality)
            lon, lat = transform * (c0 + cmin, r0 + rmin)
            rlat, rlon = h3.h3_to_geo(hexbin)
            print(
                f"Centalic node at ({lon}, {lat}). [Actual center at ({rlon}, {rlat}).]"
            )
            engine.execute(hex.update().where(hex.c.hexbin == hexbin).values({
                "vlatitude":
                lat,
                "vlongitude":
                lon
            }))
            try:
                db.execute(
                    t_dist.insert({
                        "hexbin1": hexbin,
                        "hexbin2": hexbin,
                        "flat_distance": 0.0,
                        "distance": max_dist,
                        "source": 4
                    }))
            except sqlalchemy.exc.IntegrityError:
                pass
Beispiel #30
0
def h3_hex_centroid(hex):
    """
  Get the centroid from a h3 hex location
  """
    (lat, lon) = h3.h3_to_geo(hex)
    return {"lat": lat, "lon": lon}