|
4 | 4 | "cell_type": "markdown",
|
5 | 5 | "metadata": {},
|
6 | 6 | "source": [
|
7 |
| - "# Advanced Topics\n", |
| 7 | + "# Spatially Enabled DataFrames - Advanced Topics\n", |
8 | 8 | "\n",
|
9 | 9 | "The information in this section provides a brief introduction to advanced topics with the `Spatially Enabled DataFrame` structure. \n",
|
10 | 10 | "\n",
|
11 | 11 | "One of the most important tasks for software applications is to quickly retrieve and process information. Enterprise systems, whether storing GIS information or not, all utilize the concept of indexing to allow for quick searching through large data stores to locate and select specific information for subsequent processing. \n",
|
12 | 12 | "\n",
|
13 |
| - "This document will outline how row and column indexing work in the Spatial Dataframe and also demonstrate building a spatial index on dataframe geometries to allow for quick searching, accessing, and processing. The document will also demonstrate spatial joins to combine dataframes.\n", |
| 13 | + "This document will outline how row and column indexing work in Spatially Enabled Dataframes and also demonstrate building a spatial index on dataframe geometries to allow for quick searching, accessing, and processing. The document will also demonstrate spatial joins to combine dataframes.\n", |
14 | 14 | "\n",
|
15 |
| - " * [Dataframe Index](#Dataframe-Index)\n", |
| 15 | + " * [DataFrame Index](#DataFrame-Index)\n", |
| 16 | + " * [Slicing DataFrames](#Slicing-DataFrames)\n", |
16 | 17 | " * [Spatial Index](#Spatial-Index)\n",
|
17 | 18 | " * [Intersection with the Spatial Index](#Intersection-with-the-Spatial-Index)\n",
|
18 | 19 | " * [Spatial Joins](#Spatial-Joins)\n",
|
|
23 | 24 | "cell_type": "markdown",
|
24 | 25 | "metadata": {},
|
25 | 26 | "source": [
|
26 |
| - "## Dataframe Index\n", |
27 |
| - "As mentioned in the [Introduction to the spatial dataframe guide](../introduction-to-the-spatial-dataframe), the Pandas [dataframe structure](https://pandas.pydata.org/pandas-docs/stable/dsintro.html#dataframe) underlies the ArcGIS API for Python Spatial Dataframe. Pandas dataframes are analagous to spreadsheets. They have a row axis and a column axis. Each of these axes are indexed and labeled for quick and easy identification, data alignment, and retrieval and updating of data subsets.\n", |
| 27 | + "## DataFrame Index\n", |
| 28 | + "As mentioned in the [Introduction to the Spatially Enabled DataFrame guide](../introduction-to-the-spatially-enabled-dataframe), the Pandas [DataFrame structure](https://pandas.pydata.org/pandas-docs/stable/dsintro.html#dataframe) underlies the ArcGIS API for Python's Spatially Enabled DataFrame. Pandas DataFrames are analagous to spreadsheets. They have a row axis and a column axis. Each of these axes are indexed and labeled for quick and easy identification, data alignment, and retrieval and updating of data subsets.\n", |
28 | 29 | "\n",
|
29 |
| - "Lets explore the axis labels and indices and how they allow for data exploraation:" |
| 30 | + "Let's explore the axes labels and indices and how they allow for data exploraation:" |
30 | 31 | ]
|
31 | 32 | },
|
32 | 33 | {
|
|
43 | 44 | "cell_type": "markdown",
|
44 | 45 | "metadata": {},
|
45 | 46 | "source": [
|
46 |
| - "When working with an ArcGIS Online feature layer, the [`query()`](https://esri.github.io/arcgis-python-api/apidoc/html/arcgis.features.toc.html#arcgis.features.FeatureLayer.query) method returns a `FeatureSet` object which has a `df` method to instantiate a Spatial Dataframe." |
| 47 | + "When working with an ArcGIS Online feature layer, the [`query()`](https://esri.github.io/arcgis-python-api/apidoc/html/arcgis.features.toc.html#arcgis.features.FeatureLayer.query) method returns a `FeatureSet` object which has a `sdf` method to instantiate a Spatially Enabled DataFrame." |
47 | 48 | ]
|
48 | 49 | },
|
49 | 50 | {
|
|
551 | 552 | "cell_type": "markdown",
|
552 | 553 | "metadata": {},
|
553 | 554 | "source": [
|
| 555 | + "### Slicing DataFrames\n", |
554 | 556 | "We can access rows, columns and subsets of rows and columns using Python slicing:"
|
555 | 557 | ]
|
556 | 558 | },
|
|
774 | 776 | "metadata": {},
|
775 | 777 | "source": [
|
776 | 778 | "## Spatial Index\n",
|
777 |
| - "In addition to row and column indices to search a dataframe, we can use a spatial indexes quickly access information based on its location and relationship with other features. They are based on the concept of a minimum bounding rectangle - the smallest rectangle that contains an entire geometric shape. Each of these rectangles are then grouped into `leaf` nodes representing a single shape and `node` structures containing groups of shapes according to whatever algorithm the different types of spatial indexing use. Querying these rectangles requires magnitudes fewer computer resources for accessing and processing geometries relative to accessing the entire feature array of coordinate pairs that compose a shape. Access to points, complex lines and irregularly-shaped polygons becomes much quicker and easier through different flavors of spatial indexing.\n", |
| 779 | + "In addition to row and column indices to search a DataFrame, we can use a spatial indexes to quickly access information based on its location and relationship with other features. They are based on the concept of a **minimum bounding rectangle** - the smallest rectangle that contains an entire geometric shape. Each of these rectangles are then grouped into `leaf` nodes representing a single shape and `node` structures containing groups of shapes according to whatever algorithm the different types of spatial indexing use. Querying these rectangles requires magnitudes fewer compute resources for accessing and processing geometries relative to accessing the entire feature array of coordinate pairs that compose a shape. Access to points, complex lines and irregularly-shaped polygons becomes much quicker and easier through different flavors of spatial indexing.\n", |
778 | 780 | "\n",
|
779 |
| - "The Spatial DataFrame uses an implementation of spatial indexing known as [QuadTree indexing](https://en.wikipedia.org/wiki/Quadtree), which searches nodes when determining locations, relationships and attributes of specific features. QuadTree indexes are the default spatial index, but the SEDF also supports r-tree implementations. In the [**Dataframe Index**](#Datframe-index) section of this notebook, the USA Major Cities feature layer was queried and the `df` method was called on the results to create a data frame. The [`sindex`](https://esri.github.io/arcgis-python-api/apidoc/html/arcgis.features.html?highlight=style#arcgis.features.SpatialDataFrame.sindex) method on the `df` creates a quad tree index:" |
| 781 | + "The Spatially Enabled DataFrame uses an implementation of spatial indexing known as [QuadTree indexing](https://en.wikipedia.org/wiki/Quadtree), which searches nodes when determining locations, relationships and attributes of specific features. `QuadTree` indexes are the default spatial index, but the SEDF also supports `r-tree` implementations. In the [**DataFrame Index**](#DataFrame-index) section of this notebook, the USA Major Cities feature layer was queried and the `sdf` property was called on the results to create a DataFrame. The [`sindex`](https://esri.github.io/arcgis-python-api/apidoc/html/arcgis.features.toc.html#arcgis.features.GeoAccessor.sindex) method on the DataFrame creates a QuadTree index:" |
780 | 782 | ]
|
781 | 783 | },
|
782 | 784 | {
|
|
792 | 794 | "cell_type": "markdown",
|
793 | 795 | "metadata": {},
|
794 | 796 | "source": [
|
795 |
| - "Let's visually inspect the external frame of the Quadtree index. We'll then plot the spatial dataframe to ensure the spatial index encompasses all our features:" |
| 797 | + "Let's visually inspect the external frame of the QuadTree index. We'll then plot the spatial dataframe to ensure the spatial index encompasses all our features:" |
796 | 798 | ]
|
797 | 799 | },
|
798 | 800 | {
|
|
861 | 863 | "cell_type": "markdown",
|
862 | 864 | "metadata": {},
|
863 | 865 | "source": [
|
864 |
| - "Let's use the feature we drew above to define a spatial reference variable for use throughout the rest of this guide." |
| 866 | + "Let's use the feature we drew earlier to define a spatial reference variable for use throughout the rest of this guide." |
865 | 867 | ]
|
866 | 868 | },
|
867 | 869 | {
|
|
1477 | 1479 | "sym_poly = {\n",
|
1478 | 1480 | " \"type\": \"esriSFS\",\n",
|
1479 | 1481 | " \"style\": \"esriSFSSolid\",\n",
|
1480 |
| - " \"color\": [0,0,0,0],\n", |
| 1482 | + " \"color\": [0,0,0,0], # hollow, no fill\n", |
1481 | 1483 | " \"outline\": {\n",
|
1482 | 1484 | " \"type\": \"esriSLS\",\n",
|
1483 | 1485 | " \"style\": \"esriSLSSolid\",\n",
|
1484 |
| - " \"color\": [255,0,0,255],\n", |
| 1486 | + " \"color\": [255,0,0,255], # red border\n", |
1485 | 1487 | " \"width\": 3}\n",
|
1486 | 1488 | "}\n",
|
1487 | 1489 | "\n",
|
|
1512 | 1514 | "sym_poly_aoi = {\n",
|
1513 | 1515 | " \"type\": \"esriSFS\",\n",
|
1514 | 1516 | " \"style\": \"esriSFSSolid\",\n",
|
1515 |
| - " \"color\": [0,0,0,0],\n", |
| 1517 | + " \"color\": [0,0,0,0], # hollow, no fill\n", |
1516 | 1518 | " \"outline\": {\n",
|
1517 | 1519 | " \"type\": \"esriSLS\",\n",
|
1518 | 1520 | " \"style\": \"esriSLSSolid\",\n",
|
1519 |
| - " \"color\": [0,255,0,255],\n", |
| 1521 | + " \"color\": [0,255,0,255], # green border\n", |
1520 | 1522 | " \"width\": 3}\n",
|
1521 | 1523 | "}\n",
|
1522 | 1524 | "\n",
|
|
1783 | 1785 | "df.iloc[index_of_features]"
|
1784 | 1786 | ]
|
1785 | 1787 | },
|
| 1788 | + { |
| 1789 | + "cell_type": "markdown", |
| 1790 | + "metadata": {}, |
| 1791 | + "source": [ |
| 1792 | + "Let us plot these features that intersect on a map:" |
| 1793 | + ] |
| 1794 | + }, |
1786 | 1795 | {
|
1787 | 1796 | "cell_type": "code",
|
1788 | 1797 | "execution_count": 27,
|
1789 |
| - "metadata": {}, |
| 1798 | + "metadata": { |
| 1799 | + "scrolled": true |
| 1800 | + }, |
1790 | 1801 | "outputs": [
|
1791 | 1802 | {
|
1792 | 1803 | "data": {
|
|
1842 | 1853 | "pt_sym = {\n",
|
1843 | 1854 | " \"type\": \"esriSMS\",\n",
|
1844 | 1855 | " \"style\": \"esriSMSDiamond\",\n",
|
1845 |
| - " \"color\": [255,140,0,255], \n", |
| 1856 | + " \"color\": [255,140,0,255], # yellowish\n", |
1846 | 1857 | " \"size\": 8,\n",
|
1847 | 1858 | " \"angle\": 0,\n",
|
1848 | 1859 | " \"xoffset\": 0,\n",
|
|
1856 | 1867 | " m2.draw(shape = df.iloc[pt_index]['SHAPE'], symbol = pt_sym) "
|
1857 | 1868 | ]
|
1858 | 1869 | },
|
| 1870 | + { |
| 1871 | + "cell_type": "markdown", |
| 1872 | + "metadata": {}, |
| 1873 | + "source": [ |
| 1874 | + "Thus we were able to use the spatial indexes to query features that fall within an extent." |
| 1875 | + ] |
| 1876 | + }, |
1859 | 1877 | {
|
1860 | 1878 | "cell_type": "markdown",
|
1861 | 1879 | "metadata": {},
|
1862 | 1880 | "source": [
|
1863 | 1881 | "## Spatial Joins\n",
|
1864 |
| - "Dataframes are table-like structures comprised of rows and columns. In relational database, SQL `joins` are fundamental operations that combine columns from one or more tables using values that are common to each. They occur in almost all database queries.\n", |
| 1882 | + "DataFrames are table-like structures comprised of rows and columns. In relational database, SQL `joins` are fundamental operations that combine columns from one or more tables using values that are common to each. They occur in almost all database queries.\n", |
1865 | 1883 | "\n",
|
1866 | 1884 | "A Spatial join is a table operation that affixes data from one feature layer’s attribute table to another based on a spatial relationship. The spatial join involves matching rows from the Join Features (data frame1) to the Target Features (data frame2) based on their spatial relationship.\n",
|
1867 | 1885 | "\n",
|
1868 |
| - "Let's look at how joins work with dataframes by using subsets of our original dataframe and the pandas `merge` fucntionality. We'll then move onto examining a spatial join to combine features from one dataframe with another based on a common attribute value.\n", |
| 1886 | + "Let's look at how joins work with dataframes by using subsets of our original DataFrame and the pandas `merge` fucntionality. We'll then move onto examining a spatial join to combine features from one dataframe with another based on a common attribute value.\n", |
1869 | 1887 | "\n",
|
1870 |
| - "Query the dataframe to extract 3 attribute columns of information from 2 states, Ohio and Michigan:" |
| 1888 | + "Query the DataFrame to extract 3 attribute columns of information from 2 states, Ohio and Michigan:" |
1871 | 1889 | ]
|
1872 | 1890 | },
|
1873 | 1891 | {
|
|
2507 | 2525 | "cell_type": "markdown",
|
2508 | 2526 | "metadata": {},
|
2509 | 2527 | "source": [
|
2510 |
| - "Notice how all the rows from the left dataframe appear in the result with all the attribute columns and values appended from the right dataframe where the column value of NAME matched. The `POP2010` attribute from the left dataframe is combined with all the attributes from the right dataframe." |
| 2528 | + "Notice how all the rows from the left `DataFrame` appear in the result with all the attribute columns and values appended from the right `DataFrame` where the column value of `NAME` matched. The `POP2010` attribute from the left `DataFrame` is combined with all the attributes from the right `DataFrame`." |
2511 | 2529 | ]
|
2512 | 2530 | },
|
2513 | 2531 | {
|
|
2879 | 2897 | "cell_type": "markdown",
|
2880 | 2898 | "metadata": {},
|
2881 | 2899 | "source": [
|
2882 |
| - "The rows where the on parameter value is the same in both tables have all attributes from both dataframes in the result. The rows from the first dataframe that do not have a matching `NAME` value in the second dataframe have values filled in with NaN values." |
| 2900 | + "The rows where the on parameter value is the same in both tables have all attributes from both DataFrames in the result. The rows from the first DataFrame that do not have a matching `NAME` value in the second dataframe have values filled in with `NaN` values." |
2883 | 2901 | ]
|
2884 | 2902 | },
|
2885 | 2903 | {
|
2886 | 2904 | "cell_type": "markdown",
|
2887 | 2905 | "metadata": {},
|
2888 | 2906 | "source": [
|
2889 |
| - "A spatial join works similarly on matching attribute values.\n", |
| 2907 | + "A spatial join works similarly on matching attribute values. However, instead of joining on an attribue field (like you did earlier), you will join based on the spatial relationship between the records in the two tables.\n", |
2890 | 2908 | "\n",
|
2891 | 2909 | "#### Example: Merging State Statistics Information with Cities\n",
|
2892 | 2910 | "\n",
|
2893 |
| - "The goal is to get Wyoming's city locations and census data joined with Wymoing's state census data.\n", |
| 2911 | + "The goal is to get Wyoming's city locations and census data joined with Wyoming's state census data.\n", |
2894 | 2912 | "> If you do not have access to the `ArcPy` site-package from the Python interpreter used to execute the following cells, you must authenticate to an ArcGIS Online Organization or ArcGIS Enterprise portal."
|
2895 | 2913 | ]
|
2896 | 2914 | },
|
|
2948 | 2966 | "cell_type": "markdown",
|
2949 | 2967 | "metadata": {},
|
2950 | 2968 | "source": [
|
2951 |
| - "We will use python's list comprehensions to create lists of the attribute columns in the dataframe, then print out the lists to see the names of all the attribute columns." |
| 2969 | + "We will use python's list comprehensions to create lists of the attribute columns in the DataFrame, then print out the lists to see the names of all the attribute columns." |
2952 | 2970 | ]
|
2953 | 2971 | },
|
2954 | 2972 | {
|
|
3036 | 3054 | "cell_type": "markdown",
|
3037 | 3055 | "metadata": {},
|
3038 | 3056 | "source": [
|
3039 |
| - "Create a dataframe for the cities in Wyoming:" |
| 3057 | + "Create a DataFrame for the cities in Wyoming:" |
3040 | 3058 | ]
|
3041 | 3059 | },
|
3042 | 3060 | {
|
|
3703 | 3721 | "sdf2"
|
3704 | 3722 | ]
|
3705 | 3723 | },
|
| 3724 | + { |
| 3725 | + "cell_type": "markdown", |
| 3726 | + "metadata": {}, |
| 3727 | + "source": [ |
| 3728 | + "Notice, you retain the geometry type of your left DataFrame (points) in this case, however, you get all the attributes from both the left and right DataFrames. Let us plot the results of the spatial join on a map:" |
| 3729 | + ] |
| 3730 | + }, |
3706 | 3731 | {
|
3707 | 3732 | "cell_type": "code",
|
3708 | 3733 | "execution_count": 47,
|
|
3755 | 3780 | "for idx, row in sdf2.iterrows():\n",
|
3756 | 3781 | " m3.draw(row['SHAPE'], symbol=pt_sym)"
|
3757 | 3782 | ]
|
| 3783 | + }, |
| 3784 | + { |
| 3785 | + "cell_type": "markdown", |
| 3786 | + "metadata": {}, |
| 3787 | + "source": [ |
| 3788 | + "## Conclusion\n", |
| 3789 | + "Spatially Enabled DataFrame give you powerful data analysis and data wrangling capabilities. In addition to performing sql like operations on attribute data, you can perform geographic queries. This guide demonstrated some of these advanced capabilities of the SEDF." |
| 3790 | + ] |
3758 | 3791 | }
|
3759 | 3792 | ],
|
3760 | 3793 | "metadata": {
|
|
3773 | 3806 | "name": "python",
|
3774 | 3807 | "nbconvert_exporter": "python",
|
3775 | 3808 | "pygments_lexer": "ipython3",
|
3776 |
| - "version": "3.6.5" |
| 3809 | + "version": "3.6.6" |
3777 | 3810 | }
|
3778 | 3811 | },
|
3779 | 3812 | "nbformat": 4,
|
|
0 commit comments