Python Blog - Page 8

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Latest Activity

(198 Posts)
DanPatterson_Retired
MVP Emeritus

X  The xlrd and openpyxl modules packaged with ArcGIS Pro is a pretty cool for working with Excel files... if you are stuck and have to use them.  Pandas depends on them, so you could just use Pandas to do the data conversion, but, numpy can be called into play to do a pretty good and quick conversion while at the same time cleaning up the data on its way in to a table in ArcGIS Pro

------------------------------------------------------

(1) ---- Spreadsheets gone bad

Here is a spreadsheet with so flubs builtin.

Column A contains integers, but excel treats them as just floating point numbers without a decimal place.

Column D is just text but with leading/trailing spaces, cells with spaces, empty cells and just about anything that can go wrong when working with text.

Column E has floats but two of the cells are empty or worse... a space.

All these conditions need to be fixed.

As for fixing blank rows, missing column headers, data not in the upper left quadrant of a sheet, or data that share the page with other stuff (like graphs etc etc)… its not going to happen here.  This discussion assumes that you have an understanding on how you should work with spreadsheet data if you have to.

------------------------------------------------------

(2) ---- Spreadsheets to array

So with a tad of code, the spreadsheet can be converted to a numpy structured/recarray.

During the process, numeric fields which are obviously integer get cast to the correct format.

Malformed text fields/columns are cleaned up.  Leading/trailing spaces are removed and empty cells and/or those with nothing but spaces in them are replaced by 'None'.

Empty cells in numeric floating point fields are replaced with 'nan' (not a number).  Sadly there isn't an equivalent for integers, so you will either have to upcast your integer data or provide a null value yourself.

Best approach... provide your own null/nodata values

------------------------------------------------------

(3) ---- Spreadsheets to array to geodatabase table

Now... The array can be converted to a geodatabase table using NumPyArrayToTable.

arcpy.da.NumPyArrayAsTable(array, path)

where

`array` is from the previous step 

`path`  the full path and name of the geodatabase table.

it comes in as expected.  The dtypes are correct and the text column widths are as expected. Note that text column widths are twice the Unicode dtype width (ie U20 becomes 40 characters for field length)

------------------------------------------------------

(4) ---- Spreadsheets to geodatabase table via arcpy

Excel to Table does a good job on the data types, but it takes some liberty with the field length. This may be by design or useful or a pain, depending what you intend to do with the data subsequently.

You can even combine xlrd with arcpy to batch read multiple sheets at once using the code snippet in the reference link below.

(5) ---- Spreadsheets to Pandas to table

Yes pandas does it via xlrd, then the data to numpy arrays, then to series and dataframes, then out to geodatabase tables.  So you can skip pandas altogether if you want.

The data types can be a bit unexpected however, and there is no cleaning up of text fields isn't carried out completely, blank/empty cells are translated to 'nan' (not a number?) but a space in a cell remains as such.

The data type for the text column is an 'object' dtype which is usually reserved for ragged arrays (ie mixed length or data type).

df['Text_null'].tolist()
[' a leading space', 'b', 'a trailing space ', nan, ' ', 'back_to_good', '    four_leading', 'b', 'a', 'done']

(6) ---- The code

I put the code in the  link to my `gist` on GitHub in case code formatting on this site isn't fixed.

excel_np.py .... convert excel to a structured array

There are some things you can do to ensure a proper data type.  The following demonstrates how one little blank cell can foul up a whole column or row of data.

def isfloat(a):
    """float check"""
    try:
        i = float(a)
        return i
    except ValueError:
        return np.nan
    
# ---- Take some numbers... but you forgot a value so the cell is empty ie ''
#
vals = [6, 9, 1, 3, '', 2, 7, 6, 6, 9]

# ---- convert it to an array... we will keep it a surprise for now
#
ar = np.asarray(vals)

# ---- use the helper function `isfloat` to see if there are numbers there
#
np.array([isfloat(i) for i in ar])

# ---- yup! they were all numbers except for the blank
#
array([ 6.,  9.,  1.,  3., nan,  2.,  7.,  6.,  6.,  9.])

# ---- if we hadn't checked we would have ended up with strings
#
array(['6', '9', '1', '3', '', '2', '7', '6', '6', '9'], dtype='<U11')‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

If you really need to conserve the integer data type, they you will have to some hurdle jumping to check for `nan` (aka not-a-number)

# ---- our list of integers with a blank resulted in a float array
#
np.isnan(ar)  # --- conversion resulted in one `nan`
array([False, False, False, False,  True, False, False, False, False, False])

# ---- assign an appropriate integer nodata value
#
ar = ar[np.isnan(ar)] = -999

# ---- cast the array to integer and you are now done
#
ar = ar.astype('int')
array([   6,    9,    1,    3, -999,    2,    7,    6,    6,    9])‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

(7) ---- End notes...

So the next time you need to work with spreadsheets and hope that the magic of xlrd, openpyxl or pandas (which uses both) can solve all your problems.... take the time to look at your data carefully and decide if it is truly in the format you want BEFORE you bring it into ArcGIS Pro as a table

arr = excel_np("c:/temp/x.xlsx")

arr
 
array([('aaa', '01', 1), ('bbb', '02', 2)],
      dtype=[('field1', '<U4'), ('field2', '<U4'), ('field3', '<i4')])

import arcpy
arcpy.da.NumPyArrayToTable(arr, r"C:\Your_spaceless_path_to\a.gdb\x_arr")

An example for a very simple table

If you have any use cases where the standard conversion methods aren't good let me know.

References:

excel to table ...

xlrd on GitHub …

openpyxl on bitbucket... and openpyxl docs page...

more
4 3 2,169
DanPatterson_Retired
MVP Emeritus

Recently stumbled upon…          Using conda in spyder

I will just leave this as a thought.  It is one of those IPython %magic things

Update...       Spyder 3.3.6 is out  2019-07-16

Battle cry.... Install Spyder, Jupyter console and Jupyter notebook for ArcGIS Pro by default 

                      Make it so.... now on to the content

 Spyder... install once, use in multiple environments New... 2018-08-30

Table of contents:  (use browser back to return here)

:--------- Latest Version

    Version 3.3.6: installed 2019-07-16

    Use proenv.bat and just ran..... conda update spyder

:--------- Installing Spyder in ArcGIS Pro

arcgis-pro-your-conda-environments

/blogs/dan_patterson/2018/12/28/clone 

:--------- Some other links

Script documenting ... It is all in the docs - links to spyder help pane for user-created help.

Spyder on GitHub ... If you want to keep abreast of issues and/or enhancement requests

Spyder Documentation …. On GitHub or Spyder Documentation

Spyder-notebook ... Jupyter notebook inside Spyder...

Spyder in pictures

:---- The Icon 

:----- The whole interface

... which can be arranged to suit

:---- Keep track of project files

:---- Need a little help?

:---- Fancy documentation with minimal effort

:---- Help for IPython?

:---- Help for other Modules?

:---- Check out your variables

:---- Some graphs? 

Yes from within Spyder, you can use Matplotlib or any other installed graphics pack (ie seaborn, orange etc)

:---- See your scripts in outline mode,

Quickly navigate within them like a table of contents or use outline to get a basic shell listing of your script


The trick to outline is to use # ---- Your comment here   4 dashes seems to be the key for some reason

:---- Don't like something? 

Change it

: ----  Set Spyder as your IDE for PRO

: ---- Fear not...

You can even pretty up the interface

/blogs/dan_patterson/2018/10/08/making-conda-package-installs-easier 

More later

: --------

more
9 9 10.1K
DanPatterson_Retired
MVP Emeritus

KD trees

Table of contents:  (use browser back to return here)

Distance stuff, lots of tree types.  Your distribution of Python comes with scipy which has a couple of implementations.

This is just a quick demo of its potential use.  And an homage to Canadian university students, for which KD will always have a special meaning as a primary food group. Kraft Dinner for the non-student

Start with some points and you then want to calculate the closest 2 points to form point origin-destination pairs... because it can be done.

Steps.

  • Just deal with the coordinates first, leave the attribute baggage to the side for now.
  • Decide on the number of points you want to find the 'closest' of.  Don't get ridiculous and ask for an origin-destination matrix with a couple of thousand points.  Go back to the project design stage or look at scipy.distance.cdist and a new computer.
  • Sorting the points by X, then Y coordinate is useful in some situations.  An option to do so is provided.
  • Building the KDTree is fairly straightforward using scipy.
    • decide on the number of points to find
    • the returned list of indices will include the origin point itself, so if you want the closest 2 points, then set your query to N = 3.  This can be exploited to suck up the x,y values to form origin-destination pairs if you want to form lines, and/or polygons.
  • Decide if you want to just pull out the indices of the closest pairs with their distance.
  • Optionally, you can produce a structured array, which you can then bring into ArcGIS Pro as a table for use with a couple of ArcToolbox tools to create geometry
  • You are done.  Do the join thing if you really need the attributes.

The picture:

The code:

So this function just requires a point array of x,y pairs, the number of closest points (N), whether you want to do an x,y sort first and finally, whether you want an output table suitable for use in ArcGIS Pro.

From there, you simply use arcpy.NumPyArrayToTable to produce a gdb featureclass table. 

You can them use... XY to Line … to produce line segments, connecting the various origins and destinations as you see fit, or just bask in the creation of an... XY event layer.

Note:  lines 32 and 41 can use... cKDTree ...in place of... KDTree ..., if you just need speed for Euclidean calculations.

def nn_kdtree(a, N=3, sorted=True, to_tbl=True):
    """Produce the N closest neighbours array with their distances using
    scipy.spatial.KDTree as an alternative to einsum.

    Parameters:
    -----------
    a : array
        Assumed to be an array of point objects for which `nearest` is needed.
    N : integer
        Number of neighbors to return.  Note: the point counts as 1, so N=3 
        returns the closest 2 points, plus itself.
    sorted : boolean
        A nice option to facilitate things.  See `xy_sort`.  Its mini-version
        is included in this function.

    References:
    -----------
    `<https://stackoverflow.com/questions/52366421/how-to-do-n-d-distance-
    and-nearest-neighbor-calculations-on-numpy-arrays/52366706#52366706>`_.
    
    `<https://stackoverflow.com/questions/6931209/difference-between-scipy-
    spatial-kdtree-and-scipy-spatial-ckdtree/6931317#6931317>`_.
    """
    def _xy_sort_(a):
        """mini xy_sort"""
        a_view = a.view(a.dtype.descr * a.shape[1])
        idx =np.argsort(a_view, axis=0, order=(a_view.dtype.names)).ravel()
        a = np.ascontiguousarray(a[idx])
        return a, idx
    #
    def xy_dist_headers(N):
        """Construct headers for the optional table output"""
        vals = np.repeat(np.arange(N), 2)
        names = ['X_{}', 'Y_{}']*N + ['d_{}']*(N-1)
        vals = (np.repeat(np.arange(N), 2)).tolist() + [i for i in range(1, N)]
        n = [names[i].format(vals[i]) for i in range(len(vals))]
        f = ['<f8']*N*2 + ['<f8']*(N-1) 
        return list(zip(n,f))
    #    
    from scipy.spatial import cKDTree
    #
    idx_orig = []
    if sorted:
        a, idx_orig = _xy_sort_(a)
    # ---- query the tree for the N nearest neighbors and their distance
    t = cKDTree(a)
    dists, indices = t.query(a, N)
    if to_tbl:
        dt = xy_dist_headers(N)  # --- Format a structured array header
        xys = a[indices]
        new_shp = (xys.shape[0], np.prod(xys.shape[1:]))
        xys = xys.reshape(new_shp)
        ds = dists[:, 1:]  #[d[1:] for d in dists]
        arr = np.concatenate((xys, ds), axis=1)
        arr = arr.view(dtype=dt).squeeze()
        return arr
    else:
        return np.array(indices), idx_orig‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

The output

Just a slightly better formatting that you can get with one of my numpy functions... obviating the need for Pandas for table niceness.

 id  X_0    Y_0    X_1    Y_1    X_2    Y_2    d_1     d_2    
--------------------------------------------------------------
 000   3.00  98.00  10.00  94.00  23.00  94.00    8.06   20.40
 001  10.00  94.00   3.00  98.00  23.00  94.00    8.06   13.00
 002  13.00  18.00  19.00  22.00  34.00  16.00    7.21   21.10
 003  19.00  22.00  13.00  18.00  34.00  16.00    7.21   16.16
 004  23.00  94.00  10.00  94.00   3.00  98.00   13.00   20.40
 005  34.00  16.00  19.00  22.00  43.00   1.00   16.16   17.49
 006  37.00  64.00  43.00  89.00  56.00  84.00   25.71   27.59
 007  43.00   1.00  34.00  16.00  66.00   6.00   17.49   23.54
 008  43.00  89.00  56.00  84.00  61.00  87.00   13.93   18.11
 009  56.00  84.00  61.00  87.00  43.00  89.00    5.83   13.93
 010  61.00  87.00  56.00  84.00  43.00  89.00    5.83   18.11
 011  66.00   6.00  76.00  20.00  43.00   1.00   17.20   23.54
 012  67.00  41.00  78.00  50.00  76.00  20.00   14.21   22.85
 013  76.00  20.00  66.00   6.00  67.00  41.00   17.20   22.85
 014  78.00  50.00  67.00  41.00  80.00  67.00   14.21   17.12
 015  80.00  67.00  91.00  66.00  78.00  50.00   11.05   17.12
 016  82.00  91.00  94.00  95.00  61.00  87.00   12.65   21.38
 017  91.00  66.00  80.00  67.00  78.00  50.00   11.05   20.62
 018  94.00  95.00  82.00  91.00  91.00  66.00   12.65   29.15
 019  96.00  40.00  78.00  50.00  91.00  66.00   20.59   26.48‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Summary

Behind the scenes, there should be some 'spatial cleanup'.  Specifically, if you look at the image you have point pairs connected by a single segment, that is because they are the closest to one another.  Rather than duplicating the segment with opposing directions, you can 'prune' the indices and remove those prior to producing the geometry.

There are lots of tools that you can produce/show geometric relationships.  Use them to provide answers to your questions.  This implementation will appear soon on the code sharing site.  I will provide a link soon.

more
2 0 1,627
DanPatterson_Retired
MVP Emeritus

NumPy vs Pandas

JIVE has fouled up the python syntax formatting in blogs...

hopefully this will be resolved soon

Well actually Pandas can't exist without NumPy.  But apparently it has a 'friendlier' face than its parental unit .

This demonstrates a difference.

We will begin with an array derived from a table from within ArcGIS Pro. 

I used the TableToNumPyArray

TableToNumPyArray—Data Access module | ArcGIS Desktop 

A classy function.  

The array

a # ---- the array from the table ----

array([( 1, 0, 'B', 'A_', 'Hall', 26), ( 2, 1, 'C', 'C_', 'Hall', 60),
 ( 3, 2, 'D', 'A_', 'Hall', 42), ( 4, 3, 'C', 'A_', 'Hall', 57),
 ( 5, 4, 'C', 'B_', 'Hall', 51), ( 6, 5, 'B', 'B_', 'Hosp', 14),
 ( 7, 6, 'C', 'A_', 'Hall', 45), ( 8, 7, 'B', 'B_', 'Hosp', 51),
 ( 9, 8, 'B', 'A_', 'Hall', 28), (10, 9, 'C', 'C_', 'Hosp', 58),
 (11, 10, 'B', 'B_', 'Hosp', 6), (12, 11, 'C', 'A_', 'Hall', 49),
 (13, 12, 'B', 'A_', 'Hosp', 42), (14, 13, 'C', 'A_', 'Hosp', 60),
 (15, 14, 'C', 'B_', 'Hosp', 41), (16, 15, 'A', 'A_', 'Hosp', 53),
 (17, 16, 'A', 'A_', 'Hall', 42), (18, 17, 'A', 'C_', 'Hall', 59),
 (19, 18, 'C', 'C_', 'Hosp', 37), (20, 19, 'B', 'B_', 'Hall', 52)],
 dtype=[('OBJECTID', '<i4'), ('f0', '<i4'), ('County', '<U2'), ('Town', '<U6'), ('Facility', '<U8'), ('Time', '<i4')])‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

OOOO screams the crowd in disgust... it is confusing looking.

So we will revert to the every favorite Pandas.  

import pandas as pd

pd.DataFrame(a)

 OBJECTID f0 County Town Facility Time
0 1 0 B A_ Hall 26
1 2 1 C C_ Hall 60
2 3 2 D A_ Hall 42
3 4 3 C A_ Hall 57
4 5 4 C B_ Hall 51
5 6 5 B B_ Hosp 14
6 7 6 C A_ Hall 45
7 8 7 B B_ Hosp 51
8 9 8 B A_ Hall 28
9 10 9 C C_ Hosp 58
10 11 10 B B_ Hosp 6
11 12 11 C A_ Hall 49
12 13 12 B A_ Hosp 42
13 14 13 C A_ Hosp 60
14 15 14 C B_ Hosp 41
15 16 15 A A_ Hosp 53
16 17 16 A A_ Hall 42
17 18 17 A C_ Hall 59
18 19 18 C C_ Hosp 37
19 20 19 B B_ Hall 52‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

AHHHHHH the crowd cheers... much better looking.

But wait! If you just wanted the array to look pretty, you can do that with numpy and python easily as well.

How about...

id OBJECTID f0 County Town Facility Time
 -------------------------------------------------
 000 1 0 B B_ Hall 11
 001 2 1 A A_ Hall 24
 002 3 2 C C_ Hosp 43
 003 4 3 A B_ Hall 43
 004 5 4 B B_ Hall 16
 005 6 5 B A_ Hall 8
 006 7 6 A C_ Hall 26
 007 8 7 B C_ Hall 31
 008 9 8 C C_ Hall 7
 009 10 9 A A_ Hall 58
 010 11 10 A A_ Hosp 20
 011 12 11 C A_ Hosp 37
 012 13 12 C B_ Hall 36
 013 14 13 A B_ Hosp 33
 014 15 14 C C_ Hosp 51
 015 16 15 B C_ Hosp 53
 016 17 16 C A_ Hosp 21
 017 18 17 C C_ Hosp 42
 018 19 18 A B_ Hosp 43
 019 20 19 A C_ Hall 5‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

??????? now the crowd is confused.  Which is better? Which looks better?

The choice is yours.  Maybe I will reveal pd_ at sometime but I might rename it to dp_ in homage to its coder.

# ---- quick prints and formats

Too much?  How about a quick_prn of the array with edge items, width specification all done in a couple lines of code

quick_prn(a, max_lines=10)

Array fields:
('OBJECTID', 'f0', 'County', 'Town', 'Facility', 'Time')
[( 1, 0, 'B', 'A_', 'Hall', 26)
 ( 2, 1, 'C', 'C_', 'Hall', 60)
 ( 3, 2, 'D', 'A_', 'Hall', 42)
 ...
 (18, 17, 'A', 'C_', 'Hall', 59)
 (19, 18, 'C', 'C_', 'Hosp', 37)
 (20, 19, 'B', 'B_', 'Hall', 52)]‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

A few lines of code... a def for multiple purposes

def quick_prn(a, edgeitems=3, max_lines=25, wdth=100, decimals=2, prn=True):
 """Format a structured array by reshaping and replacing characters from
 the string representation
 """
 wdth = min(len(str(a[0])), wdth)
 with np.printoptions(precision=decimals, edgeitems=edgeitems,
 threshold=max_lines, linewidth=wdth):
 print("\nArray fields:\n{}\n{}".format(a.dtype.names, a))‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

---- Analysis? ----

What about pivot tables? Excel has them, so does Pandas.  A quick call to some small python/numpy defs and...

Can't do the blue bit though.

---- Comment -----

Of course this blog is purely in jest, but it serves to point out that not is all that it seems and that everything has a root.  Remember your origins, even if that means in coding.

more
0 3 1,205
DanPatterson_Retired
MVP Emeritus

Conda  vs clones

I am beginning to wonder if the reluctance of people to install packages using conda has to do with the interface.

The Package Manager in ArcGIS Pro pre  2.2 was a nice addition, although a poorer incarnation than the Anaconda package manager... but kudos for putting one in the software for those that like to keep everything together.  Esri pulled the rug out in Pro 2.2 when the killed the Package Manager from doing anything useful.

Side note

If you don't want to use conda through the recommended channels and interface.... how about using it in Spyder's IPython Console?

If not.... carry on...

-------------------------------------------------------------------------------------------------------------------------------------------------------------

---- (1) ----

So rather than explain how to install packages using conda... which I have done elsewhere... I am going to focus on how to make the proenv.bat file aka this

---- (2) ----

Which is really a shortcut to this!  (sneaky sneaky!)

---- (3) ----

When you get there, this is what you see... dark... bleak, uninviting and for some, just plain scary!

---- (4) ----

Right-click on the windows top area to bring up the context menu, and select Properties

---- (5) ----

Now away you go... start with the cursor size

---- (6) ----

Don't forget the font!

---- (7) ----

Fussy where and how it appears on opening???

---- (8) ----

How about those colors!!! less intimidating???

Now don't waste too much time... Dr Google has RGB listings for your favorite colors.  FYI  Just don't set background and text to the same color... but if someone did.. you would know how to fix it to continue doing conda installs

---- (9) ----

Too lazy to close windows... make the window opaque.

---- (10) ----

The final wrap... ready for you

And don't forget to install your packages.

Have fun!

more
0 2 2,010
DanPatterson_Retired
MVP Emeritus

Scipy ndimage morphology … I am betting that is the first thought that popped into your head.  A new set of tools for the raster arsenal.

But wait!  Their terminology is different than that used by ArcGIS Pro or even ArcMap.

What tools are there?  Lots of filtering tools, but some of the interesting ones are below

from scipy import ndimage as nd
dir(nd)[... snip ...
 'affine_transform', ... , 'center_of_mass', 'convolve', 'convolve1d', 'correlate',
 'correlate1d', ... 'distance_transform_edt', ... 'filters', ... 'generic_filter',
 ... 'geometric_transform', ... 'histogram', 'imread', 'interpolation', ... 'label',
 'labeled_comprehension', ... 'measurements', ... 'morphology', ...  'rotate', 'shift',
 'sobel',...]‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

I previously covered distance_transform_edt which performs the equivalent of Euclidean Distance and Euclidean Allocation in this post

/blogs/dan_patterson/2018/10/04/euclidean-distance-allocation-and-other-stuff 

Let's begin with a raster constructed from 3x3 windows with a repeating pattern and repeats of the pattern.

You can construct your own rasters using numpy, then apply a NumPyArrayToRaster to it.  I have covered this before, but here is the code to produce the raster

def _make_arr_():
    """Make an array with repeating patterns
    """
    a = np.arange(1, 10).reshape(3, 3)
    aa = np.repeat(np.repeat(a, 3, axis=1), 3, axis=0)
    aa = np.tile(aa, 3)
    aa = np.vstack((aa, aa))
    return aa‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

---- The raster (image) ----

---- (1) Expand ----

Expand the zone 1 values by 2 distance units

---- (2) Shrink ----

Shrink the zone 1 values by 1 distance unit.

---- (3) Regiongroup ----

Produce unique regions from the zones.  observe that the zone 1 values in the original are given unique values first. Since there were 6 zone 1s, they are numbered from 1 to 6.  Zone 2 gets numbered from 7 to 12.  and that pattern of renumbering repeats.

---- (4) Aggregate ----

Aggregation of the input array using the mode produces a spatial aggregation retaining the original values.  Our original 3x3 kernels are now reduced to a 1x1 size which has 3 times the width and height (9x area).

---- (5) Some functions to perform the above ----

In these examples buff_dist is referring to 'cells'.

For the aggregation, there are a number of options as shown in the header. 

Generally integer data should be restricted to the mode, min, max, range and central (value) since the median and mean upscale to floating point values.  This of course can be accommodated by using the python statistics package median_low and median_high functions:

statistics — Mathematical statistics functions — Python 3.7.1rc1 documentation 

So think of a function that you want.  Filtering is a snap since you can 'stride' an array using any kernel you want using plain numpy or using the builtin functions from scipy.

Enough for now...

def expand_(a, val=1, mask_vals=0, buff_dist=1):
    """Expand/buffer a raster by a distance
    """
    if isinstance(val, (list, tuple)):
        m = np.isin(a, val, invert=True).astype('int')
    else:
        m = np.where(a==val, 0, 1)
    dist, idx = nd.distance_transform_edt(m, return_distances=True,
                                          return_indices=True)
    alloc = a[tuple(idx)]
    a0 = np.where(dist<=buff_dist, alloc, a)  #0)
    return a0


def shrink_(a, val=1, mask_vals=0, buff_dist=1):
    """Expand/buffer a raster by a distance
    """
    if isinstance(val, (list, tuple)):
        m = np.isin(a, val, invert=False).astype('int')
    else:
        m = np.where(a==val, 1, 0)
    dist, idx = nd.distance_transform_edt(m, return_distances=True,
                                          return_indices=True)
    alloc = a[tuple(idx)]
    m = np.logical_and(dist>0, dist<=buff_dist)
    a0 = np.where(m, alloc, a)  #0)
    return a0


def regions_(a, cross=True):
    """currently testing regiongroup
    np.unique will return values in ascending order

    """
    if (a.ndim != 2) or (a.dtype.kind != 'i'):
        msg = "\nA 2D array of integers is required, you provided\n{}"
        print(msg.format(a))
        return a
    if cross:
        struct = np.array([[0,1,0], [1,1,1], [0,1,0]])
    else:
        struct = np.array([[1,1,1], [1,1,1], [1,1,1]])
    #
    u = np.unique(a)
    out = np.zeros_like(a, dtype=a.dtype)
    details = []
    is_first = True
    for i in u:
        z = np.where(a==i, 1, 0)
        s, n = nd.label(z, structure=struct)
        details.append([i, n])
        m = np.logical_and(out==0, s!=0)
        if is_first:
            out = np.where(m, s, out)
            is_first = False
            n_ = n
        else:
            out = np.where(m, s+n_, out)
            n_ += n
    details = np.array(details)
    details = np.c_[(details, np.cumsum(details[:,1]))]
    return out, details


def aggreg_(a, win=(3,3), agg_type='mode'):
    """Aggregate an array using a specified window size and an aggregation
    type

    Parameters
    ----------
    a : array
        2D array to perform the aggregation
    win : tuple/list
        the shape of the window to construct the blocks
    agg_type : string aggregation type
        max, mean, median, min, mode, range, sum, central

    """
    blocks = block(a, win=win)
    out = []
    for bl in blocks:
        b_arr = []
        for b in bl:
            if agg_type == 'mode':
                uni = np.unique(b).tolist()
                cnts = [len(np.nonzero(b==u)[0]) for u in uni]
                idx = cnts.index(max(cnts))
                b_arr.append(uni[idx])
            elif agg_type == 'max':
                b_arr.append(np.nanmax(b))
            elif agg_type == 'mean':
                b_arr.append(np.nanmean(b))
            elif agg_type == 'median':
                b_arr.append(np.nanmedian(b))
            elif agg_type == 'min':
                b_arr.append(np.nanmin(b))
            elif agg_type == 'range':
                b_arr.append((np.nanmax(b) - np.nanmin(b)))
            elif agg_type == 'sum':
                b_arr.append(np.nansum(b))
            elif agg_type == 'central':
                b_arr.append(b.shape[0]//2, b.shape[1]//2)
            else:
                tweet("\naggregation type not found {}".format(agg_type))
                b_arr.append(b.shape[0]//2, b.shape[1]//2)
        out.append(b_arr)
    out = np.array(out)
    return out

more
0 0 2,090
DanPatterson_Retired
MVP Emeritus

Your standard fare in raster world

Fill in some holes … 'buffer' a line... allocate space to stuff in space... identify unique regions

Fancy names.  Nibble, Euclidean distance, Euclidean allocation, Regiongroup

---- (1) The task ----

Start with a raster or array.  Fancy labels in the top left, some random-ish color scheme with values noted in the middle.

Now, zero ( 0 ) we will say is nodata.  The other numbers represent some class value. 

Fill in the 'gaps'... aka, nodata, with the value of a cell with data based on the closest distance.  Euclidean, crow flies, for our purposes, but it need not be. 

Go! 

What did you get for cells A04, H01 and H02?  What about cell D07 and H08?

---- (1) The reveal ----

Let's see how we did

A04 - 2   can't be 1 because the diagonal to '1' is 1.414*cell width, so 2 it is

H01 - 2   could have been a 2 or a 3, because both are 3 cells away from cells with values

H02 - 3   no brainer

D07 - 3   could have been 3 or 4, but 3 wins

H08 -3    3 is 2 cells away and 1 and 5 are a greater distance on an angle

---- (3) The distances ----

Pretty boring and obvious... but for completeness.

I don't do maps, but the dominant colors are 0 or root 2 as you can see from the spiffy ArcGIS Pro symbology tab.So no big surprises

 

---- (4) Allocation around linear features ----

Yes, that is possible too, sort of like a variable buffer, trade area, but currently just a simple Euclidean spatial allocation.

---- (5) The references ----

 Euclidean distance

Euclidean Allocation

NumPy/SciPy/  plus Arcpy stuff solution is what I used

import sys
import numpy as np
from scipy import ndimage as nd
from arcpy.geoprocessing import env
from arcpy.arcobjects import Point
from arcgisscripting import NumPyArrayToRaster, RasterToNumPyArray

env.overwriteOutput = True

def euclid_calc(a, mask_vals=0, dist=True, alloc=True):
    """Calculate the euclidean distance and/or allocation

    Parameters:
    a : array
        numpy float or integer array
    mask_vals : number, list or tuple
        If a single number is provided, a `mask` will be created using it.  A
        list or tuple of values can be used to provide multiple value masking.
    dist : boolean
        True, the distance of the closest non-masked value to the masked cell
    alloc : boolean
        True, the value of the closest non-masked value to the masked cell
    """
    if not dist:
        dist = None
    if not alloc:
        alloc = None
    m = np.isin(a, mask_vals).astype('int')
    dist, idx = nd.distance_transform_edt(m, return_distances=True,
                                          return_indices=True)
    alloc = a[tuple(idx)]
    return dist, alloc

# ----------------------------------------------------------------------
# .... final code section
if len(sys.argv) == 1:
    testing = True
    r_in = r"C:\GIS\A_Tools_scripts\Raster_tools\Data\poly.tif"
    a = RasterToNumPyArray(r_in)
    dist, alloc = euclid_calc(a, mask_vals=0, dist=True, alloc=True)
else:
    testing = False
    r_in = sys.argv[1]
    r_out = sys.argv[2]
    LLx = sys.argv[3]
    LLy = sys.argv[4]
    cell_sze = sys.argv[5]
    a = RasterToNumPyArray(r_in)
    dist, alloc = euclid_calc(a, mask_vals=0, dist=True, alloc=True)
    #
    # specify a, dist or alloc below... this could be a tool choice if needed
    #
    r0 = NumPyArrayToRaster(a, Point(LLx, LLy), cell_sze)  
    r0.save(r_out)‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Of course, when run from within the amazing Spyder python IDE, you can simply skip saving to output raster if needed, or try various other options from with the scipy slate other than the distance_transform_edt

On to other "special analyst" tools soon.

more
2 3 1,925
DanPatterson_Retired
MVP Emeritus

Striding - Sliding - Moving - Rolling

One of my favorite topics.

It was an innocuous question

 How to count the adjacent cells that have a different value in a raster dataset? 

Obviously! Focal statistics in the Spatial Analyst extension. 

There has to be one of them … not focal mean, median, min, max, std dev, var, range... that leaves majority, minority and variety, - close, but no vape.  The catch was, that Mark needed to know the number of cells in the immediate neighborhood that differed in value from the core/focal cell.  As such, variety wouldn't cut it since variety since all 9 cells in a 3x3 window are considered without comparison to the focal cell.  I will address the final puzzle at the end, but let us begin with some basics.

Striding function basics

Begin with a basic array with 4 rows and 5 columns.  This is a raster of course because I could save it out to esri grid or tif format.

Now if I begin shifting a 3x3 window over the top of the raster we begin to form the data in lines 9 and on.  But how did I arrive at?

Steps

    • pick a nodata value... in this case I have decided that 0 represents nodata.
    • convert the nodata values to "not a number... nan"
    • pad the raster by 1 cell using a constant value (nan) on all 4 sides
    • slide beginning at the top left of the padded array.  In this case a 3x3 moving window was used.  The 'window' is stepped 1 column at a time until the end of the first row is reached, then a step down a row follows this .

Figure 1

Striding a simple array/raster
Original array...
-shape (1, 4, 5), ndim 3
  .  0  0  1  0  2  
  .  0  1  1  2  0  
  .  3  0  3  0  4  
  .  3  3  4  5  5  


Strided array...
-shape (4, 5, 3, 3), ndim 4
-------------------------
-(0, + (5, 3, 3)
  .  nan  nan  nan    nan  nan  nan    nan  nan  nan    nan  nan  nan    nan  nan  nan  
  .  nan  nan  nan    nan  nan    1    nan    1  nan      1  nan    2    nan    2  nan  
  .  nan  nan    1    nan    1    1      1    1    2      1    2  nan      2  nan  nan  
-------------------------
-(1, + (5, 3, 3)
  .  nan  nan  nan    nan  nan    1    nan    1  nan      1  nan    2    nan    2  nan  
  .  nan  nan    1    nan    1    1      1    1    2      1    2  nan      2  nan  nan  
  .  nan    3  nan      3  nan    3    nan    3  nan      3  nan    4    nan    4  nan  
-------------------------
-(2, + (5, 3, 3)
  .  nan  nan    1    nan    1    1      1    1    2      1    2  nan      2  nan  nan  
  .  nan    3  nan      3  nan    3    nan    3  nan      3  nan    4    nan    4  nan  
  .  nan    3    3      3    3    4      3    4    5      4    5    5      5    5  nan  
-------------------------
-(3, + (5, 3, 3)
  .  nan    3  nan      3  nan    3    nan    3  nan      3  nan    4    nan    4  nan  
  .  nan    3    3      3    3    4      3    4    5      4    5    5      5    5  nan  
  .  nan  nan  nan    nan  nan  nan    nan  nan  nan    nan  nan  nan    nan  nan  nan  ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

-----------

How about in pictoral form

Some people don't work well with numbers so have a gander.  

Remember, we are simply sliding a 3x3 window over by 1 column until it hits the end of the row, then it drops one row and repeats.  nan in both situations is Not A Number.  There is Nan, NaT (not a time) but no Nai (not an integer).  Integers require you temporarily upscale the data to floats, process, then downgrade... or use masked arrays or masked operations.

----------->      Sliding over one column at a time    ---------->

Shift down a row

Again

And Again

---------

Some Examples of Focal Statistics

Here are some examples... see if you can do the mental moving math.

You can make 2 choices when doing focal statistics.

  • if the focal cell is nan, process the surrounding cells for the statistics.
  • if nan is focal cell is nan... assign nan to the result

Both options have their uses, for example to 'smooth' out data getting rid of nodata speckles, the first option would be chosen.  In the situations that you want to preserve locale observations, you would use the second option.

A hard one (sort of)

The difference of the surround cells from the core cell accounting for nodata and assigning nodata if the focal cell is nodata.  In the original array, nodata was 0 and in the output -1 is used.

An easy one (the maximum)

The sample code that does the focal maximum.  The padding and striding function can be found on the toolbox on the 

ArcGIS Code Sharing site. 

The link is ….. Raster Tools: Focal and Local Statistics 

If you have any other raster functionality that involves multidimensional arrays/rasters that you need implemented, send me an email and I will add them to the "Special Analyst" toolset.

more
0 0 1,948
DanPatterson_Retired
MVP Emeritus

The usual.... Another distance question.  This one is a little bit different.  Either the standard distance (a statistical measure in the Spatial Statistics toolset) or a distance matrix and its parameters were needed.

Why not do both without the extension or an advanced license. 

Totally supported since python and numpy and the tools to work with them are provided for you.

Note code savvy????  You can always purchase what you need.

Let's start with the scenario....

You can see the points that are within the polygons.  Objective! either determine the distance matrix of the points contained within each polygon AND/OR calculate the standard distance similarly.

: -----------------------------------------------------------------------------------------------------------------------------------------------------

In short... 

Here is the workflow.

  1. Make your imports.  Arraytools is stuff I have written (on GitHub in sortof organized form)
  2. Select your input featureclass which is created by 'Intersect' ing your points and the polygon.  That way you can bring over your attributes into the resultant point file.
  3. Make a structured array from the featureclass just bringing over the X, Y and an identifier field.
  4. Sort the result in step 3 by the identifier field... this just makes splitting it easier.
  5. Split the array into subarrays for processing.
  6. Lines 10 -19 are just for formatting the output.
  7. Line 21 and on, is the processing steps.
    1. for each subarray, get the X,Y coordinates (line 23)
    2. calculate the center of the point distribution
    3. calculate the variance for X and Y
    4. Use the above to determine the Standard Distance (1 std level, multiply by 2 or 3 for 2 std)
    5. Determine the interpoint distance matrix (line 28) returning an array with the diagonal set to zero (point to itself) and redundant (duplicate) calculations set to zero (line 29)
    6. From the nonzero values (there should be no duplicate points anyway, BTW), calculate the distance's statistical parameters.
    7. Fancy print the results

import arcpy
import arraytools as art

in_fc = r"C:\Path_to_Your\File_geodatabase.gdb\pnts_intersect_polygons"

a = arcpy.da.FeatureClassToNumPyArray(in_fc, ['SHAPE@X', 'SHAPE@Y', 'ID_poly'])
a_sort = np.sort(a, order='ID_poly')
a_split = art.split_array(a_sort, fld='ID_poly')

frmt = """
Group .... {}
center ... {}
standard distance ... {}
distance matrix...{}
distance results...  mean {}, std dev. {}  min  {}, max      {}
"""

# ---- let's role ----
for i in range(len(a_split)):
    a0 = a_split[i][['SHAPE@X', 'SHAPE@Y']]
    a0_xy = art.geom._view_(a0)
    cent = np.mean(a0_xy, axis=0)
    var_x = np.var(a0_xy[:, 0])
    var_y = np.var(a0_xy[:, 1])
    stand_dist = np.sqrt(var_x + var_y)
    dm = art.geom.e_dist(a0_xy, a0_xy)
    dm_result = np.tril(dm, -1)
    dm_vals = dm_result[np.nonzero(dm_result)]
    args = [i,
            cent,
            stand_dist,
            art.form_(dm_result, deci=1, prn=False),
            dm_vals.mean(),
            dm_vals.std(),
            dm_vals.min(),
            dm_vals.max()]
    print(frmt.format(*args))‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Here is the output for the first polygon.

Group .... 0
center ... [ 304932.447  5029991.887]
standard distance ... 795.1178530213251
distance matrix...

Array... ndim: 2  shape: (24, 24)
. .     0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0.....
. .   253.6    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0.....
. .   179.9  214.1    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0.....
. .   377.4  417.6  225.6    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0.....
. .   644.3  513.3  466.6  379.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0.....
. .   866.3  685.6  697.3  637.8  259.5    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0.....
. .   819.0  696.3  639.5  514.0  183.1  219.6    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0.....
. .  1289.9 1164.9 1110.1  960.7  654.6  527.5  473.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0.....
. .  1431.1 1290.0 1251.8 1113.8  788.6  622.9  612.4  164.4    0.0    0.0    0.0    0.0    0.0    0.0.....
. .  1583.5 1385.9 1416.1 1340.3  965.7  718.9  836.0  567.6  446.2    0.0    0.0    0.0    0.0    0.0.....
. .  1504.4 1410.2 1326.3 1148.0  897.6  810.8  715.9  292.8  309.6  745.2    0.0    0.0    0.0    0.0.....
. .  1777.6 1566.1 1616.3 1556.9 1178.8  924.2 1061.2  801.3  669.2  237.4  953.7    0.0    0.0    0.0.....
. .  1587.4 1483.2 1408.4 1236.2  969.9  861.3  786.9  333.8  297.2  703.4  101.2  898.4    0.0    0.0.....
. .  1643.8 1489.1 1465.6 1336.7  999.5  807.5  829.1  391.9  228.1  368.6  429.3  540.1  361.5    0.0.....
. .  1825.6 1740.4 1649.0 1461.7 1228.7 1138.9 1047.5  613.0  571.6  932.6  332.2 1096.0  282.0  565.3.....
. .  2069.4 1859.9 1906.4 1838.6 1462.6 1211.4 1335.0 1018.9  866.6  499.1 1108.9  294.1 1033.9  680.2.....
. .  2218.6 2007.6 2056.0 1988.4 1612.5 1361.3 1484.1 1157.9 1002.1  648.5 1229.6  441.6 1149.2  804.7.....
. .  2004.9 1880.9 1825.1 1663.3 1371.9 1220.5 1190.2  717.4  597.6  791.3  533.6  889.5  435.4  454.5.....
. .  2202.6 2002.9 2034.8 1950.7 1580.4 1337.6 1439.5 1076.4  915.1  619.2 1116.6  455.6 1030.7  702.8.....
. .  2075.5 1916.9 1897.4 1766.0 1431.2 1232.4 1260.5  810.0  652.3  633.7  736.6  650.5  637.8  431.7.....
. .  2144.5 1974.1 1968.1 1848.3 1501.8 1288.7 1337.3  904.1  741.6  636.9  859.7  602.4  763.0  514.0.....
. .  2161.4 2055.3 1982.6 1806.5 1542.4 1413.2 1359.3  893.4  795.7 1021.5  658.6 1115.3  574.4  678.7.....
. .  2245.4 2089.5 2066.9 1931.0 1601.2 1405.5 1428.7  971.7  817.8  798.8  868.6  788.6  767.6  602.0.....
. .  2390.9 2267.3 2211.2 2046.4 1758.7 1603.1 1577.0 1104.2  981.0 1103.4  905.0 1140.0  811.6  813.9.....‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

I will put this in the Point Tools toolset at some point.  

If people need the code, email me at the link on my profile and I can direct you to the links on GitHub.

more
0 0 1,816
DanPatterson_Retired
MVP Emeritus

Make it happen

/blogs/dan_patterson/2018/10/08/making-conda-package-installs-easier 

 Install Spyder, Jupyter console and Jupyter notebook for ArcGIS Pro by default 

With ArcGIS PRO 2.2 there has been a slight change in the way packages can be installed. 

This will evolve but some pictures to get you going.

---------------------     ---------------------     ---------------------    ---------------------    

Updates....

---------------------     ---------------------     ---------------------    ---------------------    

Readings

Esri's Anaconda cloud repo... location of the install packages for Pro 2.2

Spyder .... a view of the IDE's capabilities

The Python Package Manager—ArcPy Get Started | ArcGIS Desktop 

Issues and workarounds

Mangled paths issue … package manager fails to read the _ in the _backup

comment on arcgis pro 2.2.0 and python package manager 

---------------------     ---------------------     ---------------------    ---------------------    

Current installation

Here is where I installed Pro 2.2 a while ago and here it still resides today.

Now some of you don't have the luxury of being able to install your software where you want, but most of this should work if you are given the slightest bit of freedom in how you want to perform your work.  You will be able to perform most of the following in your User profile though (albeit, creating ridiculously long and convoluted path lengths..

Onward.... find out where ArcGIS Pro is installed....

---------------------     ---------------------     ---------------------    ---------------------    

Make some shortcuts

I covered making shortcuts previously, but I will reiterate here.  I like shortcuts on the desktop and I like to dock them on the Task Bar.  First... create your shortcut

Conda access shortcut

Follow the path to the proenv.bat file located as shown in the following figure.

My installation path is C:\ArcGISPro\ You just need to change that portion in your searching and the rest will be the same.

When I located, the file, I created a shortcut and modified the contents of the shortcut as shown below.  I then copied that shortcut to my desktop.

I always keep a separate folder containing customizations like shortcuts so that I can share and/or modify as needed.

: ----------------------------------------------------------------------------

Installing Spyder and other packages

Yes... spyder is in the default package, but since the ArcGISpro-py3 environment is shut down, you have to do installs using conda..

If you don't have a shortcut created... just fire up the python prompt

Or fire up your new shortcut and follow along

Navigate to  C:\Your_Install_Folder\bin\Python\envs\arcgispro-py3\Scripts\spyder-script.py

and make a shortcut like...

Target

C:\ArcGISPro\bin\Python\envs\arcgispro-py3\pythonw.exe "C:\ArcGISPro\bin\Python\envs\arcgispro-py3\Scripts\spyder-script.py"

NOTE...
!!! if your default installation path has flotsam (like spaces, dashes and dots),
 you may have to enclose both portions of the Target in double quotes.  !!!!!

If you want to make a development environment, you now need to clone it to install packages.

Here is the Manage Environments dialog, found on the Project page.

---------------------     ---------------------     ---------------------    ---------------------    

Setup Spyder as your script IDE

You get to reuse the Target shortcut used before.  

Just remember 

  • the pythonw.exe and spyder-script.py paths below need to be on one line.
  • if the python path is in a horrid space or flotsam filled path... enclose it in double quotes.
  • always enclose the spyder-script.py path in double quotes
  • Remember to replace C:\ArcGISPro with your installation path... everything else is the same
  • This is your target path and it goes into the geoprocessing editor selection as below
  • environment:  C:\ArcGISPro\bin\Python\envs\arcgispro-py

Put them together....

     env\pythonw.exe "env\Scripts\spyder-script.py"

Yields....

C:\ArcGISPro\bin\Python\envs\arcgispro-py3\pythonw.exe "C:\ArcGISPro\bin\Python\envs\arcgispro-py3\Scripts\spyder-script.py"

---------------------     ---------------------     ---------------------    ---------------------    

Alternative IDEs ...

Of course you can always install and use Pythonwin for that easy-to-use Python IDE

How about just a simple QtConsole for parallel IDEs

---------------------     ---------------------     ---------------------    ---------------------    

Jupyter Notebook... graphing, analysis and graphing...

Just create a folder structure to store your notebooks and it can be replicated within the jupyter setup making it easy to find your examples.

A graphing example... there are lots

---------------------     ---------------------     ---------------------    ---------------------    

To Come... Managing your packages...

If will fill these in over the next week or so... a few things have to be cleaned up since they may not be for everyone.  So I will delay for now

I just used conda to upgrade jupyter notebook and install jupyter lab.  To stop it from trying to downgrade a bunch of packages, just add the default channel and --no-pin.  

ArcGIS Pro's package manager

Currently locked down for editing the initial install... and there are issues 'cloning' the existing one to make changes in.  Mind you... you can do your package installations using conda after the initial install, skipping the package manager altogether.  BUT .... if things get totally fouled up, you may be left with a dysfunctional installation... so only proceed if you sortof know what you are doing

Anaconda Navigator

So very useful, since you can access other Anaconda packages through one interface... but currently not ArcGIS Pro, but many others including documentation and the like.

https://community.esri.com/ideas/14817-anaconda-navigator-to-arcgis-pro

So... Once Anaconda Navigator got installed, I decided to see whether I could clone an environment that Pro 2.2 could see ... which seems to be an issue.  It seems to have worked so far.  Have a look

Now to experiment....

IF you have comments and questions... email me through my profile link

more
13 1 15.4K
229 Subscribers
Labels
  • Py...Blog 165