Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Define a streetTalk() function that takes a lat/lng pair and a city name as inputs, and returns a conversational string stating nearest street as well as enclosing streets #5

Open
dmarulli opened this issue Dec 19, 2017 · 7 comments

Comments

@dmarulli
Copy link
Contributor

dmarulli commented Dec 19, 2017

This function can use the nearestSegment() and intersectingStreets() functions.

@dmarulli dmarulli changed the title Compare street names of intersecting streets with original segment to determine to/from streets Define a streetTalk() function that takes a lat/lng pair and a city name as inputs, and returns a conversational string stating nearest street as well as enclosing streets Dec 19, 2017
@YukunVVan
Copy link
Collaborator

I'm going to design the function as below:

def streetTalk(point,cityname,networkType='drive'):
    '''
    This function takes a lat/lng pair and a city name as inputs, and returns
    a conversational string stating nearest street as well as enclosing streets
    point: shapely.geometry.Point
    cityname: string
    networkType: string
    '''
    try:
        #If the map of city is downloaded, use them directly
        citymap_node = gpd.read_file('data/'+cityname+'/nodes/nodes.shp')
        citymap_edge = gpd.read_file('data/'+cityname+'/edges/edges.shp')
    except:
        #If the map is not downloaded, download the map of city via OpenStreetMap
        G = ox.graph_from_place(cityname + ', USA', network_type=networkType)
        #Save the map in shapefile locally
        ox.save_load.save_graph_shapefile(G, filename=cityname, folder=None, encoding='utf-8')
        print('Map of ' + cityname + 'is saved in shapefile locally!')
        citymap_node = gpd.read_file('data/'+cityname+'/nodes/nodes.shp')
        citymap_edge = gpd.read_file('data/'+cityname+'/edges/edges.shp')
    
    nearest_name, nearest_id, from_id, to_id = nearestSegment(point,citymap_edge)
    intersectingStreets(from_id)
    intersectingStreets(to_id)
    return conversational_string

Need to confirm:

  1. what's the input format of lat/lon pair?
  2. can we use from_id/to_id directly as I mentioned in issue for intersectingStreets()?

@dmarulli
Copy link
Contributor Author

dmarulli commented Jan 1, 2018

We will still need to add a step to compare the nearest_name to the names of the intersectingStreets in order to know which are the enclosing streets, but looks like a great start.

And to be explicit about your questions:

  1. For the input, let's use the actual latitude/longitude coordinates as opposed to some more abstract data structure.
  2. Yes, using the from_id/to_id directly as opposed to doing a spatial query is a great idea.

@dmarulli
Copy link
Contributor Author

dmarulli commented Jan 6, 2018

One thought I am having for this piece is that if we want to use this function on each record in a dataset, we shouldn't be loading the shapefile on each run if all points in the dataset are in the same city.

One way to handle this might be to explicitly create a global variable within the function and check to see if that variable is defined before loading in the shapefile.

Something like: globals()['citymap_edge'] = gpd.read_file('data/'+cityname+'/edges/edges.shp')

Perhaps there is a more elegant solution though.

@YukunVVan
Copy link
Collaborator

David, thanks for insight!!! It really helps to improve the performance! If there are multiple cities in one dataset, then we'd better to set different key for each cities. Here is the code I have. Any advice?

def streetTalk(lon,lat,cityname,networkType='drive'):
    '''
    This function takes a lat/lng pair and a city name as inputs, and returns
    a conversational string stating nearest street as well as enclosing streets
    lon: float, longitude
    lat: float, latitude
    cityname: string
    networkType: string
    '''
    
    if cityname not in globals():
        try:
            #If the map of city is downloaded, use them directly
            globals()[cityname] = gpd.read_file('data/'+cityname+'/edges/edges.shp')
        except:
            #If the map is not downloaded, download the map of city via OpenStreetMap
            G = ox.graph_from_place(cityname + ', USA', network_type=networkType)
            #Save the map in shapefile locally
            ox.save_load.save_graph_shapefile(G, filename=cityname, folder=None, encoding='utf-8')
            print('Map of ' + cityname + 'is saved in shapefile locally!')
            #citymap_node = gpd.read_file('data/'+cityname+'/nodes/nodes.shp')
            globals()[cityname] = gpd.read_file('data/'+cityname+'/edges/edges.shp')
    
    citymap_edge = globals()[cityname]
    
    point = Point(lon,lat)
    nearest_name, nearest_id, from_id, to_id = nearestSegment(point,citymap_edge)
    
    enclosing_from = intersectingStreets(from_id,citymap_edge)
    enclosing_to = intersectingStreets(to_id,citymap_edge)
    
    street_from  = enclosing_from[1] if enclosing_from[0] == nearest_name else enclosing_from[0]
    street_to  = enclosing_to[1] if enclosing_to[0] == nearest_name else enclosing_to[0]

    conversational = "{} between {} and {}".format(nearest_name,street_from,street_to)
    return conversational

@dmarulli
Copy link
Contributor Author

dmarulli commented Jan 7, 2018

Okay, awesome.

Let's assume each dataset represents a single city for now.

And code looks great to me. My only advice would be to catch the edge cases we saw earlier with something like:

try:
       street_from  = enclosing_from[1] if enclosing_from[0] == nearest_name else enclosing_from[0]
       street_to  = enclosing_to[1] if enclosing_to[0] == nearest_name else enclosing_to[0]
       conversational = "{} between {} and {}".format(nearest_name,street_from,street_to)
   except:
       conversational = nearest_name
       
   return conversational

My thinking is let's wrap up a stable version and start a nice write up. The write-up can include thinking creatively about use cases outside of SQUID and/or explaining what is going on technically; or both. Basically the idea with the write-up is to have something for you to show off. We will publish it and push it out into our network, but feel free to take it in whichever direction you feel will be most useful for you.

After getting that started, we can circle back to updating the code if we want to add anything additional. (For example, it might be useful to explicitly identify points that are in intersections as opposed to on street segments.)

@YukunVVan
Copy link
Collaborator

Hi David, the code has been updated several days ago. For the write-up, do I need to write the blog post based on the original one, or to write a new one based on what we did? And after the write-up, will we continue to develop an API described in original post?

@dmarulli
Copy link
Contributor Author

dmarulli commented Jan 16, 2018

Hey Yukun -

The plan for this project was to create the open-source streetTalk() function. So I have not scoped out an implementation plan for the other pieces. However, we can hop on a call together next week to sketch that out if you would like. Just let me know.

A recommendation for the write-up would be describing motivations for creating this more conversational way of referencing locations--these could come from the original blog post, this repo's README, and/or any applications you have in mind. The write-up would also include approach we took.

To reiterate though: at the end of the day, the write-up is for you to present your work. So please feel free to take it in a different direction if you would prefer that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants