Python Built-in Types¶
We are going to start using spyndex with the simplest objects: int
, float
, and… list
?.
Before starting, make sure you have spyndex
and the latest dask
version. If not, you can upgrade them here:
[ ]:
!pip install -U spyndex
Now, let’s start!
First, import spyndex
:
[1]:
import spyndex
int
¶
Now, let’s emulate some values for the Near Infrared (NIR
) and Red (RED
) reflectances of vegetation with an int
data type:
Let’s say that the data values go from 0 to 10000.
[2]:
NIR = 6723
RED = 1243
If we check the data types for each one of our variables, we will see that they are int
:
[3]:
print(f"NIR type: {type(NIR)}, value: {NIR}")
print(f"RED type: {type(RED)}, value: {RED}")
NIR type: <class 'int'>, value: 6723
RED type: <class 'int'>, value: 1243
Now, let’s go and compute the NDVI
! Let’s check the attributes of the index:
[4]:
spyndex.indices.NDVI
[4]:
NDVI: Normalized Difference Vegetation Index (attributes = ['bands', 'contributor', 'date_of_addition', 'formula', 'long_name', 'reference', 'short_name', 'type'])
From these attributes, we need to know the standard name of the bands so we can compute it:
[5]:
spyndex.indices.NDVI.bands
[5]:
('N', 'R')
That’s it! We need the N
and R
parameters! Let’s create a dict
to store them (Psst! This dictionary is useful since we can pass it to the params
argument in the index computation!):
[6]:
parameters = {"N": NIR, "R": RED}
Now we just have to compute the index! It can be easily done with spyndex.computeIndex()
:
[7]:
idx = spyndex.computeIndex("NDVI", parameters)
If we check the data type of our result, we’ll see that it is a float
!
Usually, spectral indices go from -1 to 1 since most of them are normalized differences!
[8]:
print(f"idx type: {type(idx)}, value: {idx}")
idx type: <class 'float'>, value: 0.6879236756213909
float
¶
What if we, besides the NDVI
, want to compute another index, mmmm, let’s say… the SAVI
?
[9]:
spyndex.indices.SAVI.bands
[9]:
('L', 'N', 'R')
Wow! It seems that now, besides the N
and R
, we need another parameter… the L
!? What is that? Well, let’s check it! With the spyndex.constants
object we can check what are those weird parameters that are not bands and we don’t know!
[10]:
spyndex.constants.L
[10]:
Canopy background adjustment (default = 1.0)
Ohh, it is the canopy background adjustment! Now we can give it the desired value!
For SAVI, the default L value is 0.5… But don’t get confused! For the EVI the default value is 1.0!
[11]:
parameters = {"N": NIR / 10000, "R": RED / 10000, "L": 0.5}
Did you notice that we divided the values by 10000? Well, the idea of that computation is to scale the values to [-1,1]. This is because SAVI
can’t be used with values outside that range! Let’s check our data types now:
[12]:
print(f"NIR type: {type(parameters['N'])}, value: {parameters['N']}")
print(f"RED type: {type(parameters['R'])}, value: {parameters['R']}")
print(f"L type: {type(parameters['L'])}, value: {parameters['L']}")
NIR type: <class 'float'>, value: 0.6723
RED type: <class 'float'>, value: 0.1243
L type: <class 'float'>, value: 0.5
Amazing! Now we can compute our indices! Just pass a list of them to spyndex.computeIndex()
:
[13]:
idx = spyndex.computeIndex(["NDVI","SAVI"], parameters)
What do you think we will get as a result?…
[14]:
print(f"idx type: {type(idx)}, value: {idx}")
idx type: <class 'list'>, value: [0.687923675621391, 0.6339657565941694]
That’s right! A list! Why? Because we computed more than one spectral index! The length of the resulting list is equal to the number of indices that we computed!
list
?¶
Nice, very nice… But what if now we have a list of reflectance values and for each pair/group we want to compute the indices?
[15]:
NIR = [0.634, 0.654, 0.567]
RED = [0.123, 0.156, 0.198]
Remember, these are lists!
[16]:
print(f"NIR type: {type(NIR)}, value: {NIR}")
print(f"RED type: {type(RED)}, value: {RED}")
NIR type: <class 'list'>, value: [0.634, 0.654, 0.567]
RED type: <class 'list'>, value: [0.123, 0.156, 0.198]
Be careful!
[17]:
parameters = {"N": NIR, "R": RED, "L": 0.5}
Are you ready? Let’s compute the indices!
[18]:
idx = spyndex.computeIndex(["NDVI","SAVI"], parameters)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
/tmp/ipykernel_17173/2483861871.py in <module>
----> 1 idx = spyndex.computeIndex(["NDVI","SAVI"], parameters)
~/gh/spyndex/spyndex/spyndex.py in computeIndex(index, params, online, returnOrigin, coordinate)
206 else:
207 _check_params(idx, params)
--> 208 result.append(eval(indices[idx]["formula"], {}, params))
209
210 if len(result) == 1:
<string> in <module>
TypeError: unsupported operand type(s) for -: 'list' and 'list'
Mein Gott!!! What happened? An error? This is outrageous! Somebody kill me!
Relax, relax… that was an expected error, and I will tell you why:
spyndex
doesn’t care what kind of objects you use as long as they support overloaded operators.With
int
andfloat
types that’s not a problem because they by default support overloaded operators.The bad thing, is that
list
types DON’T SUPPORT OVERLOADED OPERATORS… (Ehmmmm, they support the+
, but that’s a concatenation operation, not an addition)
Well, now what do we do?…
Don’t worry, people, because numpy
is here to save us!
[19]:
import numpy as np
Let’s transform those lists to numpy.ndarray
objects!
[20]:
parameters = {"N": np.array(NIR), "R": np.array(RED), "L": 0.5}
Let’s check the data types to be sure!
[21]:
print(f"NIR type: {type(parameters['N'])}, value: {parameters['N']}")
print(f"RED type: {type(parameters['R'])}, value: {parameters['R']}")
print(f"L type: {type(parameters['L'])}, value: {parameters['L']}")
NIR type: <class 'numpy.ndarray'>, value: [0.634 0.654 0.567]
RED type: <class 'numpy.ndarray'>, value: [0.123 0.156 0.198]
L type: <class 'float'>, value: 0.5
Since L
is a constant, you don’t need to create a repeated list of it ;) Now, let’s compute the indices!
[22]:
idx = spyndex.computeIndex(["NDVI","SAVI"], parameters)
No error! :))) Let’s check our result!
[23]:
print(f"idx type: {type(idx)}, value: {idx}")
idx type: <class 'numpy.ndarray'>, value: [[0.67503303 0.61481481 0.48235294]
[0.6097852 0.57022901 0.43754941]]
Wow! The result is a numpy.ndarray
? YES! As long as returnOrigin=True
, spyndex
will return the result in the same data type as the input!
Nice, right?