# np.gradient() — A Simple Illustrated Guide

In Python, the `numpy.gradient()` function approximates the gradient of an N-dimensional array. It uses the second-order accurate central differences in the interior points and either first or second-order accurate one-sided differences at the boundaries for gradient approximation. The returned gradient hence has the same shape as the input array.

Here is the argument table of `numpy.gradient()`.

If it sounds great to you, please continue reading, and you will fully understand the `numpy.gradient()` function through Python NumPy code snippets and vivid visualization.

• First, I will introduce its underlying concepts, `numpy.gradient()` syntax and arguments.
• Then, you will learn some basic examples of this function.
• Finally, I will address two top questions about `numpy.gradient()`, including `np.gradient edge_order` and `np.gradient axis`.

You can find all codes in this tutorial here.

Besides, I explained the difference between `numpy.diff()` and `numpy.gradient()` in another exciting guide to `numpy.diff()` method here.

## Underlying Concepts: Gradient and Finite Difference

For this part, if you are familiar with gradient and finite difference, feel free to skip it and head over to its syntax and arguments!

🎓 Definition gradient: In vector calculus, the gradient of a scalar-valued differentiable function f of several variables is the vector field whose value at a point p is the vector whose components are the partial derivatives of f at p. (Wikipedia)

For example, the blue arrows in the following graph depict the gradient of the function f(x,y) = −(cos2x + cos2y)^2 as a projected vector field on the bottom plane.

Intuitively, you can consider gradient as an indicator of the fastest increase or decrease direction at a point. Computationally, the gradient is a vector containing all partial derivatives at a point.

Since the `numpy.gradient()` function uses the finite difference to approximate gradient under the hood, we also need to understand some basics of finite difference.

🎓 Definition Finite Difference: A finite difference is a mathematical expression of the form f(x + b) − f(x + a). If a finite difference is divided by b − a, one gets a difference quotient. (Wikipedia)

Don’t panic! Here are my hand-written explanation and deduction for first and second-order forward, backward, and central differences. These formulas are used by `numpy.gradient` under the hood.

## Syntax and Arguments

Here is the syntax of `numpy.gradient()`:

```# Syntax

Here is the argument table of `numpy.gradient()`:

Later, I will delve more into the arguments, `edge_order` and `axis`

As for the argument `varargs`, you can leave it right now and resort to it when you have non-unitary spacing dimensions 🙂

The output of `numpy.gradient()` function is a list of `ndarrays` (or a single `ndarray` if there is only one dimension) corresponding to the derivatives of input `f` with respect to each dimension. Each derivative has the same shape as input `f`.

## Basic Examples

Seen pictorially, here is an illustration of the gradient computation in a one-dimensional array.

Here is a one-dimensional array code example:

```import numpy as np

one_dim = np.array([1, 2, 4, 8, 16], dtype=float)
'''
# Default edge_order = 1
gradient = (one_dim - one_dim)/1 = (2. - 1.)/1 = 1.

# Interior points
gradient = (one_dim - one_dim)/2 = (4. - 1.)/2 = 1.5
gradient = (one_dim - one_dim)/2 = (8. - 2.)/2 = 3.
gradient = (one_dim - one_dim)/2 = (16. - 4.)/2 = 6.

# Default edge_order = 1
gradient = (one_dim - one_dim)/1 = (16. - 8.)/1 = 8.
'''
```

Output:

In our basic example, we did not pass any parameters to the `numpy.gradient()` function.

In this section, I will show you how to deploy the argument `edge_order` and set different order differences for boundary elements.

Just to refresh your memory, here is the argument table of `numpy.gradient()`:

We can set the argument `edge_order` to be 1 or 2. Its default value is 1.

First, our previous basic example uses its default value, 1.

```import numpy as np

# edge_order = 1
one_dim = np.array([1, 2, 4, 8, 16], dtype=float)
'''
# Default edge_order = 1
gradient = (one_dim - one_dim)/1 = (2. - 1.)/1 = 1.

# Interior points
gradient = (one_dim - one_dim)/2 = (4. - 1.)/2 = 1.5
gradient = (one_dim - one_dim)/2 = (8. - 2.)/2 = 3.
gradient = (one_dim - one_dim)/2 = (16. - 4.)/2 = 6.

# Default edge_order = 1
gradient = (one_dim - one_dim)/1 = (16. - 8.)/1 = 8.
'''
```

Output:

Second, we can set the `edge_order` to be 2 and calculate the second-order differences for the boundary elements.

```import numpy as np
# edge_order = 2
one_dim = np.array([1, 2, 4, 8, 16], dtype=float)
'''
# edge_order = 2
gradient = (4*one_dim[0+1] - one_dim[0+2*1] - 3*one_dim)/(2*1)
= (4*2. - 4. + 3*1.)/2 = 0.5

# Interior points
gradient = (one_dim - one_dim)/2 = (4. - 1.)/2 = 1.5
gradient = (one_dim - one_dim)/2 = (8. - 2.)/2 = 3.
gradient = (one_dim - one_dim)/2 = (16. - 4.)/2 = 6.

# edge_order = 2
gradient = (3*one_dim + one_dim[4-2*1] - 4*one_dim[4-1])/(2*1)
= (3*16. + 4. - 4*8.)/2
= 10.
'''
```

Output:

For the rationale behind the second-order forward and backward difference formulas, please take a look at my previous hand-written deduction. I understand they do look quite strange but there is a logic behind 🙂

In this part, I will show you how to deploy the argument `axis` and calculate (actually approximate) the gradient for the dimension(s) you want with a 2d array example case.

Just to refresh your memory, here is the argument table of `numpy.gradient()`:

When we have an input with more than one dimension, we can set `axis` argument as `None` or `int` or tuple of ints to approximate the gradient along the corresponding axis or axes.

Let’s take a two-dimensional array as an example case.

First, let’s see what the default value, `None`, will do.

```import numpy as np

# axis = None (Default)
two_dim = np.array([[1, 2, 4, 8, 16],
[2, 5, 8, 10, 20]], dtype=float)
# Same as:
```

Output:

As we can see, if `axis = None`, `numpy.gradient()` function will output gradient for all axes of the input array.

In this case, we can also pass an integer to `axis` argument.

```import numpy as np

# axis = int
two_dim = np.array([[1, 2, 4, 8, 16],
[2, 5, 8, 10, 20]], dtype=float)

# Same as:

print(f'axis = 0 or -2: \n\n{row_gradient}')
print('-'*85)
print(f'axis = 1 or -1: \n\n{col_gradient}')
```

Output:

Last, we can try passing a tuple of ints to the `axis` argument.

```import numpy as np

# axis = a tuple of ints
two_dim = np.array([[1, 2, 4, 8, 16],
[2, 5, 8, 10, 20]], dtype=float)

That’s it for our `np.gradient()` article.
We also worked on the top two questions about the `np.gradient()` function, ranging from `np.gradient edge_order` and `np.gradient axis`