De buffers in de eerste plot ("geometry_buffer") lijken cirkelvormig terwijl die in de tweede plot ("geometry_geodesic_buffer") ovaalvormig lijken. Waarom is dat? Beide kaarten worden gegenereerd op een kaart op basis van de breedte- en lengtegraadcoördinaten. In deze grafieken is één graad breedtegraad gelijk aan één graad lengtegraad in lengte. Op de aarde verschillen de lengtes van één graad breedte- en lengtegraad, waarbij een graad lengtegraad korter en korter wordt naarmate je dichter bij de polen komt. De Wikipedia-pagina over <\/SPAN>Longitude<\/A> <\/SPAN>bespreekt dit in detail als je meer informatie wilt. Wanneer de geodetische buffers op deze specifieke kaartprojectie worden weergegeven, lijken ze uitgerekt tot ovalen, terwijl ze op het aardoppervlak cirkelvormig zouden zijn.<\/LI><\/UL>Als we de geodetische buffer zouden plotten in ons lokale Boston-coördinatensysteem (SRID 2249), zien de buffers eruit als de cirkels die we zouden verwachten.<\/P>We kunnen de kaart bijwerken wanneer we deze plotten door een <\/SPAN>sr<\/FONT> <\/SPAN>(spatial reference) parameter toe te voegen. De onderstaande voorbeeldcode toont dit aan. Meer informatie over de parameters voor <\/SPAN>st.plot<\/FONT> <\/SPAN>is te vinden in de <\/SPAN>API reference<\/A>.<\/P> <\/P>
# plotten van de geometry_geodesic_buffer op een kaart met spatial reference 2249
df_schools\\
.st.plot(basemap="streets", geometry="geometry_geodesic_buffer", alpha=0.5, edgecolor="black", sr=2249);<\/code><\/pre><P> <\/P><P>Over het algemeen is het sneller om<SPAN> <\/SPAN><A href="https:\/\/developers.arcgis.com\/geoanalytics-fabric\/sql-functions\/st_buffer\/\ target="_blank" rel="noopener nofollow noreferrer">ST_H3Bin</A><SPAN> </SPAN>functie om de<SPAN> </SPAN><A href="https://h3geo.org/" target="_blank" rel="noopener nofollow noreferrer">H3 bin</A><SPAN> </SPAN>te identificeren waarin elk van onze serviceverzoekpunten zich bevindt. We zullen vervolgens een PySPark<SPAN> </SPAN><A href="https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.DataFrame.groupBy.html" target="_blank" rel="noopener nofollow noreferrer">GroupBy</A><SPAN> </SPAN>functie gebruiken om een vereenvoudigde DataFrame te maken die het aantal punten binnen elke bin vermeldt.</P><P>De grootte van H3 bins is gebaseerd op een resolutiewaarde. Voor dit voorbeeld gebruiken we een resolutie van 8, wat overeenkomt met een gemiddelde hexagonale bin-grootte van 0,73 vierkante kilometer. Meer informatie over<SPAN> </SPAN><A href="https://h3geo.org/docs/core-library/restable" target="_blank" rel="noopener nofollow noreferrer">H3 bin-resoluties is hier te vinden</A>.</P><P>Het toevoegen van de ID voor een bin is zo eenvoudig als het maken van een nieuwe kolom voor de data en het gebruik van de bin-functie voor het geometrietype dat je wilt (hexagonaal, vierkant of H3):</P><P> </P><pre class="lia-code-sample language-python"><code># voeg een kolom toe met de H3 bin _id_ waarin elk punt valt
df = df\
.withColumn("h3_bin", ST.h3_bin("geometry", 8))
De
ST_H3Bin functie voegt een bin id toe aan elk record. Het voegt niet specifiek de geometrie toe, omdat er veel duplicaten van de geometrie zouden zijn (één voor elk punt binnen de bin) en het efficiënter is om met de ID te werken totdat we de geometrieën nodig hebben voor analyse of visualisatie. We kunnen deze nieuwe bin-ID's zien in de onderstaande tabel:
Met behulp van het h3_bin ID-veld kunnen we vervolgens de waarden in onze tabel groeperen om het aantal records in elke bin te tellen. # groepeer de serviceverzoeken DataFrame met behulp van de h3 bin ID en tel alle records
df_by_bin = df.groupBy("h3_bin").count() Na het groeperen kunnen we zien dat elke bin-ID een telling heeft van het aantal punten erin. Nadat we dit hebben gedaan, kunnen we vervolgens de bin-ID's omzetten in geometrieën en de resultaten visualiseren.
Hier is hoe we de bin-geometrie aan de tabel toevoegen met behulp van de ST_BinGeometry-functie: # voeg de bin-geometrie toe op basis van de bin-ID met ST_BinGeometry
df_by_bin = df_by_bin\
.withColumn("geometry_bin", ST.bin_geometry("h3_bin")) Het plotten van de resultaten toont ons nu waar de grootste concentratie serviceverzoeken plaatsvindt:
Laten we nu verder gaan met het berekenen van lijnen en afstanden tussen locaties!ST_ShortestLine en ST_GeodesicLineST_ShortestLine geeft een linestring-kolom terug die de kortste lijn vertegenwoordigt die twee geometrieën raakt, gebruikmakend van vlakke afstandsberekening. Deze functie retourneert slechts één kortste lijn als er meer dan één kan worden berekend tussen locaties.Om een kortste lijn te maken met geodetische afstandsberekeningen, gebruik je ST_GeodesicShortestLine.Als voorbeeld hiervan bekijken we de kortste lijn tussen de schools DataFrame die we eerder hebben gemaakt en de serviceverzoeken die in de buurt zijn. Kortste lijn gebruikt twee geometriekolommen als invoer, dus ze moeten in dezelfde DataFrame staan.In de buffer voorbeelden hierboven gebruikten we ST_Contains om alle punten binnen het bufferpolygon te vinden.In dit voorbeeld gebruiken we een andere ruimtelijke berekening genaamd ST_DWithin(afstand binnen) om alle punten binnen een gespecificeerde afstand van de schoolpunten te vinden. Dit kan effectief hetzelfde resultaat geven, maar DWithin is vaak performanter dan het maken van een buffer en uitvoeren van een ruimtelijke join. DWithin gebruikt standaard vlakke berekeningen, dus we moeten ofwel de geometrie transformeren naar een lokaal coördinatensysteem, of de parameter instellen om geodetische berekeningen te gebruiken.In dit geval gebruiken we ST_Transform om het coördinatensysteem voor deze berekening bij te werken. We doen dit in één enkele berekening waarbij we de scholen en serviceverzoeken joinen en een nieuwe DataFrame maken met de resultaten: # vind alle punten binnen 500 voet van elke school
# gebruik een ruimtelijke join om elk punt te matchen dat binnen de gespecificeerde afstand van de school ligt
# aangezien de datasets oorspronkelijk in breedte-/lengtegraadcoördinaten zijn, transformeren we eerst naar een lokaal coördinatensysteem
df_schools_requests = df.join(df_schools.select("name", F.col("geometry").alias("geometry_school")),
ST.dwithin(ST.transform("geometry", 2249), ST.transform("geometry_school", 2249), 500)) Nu elke school zowel de geometrie voor de school als voor nabijgelegen punten heeft, kunnen we die twee geometrieën gebruiken om de kortste lijn te berekenen tussen elk serviceverzoekpunt en de school. # bereken de kortste lijn van elk punt naar elke school
df_schools_requests = df_schools_requests\
.withColumn("geometry_line", ST.shortest_line("geometry", "geometry_school")) Laten we eens kijken naar het resultaat voor één school: # plot verbindingslijnen tussen één school en alle punten binnen 500 voet van deze locatie
df_schools_requests.filter(F.col("name") == "Hurley K-8").st.plot(basemap="streets", geometry="geometry_line", linewidth=0.5, alpha=0.7);
Voor korte afstanden is ST_ShortestLineeen goede keuze, maar voor langere afstanden kun je overwegen ST_GeodesicShortestLinete gebruiken zodat de gemaakte lijn het kortste pad op de bol representeert. Als voorbeeld van het verschil tussen de "kortste lijn" (vlakke berekening) en de geodetische lijn kunnen we het verschil verkennen tussen een lijn verbonden tussen Los Angeles en Londen. In dit voorbeeld lijkt de geodetische lijn (oranje) gebogen en langer in deze projectie, maar het is eigenlijk wel degelijk de kortste lijn!
# geodetische lijn (geodesic) (in oranje) vs. "kortste lijn" (vlakke) (in blauw)
# De geodetische lijn lijkt gebogen en langer in deze projectie, maar is eigenlijk wel degelijk de kortste lijn!
# maak punten voor twee locaties
data = [
("POINT (-118.2426 34.0549 )", "Los Angeles",
"POINT (0.1276 51.5072 )", "London")
]
# maak een DataFrame met de twee locaties
# converteer de locaties van well-known text naar geometrie
df_lines = spark.createDataFrame(data, ["wkt-origin", "city-origin", "wkt-dest", "city-dest"])\
.select("city-origin",
"city-dest",
ST.geom_from_text("wkt-origin", 4326).alias("geometry-origin"),
ST.geom_from_text("wkt-dest", 4326).alias("geometry-dest"))
# plot de resultaten om de twee gegenereerde lijnen te vergelijken (geodesic vs. kortste)
myplt = df_lines.select(ST.geodesic_shortest_line("geometry-origin", "geometry-dest")).st.plot(basemap="light", figsize=(10,10), color="orange")
df_lines.select(ST.shortest_line("geometry-origin", "geometry-dest")).st.plot(ax=myplt);

Afstand en Lengte berekeningen
Laten we nu kijken naar afstand en lengte voor deze lijnen...
- ST_Distance en ST_GeodesicDistance zullen de afstand tussen twee invoerlocaties berekenen. De eenheid voor ST_Distance is hetzelfde als de invoergeometrieën. Voor ST_GeodesicDistance wordt de afstand in meters berekend.
- ST_Length en ST_GeodesicLength zullen de lengte van een invoerfeature berekenen. De eenheid voor ST_Length is hetzelfde als de invoergeometrie. Voor ST_GeodesicLength wordt de lengte in meters berekend.
We zullen deze berekeningen bekijken met behulp van de lijnen die we eerder hebben gegenereerd die schoollocaties verbinden met de nabijgelegen servicemeldingen.
Met de afstandsberekening kunnen we ook kijken naar een bijzonder mooie functie van de GeoAnalytics bibliotheek - projectie on the fly. Als je een eigenschap of relatie wilt berekenen met behulp van twee geometrieën die in verschillende coördinatensystemen zijn, kan de bibliotheek dit verschil vaak voor je verzoenen zodat je de data niet hoeft te transformeren.
- De geometry (servicemeldingen) kolom is in het Massachusetts State Plane coördinatensysteem (SRID 2249)
- De geometry_school (schoollocaties) kolom is in WGS84 breedte- en lengtegraad (SRID 4326)
Laten we deze twee geometrieën gebruiken en verschillende afstandsberekeningen uitvoeren en zien hoe GeoAnalytics kan werken met geometrieën in verschillende coördinatensystemen! In de onderstaande cel berekenen we:
- Afstand tussen de twee geometrieën zonder transformatie van de coördinaten
- Afstand tussen de twee geometrieën met een transformatie om de geometry_school om te zetten naar Massachusetts State Plane (2249)
- Geodetische afstand tussen de twee geometrieën zonder transformatie
We zullen ook de lengte van de lijn geometry_line berekenen die we eerder hebben gemaakt om de twee puntlocaties te verbinden. We voeren deze berekeningen uit en tonen de resultaten als voorbeeld:
display(
df_schools_requests.select("geometry",
"geometry_school",
F.round(ST.distance("geometry", "geometry_school"), 2).alias("Afstand (geen transformatie)"),
F.round(ST.distance("geometry", ST.transform("geometry_school", 2249)),2).alias("Afstand (transformatie)"),
F.round(ST.geodesic_distance("geometry", "geometry_school"),2).alias("GeodetischeAfstand (meters)"),
"geometry_line",
F.round(ST.length("geometry_line"),2).alias("Lengte (feet)"),
F.round(ST.geodesic_length("geometry_line"),2).alias("GeodetischeLengte (meters)")
)
)

Dit toont aan hoe je deze berekeningen kunt uitvoeren, zelfs met geometrieën in verschillende coördinatensystemen! GeoAnalytics for Fabric is uitstekend in het helpen mitigeren van verschillen in coördinatensystemen waar mogelijk.
Laten we nu nog één keer kijken naar enkele eigenschappen die we kunnen berekenen en het gebied verkennen.
ST_Area en ST_GeodesicArea
ST_Area - berekent een vlak gebied voor elke geometrie. De eenheid van het gebied is hetzelfde als die van de invoergeometrieën. Als je gebied berekent op een dataset in een geografisch coördinatensysteem, zijn de eenheden vierkante decimale graden. Dit is geen aanbevolen eenheid. Voor het gebruik van de ST_Area functie is het het beste om een geprojecteerd coördinatensysteem te gebruiken. Meer informatie is beschikbaar in het Coordinate Systems and Transformations kernconcept document.
ST_GeodesicArea berekent het gebied voor elke geometrie in vierkante meters, en vereist dat er een ruimtelijke referentie is ingesteld op de invoergeometriekolom.
Voor dit voorbeeld zullen we gebieden berekenen voor Amerikaanse staten die we hebben ingelezen vanuit een ArcGIS feature service.
# US states feature service van Esri Living Atlas of the World
# Voor meer informatie over deze dataset: https://www.arcgis.com/home/item.html?id=774019f31f8549c39b5c72f149bbe74e
fs_url = "https://services.arcgis.com/P3ePLMYs2RVChkJx/arcgis/rest/services/USA_Census_States/FeatureServer/0"
df_states = spark.read.format('feature-service').load(fs_url)
Voordat we het gebied gaan berekenen, moeten we het coördinatensysteem van de data controleren zodat we meer weten over de gebruikte eenheden in het coördinatensysteem en kunnen beslissen of we ST_Area of ST_GeodesicArea gaan gebruiken. Dit kunnen we doen met de get_spatial_reference() functie
df_states.st.get_spatial_reference()
Wat informatie teruggeeft dat de data een SRID heeft van 4326 (WGS84 coördinatensysteem)
SpatialReference(srid=4326, is_projected=False, unit='Degree', wkt='GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]]')
Voor deze dataset bekijken we de waarden die worden berekend door ST_Area en ST_GeodesicArea.
In het onderstaande voorbeeld tonen we de originele data voor naam van staat en vierkante mijlen, en drie nieuwe berekende velden, allemaal afgerond op twee decimalen voor leesbaarheid met PySpark Round()
- gebied met ST_Area - aangezien de ruimtelijke referentie 4326 is met een eenheid Degree, zullen de resultaten in vierkante decimale graden zijn, wat geen echte toepasbare waarde heeft
- gebied met ST_Area op een getransformeerde geometrie met behulp van USA Contiguous Albers Equal Area projectie (102003). Deze berekening geeft vierkante meters terug, dus ze worden in het onderstaande voorbeeld omgezet naar vierkante mijlen
- gebied met ST_GeodesicArea op de originele geometrie. Deze berekening geeft vierkante meters terug, dus ze worden omgezet naar vierkante mijlen in de voorbeeld hieronder
De geretourneerde waarden liggen allemaal dicht bij elkaar in waarde, maar zijn niet exact hetzelfde. Deze afwijkingen zijn te wijten aan vervorming bij de berekening van het gebied voor grote regio's (het Coordinate Systems and Transformations core concept document biedt meer informatie over vervorming in projecties), evenals kleine variaties in precisie die kunnen worden geïntroduceerd door het projectie- en transformatieproces.
# Bij het lezen van feature services bevindt de geometrie zich meestal in een kolom genaamd "Shape." Dit kan worden bevestigd door naar de weergegeven tabel hierboven te kijken
display(
df_states.select("STATE_NAME",
"SQMI",
F.round(ST.area("Shape"), 2).alias("Area (sq decimal degrees"),
F.round(ST.area(ST.transform("Shape", 102003))/2.59e+6, 2).alias("Area (sqmi)"),
F.round(ST.geodesic_area("Shape")/2.59e+6, 2).alias("GeodesicArea (sqmi)")
)
)

Conclusie
Hopelijk is deze korte introductie over het maken van nieuwe geometrieën en het berekenen van hun eigenschappen nuttig geweest. We zullen aanvullende inhoud plaatsen om je op weg te helpen, dus kom terug op de Community voor meer! En laat ons alsjeblieft weten over welke onderwerpen je graag meer zou willen leren!