Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make a contour plot by using three 1D arrays in python

Tags:

python

contour

As the title indicates I would like to make a contour plot by using three 1D arrays. Let's say that

x = np.array([1,2,3])

and

y = np.array([1,2,3])

and

z = np.array([20,21,45])

To do a contourplot in matplotlib i meshed the x and y coordinate as X,Y = meshgrid(x,y) but then the z array must also be a 2D array. How do I then turn z into a 2d array so it can be used?

like image 279
David Halley Avatar asked Jan 27 '17 15:01

David Halley


People also ask

How do you plot 3D contour in Python?

The ax. contour3D() function creates three-dimensional contour plot. It requires all the input data to be in the form of two-dimensional regular grids, with the Z-data evaluated at each point.


2 Answers

Although OP realized that it is not possible to draw a contour plot with the data in the question, this is still a relevant question in situations where the data can be thought of a 3d surface.

Contour plotting options for three 1D arrays

There are basically three options

  1. Use tricontourf to draw it, if you don't absolutely have to use the regular contourf function. Works with gridded and non-gridded data.
  2. If your data is gridded, but in three separate 1d arrays, you can make break them into two 1d arrays and one 2d array, and plot them with contourf
  3. If your data is not gridded, and you do not want to use tricontourf, you can interpolate the data into a grid and plot it with contourf. There are many 3d interpolation questions which can help you with that. After interpolating your data, you can use the technique shown in Option 2.

Option 1: tricontourf

This one is super-simple. Just use the plt.tricontourf function like this (see creation of the example data in the appendix)

from matplotlib import pyplot as plt

plt.tricontourf(xdata, ydata, zdata)
plt.show()

Output

tricontourf

Option 2: Gridded 1D arrays and contourf

If one has gridded data stored in three 1D-arrays, and for some reason does not want to use tricontourf, there is how you could make a contourf plot out of it. (Example data given in the Appendix)

import pandas as pd
from matplotlib import pyplot as plt 

df = pd.DataFrame(dict(x=xdata, y=ydata, z=zdata))
xcol, ycol, zcol = "x", "y", "z"
df = df.sort_values(by=[xcol, ycol])
xvals = df[xcol].unique()
yvals = df[ycol].unique()
zvals = df[zcol].values.reshape(len(xvals), len(yvals)).T
plt.contourf(xvals, yvals, zvals)
plt.show()

Output

contourf

Idea explained

  • First, the data has to be gridded, since that is how a plt.contour plot works. It it is not, you can interpolate it to new grid.
  • Then, create pandas.DataFrame df as intermediate medium.
  • Then, use the df.sort_values() method to sort the x- and y-data. This makes the values given by unique() in the next step, sorted.
  • Get all the unique values for x- and y-data with unique(). This is kind of the inverse of "meshgrid" operation.
  • Since the values of pandas dataframe columns are just numpy arrays, you can call the reshape() method to create the needed 2d-array.
  • Now if x had N unique values, y had M unique values, then zvals will be a (N,M) 2d-array which can be fed to plt.contour.

Appendix: Example data

import numpy as np
import pandas as pd

xs, ys = np.linspace(-4, 4), np.linspace(-4, 4)
xgrid, ygrid = np.meshgrid(xs, ys)
xdata, ydata = np.ravel(xgrid), np.ravel(ygrid)
zdata = (
    2.3 * (1 - xdata) ** 2 * np.exp(-(ydata ** 2) - (xdata + 0.9) ** 2)
    - 13.3
    * (ydata / 2.2 - ydata ** 3 - xdata ** 4)
    * np.exp(-(ydata ** 2) - xdata ** 2)
    - 0.8 * np.exp(-((ydata + 1) ** 2) - xdata ** 2)
)

like image 84
np8 Avatar answered Sep 22 '22 05:09

np8


I encounter this issue frequently if I am using data that I had raveled for easier manipulation. In the raveled data a 2-D array is flattened.

The original data has x, y, and z values for every coordinate:

x = [0, 1, 2; 0, 1, 2]

y = [0, 0, 0; 1, 1, 1]

z = [0.1 , 0.2, 0.3 ; 0.2, 0.3, 0.4]

Using np.ravel() for all three arrays makes them a one-dimensional 6 element long array.

xx = np.ravel(x); yy = np.ravel(y) ; zz = np.ravel(z)

Now xx = ([0, 1, 2, 0, 1, 2]), and similarly for yy and zz.

If this is the kind of data you are working with and the data is thoroughly sampled, you can simulate a contourf plot using a scatter plot. This only works if your dataset is sampled well enough to fill in all of the space.

plt.scatter(xx,yy,c=zz,cmap=cm.Reds)

enter image description here

like image 34
J. Kent Avatar answered Sep 21 '22 05:09

J. Kent