I have a dataset where I've managed to calculate the different percentages of features that have a specific landuse, e.g. grass, woodland, arable etc but I now have several rows for each filter. What i'd like to b able to do is create just one row per feature which has the original attributes plus new fields giving the different percentages of land use. What I have is
lucode | Land_Use_D | Land_Cover | ListEntry | Shape_Leng | Shape_Area | Perc |
PG01 | Grass | 1001718 | 167.19716784000 | 2141.68791892000 | 100 | |
PG01 | Grass | 1001719 | 84.34317002770 | 226.68991995300 | 23.95 | |
TC01 | Perennial Crops and Isolated Trees | Trees | 1001719 | 104.03389277900 | 719.78224659500 | 76.05 |
PG01 | Grass | 1001720 | 433.06711916800 | 6118.86022813000 | 40.04 | |
TC01 | Perennial Crops and Isolated Trees | Trees | 1001720 | 447.45356525900 | 2407.74789032000 | 15.76 |
WO12 | Trees and Scrubs, short Woody plants, hedgerows | 1001720 | 359.49582097800 | 6754.43756722000 | 44.2 |
What I want is
ListEntry | Shape_Leng | Shape_Area | Perc | Landuse1 | Landuse1_% | Landuse2 | Landuse2_% | Landuse3 | Landuse3_% |
1001718 | 167.19716784000 | 2141.68791892000 | 100 | Grass | 100.00 | ||||
1001719 | 84.34317002770 | 226.68991995300 | 23.95 | Perennial Crops and Isolated Trees | 76.05 | Grass | 23.95 | ||
1001720 | 433.06711916800 | 6118.86022813000 | 40.04 | Trees and Scrubs, short Woody plants, hedgerows | 44.20 | Grass | 40.04 | Perennial Crops and Isolated Trees | 15.76 |
Is this possible? There've been some really helpful people who've helped me split tables, but this is the opposite.
i'm happy to provide the dataset if that helps, but it's quite big.
I hope someone can help.
Ta
not quite a pivot table?
Pivot Table (Data Management)—ArcGIS Pro | Documentation
Hi Simon.
This is a script to run in Python - just use a Jupyter Notebook in Pro. Note that I matched your variable naming when available. In the first code block (chunk):
classes=['AB0', 'AB1', 'AB2', 'AB3', 'AB4']
classes_pct = ['AB0_pct', 'AB1_pct', 'AB2_pct', 'AB3_pct', 'AB4_pct']
These are values I created for the lucode (as examples). Follow Comments (#) and reach out with any Qs. Note that you need to create your new feature in advance - feat_create, and add the classes_pct values as fields to the attribute table of said new feature. Since they are percentages, create a type Double.
@DanPatterson method is way easier if you have the license, however you may need to copy in the geometry when it's run as upon my test, it only outputs a Table, not a Feature Class.
# esri forum
import numpy as np
import pandas as pd
import copy as copy
# Original Split Feature
feat_base = 'esri_forum'
# Create a New Feature of Same geometry
feat_create = 'esri_forum2'
classes=['AB0', 'AB1', 'AB2', 'AB3', 'AB4']
classes_pct = ['AB0_pct', 'AB1_pct', 'AB2_pct', 'AB3_pct', 'AB4_pct']
# Use this later for efficieny - it's a dictionary
fld_dict={k:v for k,v in zip(classes, classes_pct)}
# Create a Pandas DataFrame (basically an Excel spreadsheet)
# Number of rows = Number of unique ListDir values
# Number of cols = Number of unique classifications i.e. Grass, Trees, etc.
num_rows = 3
num_cols = 5
arr = np.zeros([num_rows, num_cols])
col_names=copy.copy(classes_pct)
unique_ListEntry=[100,111,124]
df_pct=pd.DataFrame(data=arr, index=unique_ListEntry, columns=col_names)
# Populate DataFrame with Values from Attribute Table per row and column
with arcpy.da.SearchCursor(feat_base, ['lucode','Perc','ListEntry']) as cursor_src:
for row in cursor_src:
col_name=fld_dict[row[0]]
df_pct.at[row[2], col_name]=row[1]
# Trick to create new Row ONLY when it hasn't been created; only need one row per ListEntry
arr_flag=np.full((3,1), False)
df_flag = pd.DataFrame(arr_flag, index=unique_ListEntry, columns=['FLAG'])
# Add Rows to New Feature Class; one row for each unique ListEntry
# flds_tgt = the fields to include in new FC
flds_tgt=['SHAPE@','ListEntry']
flds_tgt.extend(classes_pct)
with arcpy.da.SearchCursor(feat_base, ['SHAPE@','ListEntry']) as cursor_src:
with arcpy.da.InsertCursor(feat_create, flds_tgt) as cursor_tgt:
for row_src in cursor_src:
if not df_flag.loc[row_src[1],'FLAG']:
new_row_atts = df_pct.loc[row_src[1]].to_list()
# Add geometry
new_row = [row_src[0]]
# Add ListEntry Val
new_row.append(row_src[1])
new_row.extend(new_row_atts)
df_flag.at[row_src[1],'FLAG']=True
cursor_tgt.insertRow(new_row)
else:
pass
del cursor_src
del cursor_tgt
Hi Zachary, Thanks for that. I can't pretend that I understand what this is or how it works, but if it does the job, great.
I'm afraid that I do have a couple of questions, the key one is where to create the new feature. Does it have to be somewhere specific, and how do I point to it.
It's not a massive issue if it only creates a table as I can easily join that back to the feature class by ListUID.
Thanks again.
Hi Simon - do you have an Advanced License to run a Pivot Table? If so, then that's way easier - as you said just join the resultant table to an adapted version of the data. By adapted I mean, use a version of the data with just one row for each ListEntry. I honestly did not know about a Pivot Table in Arc. I've heard of it in Excel and general, but never knew what it was.
If you don't have the license, this script works, and quickly, but I need to instruct you on where to change variables, etc. to match your data.
Hi Zachary, I'll have to check with our IT team, as I don't honestly know.
I'll come back if not; if you're okay to talk me through it, that would be very kind.
Thanks