<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 How to build a GeoDataFrame
We firstly explore how to do this by using the GeoJSON schema.
See https
Step1:  Notes
Some things that jumped out at me as I read the GeoJSON spec
Step2:  Support in the library
Step3:  For relations
We can build a geo data frame with the raw data from a relation.
Step4:  Looking at relations
These are harder to compute automatically, because the exact interpretation of the sub-elements depends upon context.  However, most relations which have "interesting" geometry (as opposed to giving contextual information on other elements) are of "multi-polygon" type, and can be recognised by the presence of ways with the "role" of "inner" or "outer".
I found that using the shapely library itself was the easiest way to conver the geometry.
There are some cases of geometry which shapely cannot handle.  For example
<ASSISTANT_TASK:>
Python Code:
point_features = [{"geometry": {
               "type": "Point",
               "coordinates": [102.0, 0.5]
            },
           "properties": {
               "prop0": "value0", "prop1": "value1"
           }
       }]
point_data = gpd.GeoDataFrame.from_features(point_features)
point_data
point_data.ix[0].geometry
line_features = [{"geometry": {
               "type": "LineString",
               "coordinates": [[102.0, 0.5], [104, 3], [103, 2]]
           },
           "properties": {
               "prop3": "value3"
           }
       }]
line_data = gpd.GeoDataFrame.from_features(line_features)
line_data
line_data.ix[0].geometry
polygon_features = [{"geometry": {
               "type": "Polygon",
               "coordinates": [[[102.0, 0.5], [104, 3], [102, 2], [102,0.5]]]
           },
           "properties": {
               "prop4": "value4", "prop1": "value1"
           }
       }]
data = gpd.GeoDataFrame.from_features(polygon_features)
data
data.plot()
data.ix[0].geometry
features = []
features.extend(point_features)
features.extend(line_features)
features.extend(polygon_features)
gpd.GeoDataFrame.from_features(features)
Explanation: How to build a GeoDataFrame
We firstly explore how to do this by using the GeoJSON schema.
See https://gist.github.com/sgillies/2217756 for the "__geo_interface__".
But this basically copies GeoJSON, for which see https://tools.ietf.org/html/rfc7946
It's then as simple as this...
End of explanation
type(point_data.geometry[0]), type(line_data.geometry[0]), type(data.geometry[0])
import shapely.geometry
pts = shapely.geometry.LineString([shapely.geometry.Point(0,0), shapely.geometry.Point(1,0), shapely.geometry.Point(1,1)])
df = gpd.GeoDataFrame({"geometry": [pts], "key1":["value1"], "key2":["value2"]})
df
df.ix[0].geometry
Explanation: Notes
Some things that jumped out at me as I read the GeoJSON spec:
Coordinates are always in the order: longitude, latitude.
A "Polygon" is allowed to contain holes.  The "outer" edge should be ordered counter-clockwise, and each "inner" edge (i.e. a "hole") should be clockwise.
If a polygon contains more than one array of points, then the first array is the outer edge, and the rest inner edges.
Lines crossing the anti-meridian need to be split.  (I wonder what OSM does?)
Via using shapely
Under the hood, geopandas uses the shapely library, and we can alternatively build data frames by directly building shapely objects
End of explanation
import osmdigest.geometry as geometry
import osmdigest.sqlite as sq
import os
filename = os.path.join("..", "..", "..", "Data", "california-latest.db")
db = sq.OSM_SQLite(filename)
way = db.complete_way(33088737)
series = geometry.geoseries_from_way(way)
series
gpd.GeoDataFrame(series).T.plot()
way = db.complete_way(285549437)
series = geometry.geoseries_from_way(way)
series
df = gpd.GeoDataFrame(series).T
df
df.plot()
Explanation: Support in the library
End of explanation
relation = db.complete_relation(2866485)
geometry.geodataframe_from_relation(relation)
geometry.geodataframe_from_relation( db.complete_relation(63222) )
Explanation: For relations
We can build a geo data frame with the raw data from a relation.
End of explanation
gen = db.relations()
for _ in range(15):
    next(gen)
relation = next(gen)
print(relation)
series = geometry.geoseries_from_relation(db.complete_relation(relation))
series
gpd.GeoDataFrame(series).T.plot()
Explanation: Looking at relations
These are harder to compute automatically, because the exact interpretation of the sub-elements depends upon context.  However, most relations which have "interesting" geometry (as opposed to giving contextual information on other elements) are of "multi-polygon" type, and can be recognised by the presence of ways with the "role" of "inner" or "outer".
I found that using the shapely library itself was the easiest way to conver the geometry.
There are some cases of geometry which shapely cannot handle.  For example:
- http://www.openstreetmap.org/relation/70986  (A lot of self-intersection, I think).
- http://www.openstreetmap.org/relation/184199  (Ditto).
- http://www.openstreetmap.org/relation/1483140  (Adjoining polygons).
End of explanation
<END_TASK>