# 3D plotting with matplotlib

There are a number of options available for creating 3D like plots with matplotlib. Let’s get started by first creating a 3d scatter plot.

## 3D scatter plot

Let’s first create some data:

```
import numpy as np
xyz=np.array(np.random.random((100,3)))
```

and assign it to specific variables (for clarity and also to modify the z values):

```
x=xyz[:,0]
y=xyz[:,1]
z=xyz[:,2]*100
```

Now we need to import the 3d package:

```
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
```

To create our 3D plot, we must take a slightly different approach which will provide us with greater opportunity for plot customisation. First we will create and assign a figure object:

```
fig = plt.figure()
```

Now, from the figure object we are going to create a subplot (of which there will only be one) - the need to do this is to ensure that we have specific access to the properties of the figure we are creating (before, where we called say `plt.scatter()`

we were unable to specifically access its axis properties other than by default):

```
ax = fig.add_subplot(111, projection='3d')
```

We will revisit what is meant by the `111`

later on in the multiple plots section. For now, have a look at the number of options now available to you for modifying the axis object by typing `ax.`

followed by the tab key.

The 3D scatter plotting function (`Axes3D.scatter()`

) takes in x, y and z values which we can set using our `xyz`

array object:

```
ax.scatter(x,y,z)
```

which we can then show (or even save) as normal - have a go at interacting with the figure that pops up:

```
plt.show()
```

To add a colorbar, we need to assign the definition of the scatter plot to a variable which we then pass to the colorbar function. First, re-assign the figure and axis variables:

```
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
```

Now recreate the scatter plot and assign it ot a variable name (we call ours pnt3d) - to make the colorbar work, you must also set the `c`

option - as we are using our `z`

variable to colour our pioints, we set this as `c=z`

:

```
pnt3d=ax.scatter(x,y,z,c=z)
```

Now create your colorbar, and pass in the scatter plot (called `pnt3d`

):

```
cbar=plt.colorbar(pnt3d)
```

Using the colorbar object (`cbar`

), we can also give it a title:

```
cbar.set_label("Values (units)")
```

We can then plot this as normal:

```
plt.show()
```

and you should end up with something like this:

## 3D surface plot

To make a 3D surface plot, we can reuse the dem we opened before (which you can save using this link).

Read this in as a numpy array using `scipy.misc.imread`

:

```
from scipy import misc
dem=misc.imread('/path/to/dem.tif')
```

The function to plot 3d surfaces is available as for the 3d scatter plot demonstrated above - it can be imported as follows:

```
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
```

Notice that we have set an alias for each of the imports - `plt`

for `matplotlib.pyplot`

and `Axes3D`

for `mpl_toolkits.mplot3d`

.

If you have a look at the documentation for mpl_toolkits.mplot3d.plot_surface (which you can access using your alias by typing `Axes3D.plot_surface?`

), you will see that it takes in x, y and z values that must *all* be 2D arrays - the problem at the moment is that your surface array (`dem`

) only provides the z data - you don’t have the x or y components.

To create this, we can use a function from numpy called meshgrid. For a given array of values, the meshgrid function creates 2 equally sized grids that represent the x and y location at each element of the array, that is to say that for an element in our `dem`

array, the x and y mesh grids will provide information of its location in x and y space… let’s try an example…

First, check on the shape of your `dem`

array:

```
>>> dem.shape
>>> (592L, 584L)
```

Now import `numpy`

- we’ll give it an alias of `np`

):

```
import numpy as np
```

Now we need to create the dimensions of what will be our mesh grids of x and y. First assign the dimensions of the `dem`

array to variables of `nx`

and `ny`

:

```
ny, nx = dem.shape
```

The above statement assigns the two values returned by the `dem.shape`

call to the two variables `nx`

and `ny`

.

We now need to make two lists of values ranging from 0 to the maximum length of the image in both the x and y dimensions - we can do this by using numpy’s linspace function:

```
x = np.linspace(0, 1, nx)
y = np.linspace(0, 1, ny)
```

This has created every likely element position in the x and y dimensions - remember that for a given column, the x value will remain the same (now matter how far up or down the column it is) and the same for y in the horizontal direction - if this doesn’t make sense, we’ll have an image to look at in a minute.

Now we just need to pass in the `x`

and `y`

variables to `np.meshgrid()`

to get our arrays of x and y position (calling the resultant grids `xv`

and `yv`

):

```
xv, yv = np.meshgrid(x, y)
```

To visualise these grids, here is x, the values of which only change from left to right:

and here is y, the values of which only change from top to bottom:

The key point now is that we have 3 2d arrays, representing x, y and z, held by the variables `xv`

, `yv`

and `dem`

respectively. Now we can pass these into the `Axes3D.surface_plot()`

. We have to do this in the same way as for the 3d scatter plot above, so type:

```
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
dem3d=ax.plot_surface(xv,yv,dem)
plt.show()
```

To adjust the colours, set the type of colormap you want to use using the `cmap`

option when creating the main plot:

```
dem3d=ax.plot_surface(xv,yv,dem,cmap='afmhot')
```

You might also want to add a title and axis labels to the plot - as we are using a specific call to the plot axis, we must set this using:

```
ax.set_title('DEM')
ax.set_zlabel('Elevation (m)')
```

You can then view it using:

```
plt.show()
```

If you prefer a smoother looking image, then you want to adjust the `linewidth`

option when creating the plot:

```
dem3d=ax.plot_surface(xv,yv,dem,cmap='afmhot', linewidth=0)
```

You might also like to play with the `alpha`

option which changes transparency:

```
dem3d=ax.plot_surface(xv,yv,dem,cmap='afmhot', linewidth=0, alpha=0.2)
```

If you want to change the scale of the values in the `dem`

array, then you are best modifying the values before plotting it e.g.:

```
dem_100=dem/100
```

Remember that if you make these changes, you need to then recreate the figure and axis instances. So, after making some additional changes, we create the figure by typing:

```
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
dem3d=ax.plot_surface(xv,yv,dem_100,cmap='afmhot', linewidth=0)
ax.set_title('DEM')
ax.set_zlabel('Elevation (x$10^{-2}$ m)')
plt.show()
```

Your plot should look something like this: