Make a contour plot by using three 1D arrays
Asked Answered
N

4

9

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?

Neuroblast answered 27/1, 2017 at 15:32 Comment(1)
It looks like the answer from NP8 is the only answer that answers the question that you asked, a list of x, y and z values. I found that one very useful. I dont understand your reasoning for preferring the one you marked as correctAmathiste
A
-2

Your z is wrong. It needs to give the values at every point of the mesh. If z is a function of x and y, calculate z at what I refer to as X_grid below:

import numpy as np
import matplotlib.pyplot as plt

def f(x):
    return (x[:,0]**2 + x[:,1]**2)

x = np.array([1,2,3])
y = np.array([1,2,3])
xx, yy = np.meshgrid(x, y)
X_grid = np.c_[ np.ravel(xx), np.ravel(yy) ]
z = f(X_grid)

z = z.reshape(xx.shape)

plt.contour(xx, yy, z)
Anglicism answered 27/1, 2017 at 15:39 Comment(8)
What is xx1 and xx2?Neuroblast
Take care of the z = "values at ..." because here you are assigning a string to z. Apart from this I am getting the following error: ValueError: total size of new array must be unchangedNeuroblast
@SmailKozarcanin You need a z value for each grid point but you did not provide this so your question is not really answerable unless you tell us how to find the missing z values... See Theo's answer which is more of a comment.Sophia
Yes I do see that nowNeuroblast
See the updated code. It plots an example function and shows you the correct use of plt.contour.Anglicism
The question asked how to generate a graph from a list of z values. It did not ask how to generate the graph from a function. As use cases they are completely different, and the answer is not useful for the question as asked. I.e., you did not answer the question.Amathiste
It "somehow" counts as correct because the OP accepted it as an answer - suggesting he found the information useful to his problem. No one forced him nor tried to convince him to do that. I guess what is really frustrating is the boredom of being in a lockdown, which is understandable.Anglicism
Perhaps the correct answer from @NP8 was posted after he erroneously marked you correct. There is no basis for the claim that because the OP selects it, it is correct. If the OP is such an expert, he wouldn't need to ask.Amathiste
L
22

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)
)

Longdrawn answered 6/12, 2020 at 20:48 Comment(1)
This is the only answer so far that is correct and addresses the question that was asked, And it is a very good answer for thoroughness and clarity.Amathiste
B
2

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

Backflow answered 18/12, 2017 at 20:48 Comment(0)
H
0

It seems to me that you're describing a one-dimensional curve through the space rather than a surface. I say that bacause I assume x[i], y[i] and z[i] are the coordinates of a point. You cannot use these points to define a surface in an easy way, because your points only depend on one variable i and so only describes a shape with one degree of freedom. Consider that you can connect each point in the list to the next, and that this only gives you a one dimensional chain of points. In oder to make a surface out of three arrays, you must define 9 z values, not 3.

I'm sorry that this isn't a helpful answer, but I don't have the reputation to post a comment.

Holocaust answered 27/1, 2017 at 15:50 Comment(1)
I see what you mean. Thank you.Neuroblast
A
-2

Your z is wrong. It needs to give the values at every point of the mesh. If z is a function of x and y, calculate z at what I refer to as X_grid below:

import numpy as np
import matplotlib.pyplot as plt

def f(x):
    return (x[:,0]**2 + x[:,1]**2)

x = np.array([1,2,3])
y = np.array([1,2,3])
xx, yy = np.meshgrid(x, y)
X_grid = np.c_[ np.ravel(xx), np.ravel(yy) ]
z = f(X_grid)

z = z.reshape(xx.shape)

plt.contour(xx, yy, z)
Anglicism answered 27/1, 2017 at 15:39 Comment(8)
What is xx1 and xx2?Neuroblast
Take care of the z = "values at ..." because here you are assigning a string to z. Apart from this I am getting the following error: ValueError: total size of new array must be unchangedNeuroblast
@SmailKozarcanin You need a z value for each grid point but you did not provide this so your question is not really answerable unless you tell us how to find the missing z values... See Theo's answer which is more of a comment.Sophia
Yes I do see that nowNeuroblast
See the updated code. It plots an example function and shows you the correct use of plt.contour.Anglicism
The question asked how to generate a graph from a list of z values. It did not ask how to generate the graph from a function. As use cases they are completely different, and the answer is not useful for the question as asked. I.e., you did not answer the question.Amathiste
It "somehow" counts as correct because the OP accepted it as an answer - suggesting he found the information useful to his problem. No one forced him nor tried to convince him to do that. I guess what is really frustrating is the boredom of being in a lockdown, which is understandable.Anglicism
Perhaps the correct answer from @NP8 was posted after he erroneously marked you correct. There is no basis for the claim that because the OP selects it, it is correct. If the OP is such an expert, he wouldn't need to ask.Amathiste

© 2022 - 2024 — McMap. All rights reserved.