def paleolithology(request): anchor_plate_id = request.GET.get('pid', 0) time = request.GET.get('time', 0) model = request.GET.get('model', settings.MODEL_DEFAULT) model_dict = get_reconstruction_model_dict(model) rotation_model = pygplates.RotationModel([ str('%s/%s/%s' % (settings.MODEL_STORE_DIR, model, rot_file)) for rot_file in model_dict['RotationFile'] ]) paleolithology_datafile = '%s/boucot_paleolithology_combined.shp' % settings.PALEO_STORE_DIR static_polygons_filename = str( '%s/%s/%s' % (settings.MODEL_STORE_DIR, model, model_dict['StaticPolygons'])) #select points based on age before doing plate id assignment - should be quicker?? paleolithology_points = pygplates.FeatureCollection( paleolithology_datafile) valid_points = [] for point in paleolithology_points: if point.get_valid_time()[0] > float( time) and point.get_valid_time()[1] <= float(time): valid_points.append(point) print(valid_points) assigned_features = pygplates.partition_into_plates( static_polygons_filename, rotation_model, valid_points, properties_to_copy=[ pygplates.PartitionProperty.reconstruction_plate_id ], partition_method=pygplates.PartitionMethod.most_overlapping_plate) reconstructed_paleolithology_points = [] pygplates.reconstruct(assigned_features, rotation_model, reconstructed_paleolithology_points, float(time), anchor_plate_id=anchor_plate_id) ret = write_json_reconstructed_point_features( reconstructed_paleolithology_points, attributes=[('LithCode', 'string'), ('Period', 'string')]) #add header for CORS #http://www.html5rocks.com/en/tutorials/cors/ response = HttpResponse(ret, content_type='application/json') #TODO: #The "*" makes the service wide open to anyone. We should implement access control when time comes. response['Access-Control-Allow-Origin'] = '*' return response
def test_post(request): if not request.method == "POST": return HttpResponseBadRequest('expecting post requests!') else: #print request.POST json_feature_collection = json.loads(request.body) model = request.GET.get('model', settings.MODEL_DEFAULT) features = [] for json_feature in json_feature_collection['features']: feature = pygplates.Feature() point = json_feature['geometry']['coordinates'] feature.set_geometry(pygplates.PointOnSphere(point[1], point[0])) feature.set_valid_time(json_feature['properties']['age'], 0) features.append(feature) model_dict = get_reconstruction_model_dict(model) rotation_model = pygplates.RotationModel([ str('%s/%s/%s' % (settings.MODEL_STORE_DIR, model, rot_file)) for rot_file in model_dict['RotationFile'] ]) static_polygons_filename = str( '%s/%s/%s' % (settings.MODEL_STORE_DIR, model, model_dict['StaticPolygons'])) # assign plate-ids to points using static polygons assigned_point_features = pygplates.partition_into_plates( static_polygons_filename, rotation_model, features, properties_to_copy=[ pygplates.PartitionProperty.reconstruction_plate_id ]) feature_collection = pygplates.FeatureCollection( assigned_point_features) reconstructed_features = reconstruct_to_birth_time( feature_collection, rotation_model) # prepare the response to be returned ret = '{"coordinates":[' for g in reconstructed_features: ret += '[{0:5.2f},{1:5.2f}],'.format( g.get_geometry().to_lat_lon()[1], g.get_geometry().to_lat_lon()[0]) ret = ret[0:-1] ret += ']}' return HttpResponse(ret, content_type='application/json')
def subduction(request): if not request.method == "POST": return HttpResponseBadRequest('expecting post requests!') else: #print request.POST json_feature_collection = json.loads(request.body) model = request.GET.get('model', settings.MODEL_DEFAULT) features = [] for json_feature in json_feature_collection['features']: feature = pygplates.Feature() point = json_feature['geometry']['coordinates'] feature.set_geometry(pygplates.PointOnSphere(point[1], point[0])) feature.set_valid_time(json_feature['properties']['age'], 0) features.append(feature) model_dict = get_reconstruction_model_dict(model) rotation_model = pygplates.RotationModel([ str('%s/%s/%s' % (settings.MODEL_STORE_DIR, model, rot_file)) for rot_file in model_dict['RotationFile'] ]) static_polygons_filename = str( '%s/%s/%s' % (settings.MODEL_STORE_DIR, model, model_dict['StaticPolygons'])) # assign plate-ids to points using static polygons assigned_point_features = pygplates.partition_into_plates( static_polygons_filename, rotation_model, features, properties_to_copy=[ pygplates.PartitionProperty.reconstruction_plate_id ]) seed_point_features = pygplates.FeatureCollection( assigned_point_features) df_OreDepositBirthTimeStats = subduction_parameters( seed_point_features, rotation_model) html_table = df_OreDepositBirthTimeStats.to_html(index=False) return render(request, 'list_template.html', {'html_table': html_table})
def get_plate_id(lons, lats, static_polygons, rotation_model): p_len = len(lons) assert (p_len == len(lats)), 'The lons and lats must have the same length.' point_features = [] for i in range(p_len): point = pygplates.PointOnSphere(float(lats[i]), float(lons[i])) point_feature = pygplates.Feature() point_feature.set_geometry(point) point_feature.set_name(str(i)) point_features.append(point_feature) plate_ids = [np.nan] * p_len # partition features points = pygplates.partition_into_plates(static_polygons, rotation_model, point_features) for p in points: plate_ids[int(p.get_name())] = p.get_reconstruction_plate_id() return plate_ids
def reconstruct_points(request): points = request.GET.get('points', None) plate_id = request.GET.get('pid', None) time = request.GET.get('time', None) rotation_model = pygplates.RotationModel( MODEL_DEFAULT+"Seton_etal_ESR2012_2012.1.rot") static_polygons_filename = \ MODEL_DEFAULT+"Seton_etal_ESR2012_StaticPolygons_2012.1.gpmlz" point_features = [] if points: ps = points.split(',') if len(ps)%2==0: for lat,lon in zip(ps[1::2], ps[0::2]): point_feature = pygplates.Feature() point_feature.set_geometry(pygplates.PointOnSphere(float(lat),float(lon))) point_features.append(point_feature) #for f in point_features: # f.set_reconstruction_plate_id(int(plate_id)) assigned_point_features = pygplates.partition_into_plates( static_polygons_filename, rotation_model, point_features, properties_to_copy = [ pygplates.PartitionProperty.reconstruction_plate_id, pygplates.PartitionProperty.valid_time_period]) assigned_point_feature_collection = pygplates.FeatureCollection(assigned_point_features) reconstructed_feature_geometries = [] pygplates.reconstruct(assigned_point_feature_collection, rotation_model, reconstructed_feature_geometries, float(time)) ret='{"coordinates":[' for g in reconstructed_feature_geometries: ret+='[{0:5.2f},{1:5.2f}],'.format( g.get_reconstructed_geometry().to_lat_lon()[1], g.get_reconstructed_geometry().to_lat_lon()[0]) ret=ret[0:-1] ret+=']}' return HttpResponse(ret, content_type='application/json')
def reconstruct_files(request): if not request.method == "POST": return HttpResponseBadRequest('expecting post requests!') try: print((request.FILES)) if not len(list(request.FILES.items())): return HttpResponseBadRequest("No File Received") if not os.path.isdir(settings.MEDIA_ROOT + "/rftmp"): os.makedirs(settings.MEDIA_ROOT + "/rftmp" ) reconstructable_files = [] for fs in request.FILES.lists(): for f in fs[1]: print((f.name)) (name,ext) = os.path.splitext(f.name) if ext in ['.shp', '.gpml','.gpmlz']: reconstructable_files.append(f.name) with open(settings.MEDIA_ROOT + "/rftmp/" + f.name, 'wb+') as fp: for chunk in f.chunks(): fp.write(chunk) time = request.POST.get('time', None) model = request.POST.get('model',settings.MODEL_DEFAULT) print(model) model_dict = get_reconstruction_model_dict(model) if not model_dict: return HttpResponseBadRequest('The "model" ({0}) cannot be recognized.'.format(model)) rotation_model = pygplates.RotationModel([str('%s/%s/%s' % (settings.MODEL_STORE_DIR,model,rot_file)) for rot_file in model_dict['RotationFile']]) static_polygons_filename = str('%s/%s/%s' % (settings.MODEL_STORE_DIR,model,model_dict['StaticPolygons'])) for f in reconstructable_files: #print(f) features = pygplates.partition_into_plates( static_polygons_filename, rotation_model, (settings.MEDIA_ROOT + "/rftmp/" + f).encode("utf-8"), partition_method = pygplates.PartitionMethod.most_overlapping_plate, properties_to_copy = [pygplates.PartitionProperty.reconstruction_plate_id, pygplates.PartitionProperty.valid_time_period] ) feature_collection = pygplates.FeatureCollection(features) feature_collection.write((settings.MEDIA_ROOT + "/rftmp/" + f+'.partitioned.gpml').encode("utf-8")) if not os.path.isdir(settings.MEDIA_ROOT + "/rftmp/dst/"): os.makedirs(settings.MEDIA_ROOT + "/rftmp/dst/" ) pygplates.reconstruct((settings.MEDIA_ROOT + "/rftmp/" + f+'.partitioned.gpml').encode("utf-8"), rotation_model, ((settings.MEDIA_ROOT + "/rftmp/dst/" + f + '_' + model + '_' + str(time) + 'Ma').replace('.','_') + '.shp').encode("utf-8"), float(time)) s = io.StringIO() zf = zipfile.ZipFile(s, "w") #settings.MEDIA_ROOT + '/rftmp/dst/reconstructed_files.zip', 'w', zipfile.ZIP_DEFLATED) for r, d, files in os.walk(settings.MEDIA_ROOT + "/rftmp/dst/"): if not files: return HttpResponseServerError('No output files have been created!') for f in files: zf.write(os.path.join(r, f), 'reconstructed_files/'+f) zf.close() #f = StringIO(file(settings.MEDIA_ROOT + '/rftmp/dst/reconstructed_files.zip', "rb").read()) response = HttpResponse(s.getvalue(), content_type = 'application/x-zip-compressed') response['Content-Disposition'] = 'attachment; filename=reconstructed_files.zip' #clear_folder(settings.MEDIA_ROOT + "/rftmp" ) #clear_folder(settings.MEDIA_ROOT + "/rftmp/dst") return response except: clear_folder(settings.MEDIA_ROOT + "/rftmp" ) clear_folder(settings.MEDIA_ROOT + "/rftmp/dst") traceback.print_stack() traceback.print_exc(file=sys.stdout) err = traceback.format_exc() return HttpResponseBadRequest(err)
def reconstruct_feature_collection(request): if request.method == 'POST': params = request.POST elif request.method == 'GET': params = request.GET else: return HttpResponseBadRequest('Unrecognized request type') anchor_plate_id = params.get('pid', 0) if 'time' in params: time = params['time'] elif 'geologicage' in params: time = params['geologicage'] else: time = 140 #default reconstruction age output_format = params.get('output', 'geojson') fc_str = params.get('feature_collection') model = str(params.get('model',settings.MODEL_DEFAULT)) if 'keep_properties' in params: keep_properties = True else: keep_properties = False try: timef = float(time) except: return HttpResponseBadRequest('The "time" parameter is invalid ({0}).'.format(time)) try: anchor_plate_id = int(anchor_plate_id) except: return HttpResponseBadRequest('The "pid" parameter is invalid ({0}).'.format(anchor_plate_id)) # Convert geojson input to gplates feature collection features=[] try: fc = json.loads(fc_str)#load the input feature collection for f in fc['features']: geom = f['geometry'] feature = pygplates.Feature() if geom['type'] == 'Point': feature.set_geometry(pygplates.PointOnSphere( float(geom['coordinates'][1]), float(geom['coordinates'][0]))) if geom['type'] == 'LineString': feature.set_geometry( pygplates.PolylineOnSphere([(point[1],point[0]) for point in geom['coordinates']])) if geom['type'] == 'Polygon': feature.set_geometry( pygplates.PolygonOnSphere([(point[1],point[0]) for point in geom['coordinates'][0]])) if geom['type'] == 'MultiPoint': feature.set_geometry( pygplates.MultiPointOnSphere([(point[1],point[0]) for point in geom['coordinates']])) if keep_properties and 'properties' in f: for pk in f['properties']: p = f['properties'][pk] if isinstance(p, str): p=str(p) feature.set_shapefile_attribute(str(pk),p) features.append(feature) except Exception as e: #print e return HttpResponseBadRequest('Invalid input feature collection') model_dict = get_reconstruction_model_dict(model) if not model_dict: return HttpResponseBadRequest('The "model" ({0}) cannot be recognized.'.format(model)) rotation_model = pygplates.RotationModel([str('%s/%s/%s' % (settings.MODEL_STORE_DIR,model,rot_file)) for rot_file in model_dict['RotationFile']]) assigned_features = pygplates.partition_into_plates( settings.MODEL_STORE_DIR+model+'/'+model_dict['StaticPolygons'], rotation_model, features, properties_to_copy = [ pygplates.PartitionProperty.reconstruction_plate_id, pygplates.PartitionProperty.valid_time_period], partition_method = pygplates.PartitionMethod.most_overlapping_plate ) reconstructed_geometries = [] pygplates.reconstruct(assigned_features, rotation_model, reconstructed_geometries, timef, anchor_plate_id=anchor_plate_id) # convert feature collection back to geojson data = {"type": "FeatureCollection"} data["features"] = [] for g in reconstructed_geometries: geom = g.get_reconstructed_geometry() feature = {"type": "Feature"} feature["geometry"] = {} if isinstance(geom, pygplates.PointOnSphere): feature["geometry"]["type"] = "Point" p = geom.to_lat_lon_list()[0] feature["geometry"]["coordinates"] = [p[1], p[0]] elif isinstance(geom, pygplates.MultiPointOnSphere): feature["geometry"]["type"] = 'MultiPoint' feature["geometry"]["coordinates"] = [[lon,lat] for lat, lon in geom.to_lat_lon_list()] elif isinstance(geom, pygplates.PolylineOnSphere): feature["geometry"]["type"] = 'LineString' feature["geometry"]["coordinates"] = [[lon,lat] for lat, lon in geom.to_lat_lon_list()] elif isinstance(geom, pygplates.PolygonOnSphere): feature["geometry"]["type"] = 'Polygon' feature["geometry"]["coordinates"] = [[[lon,lat] for lat, lon in geom.to_lat_lon_list()]] else: return HttpResponseServerError('Unsupported Geometry Type.') feature["properties"] = {} if keep_properties: for pk in g.get_feature().get_shapefile_attributes(): feature["properties"][pk] = g.get_feature().get_shapefile_attribute(pk) #print feature["properties"] data["features"].append(feature) ret = json.dumps(pretty_floats(data)) #add header for CORS #http://www.html5rocks.com/en/tutorials/cors/ response = HttpResponse(ret, content_type='application/json') #TODO: response['Access-Control-Allow-Origin'] = '*' return response
def reconstruct_points(request): """ http GET request to reconstruct points **usage** <http-address-to-gws>/reconstruct/reconstruct_points/points=\ *points*\&plate_id=\ *anchor_plate_id*\&time=\ *reconstruction_time*\&model=\ *reconstruction_model* **parameters:** *points* : list of points long,lat comma separated coordinates of points to be reconstructed [Required] *anchor_plate_id* : integer value for reconstruction anchor plate id [default=0] *time* : time for reconstruction [required] *model* : name for reconstruction model [defaults to default model from web service settings] **returns:** json list of long,lat reconstructed coordinates """ if request.method == 'POST': params = request.POST elif request.method == 'GET': params = request.GET else: return HttpResponseBadRequest('Unrecognized request type') points = params.get('points', None) anchor_plate_id = params.get('pid', 0) time = params.get('time', None) model = params.get('model',settings.MODEL_DEFAULT) return_null_points = True if 'return_null_points' in params else False return_feature_collection = True if 'fc' in params else False is_reverse = True if 'reverse' in params else False timef=0.0 if not time: return HttpResponseBadRequest('The "time" parameter cannot be empty.') else: try: timef = float(time) except: return HttpResponseBadRequest('The "time" parameter is invalid ({0}).'.format(time)) try: anchor_plate_id = int(anchor_plate_id) except: return HttpResponseBadRequest('The "pid" parameter is invalid ({0}).'.format(anchor_plate_id)) model_dict = get_reconstruction_model_dict(model) if not model_dict: return HttpResponseBadRequest('The "model" ({0}) cannot be recognized.'.format(model)) rotation_model = pygplates.RotationModel([str('%s/%s/%s' % (settings.MODEL_STORE_DIR,model,rot_file)) for rot_file in model_dict['RotationFile']]) static_polygons_filename = str('%s/%s/%s' % (settings.MODEL_STORE_DIR,model,model_dict['StaticPolygons'])) # create point features from input coordinates p_index=0 point_features = [] if points: ps = points.split(',') if len(ps)%2==0: try: for lat,lon in zip(ps[1::2], ps[0::2]): point_feature = pygplates.Feature() point_feature.set_geometry(pygplates.PointOnSphere(float(lat),float(lon))) point_feature.set_name(str(p_index)) point_features.append(point_feature) p_index += 1 except pygplates.InvalidLatLonError as e: return HttpResponseBadRequest('Invalid longitude or latitude ({0}).'.format(e)) else: return HttpResponseBadRequest('The longitude and latitude should come in pairs ({0}).'.format(points)) else: return HttpResponseBadRequest('The "points" parameter is missing.') # assign plate-ids to points using static polygons partition_time = timef if is_reverse else 0. #LOOK HERE !!!! #it seems when the partition_time is not 0 #the returned assigned_point_features contains reverse reconstructed present-day geometries. #so, when doing reverse reconstruct, do not reverse reconstruct again later. assigned_point_features = pygplates.partition_into_plates( static_polygons_filename, rotation_model, point_features, properties_to_copy = [ pygplates.PartitionProperty.reconstruction_plate_id, pygplates.PartitionProperty.valid_time_period], reconstruction_time = partition_time ) # reconstruct the points assigned_point_feature_collection = pygplates.FeatureCollection(assigned_point_features) reconstructed_feature_geometries = [] if not is_reverse: pygplates.reconstruct( assigned_point_feature_collection, rotation_model, reconstructed_feature_geometries, timef, anchor_plate_id=anchor_plate_id) rfgs = p_index*[None] for rfg in reconstructed_feature_geometries: rfgs[int(rfg.get_feature().get_name())] = rfg assigned_fc = p_index*[None] for f in assigned_point_feature_collection: assigned_fc[int(f.get_name())] = f # prepare the response to be returned if not return_feature_collection: ret='{"type":"MultiPoint","coordinates":[' for idx in range(p_index): lon = None lat = None if not is_reverse and rfgs[idx]: lon = rfgs[idx].get_reconstructed_geometry().to_lat_lon()[1] lat = rfgs[idx].get_reconstructed_geometry().to_lat_lon()[0] elif is_reverse and assigned_fc[idx]: lon = assigned_fc[idx].get_geometry().to_lat_lon()[1] lat = assigned_fc[idx].get_geometry().to_lat_lon()[0] if lon is not None and lat is not None: ret+='[{0:5.2f},{1:5.2f}],'.format(lon, lat) elif return_null_points: ret+='null,' else: ret='{"type":"FeatureCollection","features":[' for idx in range(p_index): lon = None lat = None begin_time = None end_time = None if not is_reverse and rfgs[idx]: lon = rfgs[idx].get_reconstructed_geometry().to_lat_lon()[1] lat = rfgs[idx].get_reconstructed_geometry().to_lat_lon()[0] elif is_reverse and assigned_fc[idx]: lon = assigned_fc[idx].get_geometry().to_lat_lon()[1] lat = assigned_fc[idx].get_geometry().to_lat_lon()[0] if assigned_fc[idx]: valid_time = assigned_fc[idx].get_valid_time(None) if valid_time: begin_time, end_time = valid_time ret+='{"type":"Feature","geometry":' if lon is not None and lat is not None: ret+='{'+'"type":"Point","coordinates":[{0:5.2f},{1:5.2f}]'.format(lon, lat)+'},' else: ret+='null,' if begin_time is not None and end_time is not None: #write out begin and end time if begin_time == pygplates.GeoTimeInstant.create_distant_past(): begin_time = '"distant past"' if end_time == pygplates.GeoTimeInstant.create_distant_future(): end_time = '"distant future"' ret+='"properties":{'+'"valid_time":[{0},{1}]'.format(begin_time,end_time)+'}},' else: ret+='"properties":{}'+'},' ret=ret[0:-1] ret+=']}' #add header for CORS #http://www.html5rocks.com/en/tutorials/cors/ response = HttpResponse(ret, content_type='application/json') #TODO: #The "*" makes the service wide open to anyone. We should implement access control when time comes. response['Access-Control-Allow-Origin'] = '*' return response
def reconstruct_feature_collection(request): DATA_DIR = Model_Root+'caltech/' if request.method == 'POST': return HttpResponse('POST method is not accepted for now.') geologicage = request.GET.get('geologicage', 140) output_format = request.GET.get('output', 'geojson') fc_str = request.GET.get('feature_collection') fc = json.loads(fc_str) features=[] for f in fc['features']: geom = f['geometry'] feature = pygplates.Feature() if geom['type'] == 'Point': feature.set_geometry(pygplates.PointOnSphere( float(geom['coordinates'][1]), float(geom['coordinates'][0]))) if geom['type'] == 'LineString': feature.set_geometry( pygplates.PolylineOnSphere([(point[1],point[0]) for point in geom['coordinates']])) if geom['type'] == 'Polygon': feature.set_geometry( pygplates.PolygonOnSphere([(point[1],point[0]) for point in geom['coordinates'][0]])) if geom['type'] == 'MultiPoint': feature.set_geometry( pygplates.MultiPointOnSphere([(point[1],point[0]) for point in geom['coordinates']])) features.append(feature) if float(geologicage) < 250: rotation_files = [DATA_DIR+'/Seton_etal_ESR2012_2012.1.rot'] else : rotation_files = [DATA_DIR+'/Global_EB_410-250Ma_GK07_Matthews_etal.rot'] rotation_model = pygplates.RotationModel(rotation_files) assigned_features = pygplates.partition_into_plates( DATA_DIR+'Seton_etal_ESR2012_StaticPolygons_2012.1.gpmlz', rotation_model, features, properties_to_copy = [ pygplates.PartitionProperty.reconstruction_plate_id, pygplates.PartitionProperty.valid_time_period], partition_method = pygplates.PartitionMethod.most_overlapping_plate ) reconstructed_geometries = [] pygplates.reconstruct(assigned_features, rotation_model, reconstructed_geometries, float(geologicage), 0) data = {"type": "FeatureCollection"} data["features"] = [] for g in reconstructed_geometries: geom = g.get_reconstructed_geometry() feature = {"type": "Feature"} feature["geometry"] = {} if isinstance(geom, pygplates.PointOnSphere): feature["geometry"]["type"] = "Point" p = geom.to_lat_lon_list()[0] feature["geometry"]["coordinates"] = [p[1], p[0]] elif isinstance(geom, pygplates.MultiPointOnSphere): feature["geometry"]["type"] = 'MultiPoint' feature["geometry"]["coordinates"] = [[lon,lat] for lat, lon in geom.to_lat_lon_list()] elif isinstance(geom, pygplates.PolylineOnSphere): feature["geometry"]["type"] = 'LineString' feature["geometry"]["coordinates"] = [[lon,lat] for lat, lon in geom.to_lat_lon_list()] elif isinstance(geom, pygplates.PolygonOnSphere): feature["geometry"]["type"] = 'Polygon' feature["geometry"]["coordinates"] = [[[lon,lat] for lat, lon in geom.to_lat_lon_list()]] else: raise 'Unrecognized Geometry Type.' feature["properties"]={} data["features"].append(feature) ret = json.dumps(pretty_floats(data)) return HttpResponse(ret, content_type='application/json')
input_feature_filename = pygplates.FeatureCollection( 'tectonic_data/Neoproterozoic_shapes.gpml') input_rotation_filename = pygplates.RotationModel( 'tectonic_data/Neoproterozoic_rotations.rot') output_reconstructed_feature_filename = 'reconstructions/' + str( p) + '/' + str(p) + '_points' + '.shp' if not os.path.exists( os.path.dirname(output_reconstructed_feature_filename)): try: os.makedirs(os.path.dirname(output_reconstructed_feature_filename)) except OSError as exc: if exc.errno != errno.EEXIST: raise df_temp = my_reservoir_data[ my_reservoir_data.SYSTEM == p] # making the following manual iteration quicker by reducing data set size point_features = [] for index, row in df_temp.iterrows(): point = pygplates.PointOnSphere(float(row.LAT_DD), float(row.LON_DD)) point_feature = pygplates.Feature() point_feature.set_geometry(point) point_feature.set_shapefile_attribute('MMBOE', row.EUR_MMBOE) point_feature.set_shapefile_attribute('Region', row.REG_NAME) point_feature.set_shapefile_attribute('Lithology', row.RSVR_LITH1) point_features.append(point_feature) partitioned_point_features = pygplates.partition_into_plates( input_feature_filename, input_rotation_filename, point_features) pygplates.reconstruct(partitioned_point_features, input_rotation_filename, output_reconstructed_feature_filename, reconstruction_time)