Menambahkan GeoPandas Dataframe ke tabel PostGIS?


15

Saya memiliki GeoPandas Dataframe sederhana:

masukkan deskripsi gambar di sini

Saya ingin mengunggah GeoDataframe ini ke tabel PostGIS. Saya sudah memiliki pengaturan Database dengan ekstensi PostGIS tetapi sepertinya tidak bisa menambahkan Dataframe ini sebagai tabel.

Saya sudah mencoba yang berikut ini:

engine = <>
meta = MetaData(engine)
eld_test = Table('eld_test', meta, Column('id', Integer, primary_key=True), Column('key_comb_drvr', Text), 
                 Column('geometry', Geometry('Point', srid=4326))) 
eld_test.create(engine) 
conn = engine.connect() 
conn.execute(eld_test.insert(), df.to_dict('records'))

Saya telah mencoba yang berikut ini: engine = <> # create table meta = MetaData (engine) eld_test = Table ('eld_test', meta, Column ('id', Integer, primary_key = True), Column ('key_comb_drvr', Text) , Kolom ('geometri', Geometri ('Titik', srid = 4326))) eld_test.create (mesin) # Eksekutif DBAPI dengan daftar dicts conn = engine.connect () conn.execute (eld_test.insert (), df .to_dict ('records'))
theecmanman

1
Selamat datang di GIS SE, silakan baca tur kami ! Bisakah Anda mengedit posting Anda untuk memasukkan kode Anda diposting di komentar?
GISKid

Jawaban:


30

Menggunakan metode to_sql Panda dan SQLAlchemy Anda dapat menyimpan dataframe di Postgres. Dan karena Anda menyimpan Geodataframe, GeoAlchemy akan menangani kolom geom untuk Anda. Berikut ini contoh kode:

# Imports
from geoalchemy2 import Geometry, WKTElement
from sqlalchemy import *
import pandas as pd
import geopandas as gpd

# Creating SQLAlchemy's engine to use
engine = create_engine('postgresql://username:password@host:socket/database')


geodataframe = gpd.GeoDataFrame(pd.DataFrame.from_csv('<your dataframe source>'))
#... [do something with the geodataframe]

geodataframe['geom'] = geodataframe['geometry'].apply(lambda x: WKTElement(x.wkt, srid=<your_SRID>)

#drop the geometry column as it is now duplicative
geodataframe.drop('geometry', 1, inplace=True)

# Use 'dtype' to specify column's type
# For the geom column, we will use GeoAlchemy's type 'Geometry'
geodataframe.to_sql(table_name, engine, if_exists='append', index=False, 
                         dtype={'geom': Geometry('POINT', srid= <your_srid>)})

Patut dicatat bahwa parameter 'if_exists' memungkinkan Anda untuk menangani cara bingkai data akan ditambahkan ke tabel postgres Anda:

    if_exists = replace: If table exists, drop it, recreate it, and insert data.
    if_exists = fail: If table exists, do nothing.
    if_exists = append: If table exists, insert data. Create if does not exist.

Apakah ada peluang untuk memproyeksikan ulang di sini dengan menentukan SRID yang berbeda dari yang ada di kolom geometri, atau apakah SRID saat ini harus digunakan? Juga apa cara terbaik untuk mendapatkan SRID integer dari kolom geometri ?
rovyko

4

Saya juga memiliki pertanyaan yang sama dengan yang Anda tanyakan dan telah menghabiskan banyak hari untuk itu (lebih dari yang saya akui) mencari solusi. Dengan asumsi tabel postgreSQL berikut dengan ekstensi postGIS,

postgres=> \d cldmatchup.geo_points;
Table "cldmatchup.geo_points"
Column   |         Type         |                               Modifiers                                
-----------+----------------------+------------------------------------------------------------------------
gridid    | bigint               | not null default nextval('cldmatchup.geo_points_gridid_seq'::regclass)
lat       | real                 | 
lon       | real                 | 
the_point | geography(Point,4326) | 

Indexes:
"geo_points_pkey" PRIMARY KEY, btree (gridid)

inilah yang akhirnya saya kerjakan:

import geopandas as gpd
from geoalchemy2 import Geography, Geometry
from sqlalchemy import create_engine, MetaData, Table
from sqlalchemy.orm import sessionmaker
from shapely.geometry import Point
from psycopg2.extensions import adapt, register_adapter, AsIs

# From http://initd.org/psycopg/docs/advanced.html#adapting-new-types but 
# modified to accomodate postGIS point type rather than a postgreSQL 
# point type format
def adapt_point(point):
    from psycopg2.extensions import adapt, AsIs
    x = adapt(point.x).getquoted()
    y = adapt(point.y).getquoted()
    return AsIs("'POINT (%s %s)'" % (x, y))

register_adapter(Point, adapt_point)

engine = create_engine('postgresql://<yourUserName>:postgres@localhost:5432/postgres', echo=False)
Session = sessionmaker(bind=engine)
session = Session()
meta = MetaData(engine, schema='cldmatchup')

# Create reference to pre-existing "geo_points" table in schema "cldmatchup"
geoPoints = Table('geo_points', meta, autoload=True, schema='cldmatchup', autoload_with=engine)

df = gpd.GeoDataFrame({'lat':[45.15, 35., 57.], 'lon':[-35, -150, -90.]})

# Create a shapely.geometry point 
the_point = [Point(xy) for xy in zip(df.lon, df.lat)]

# Create a GeoDataFrame specifying 'the_point' as the column with the 
# geometry data
crs = {'init': 'epsg:4326'}
geo_df = gpd.GeoDataFrame(df.copy(), crs=crs, geometry=the_point)

# Rename the geometry column to match the database table's column name.
# From https://media.readthedocs.org/pdf/geopandas/latest/geopandas.pdf,
# Section 1.2.2 p 7
geo_df = geo_df.rename(columns{'geometry':'the_point'}).set_geometry('the_point')

# Write to sql table 'geo_points'
geo_df.to_sql(geoPoints.name, engine, if_exists='append', schema='cldmatchup', index=False)

session.close()

Saya tidak bisa mengatakan apakah logika koneksi basis data saya adalah yang terbaik karena pada dasarnya saya menyalinnya dari tautan lain dan hanya senang bahwa saya berhasil mengotomatiskan (atau mencerminkan) tabel saya yang ada dengan definisi geometri yang dikenali. Saya telah menulis kode spasial python ke sql hanya beberapa bulan, jadi saya tahu ada banyak yang harus dipelajari.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.