天天看點

第七章 用于地理處理的基本Python子產品和包 (5)

原書連結

7.7 Working with Excel files using

openpyxl

EXCEL電子表格是一種廣泛使用的資料處理格式,excel中不僅存儲表格資料還可以存儲圖像、公式等,并且可以包含空行、空列等,這在資料庫表中是不被支援的。

有幾個子產品支援再python中使用excel檔案,arcgis pro自帶的

openpyxl

不是python标準庫的内容,

xlrd

包也可以處理而excel文檔,或者使用Pandas去處理。

典型的Excel 檔案與純文字或CSV格式的表格資料有點不同。首先,Excel 可以包含多個工作表,每個工作表代表一個單獨的表。除了打開Excel ,還必須指向特定的sheet工作表。其次,Excel工作表中的資料以單元格形式輸入,單元格按行和列組織。

必須引用特定的單元格,然後擷取其值,

openpyxl

子產品具有用于這些任務的函數和類。

使用openpyxl打開一個EXCEL,可以使用

openpyxl.load_wordbook()

函數,如下所示:

import openpyxl
book = openpyxl.load_workbook("C:/Data/Example.xlsx")
           

這個函數傳回一個

wordbook

對象。接下來,可以使用workbook對象的方法擷取Excel 中的工作表。您可以使用sheetnames屬性擷取所有工作表的清單:

sheets = book.sheetnames
           

可以添加索引擷取特定的工作表:

引用某個表中的行和列來處理單元格并且擷取值。首先引用單元格,之後才能擷取值:

b3 = sheet["B3"]
print(b3.value)
           

第一個代碼傳回一個

Cell

對象,并且

value

屬性傳回了這個單元格的值。一個可以替代的方式是擷取特定行列位置的值:

b3 = sheet.cell(column=2, row=3)
print(b3.value)
           

這裡的第一行第一列是從1開始的,并不是0。這裡的2和3也不是索引,隻是行和列關鍵詞的參數。

一個更典型的場景是讀取所有的單元格,而不是特定的單元格。可以通過使用

iter_cols()

方法疊代列或者

iter_rows()

方法來疊代行讀取所有的單元格。以下示例使用

iter_cols()

讀取工作表中的所有的單元格:

for col in sheet.iter_cols():
    for cell in col:
        print(cell.value)
           

使用

iter_rows()

方法周遊行的工作原理如下:

for row in sheet.iter_rows():
    for cell in row:
        print(cell.value)
           

周遊所有的行或者列都可以列印所有的值,但是一般選擇逐行讀取的方式。預設情況下,

iter_cols()

iter_rows()

方法将繼續,直到分别沒有剩餘的列或行具有有效的單元格值。當有空列時,這個方法不會停止讀取,而是繼續讀取行和列,直到沒有剩餘的單元格值為止。

使用

iter_cols()

iter_rows()

的另一種方法是從列或行的起始值(數字1)開始疊代,直到讀取具有有效單元格值的最大列或行數,是使用工作表的

maxcol

maxrow

可以獲得的最大值。

由于單元格值可以為空,是以可能需要檢查單元格是否包含值,用于檢查單元格是否包含值的代碼為:

代碼可以被簡寫為:

前面用于處理CSV 的相同腳本如下所示,用于處理Excel 。作為提醒,腳本從檔案讀取坐标以建立點特征,該檔案的Excel版本顯示在圖中:

第七章 用于地理處理的基本Python子產品和包 (5)

使用

openpyxl

子產品處理.xlsx格式Excel 的腳本如下:

import arcpy
import openpyxl
fgdb = "C:/Data/Demo.gdb"
infile = "C:/Data/points.xlsx"
fc = "points"
sr = arcpy.SpatialReference(26910)
arcpy.env.workspace = fgdb
arcpy.CreateFeatureclass_management(fgdb, fc, "Point", "", "", "", sr)
with arcpy.da.InsertCursor(fc, ["[email protected]"]) as cursor:#使用插入遊标
    point = arcpy.Point()
    book = openpyxl.load_workbook(infile)#打開excel檔案
    sheet = book.worksheets[0]#打開特定sheet
    for i in range (1, sheet.max_row):
        point.ID = sheet.cell(row = i, column = 1).value
        point.X = sheet.cell(row = i, column = 2).value
        point.Y = sheet.cell(row = i, column = 3).value
        cursor.insertRow([point])
           

在此腳本解決方案中,

load_workbook()

函數打開Excel 。通過使用

workbook[0]

選擇感興趣的工作表,該工作表選擇第一個工作表。接下來,腳本從第1行疊代工作表的行,直到沒有剩餘的行(

max_row

)。另一種疊代是使用

sheet.iter_rows()

。因為總共隻有三列,是以在腳本中指定了列号。對于許多列,另一種解決方案是使用

For row in sheet.iter_rows():

For cell in col:

對行和列進行疊代。最後,使用value屬性獲得單元值,并将這些值配置設定給Point對象的ID、X和Y屬性。

7.8 working with JSON using

json

JavaScript Object Notation (JSON) 是一種基于文本的資料格式,用于在應用程式之間共享資料。JSON起源于JavaScript程式設計語言。然而,JSON已經成為自己的标準,被認為是語言不可知的,這意味着它獨立于特定的 程式設計語言。是以,它在不同平台上的許多不同程式設計語言中被廣泛使用,并成為資訊共享的事實标準,使用包括空間資料集。

考慮一個JSON 檔案的簡單示例,以下示例通過使用name、hobbies、age和children來描述一個人, 每個children也有名字和年齡:

{
    "firstName": "Jennifer",
    "lastName": "Smith",
    "hobbies": ["dancing", "tattoos", "geocaching"],
    "age": 42,
    "children": [
        {
            "firstName": "Mark",
            "age": 7
       },
       {
           "firstName": "Ashley",
           "age": 11
       }
    ]
}
           

注意,括号的縮進和使用與Python不同,因為它基于JavaScript,示例說明JSON支援數字和字元串等資料類型,以及清單和對象。還要注意,該結構看起來有點像Python字典。JSON建構在兩種類型的結構上:(1)名稱/值對的集合,以及(2)值的有序清單,這些類型是程式設計中的通用資料結構,這使得JSON可以與許多程式設計語言互換。

使用作為标準庫一部分的JSON子產品可以友善地直接處理JSON對象,這個子產品可用于在JSON和Python之間進行轉換。Python中的JSON對象是通過将整個對象作為字元串輸入來建立的,下面的示例使用這個簡化的 JSON:

{
    "name": "Joe",
    "languages": ["Python", "Java"]
}
           

由于JSON是文本格式的,是以JSON對象被建立為字元串,如下所示:

import json
person = '{"name": "Joe", "languages": ["Python", "Java"]}'
           

JSON對象可以使用JSON子產品的

loads()

函數轉換為Python字典,如下所示:

py_person = json.loads(person)
print(py_person["languages"])
           

結果如下所示:

JSON對象也可以存儲為擴充名為.JSON 的文本檔案。json子產品的 load()函數可以讀取此檔案并将其轉換為Python字典。在以下示例中,person.json 檔案包含與前面引用的json對象相同的文本,内容如下:

import json
person = open("person.json")
py_person = json.load(person)
print(py_person["languages"])
           

Python字典可以使用JSON子產品的

dumps()

函數轉換為JSON對象,如下所示:

import json
person = {"name": "Joe", "languages": ["Python", "Java"]}
json_person = json.dumps(person)
print(json_person)
           

結果将整個JSON對象作為一個字元串。

dump()

函數可用于将JSON對象寫入檔案,如下所示:

import json
person = '{"name": "Al", "languages": ["Python", "C"]}'
json_file = open("newperson.json", "w")# open() 函數用于打開一個檔案,建立一個 file 對象
json.dump(person, json_file)
json_file.close()
           

為了提高JSON Ales的可讀性,使用漂亮的列印JSON(也稱為漂亮的JSON或PJSON)非常有用。例如,前面的示例将JSON對象列印為簡單字元串,如下所示:

import json
person = {"name": "Joe", "languages": ["Python", "Java"]}
json_person = json.dumps(person)
print(json_person)
           

結果是一個字元串:

格式可以通過使用dumps()函數的附加參數進行修改,包括縮進:

result是一種更清晰地說明JSON對象組織的格式,如下所示:

{
    "name": "Joe",
    "languages": [
        "Python",
        "Java"
    ]
}
           

通過添加參數

sort_keys=True

,可以完成其他排序。PJSON的使用對實際資料沒有影響,當儲存到檔案時,檔案擴充名是相同的。

JSON被廣泛用于共享資料,并已成為地理空間社群中的流行格式。作為這種廣泛接受的一個例子,ArcGIS Pro有标準工具可以轉換為JSON 和JSON 轉出為其他的,即Features to JSON和JSON to Features。JSON也用于使用ArcGIS REST API建立的服務。此外,GeoJSON格式已被開發為檔案格式,以将地理資料表示為JSON。這兩種格式都被廣泛使用,許多應用程式可以使用這兩種形式,JSON的檔案擴充名為.JSON,而GeoJSON的檔案擴充名為.GeoJSON。

以下是在Python腳本中處理JSON對象的幾種方法。首先,當從線上資源下載下傳資料時,JSON被廣泛用作替代檔案格式,例如,使用

urllib

requests

。其次,您可以使用ArcGIS Pro 中的标準工具(如Features to JSON)将現有空間資料轉換為JSON .第三,可以直接在腳本中處理JSON對象,例如,使用arcpy.da子產品的cursor或在腳本本身中建立JSON對象(如前面的示例所示)。

還有幾個例子說明了其中的一些場景。

前面的JSON 檔案示例不包含地理資料,是以繼續使用一個包含地理資料的示例很有幫助。考慮具有單個多邊形要素和少量屬性的地塊要素類。

第七章 用于地理處理的基本Python子產品和包 (5)

将此多邊形特性轉換為JSON時,空間資料僅表示為文本,可以使用簡單的文本編輯器檢視。JSON 檔案的第一部分包括關于屬性表(FID和PARCEL_ID)中 的資訊 、幾何類型(esriGeometryPolygon)和空間參考(factory code 2277)。請注意,不包括Shape field,因為這些資訊是通過幾何類型、坐标系和實際坐标擷取的。

第七章 用于地理處理的基本Python子產品和包 (5)

JSON檔案的第二部分包含有關特性的資訊,在本例中,僅包含一個多邊形,是由兩個屬性字段的值以及頂點的坐标組成的資訊,共有5個頂點,但第一個和最後一個頂點具有相同的坐标值,并且重合 “rings”引用表示JSON支援使用外部和内部環來表示帶有孔的多邊形,但在本示例中隻需要一個環。

第七章 用于地理處理的基本Python子產品和包 (5)

必須詳細檢視JSON 檔案的内容并不常見,但它說明了整個空間資料集(包括坐标系、屬性結構、屬性值和特征)是如何僅以文本表示的。

此處使用的格式使用PJSON來提高易讀性。如果不使用其他格式,則整個JSON檔案是一行很長的文本,這很難解釋。以下是未格式化的JSON檔案的外觀說明。

{“displayFieldName”:“”,“AeldAliases”:

{“FID”:“FID”,“PARCEL_ID”:“PARCEL_ID”},“geometryType”:“esriGeometryPolygon”,“spatialReference”:

{“wkid”:102739,“latestWkid”:2277},“Aelds”:

[{“name”:“FID”,“type”:“esriFieldTypeOID”,“alias”:“FID”},

{“name”:“PARCEL_ID”,“type”:“esriFieldTypeString”,“alias”:“PARCEL_ID”,“length”:15}],“features”:[{“attributes”:

{“FID”:0,“PARCEL_ID”:“0206042001”},“geometry”:{“rings”:

[[[3116036.110156253,10071403.570008084],

[3115768.3600355834,10071482.069851086],

[3115847.3598775864,10071747.569976255],

[3116114.2300787568,10071667.570136249],

[3116036.110156253,10071403.570008084]]]}}]}

如本節前面所述,Python的json子產品可以在json和Python對象之間進行轉換,ArcGIS Pro中的地理處理工具可以在存儲為檔案的json對象和要素類之間進行轉換。此外,ArcPy函數

AsShape()

可以在JSON對象和ArcPy幾何對象之間進行轉換。它的功能使得可以使用JSON對象來存儲和建立空間資料,而無需将資料儲存到檔案。

arcpy.AsShape()

函數的文法如下:

第一個參數是一個JSON對象,表示為Python字典。第二個參數表示對象是JSON(True)還是GeoJSON(False)對象。以下示例為具有坐标系的單點要素建立JSON對象,并将其轉換為ArcPy point對象:

import arcpy
geo = {"x": -124.7548, "y": 46.5783,
        "spatialReference":
    {"wkid": 4326}}
point = arcpy.AsShape(geo, True)
           

AsShape()

函數根據輸入的JSON對象傳回幾何對象。通過使用“x”和“y”建立點。使用“paths”建立多段線,使用“rings”建立多邊形。例如,以下示例基于坐标清單建立單個Polyline對象:

import arcpy
geo = {
    "paths": [
        [[166.4359,19.5043], [166.4699,19.5098],
        [166.5086,19.4887], [166.5097,19.4668],
        [166.4933,19.4504], [166.4617,19.4410]]],
    "spatialReference": {"wkid":4326}}
polyline = arcpy.AsShape(geo, True)
           

PJSON在最後一個示例中并未完全保留其格式,以減少顯示目的的行數。

到目前為止,使用的JSON對象相對簡單,因為它們隻有一個特性。使用多點特征的JSON對象示例如下:

{"features":[{"geometry":{"x":3116036,"y":10071403}},
             {"geometry":{"x":3115768,"y":10071482}},
             {"geometry":{"x":3115847,"y":10071747}}]}
           

JSON對象還可以使用

load()

loads()

函數轉換為Python字典,将每個點轉換為幾何對象需要在“features”鍵上進行疊代。

本節中的示例說明了如何通過将JSON對象寫成Python字典來建立幾何對象。更複雜的JSON對象可以從文本檔案中讀取,并使用JSON子產品的load()函數轉換為Python字典。