Problems with spatial join - postgresql

I am new to sql, and attempting to use it to speed up spatial analysis on a set of ~1.2 million trips from a csv that contains the lat and lon for pickup and dropoff points.
What I am trying to do in plain English is:
select all trips that start in the area of interest (loaded into my database as a shapefile) into one table
select all trips that end in the area of interest into another
-perform a spatial join between these points and a shapefile of census tracks (which contains neighborhood names)
count by neighborhood name to list the most frequent origins/destination of trips to/ from the area of interest.
The code I am working with is below (If its helpful, NTA or neighborhood tabulation area, is the neighborhood name which I want to display in my table at the end of this operation) :
--Select all trips that end in project area
SELECT *
INTO end_PA
FROM trips, projarea
WHERE ST_Intersects(trips.dropoff, projarea.geom);
--for trips that end in project area - index by NTA of pick up point
ALTER TABLE end_PA ADD COLUMN GID SERIAL;
CREATE TABLE points_ct_end AS
SELECT nyct2010.ntacode as ct_nta, end_PA.gid as point_id
from nyct2010, end_PA WHERE ST_Intersects(nyct2010.geom , end_PA.pickup);
--Count most common NTA
--return count for each NAT as a csv
copy(
select count(ct_nta) from points_ct_end
group by ct_nta
order by count desc)
to 'C://TaxiData//Analysis//Trips_Arriving_LM.csv' DELIMITER ',' CSV HEADER;
However, I am having problems from the very start - ST_Intersects does not return any points within the area of interest!
Troubleshooting solutions I have tried thus far:
My first thought is that the points weren't in the correct SRID. When I created the 'dropoff' point I set the SRID to 4326. I tried both using ST_SetSRID to change the projection of both data sets to 4326, and manually re projecting the shapefiles to 4326 in ArcMap - but neither worked.
I plotted a small sample of the points from the 'trips' data set in Arc Map to ensure they were correctly projected and overlapping with the ProjArea shapefile. They are.
I imported the multipoint shapefile this created into my geo database to test if that worked with ST_Intersects. Nope.
I tried using ST_Within. This threw the error message:
ERROR: function st_within(character varying, geometry) does not exist
....
HINT: No function matches the given name and argument types. You
might need to add explicit type casts.
I am using Big SQL and postgres
Thanks!!

My first thought is that the points weren't in the correct SRID. When I created the 'dropoff' point I set the SRID to 4326. I tried both using ST_SetSRID to change the projection of both data sets to 4326, and manually re projecting the shapefiles to 4326 in ArcMap - but neither worked.
ST_SetSRID doesn't change the projection (reproject). It just changes the internal representation. This can totally screw everything up if the previous SRID matched the input data. You likely wanted ST_Transform().
There isn't enough information here to trouble shoot this problem. However, we can answer this...
ERROR: function st_within(character varying, geometry) does not exist
This simply means the first argument is not a geometery. Of course, we can't do anything with that at all because we don't have your query that you tried with ST_Within().
Your syntax for ST_Intersects() looks to be right. But, there simply isn't enough information provided to help. Show some schema and sample data.

Related

Errors converting Geometry to Geography

I am getting an error trying to convert data from a Geometry field to a geography field in a separate table.
INSERT INTO PIGeoData
([ID], [geo_name], [geo_wkt] ,[port_geography_binary] )
SELECT [id], [name] ,[wkt], GEOGRAPHY::STGeomFromWKB(em_ports.geom.STAsBinary(),4326)
FROM [guest].[em_ports]
where ID < 4548 and ID not in (select ID from PIGeoData)
The error I get is this
Msg 6522, Level 16, State 1, Line 1
A .NET Framework error occurred during execution of user-defined routine or aggregate "geography":
Microsoft.SqlServer.Types.GLArgumentException: 24205: The specified input does not represent a valid geography instance because it exceeds a single hemisphere. Each geography instance must fit inside a single hemisphere. A common reason for this error is that a polygon has the wrong ring orientation. To create a larger than hemisphere geography instance, upgrade the version of SQL Server and change the database compatibility level to at least 110.
Microsoft.SqlServer.Types.GLArgumentException:
at Microsoft.SqlServer.Types.GLNativeMethods.ThrowExceptionForHr(GL_HResult errorCode)
at Microsoft.SqlServer.Types.GLNativeMethods.GeodeticIsValid(GeoData& g, Double eccentricity, Boolean forceKatmai)
at Microsoft.SqlServer.Types.SqlGeography.IsValidExpensive(Boolean forceKatmai)
at Microsoft.SqlServer.Types.SqlGeography..ctor(GeoData g, Int32 srid)
at Microsoft.SqlServer.Types.SqlGeography.GeographyFromBinary(OpenGisType type, SqlBytes wkbGeography, Int32 srid)
I get the same message if I try to convert from WKT using
,GEOGRAPHY::STGeomFromText(wkt,4326)
Both these formats come from the MS documentation here
But if I copy the polygon data from the wkt and paste it into a query like this
declare #sGeo geography
declare #sWKT varchar(max)
select #sWKT = wkt from guest.em_ports where wkt like '%POLYGON ((73.50667 4.181667,73.50667 4.21,73.48 4.21,73.48 4.1783333,73.50667 4.181667,73.50667 4.181667))%'
set #sGeo = geography::STPolyFromText (#sWKT, 4326 )
Update PIGeoData
Set PortBoundaries = #sGeo
Where wkt like '%POLYGON ((73.50667 4.181667,73.50667 4.21,73.48 4.21,73.48 4.1783333,73.50667 4.181667,73.50667 4.181667))%'
that works.
So I moved all the non-geo data to the new table and started going through record by record to see which WKT was failing:
I used this query
Update PIGeoData
Set port_geography_binary = GEOGRAPHY::STGeomFromText(geo_wkt,4326)
where port_geography_binary is null and ID = <xyz>
where xyz was individual record ids
These WKT values succeeded
POLYGON ((-135.31197 59.451653,-135.32457 59.45799,-135.32996 59.454834,-135.36717 59.455154,-135.36452 59.449005,-135.36488 59.43996,-135.36697 59.43817,-135.33139 59.438065,-135.31197 59.451653,-135.31197 59.451653))
POLYGON ((-4.524549 48.365623,-4.518855 48.361416,-4.4854136 48.367413,-4.436236 48.381382,-4.420772 48.39644,-4.431077 48.398525,-4.4376454 48.393867,-4.438626 48.38611,-4.4559207 48.390007,-4.470995 48.387226,-4.4933248 48.384468,-4.499816 48.38401,-4.512855 48.3754,-4.524549 48.365623,-4.524549 48.365623))
These WKT values failed
POLYGON ((-8.788489 37.773106,-8.989748 37.785244,-9.11148 37.93065,-9.01401 38.13953,-8.993956 38.30128,-9.266149 38.264282,-9.382366 38.33244,-9.435615 38.54836,-9.656681 38.602306,-9.683701 38.883057,-9.1720295 39.00796,-8.444215 39.550682,-8.213643 39.355015,-8.537656 38.037514,-8.712016 37.782127,-8.788489 37.773106))
POLYGON ((-119.71587 34.396824,-119.69837 34.410378,-119.67453 34.41837,-119.62994 34.420082,-119.63012 34.380177,-119.62986 34.3551,-119.71534 34.355022,-119.71587 34.396824,-119.71587 34.396824))
There is nothing obvious to me in the data. Can anyone help with why these records and data are failing?
TIA
The relevant part of the error message is "A common reason for this error is that a polygon has the wrong ring orientation."
The polygons that have failed are in clockwise order.
To convert them to counter-clockwise order, you can use something like this:
DECLARE #t VARCHAR(MAX)='POLYGON ((-119.71587 34.396824,-119.69837 34.410378,-119.67453 34.41837,-119.62994 34.420082,-119.63012 34.380177,-119.62986 34.3551,-119.71534 34.355022,-119.71587 34.396824,-119.71587 34.396824))'
DECLARE #x XML=REPLACE(REPLACE(REPLACE(#t,'POLYGON ((','<root><p>'),'))','</p></root>'),',','</p><p>')
DECLARE #r VARCHAR(MAX)='POLYGON (('+STUFF((
SELECT ','+q.Point
FROM (
SELECT n.value('.','varchar(50)') AS Point, ROW_NUMBER() OVER (ORDER BY t.n) AS Position
FROM #x.nodes('/root/p') t(n)
) q ORDER BY q.Position DESC
FOR XML PATH(''), TYPE
).value('.','VARCHAR(MAX)'),1,1,'')+'))'
DECLARE #g GEOGRAPHY=GEOGRAPHY::STGeomFromText(#r,4326)
SELECT #g, #g.ToString()
Later edit:
There is a convention that says that a polygon should always be represented in counter-clockwise order. Imagine that you have a polygon in the shape of the equator; without this convention it would not be clear if the polygon represents the northern hemisphere or the southern hemisphere. See Spatial Data Types Overview in the Microsoft SQL Server documentation for details.
Additionally, there is a limitation in SQL Server when the compatibility level is 100 or below that each geography instance must fit inside a single hemisphere. If you are using SQL Server 2012 or later and you choose to use at least compatibility level 110, you can avoid the error message, but the polygon would represent the entire area that is outside of what you would normally think that the polygon represents.
If you use compatibility level is 100 or below, you could use a TRY/CATCH to detect the error and if it happens you should try reversing the polygon.
If you use compatibility level 110 or later, you can try to use STArea() to check if the polygon has a surface which is much bigger or much smaller than one hemisphere. If the area approaches 510100000000000 square meters (which approximately the area of the entire earth) then you should reverse the polygon.

PostGIS latitude incorrect when storing a linestring

I am attempting to store a LINESTRING using PostGIS into a column of type geography(LINESTRING, 4326). Here is my insert statement:
INSERT into routes (line) VALUES (st_linefromtext('LINESTRING(-35.3350743932 149.084182978,-35.3350306311 149.085041285)', 4326));
But when I run a query to get the line back out of the database.
SELECT st_astext(line) from routes;
Result:
LINESTRING(-35.3350743932 30.915817022,-35.3350306311 30.914958715)
The latitude coordinates come out completely differently from how I inputted them. Can anyone point out to me why this would be?
I am new to PostGIS - I think I must be missing something about the storage and retrieval of 4326 data. Any help appreciated.

i'm working with postgreSQL with converting long/lat to point and also want to make line with that point

i'm working with postgreSQL with converting long/lat to point and also want to make line with that point
select bs1.rental_shop_name,
bs1.lon,
bs1.lat,
bs2.rental_shop_name,
bs2.lon,
bs2.lat,
count(*),
ST_MakeLine(ST_MakePoint(bs1.lon, bs1.lat), ST_MakePoint(bs2.lon, bs2.lat))
from bikeuser as bu
join bikestation as bs1 on bs1.rental_shop_code = bu.rental_shop_code
join bikestation as bs2 on bs2.rental_shop_code = bu.return_shop_code
group by bs1.rental_shop_name,
bs1.lon,
bs1.lat,
bs2.rental_shop_name,
bs2.lon,
bs2.lat,
ST_MakeLine(ST_MakePoint(bs1.lon, bs1.lat), ST_MakePoint(bs2.lon, bs2.lat))
order by count desc limit 40
but result is failed and msg is
SQL state: 42883 the st_makepoint does not exist and also have to use explicit converter
also i tested with simple form like this.
SELECT ST_MakePoint(-71.1043443253471, 42.3150676015829);
BUT ITS SAME RESULTS...
Just ST_MakePoint is not enough with lat long. You have to set SRID of the geometry as well. If the data comes from WGS84(which usually is the case with lat long), you need to apply ST_SetSRID on the geometry.
ST_MakeLine(ST_SetSRID(ST_MakePoint(bs1.lon, bs1.lat),4326), ST_SetSRID(ST_MakePoint(bs2.lon, bs2.lat),4326))
You should take into account your own data SRID.

How to find similar trajectories

I am very new in GIS. I am using an existing data set which is a collection of triplets along with its trajectory ID. I need to find similar trajectories. I am using postgres as database. I have imported the data set and I want to visualize the trajectories.How can I convert the existing data in linestring?
Do you just need a LineString for each trajectory ID (meaning that by 'finding similar trajectories')? If so, you want to use ST_MakeLine (spatial aggregate version) in conjunction with ST_MakePoint. For PostGIS 9.0 and higher you could do something like:
SELECT points.trackid,
ST_MakeLine(points.point_geom ORDER BY points.timedetails) AS line_geom
FROM (SELECT data.trackid,
data.timedetails,
ST_MakePoint(data.longitude, data.latitude) AS point_geom
FROM your_table AS data) AS points
GROUP BY points.trackid;

Postgis and Postgres: How to perform a ST_Contains query with geometry array?

I have a boundary which is stored in a geometry array. (like {...,...,...})
My goal is to perform a ST_Contains query. I want see whether a node is inside that boundary or not.
I tried something like
SELECT ST_Contains(ST_Polygonize((SELECT CAST(bt.geomarray AS geometry[]) FROM boundarytable AS bt)), nodetable.geom)
But I always get errors like "Invalid hex character (,) encountered".
Can anybody show me the right way to do this?
Now that I know how to do it, I'm answering this question by myself.
We do not have to use an array. We step through each node's geom and create the polygon. We store the polygon in polygontable. (Notice: don't forget you need the polygon to be closed, so you have to add the first node as last node again in boundarytable before you perform the query. Otherwise you will get an error):
SELECT ST_MakePolygon(ST_MakeLine(bt.geom)) AS geomboundary
INTO TABLE polygontable
FROM boundarytable AS bt
GROUP BY bt.dummy -- (just a constant value to round up all bt.geom)
Then we can perform the ST_Contains query like
SELECT *, ST_Contains((SELECT geomboundary FROM polygontable), anytable.geom)