Abychom pomohli odstartovat veřejnou ukázku ArcGIS GeoAnalytics pro Microsoft Fabric, připravíme sérii blogových příspěvků, které prozkoumají funkce GeoAnalytics pro Fabric. V tomto příspěvku se zaměříme na základy výpočtu / konstrukce nových geometrií, jako jsou buffery, prostorové koše a nejkratší cesty. Také se podíváme na výpočet vlastností, jako je délka a plocha těchto nových geometrií.
Importování GeoAnalytics pro Fabric
Začneme připomenutím, jak importovat GeoAnalytics pro Fabric a začít s ním pracovat. Pro import GeoAnalytics pro Fabric stačí přidat import geoanalytics_fabric do buňky ve vašem notebooku. Pro více informací o povolení knihovny si přečtěte dokumentaci Začínáme.
Pro pohodlí doporučujeme také importovat geospatial functions přímo a přiřadit jim snadno použitelné aliasy pro odkazování. V níže uvedeném příkladu importujeme knihovnu a funkce s aliasem ST. Protože každá z funkcí je pojmenována ST.<function_name>, usnadňuje to jejich odkazování a identifikuje je jako Spatial Type (ST) funkce. To také odpovídá struktuře příkladů v celé dokumentaci ArcGIS GeoAnalytics. Vaše buňka bude vypadat takto:
# import ArcGIS GeoAnalytics
import geoanalytics_fabric
import geoanalytics_fabric.sql.functions as ST
Například po importu budete moci odkazovat na funkci ST_Buffer pomocí ST.buffer místo geoanalytics_fabric.sql.functions.buffer.
Výpočet nových geometrií
GeoAnalytics pro Fabric obsahuje řadu prostorových operací pro generování nových geometrií na základě vstupu. Například v tomto příspěvku prozkoumáme několik běžných funkcí:
I když se v tomto příspěvku podrobněji podíváme na několik funkcí, v knihovně GeoAnalytics pro Fabric je mnoho dalších, které by vás mohly zajímat pro vaše analytické projekty. Můžete prozkoumat rozsah funkcí v dokumentaci SQL Functions.
Pojďme začít s několika buffery!
ST_Buffer & ST_GeodesicBuffer
ST_Buffer a ST_GeodesicBuffer vytvářejí polygony představující oblast menší nebo rovnou zadané vzdálenosti kolem vstupní geometrie (např. oblast do 10 mil kolem bodu). Tyto funkce vytvoří tento buffer kolem každého prvku ve sloupci geometrie.
Abychom viděli, jak to funguje, začneme vytvořením nového DataFrame s několika školami v oblasti Bostonu. Tyto školy obalíme buffery, abychom vizuálně viděli oblast kolem každé školy. Zde je příklad vytvoření nového DataFrame s několika bodovými lokalitami:
# vytvoření DataFrame s lokalitami několika škol (v zeměpisné šířce a délce)
df_schools = spark.createDataFrame([
(-71.0777, 42.3388, "Hurley K-8"),
(-71.0919,42.3176, "Higginson Elementary School"),
(-71.1016, 42.3164, "Mendell Elementary School")], ["longitude", "latitude", "name"])
# vytvoření sloupce geometrie bodu ("geometry") ze zeměpisné délky a šířky
df_schools = df_schools\
.withColumn("geometry", ST.point("longitude", "latitude", sr=4326))
Zde jsou výsledky:

Nyní můžeme vytvořit buffery kolem těchto škol.
Jednotka vzdálenosti pro buffer je stejná jako jednotky vstupní geometrie. Například pokud jsou data ve web Mercator souřadnicovém systému, jednotky budou metry; pokud jsou data v geografickém souřadnicovém systému, jednotky budou desetinné stupně.
Funkce ST_GeodesicBuffer může být použita k vytvoření bufferů pomocí geodetické vzdálenosti v metrech. Vytvořme několik bufferů a podívejme se na ně - a uvidíme, jak se liší planar buffer a geodetický buffer.
# vytvoření příkladových bufferů pomocí ST_Buffer a ST_GeodesicBuffer
# Tento příklad generuje buffer o velikosti 0.5 _desetinných stupňů_ (jednotky vstupních dat jsou hodnoty zeměpisné šířky/délky!)
# Také vytvoří geodetický buffer o velikosti 500 metrů
df_schools = df_schools\
.withColumn("geometry_buffer", ST.buffer("geometry", 0.5))\
.withColumn("geometry_geodesic_buffer", ST.geodesic_buffer("geometry", 500))
Nejprve se podíváme na planar buffer - který byl vypočítán v jednotkách vstupní geometrie (desetinné stupně). Toto je buffer o velikosti 0.5 desetinného stupně kolem tří škol:

Všimněte si, že jsem nechal popisky os na mapě, abyste viděli, že se jedná o vykreslení na podkladové mapě v desetinných stupních.
A nyní se podíváme na geodetické buffery kolem škol. Všimněte si, že i toto je vykresleno na podkladové mapě v desetinných stupních. Vidíme, že buffery jsou mnohem menší (500 m kolem každé školy) a nejsou kruhové. Pojďme zjistit proč...

Při vykreslování těchto bufferů je třeba si všimnout několika klíčových věcí:
- Buffery v prvním grafu vypadají obrovské, zatímco buffery ve druhém jsou mnohem menší. "geometry_buffer" má velikost půl desetinného stupně, zatímco "geometry_geodesic_buffer" má jen 500 metrů. Jeden desetinný stupeň je výrazně delší než 500 metrů. Na rovníku je jeden stupeň zeměpisné šířky nebo délky téměř 111 mil!
- Buffery v prvním grafu ("geometry_buffer") vypadají kruhově, zatímco buffery ve druhém grafu ("geometry_geodesic_buffer") vypadají jako ovály. Proč tomu tak je? Oba tyto mapy jsou generovány na mapě na základě souřadnic zeměpisné šířky a délky. V těchto grafech je jeden stupeň zeměpisné šířky roven jednomu stupni zeměpisné délky na délku. Na Zemi se délka jednoho stupně zeměpisné šířky a délky liší, přičemž stupeň zeměpisné délky se zkracuje, čím blíže jste k pólům. Článek na Wikipedii o <\/SPAN>Longitude<\/A> <\/SPAN>toto podrobně rozebírá, pokud byste chtěli více informací. Když jsou geodetické buffery vykresleny na této konkrétní mapové projekci, vypadají jako protáhlé ovály, i když by na povrchu Země byly kruhové.<\/LI><\/UL>Pokud bychom vykreslili geodetický buffer v našem místním bostonském souřadnicovém systému (SRID 2249), buffery vypadají jako kruhy, které bychom očekávali.<\/P>Můžeme aktualizovat mapu při jejím vykreslování přidáním parametru <\/SPAN>sr<\/FONT> <\/SPAN>(prostorová reference). Níže uvedený příklad kódu to demonstruje. Více informací o parametrech pro <\/SPAN>st.plot<\/FONT> <\/SPAN>najdete v <\/SPAN>API reference<\/A>.<\/P>
<\/P>
# vykreslení geometry_geodesic_buffer na mapě s prostorovou referencí 2249
df_schools\\
.st.plot(basemap="streets", geometry="geometry_geodesic_buffer", alpha=0.5, edgecolor="black", sr=2249);<\/code><\/pre><P> <\/P><P>Obecně je rychlejší spustit<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>funkce pro identifikaci<SPAN> </SPAN><A href="https://h3geo.org/" target="_blank" rel="noopener nofollow noreferrer">H3 binu</A><SPAN> </SPAN>, ve kterém se nachází každý z našich bodů požadavků na službu. Poté použijeme 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>funkci k vytvoření zjednodušeného DataFrame, který uvádí počet bodů uvnitř každého binu.</P><P>Velikost H3 binů je založena na hodnotě rozlišení. Pro tento příklad použijeme rozlišení 8, což odpovídá průměrné velikosti hexagonálního binu 0,73 čtverečních kilometrů. Více informací o<SPAN> </SPAN><A href="https://h3geo.org/docs/core-library/restable" target="_blank" rel="noopener nofollow noreferrer">rozlišeních H3 binů najdete zde</A>.</P><P>Přidání ID pro bin je tak jednoduché jako vytvoření nového sloupce pro data a použití funkce bin pro typ geometrie, který chcete (hexagonální, čtvercový nebo H3):</P><P> </P><pre class="lia-code-sample language-python"><code># přidat sloupec s H3 bin _id_, ve kterém se každý bod nachází
df = df\
.withColumn("h3_bin", ST.h3_bin("geometry", 8))
Funkce
ST_H3Bin přidává bin id ke každému záznamu. Nepřidává konkrétně geometrii, protože by bylo mnoho duplicit geometrie (jedna pro každý bod uvnitř binu) a je efektivnější pracovat s ID, dokud nepotřebujeme geometrie pro analýzu nebo vizualizaci. Tyto nové bin ID můžeme vidět v tabulce níže:
Pomocí h3_bin ID pole pak můžeme seskupit hodnoty v naší tabulce a spočítat záznamy v každém binu. # seskupit DataFrame požadavků na služby podle h3 bin ID a spočítat všechny záznamy
df_by_bin = df.groupBy("h3_bin").count() Po seskupení vidíme, že každé bin ID má počet bodů uvnitř něj. Poté můžeme převést bin ID na geometrie a vizualizovat výsledky.
Zde je způsob, jak přidat geometrii binu do tabulky pomocí funkce ST_BinGeometry: # přidat geometrii binu na základě bin ID pomocí ST_BinGeometry
df_by_bin = df_by_bin\
.withColumn("geometry_bin", ST.bin_geometry("h3_bin")) Zobrazení výsledků nyní ukazuje, kde dochází k největší koncentraci požadavků na služby:
Nyní se podíváme na výpočet některých linií a vzdáleností mezi místy!ST_ShortestLine a ST_GeodesicLineST_ShortestLine vrací sloupec typu linestring představující nejkratší čáru, která se dotýká dvou geometrií, pomocí výpočtu rovinné vzdálenosti. Tato funkce vrací pouze jednu nejkratší čáru, pokud jich lze vypočítat více mezi místy.Pro vytvoření nejkratší čáry pomocí geodetických výpočtů vzdálenosti použijte ST_GeodesicShortestLine.Jako příklad si ukážeme nejkratší čáru mezi DataFrame škol, které jsme vytvořili dříve, a blízkými požadavky na služby. Nejkratší čára bude používat dva sloupce geometrie jako vstup, takže musí být ve stejném DataFrame.V příkladech bufferu výše jsme použili ST_Contains k nalezení všech bodů uvnitř polygonu bufferu.V tomto příkladu použijeme jiný prostorový výpočet nazvaný ST_DWithin(vzdálenost v rámci) k nalezení všech bodů v určené vzdálenosti od školních bodů. Efektivně to může dát stejný výsledek, avšak DWithin je často výkonnější než vytváření bufferu a provádění prostorového spojení. DWithin používá výpočty roviny ve výchozím nastavení, takže bychom měli buď transformovat geometrii do lokálního souřadnicového systému, nebo nastavit parametr pro použití geodetických výpočtů.V tomto případě použijeme ST_Transform k aktualizaci souřadnicového systému pro tento výpočet. Uděláme to v jednom výpočtu, kde spojíme školy a požadavky na služby a vytvoříme nový DataFrame s výsledky: # najít všechny body do 500 stop od každé školy
# použít prostorové spojení k přiřazení jakéhokoli bodu, který je v určené vzdálenosti od školy
# protože datové sady jsou původně v souřadnicích zeměpisné šířky/délky, nejprve transformujeme do lokálního souřadnicového systému
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)) Nyní když má každá škola geometrii školy i blízkých bodů, můžeme použít tyto dvě geometrie k výpočtu nejkratší čáry mezi každým bodem požadavku na službu a školou. # vypočítat nejkratší čáru od každého bodu ke každé škole
df_schools_requests = df_schools_requests\
.withColumn("geometry_line", ST.shortest_line("geometry", "geometry_school")) Pojďme se podívat na výsledek pro jednu školu: # vykreslit spojovací čáry mezi jednou školou a všemi body do 500 stop od tohoto místa
df_schools_requests.filter(F.col("name") == "Hurley K-8").st.plot(basemap="streets", geometry="geometry_line", linewidth=0.5, alpha=0.7);
Pro krátké vzdálenosti je ST_ShortestLine dobrou volbou, ale pro delší vzdálenosti můžete zvážit použití ST_GeodesicShortestLine, aby vytvořená čára představovala nejkratší cestu po sféře. Jako příklad rozdílu mezi "nejkratší čarou" (rovinný výpočet) a geodetickou čarou můžeme prozkoumat rozdíl mezi čarou spojenou mezi Los Angeles a Londýnem. V tomto příkladu se geodetická čára (oranžová) jeví zakřiveně a delší v této projekci, ale ve skutečnosti je to nejkratší čára! # geodetická čára (geodesic) (oranžová) vs. "nejkratší čára" (rovinná) (modrá)
# geodetická čára se v této projekci jeví zakřiveně a delší, ale ve skutečnosti je to nejkratší čára!
# vytvořit body pro dvě lokace
data = [
("POINT (-118.2426 34.0549 )", "Los Angeles",
"POINT (0.1276 51.5072 )", "London")
]
# vytvoření DataFrame se dvěma lokalitami
# převod lokalit z well-known textu na geometrii
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"))
# vykreslení výsledků pro porovnání dvou generovaných čar (geodetická vs. nejkratší)
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);
Výpočty vzdálenosti a délkyNyní se podíváme na vzdálenost a délku těchto čar...ST_Distance a ST_GeodesicDistance vypočítají vzdálenost mezi dvěma vstupními lokalitami. Jednotka pro ST_Distance je stejná jako u vstupních geometrií. Pro ST_GeodesicDistance je vzdálenost vypočítána v metrech. - ST_Length a ST_GeodesicLength vypočítají délku vstupního prvku. Jednotka pro ST_Length je stejná jako u vstupní geometrie. Pro ST_GeodesicLength je délka vypočítána v metrech.
S výpočtem vzdálenosti můžeme také využít velmi užitečnou vlastnost knihovny GeoAnalytics - projekci za běhu. Pokud chcete vypočítat vlastnost nebo vztah pomocí dvou geometrií, které jsou v různých souřadnicových systémech, knihovna často dokáže tento rozdíl vyřešit za vás, takže nemusíte data transformovat.
- Sloupec geometry (servisní požadavky) je v Massachusetts State Plane souřadnicovém systému (SRID 2249)
- Sloupec geometry_school (lokality škol) je ve WGS84 zeměpisné šířce a délce (SRID 4326)
Použijme tyto dvě geometrie a vypočítejme různé výpočty vzdálenosti a uvidíme, jak GeoAnalytics může pracovat s geometriemi v různých souřadnicových systémech! V následující buňce počítáme:
- Vzdálenost mezi dvěma geometriemi bez transformace souřadnic
- Vzdálenost mezi dvěma geometriemi s transformací pro převod geometry_school do Massachusetts State Plane (2249)
- Geodetickou vzdálenost mezi dvěma geometriemi bez transformace
Také spočítáme délku čáry geometry_line, kterou jsme dříve vytvořili pro propojení dvou bodových lokalit. Tyto výpočty provedeme a zobrazíme výsledky jako příklad:
display(
df_schools_requests.select("geometry",
"geometry_school",
F.round(ST.distance("geometry", "geometry_school"), 2).alias("Vzdálenost (bez transformace)"),
F.round(ST.distance("geometry", ST.transform("geometry_school", 2249)),2).alias("Vzdálenost (s transformací)"),
F.round(ST.geodesic_distance("geometry", "geometry_school"),2).alias("Geodetická vzdálenost (metry)"),
"geometry_line",
F.round(ST.length("geometry_line"),2).alias("Délka (stopy)"),
F.round(ST.geodesic_length("geometry_line"),2).alias("Geodetická délka (metry)")
)
)

Toto ukazuje, jak můžete provádět tyto výpočty i s geometriemi v různých souřadnicových systémech! GeoAnalytics for Fabric skvěle pomáhá zmírnit rozdíly v souřadnicových systémech, kde je to možné.
Nyní si vezmeme poslední pohled na některé vlastnosti, které můžeme vypočítat, a prozkoumáme plochu.
ST_Area a ST_GeodesicArea
ST_Area - vypočítává plošnou plochu pro každou geometrii. Jednotka plochy je stejná jako u vstupních geometrií. Pokud počítáte plochu na datasetu v geografickém souřadnicovém systému, jednotky budou čtvereční desetinné stupně. Toto není doporučená jednotka. Pro použití funkce ST_Area je nejlepší použít projektovaný souřadnicový systém. Více informací je k dispozici v dokumentu základních konceptů Souřadnicové systémy a transformace.
ST_GeodesicArea vypočítává plochu pro každou geometrii v metrech čtverečních a vyžaduje nastavení prostorové reference na vstupním sloupci geometrie.
Pro tento příklad spočítáme plochy států USA, které jsme načetli z ArcGIS feature service.
# Feature service států USA z Esri Living Atlas of the World
# Pro více informací o tomto datasetu: 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)
Před výpočtem plochy bychom měli zkontrolovat souřadnicový systém dat, abychom věděli více o jednotkách používaných v souřadnicovém systému a rozhodli se, zda použijeme ST_Area nebo ST_GeodesicArea. To můžeme udělat pomocí funkce get_spatial_reference()
df_states.st.get_spatial_reference()
Který vrací informace ukazující, že data mají SRID 4326 (souřadnicový systém WGS84)
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]]')
Pro tento dataset se podíváme na hodnoty vypočtené funkcemi ST_Area a ST_GeodesicArea.
V níže uvedeném příkladu zobrazujeme původní data pro název státu a čtvereční míle a tři nové vypočtené pole, všechny zaokrouhlené na dvě desetinná místa pro lepší čitelnost pomocí PySpark Round()
- Plocha pomocí ST_Area - protože prostorová reference je 4326 s jednotkou Degree, výsledky budou v čtverečních desetinných stupních, což nemá praktickou hodnotu
- Plocha pomocí ST_Area na transformované geometrii pomocí projekce USA Contiguous Albers Equal Area (102003). Tento výpočet vrací metry čtvereční, proto jsou v příkladu níže převedeny na čtvereční míle
- Plocha pomocí ST_GeodesicArea na původní geometrii. Tento výpočet vrací metry čtvereční, proto jsou převedeny na čtvereční míle v příklad níže
Vrácené hodnoty jsou všechny velmi blízké jedna druhé, ale nejsou přesně stejné. Tyto odchylky jsou způsobeny zkreslením při výpočtu plochy pro velké oblasti (dokument Coordinate Systems and Transformations core concept document poskytuje více informací o zkreslení v projekcích), stejně jako drobnými rozdíly v přesnosti, které mohou být zavedeny procesem projekce a transformace.
# Při čtení feature services je geometrie obvykle ve sloupci nazvaném "Shape." Toto lze potvrdit pohledem na zobrazenou tabulku výše
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)")
)
)

Závěr
Doufejme, že tento rychlý úvod do vytváření nových geometrií a výpočtu jejich vlastností byl užitečný. Budeme zveřejňovat další obsah, který vám pomůže začít, takže se vraťte na Community pro více! A prosím dejte nám vědět, o jaké typy věcí byste se chtěli dozvědět více!