Working with geometry using numpy.
Maintained by Dan-Patterson
Last update: 2022-11-22
Slowly updating I will update the documentation as soon as I can.
The following scripts are listed in this folder and the documentation guide
Links to other documentation will be provided as appropriate
Some useful functions to access and document featureclass information.
dtype_info(a, as_string=False)
Return dtype information as lists or a string.
a = np.array([(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11)],
dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4')])
npg.dtype_info(a, False)
(['f0', 'f1', 'f2'], ['<i4', '<i4', '<i4'])
npg.dtype_info(a, True)
Out[4]: ('f0, f1, f2', '<i4, <i4, <i4')
load_geo(f_name, suppress_extras=True)
Load saved arrays and supplemental information.
geo = npg.load_geo(f_name, True)
Loading...C:/Git_Dan/npgeom/data/g_arr.npz
Arrays include...['g', 'ift', 'kind', 'extents', 'spatial_ref']
(0) name : g
shape : (62, 2)
descr. : [('', '<f8')]
(1) name : ift
shape : (12, 6)
descr. : [('', '<i4')]
(2) name : kind
shape : ()
descr. : [('', '<i4')]
(3) name : extents
shape : (2, 2)
descr. : [('', '<f8')]
(4) name : spatial_ref
shape : ()
descr. : [('', '<U19')]
geo, arrs, names = npg.load_geo(f_name, False)
Loading...C:/Git_Dan/npgeom/data/g_arr.npz
Arrays include...['g', 'ift', 'kind', 'extents', 'spatial_ref']
(0) name : g
shape : (62, 2)
descr. : [('', '<f8')]
(1) name : ift
shape : (12, 6)
descr. : [('', '<i4')]
(2) name : kind
shape : ()
descr. : [('', '<i4')]
(3) name : extents
shape : (2, 2)
descr. : [('', '<f8')]
(4) name : spatial_ref
shape : ()
descr. : [('', '<U19')]
load_geo_attr(f_name)
Load the attributes in an npy file associated with a geo array.
Returns
-------
names : the list of array names.
arrs : the arrays themselves `arr` and `fields`.
The two arrays are the:
- attribute data
- field names and data type.
Example
-------
>>> f_name = "C:/arcpro_npg/data/ontario_attr.npz"
>>> names, arrs = load_geo_attr(f_name)
>>> names # ['arr', 'fields']
>>> arr = arrs[names[0]]
>>> fields = arrs[names[1]]
save_geo(g, f_name, folder)
Save an array as an npz file.
save_txt(a, name="arr.txt", sep=", ", dt_hdr=True)
Save a NumPy structured/recarray to text.
load_txt(name="arr.txt", data_type=None)
Read a structured/recarray created by save_txt. Many options are specified in save_txt. If you wish to modify this, modify save_txt as well.
Others
There are functionsto work with geojson files as well.
npg.npg_io
[... 'dtype_info', 'geojson_Geo', 'load_geo', 'load_geo_attr', 'load_geojson', 'load_txt', 'save_geo', 'save_txt']
in_fc = 'C:/Arc_projects/CoordGeom/CoordGeom.gdb/Shape2'
get_SR(in_fc, verbose=False)
getSR(in_fc, verbose=False)
<SpatialReference object at 0x2168428a1d0[0x216842398b0]>
getSR(in_fc, verbose=True)
SR name: NAD_1983_CSRS_MTM_9 factory code: 2951
get_shape_K(in_fc)
Returns the shape type for a featureclass as (kind, k), where kind is polygon, polyline, multipoint, point and variants. k is 2, 1 or 0.
fc_to_Geo(in_fc, geom_kind=2, minX=0, minY=0, info="")
Convert FeatureClassToNumPyArray to a Geo array. in_fc
is the path to the featureclass. geom_kind
is either 1 or 2 representing polylines or polygons.
id_fr_to(a, oids)
Produce the id
, from
and to points
used to delineate poly* bit geometry.
Geo_to_shapes(geo, as_singlepart=True)
Convert a geo array back to esri geometry objects.
Geo_to_fc(geo, gdb=None, name=None, kind=None, SR=None)
Produce a geodatabase featureclass from a geo array.
Other functions
There are a variety of other functions that deal with converting between geometries.
This is where the Geo class is housed along with methods and properties applicable to it.
The Geo class inherits from the numpy ndarray and methods applied to Geo arrays generally returns arrays of that class.
Geo arrays can be constructed from other ndarrays using arrays_Geo. Three sample arrays are shown below. They have been arranged in column format to save space.
array( array([[[12., 18.], array([[14., 20.],
[array([[10., 20.], [12., 12.], [10., 20.],
[10., 10.], [20., 12.], [15., 28.],
[ 0., 10.], [20., 10.], [14., 20.]])
[ 0., 20.], [10., 10.],
[10., 20.], [10., 20.],
[ 3., 19.], [20., 20.],
[ 3., 13.], [20., 18.],
[ 9., 13.], [12., 18.]],
[ 9., 19.], [[25., 24.],
[ 3., 19.]]), [25., 14.],
array([[ 8., 18.], [15., 14.],
[ 8., 14.], [15., 16.],
[ 4., 14.], [23., 16.],
[ 4., 18.], [23., 22.],
[ 8., 18.], [15., 22.],
[ 6., 17.], [15., 24.],
[ 5., 15.], [25., 24.]]])
[ 7., 15.],
[ 6., 17.]])],
dtype=object),
Both the array of arrays and the geo array are saved in the Scripts folder. To load the Geo array, save the files to disk. You can save and load arrays using the follow syntax. This was used to create the files saved here.
# ---- For single arrays
np.save("c:/path_to_file/three_arrays.npy", z, allow_pickle=True, fix_imports=False) # ---- save to disk
arr = np.load(c:/path_to_file/three_arrays.npy", allow_pickle=True, fix_imports=False) # ---- load above arrays
# ---- For multiple arrays
np.savez("c:/temp/geo_array.npz", s2=s2, IFT=s2.IFT) # ---- save arrays, s2 and s2.IFT with names (s2, IFT)
npzfiles = np.load("c:/temp/geo_array.npz") # ---- the Geo array and the array of I(ds)F(rom)T(o) values
npzfiles.files # ---- will show ==> ['s2', 'IFT']
s2 = npzfiles['s2'] # ---- slice the arrays by name from the npz file to get each array
IFT = npzfiles['IFT']
The functions here allow you to create geometry of various shapes.
Many of the functions can be used for spatial tiling. These would include rectangles, triangles and two variants of hexagons.
Circle-based functions (arc, arc sector, circle, ellipse) are also included since they are used in a variety of other functions (eg. triangulation)
For regular ndarrays like z
below with ndim=4. You can see that array is split up and organized by dimensions.
Print the array with 2 decimal places to a maximum width of 120 characters.
prn_(a, deci=2, width=120, prefix='. . ')
z = np.arange(0, 2*3*4*5).reshape(2, 3, 4, 5)
npg.npg_prn.prn_(z)
(0, 3, 4, 5)
. . 0 1 2 3 4 20 21 22 23 24 40 41 42 43 44
. . 5 6 7 8 9 25 26 27 28 29 45 46 47 48 49
. . 10 11 12 13 14 30 31 32 33 34 50 51 52 53 54
. . 15 16 17 18 19 35 36 37 38 39 55 56 57 58 59
(1, 3, 4, 5)
. . 60 61 62 63 64 80 81 82 83 84 100 101 102 103 104
. . 65 66 67 68 69 85 86 87 88 89 105 106 107 108 109
. . 70 71 72 73 74 90 91 92 93 94 110 111 112 113 114
. . 75 76 77 78 79 95 96 97 98 99 115 116 117 118 119
npg_prn.prn_Geo_shapes
This can also be called using `array.prn().
sq2.prn()
ID : Shape ID by part
R : ring, outer 1, inner 0
P : part 1 or more
ID R P x y
1 1 1 [ 0.00 0.00]
[ 2.00 8.00]
[ 8.00 10.00]
[ 10.00 10.00]
[ 10.00 8.00]
[ 9.00 1.00]
[ 0.00 0.00]
1 0 1 [ 3.00 3.00]
[ 7.00 3.00]
[ 5.00 7.00]
[ 3.00 3.00]
2 1 1 [ 8.00 10.00]
[ 8.00 11.00]
[ 8.00 12.00]
[ 12.00 12.00]
[ 12.00 8.00]
[ 10.00 8.00]
[ 10.00 10.00]
[ 8.00 10.00]
3 1 1 [ 5.00 10.00]
[ 5.00 12.00]
[ 6.00 12.00]
[ 8.00 12.00]
[ 8.00 11.00]
[ 5.00 10.00]
4 1 1 [ 5.00 12.00]
[ 5.00 15.00]
[ 7.00 14.00]
[ 6.00 12.00]
[ 5.00 12.00]
5 1 1 [ 0.00 10.00]
[ 1.00 13.00]
[ 3.00 14.00]
[ 2.50 13.00]
[ 1.00 11.50]
[ 0.00 10.00]
5 0 1 [ 1.00 12.50]
[ 1.50 12.50]
[ 1.50 13.00]
[ 1.00 12.50]
6 1 1 [ 1.00 11.50]
[ 2.50 13.00]
[ 4.00 12.50]
[ 3.00 11.00]
[ 2.00 11.00]
[ 1.00 11.50]
6 0 1 [ 1.50 11.50]
[ 2.50 11.50]
[ 2.50 12.50]
[ 1.50 11.50]
9 1 1 [ 2.00 11.00]
[ 3.00 11.00]
[ 4.00 9.00]
[ 2.00 9.00]
[ 2.00 11.00]
prn_lists
Convert the geo array to a list of lists.
z = sq2.as_lists()
npg.npg_prn.prn_lists(z)
(0)...
[(0.0, 0.0), (2.0, 8.0), (8.0, 10.0), (10.0, 10.0), (10.0, 8.0), (9.0, ...
[(3.0, 3.0), (7.0, 3.0), (5.0, 7.0), (3.0, 3.0)]]
(1)...
[(8.0, 10.0), (8.0, 11.0), (8.0, 12.0), (12.0, 12.0), (12.0, 8.0), (10 ...
(2)...
[(5.0, 10.0), (5.0, 12.0), (6.0, 12.0), (8.0, 12.0), (8.0, 11.0), (5.0 ...
(3)...
[(5.0, 12.0), (5.0, 15.0), (7.0, 14.0), (6.0, 12.0), (5.0, 12.0)]]
(4)...
[(0.0, 10.0), (1.0, 13.0), (3.0, 14.0), (2.5, 13.0), (1.0, 11.5), (0.0 ...
[(1.0, 12.5), (1.5, 12.5), (1.5, 13.0), (1.0, 12.5)]]
(5)...
[(1.0, 11.5), (2.5, 13.0), (4.0, 12.5), (3.0, 11.0), (2.0, 11.0), (1.0 ...
[(1.5, 11.5), (2.5, 11.5), (2.5, 12.5), (1.5, 11.5)]]
(6)...
[(2.0, 11.0), (3.0, 11.0), (4.0, 9.0), (2.0, 9.0), (2.0, 11.0)]]
fc_info(in_fc, prn=True)
fc_info(in_fc, prn=True)
FeatureClass:
C:/Arc_projects/CoordGeom/CoordGeom.gdb/Shape2
shapeFieldName OIDFieldName shapeType spatialReference
Shape OBJECTID Polygon NAD_1983_CSRS_MTM_9
fc_fld_info(in_fc, prn=True)
fc_fld_info(in_fc, prn=True)
FeatureClass:
C:/Arc_projects/CoordGeom/CoordGeom.gdb/Shape2
Name Type Length Nullable Required
OBJECTID OID 4 False True
Shape Geometry 0 True True
Shape_Length Double 8 True True
Shape_Area Double 8 True True
CENTROID_X Double 8 True False
CENTROID_Y Double 8 True False
INSIDE_X Double 8 True False
INSIDE_Y Double 8 True False
fc_geom_info(in_fc, SR=None, prn=True, start=0, num=50)
fc_geom_info(in_fc, SR=None, prn=True, start=0, num=50)
Featureclass:
C:/Arc_projects/CoordGeom/CoordGeom.gdb/Shape2
Shape Parts Points From_pnt To_pnt
1 2 21 0 21
2 2 18 21 39
3 1 4 39 43
fc_composition(in_fc, SR=None, prn=True, start=0, end=50)
fc_composition(in_fc, SR=None, prn=True, start=0, end=50)
C:/Arc_projects/CoordGeom/CoordGeom.gdb/Shape2
Shapes : 3
Parts : 5
max : 2
Points : 43
min : 4
median : 9
max : 11
IDs Part Points From_pnt To_pnt
1 0 11 0 11
1 1 10 11 21
2 0 9 21 30
2 1 9 30 39
3 0 4 39 43
arr = tbl_arr(in_fc)
arr = tbl_arr(in_fc)
array([(1, 86.47, 78., 300004.72, 5000014.73, 300004.72, 5000014.73),
(2, 112. , 104., 300017.5 , 5000017. , 300015. , 5000011. ),
(3, 21.5 , 16., 300013. , 5000022.67, 300013. , 5000022.67)],
dtype=[('OID_', '<i4'), ('Shape_Length', '<f8'), ('Shape_Area', '<f8'),
('CENTROID_X', '<f8'), ('CENTROID_Y', '<f8'),
('INSIDE_X', '<f8'), ('INSIDE_Y', '<f8')])
prn_tbl(arr)
prn_tbl(arr)
OID_ Shape_Length Shape_Area CENTROID_X CENTROID_Y INSIDE_X INSIDE_Y
------------------------------------------------------------------------------------------------
000 1 86.47 78.00 300004.72 5000014.73 300004.72 5000014.73
001 2 112.00 104.00 300017.50 5000017.00 300015.00 5000011.00
002 3 21.50 16.00 300013.00 5000022.67 300013.00 5000022.67
The methods used to convert esri geometries to an appropriate array format. This script will require you have a valid license for ArcGIS Pro since esri FeatureClasses in a File Geodatabase need to be read and their arcpy geometries extracted and converted to numpy arrays.
Numpy is part of the distribution for ArcGIS Pro, so no other dependencies need to be made to their conda packages. If you wish to clone their distribution or modify the existing one, some guidance is provided here.
ArcGISPro 2.4 ... Installation, package updates and installs