Python 为什么 pyplot.contour() 要求 Z 是一个二维数组?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/42045921/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does pyplot.contour() require Z to be a 2D array?
提问by dhrumeel
The matplotlib.pyplot.contour()
function takes 3 input arrays X
, Y
and Z
.
The arrays X
and Y
specify the x- and y-coordinates of points, while Z
specifies the corresponding value of the function of interest evaluated at the points.
所述matplotlib.pyplot.contour()
函数接受3个输入阵列X
,Y
和Z
。
数组X
和Y
指定点的 x 和 y 坐标,同时Z
指定在点处评估的感兴趣函数的相应值。
I understand that np.meshgrid()
makes it easy to produce arrays which serve as arguments to contour()
:
我知道这样np.meshgrid()
可以轻松生成用作以下参数的数组contour()
:
X = np.arange(0,5,0.01)
Y = np.arange(0,3,0.01)
X_grid, Y_grid = np.meshgrid(X,Y)
Z_grid = X_grid**2 + Y_grid**2
plt.contour(X_grid, Y_grid, Z_grid) # Works fine
This works fine. And conveniently, this works fine too:
这工作正常。方便的是,这也很好用:
plt.contour(X, Y, Z_grid) # Works fine too
However, why is the Z
input requiredto be a 2D-array?
但是,为什么Z
输入必须是二维数组?
Why is something like the following disallowed, even though it specifies all the same data aligned appropriately?
为什么像下面这样的内容是不允许的,即使它指定了所有相同的数据适当对齐?
plt.contour(X_grid.ravel(), Y_grid.ravel(), Z_grid.ravel()) # Disallowed
Also, what are the semantics when onlyZ
is specified (without the corresponding X
and Y
)?
另外,仅指定时的语义Z
是什么(没有相应的X
和Y
)?
回答by ImportanceOfBeingErnest
Looking at the documentation of contour
one finds that there are a couple of ways to call this function, e.g. contour(Z)
or contour(X,Y,Z)
. So you'll find that it does not require any X
or Y
values to be present at all.
查看一个人的文档contour
发现有几种方法可以调用这个函数,例如contour(Z)
or contour(X,Y,Z)
。所以,你会发现它不需要任何X
或者Y
价值能够体现的。
However in order to plot a contour, the underlying grid must be known to the function. Matplotlib's contour
is based on a rectangular grid. But even so, allowing contour(z)
, with z
being a 1D array, would make it impossible to know how the field should be plotted. In the case of contour(Z)
where Z
is a 2D array, its shape unambiguously sets the grid for the plot.
但是,为了绘制轮廓,函数必须知道底层网格。Matplotlibcontour
基于矩形网格。但即便如此,允许contour(z)
,z
作为一维数组,将无法知道应如何绘制该字段。在contour(Z)
whereZ
是二维数组的情况下,它的形状明确地设置了绘图的网格。
Once that grid is known, it is rather unimportant whether optional X
and Y
arrays are flattened or not; which is actually what the documentation tells us:
一旦知道该网格,则 optionalX
和Y
数组是否被展平就变得不重要了。这实际上是文档告诉我们的:
X and Y must both be 2-D with the same shape as Z, or they must both be 1-D such that len(X) is the number of columns in Z and len(Y) is the number of rows in Z.
X 和 Y 必须都是与 Z 形状相同的二维,或者它们都必须是一维的,这样 len(X) 是 Z 中的列数,len(Y) 是 Z 中的行数。
It is also pretty obvious that someting like
plt.contour(X_grid.ravel(), Y_grid.ravel(), Z_grid.ravel())
cannot produce a contour plot, because all the information about the grid shape is lost and there is no way the contour function could know how to interprete the data. E.g. if len(Z_grid.ravel()) == 12
, the underlying grid's shape could be any of (1,12), (2,6), (3,4), (4,3), (6,2), (12,1)
.
同样很明显,类似的东西
plt.contour(X_grid.ravel(), Y_grid.ravel(), Z_grid.ravel())
无法生成等高线图,因为有关网格形状的所有信息都丢失了,并且等高线函数无法知道如何解释数据。例如,如果len(Z_grid.ravel()) == 12
,底层网格的形状可以是 中的任何一个(1,12), (2,6), (3,4), (4,3), (6,2), (12,1)
。
A possible way out could of course be to allow for 1D arrays and introduce an argument shape
, like plt.contour(x,y,z, shape=(6,2))
. This however is not the case, so you have to live with the fact that Z
needs to be 2D.
一个可能的出路当然是允许一维数组并引入一个参数shape
,比如plt.contour(x,y,z, shape=(6,2))
. 然而事实并非如此,因此您必须接受Z
需要是 2D的事实。
However, if you are looking for a way to obtain a countour plot with flattened (ravelled) arrays, this is possible using plt.tricontour()
.
但是,如果您正在寻找一种方法来获得具有展平(散开)阵列的计数图,则可以使用plt.tricontour()
.
plt.tricontour(X_grid.ravel(), Y_grid.ravel(), Z_grid.ravel())
Here a triangular grid will be produced internally using a Delaunay Triangualation. Therefore even completely randomized points will produce a nice result, as can be seen in the following picture, where this is compared to the same random points given to contour
.
这里将使用 Delaunay Triangualation 在内部生成一个三角形网格。因此,即使是完全随机的点也会产生很好的结果,如下图所示,将其与给定的相同随机点进行比较contour
。
(Here is the code to produce this picture)
回答by Ilya V. Schurov
The actual code of an algorithm behind plt.contour
can be found in _countour.cpp. It is rather complicated C-code, so it is difficult to follow it precisely, but if I were trying to make some contours-generating code I would do it in the following way. Pick some point (x, y)
at the border and fix its z
-value. Iterate over nearby points and pick that one for which z-value is the closest to z-value of the first point. Continue iteration for new point, pick nearby point with the z-value closest to the desired (but check that you do not return to a point you just visited, so you have to go in some "direction"), and continue until you get a cycle or reach some border.
背后算法的实际代码plt.contour
可以在_countour.cpp 中找到。它是相当复杂的 C 代码,因此很难精确地遵循它,但是如果我尝试制作一些轮廓生成代码,我会按照以下方式进行。(x, y)
在边界上选择一些点并修复它的z
值。迭代附近的点并选择 z 值最接近第一个点的 z 值的点。继续迭代新点,选择 z 值最接近期望值的附近点(但检查您没有返回到您刚刚访问过的点,因此您必须朝某个“方向”前进),并继续直到您得到一个循环或到达某个边界。
It seems that something close (but a bit more complex) is implemented in _counter.cpp
.
似乎在_counter.cpp
.
As you see from the informal description of the algorithm, to proceed you have to find a point which is "nearby" to the current one. It is easy to do if you have a rectangular grid of points (need about 4 or 8 iterations like this: (x[i+1][j], y[i+1][j])
, (x[i][j+1], y[i][j+1])
, (x[i-1][j], y[i-1][j])
and so on). But if you have some randomly selected points (without any particular order), this problem becomes difficult: you have to iterate over all the points you have to find nearby ones and make the next step. The complexityof such step isO(n)
, where n
is a number of points (typically a square of a size of a picture). So an algorithm becomes much slower if you don't have a rectangular grid.
正如您从算法的非正式描述中看到的那样,要继续,您必须找到一个与当前点“附近”的点。如果您有一个矩形的点网格(需要大约 4 或 8 次迭代,像这样:(x[i+1][j], y[i+1][j])
,(x[i][j+1], y[i][j+1])
,(x[i-1][j], y[i-1][j])
等等),这很容易做到。但是如果你有一些随机选择的点(没有任何特定的顺序),这个问题就变得很困难:你必须遍历所有点,找到附近的点并进行下一步。该步骤的复杂度为O(n)
,其中n
为点数(通常为图片大小的正方形)。因此,如果您没有矩形网格,算法会变得更慢。
This is why you actually need three 2d-arrays that correpsponds to x's, y's and z's of some points located over some rectangular grid.
这就是为什么您实际上需要三个二维数组,它们对应于位于某个矩形网格上的某些点的 x、y 和 z。
As you correctly mention, x
's and y
's can be 1d-arrays. In this case, the corresponding 2d-arrays are reconstructed with meshgrid
. However, in this case you have to have z
as 2d-array anyway.
正如您正确提到的,x
's 和y
's 可以是一维数组。在这种情况下,相应的 2d 阵列用 重建meshgrid
。但是,在这种情况下,无论如何您都必须拥有z
二维数组。
If only z
is specified, x
and y
are range
's of appropriate lengths.
如果 onlyz
被指定,x
并且y
是range
适当长度的。
EDIT. You can try to "fake" two-dimensional x
, y
and z
arrays in such a way that x
and y
does not form a rectangular grid to check if my assumptions are correct.
编辑。您可以尝试“假”二维x
,y
和z
阵列,这样的方式x
,并y
没有形成一个矩形网格检查,如果我的假设是正确的。
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
x = np.random.uniform(-3, 3, size=10000)
y = np.random.uniform(-3, 3, size=10000)
z = x**2 + y**2
X, Y, Z = (u.reshape(100, 100) for u in (x, y, z))
plt.contour(X, Y, Z)
As you see, the picture does not look like anything close to the correct graph if (x, y, z)'s are just some random points.
如您所见,如果 (x, y, z) 只是一些随机点,则图片看起来与正确的图形不太相似。
Now let us assume that x
is sorted as a preprocessing step as @dhrummel suggests in the comments. Note that we can't sort x
and y
simultaniously as they are not independent (we want to preserve the same points).
现在让我们假设x
按照@dhrummel 在评论中的建议将其分类为预处理步骤。请注意,我们不能同时排序x
和排序,y
因为它们不是独立的(我们希望保留相同的点)。
x = np.random.uniform(-3, 3, size=10000)
y = np.random.uniform(-3, 3, size=10000)
z = x**2 + y**2
xyz = np.array([x, y, z]).T
x, y, z = xyz[xyz[:, 0].argsort()].T
assert (x == np.sort(x)).all()
X, Y, Z = (u.reshape(100, 100) for u in (x, y, z))
plt.contour(X, Y, Z)
Again, the picture is incorrect, due to the fact that y
's are not sorted (in every column) as they were if we had rectangular grid instead of some random points.
同样,图片是不正确的,因为y
's 没有排序(在每一列中),如果我们有矩形网格而不是一些随机点。
回答by 2Obe
The reason for X and Y to be 2D is the following. Z matches to each (x,y) coordinate in the axes system a corresponding "depth" to create a 3D plot with x,y,and z coordinates.
X 和 Y 为 2D 的原因如下。Z 与轴系统中的每个 (x,y) 坐标匹配相应的“深度”,以创建具有 x、y 和 z 坐标的 3D 绘图。
Now assume we want to point on a arbitrary point within the axes system. We can do that by providing the x and y coordinates (x,y) for this point.For example (0,0). Now consider the "line" with the x value 1. On this line there is a number of n y values, which looks smth like:
现在假设我们要指向轴系统内的任意点。我们可以通过提供该点的 x 和 y 坐标 (x,y) 来实现。例如 (0,0)。现在考虑 x 值为 1 的“线”。在这条线上有许多 ny 值,看起来像:
If we plot this lines for all x values and y values we will get smth. like:
如果我们为所有 x 值和 y 值绘制这条线,我们将得到 smth。喜欢:
As you can see we have a 2D annotation which is consisting of 2 2Darrays, one for the x values which has the shape:
如您所见,我们有一个由2 个 2D数组组成的 2D 注释,其中一个用于 x 值,其形状如下:
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
#--> Two dimensional x values array
and one for the y values which has the shape:
一个用于具有以下形状的 y 值:
10 10 10 10 10 10 10 10 10 10
9 9 9 9 9 9 9 9 9 9
8 8 8 8 8 8 8 8 8 8
...
1 1 1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0 0 0
#--> Two dimensional y values array
Those two together provides the (x,y) coordinates for each point within the coordinate system. Now we can plot for each point the "depth" means the Z value (z coordinate). Now it is also obvious why the Z variable must be 2 dimensional with the shape (len(x),len(y)) because otherwise it can't provide a value for all points.
这两者一起为坐标系中的每个点提供 (x,y) 坐标。现在我们可以为每个点绘制“深度”表示 Z 值(z 坐标)。现在也很明显为什么 Z 变量必须是具有形状 (len(x),len(y)) 的二维,否则它无法为所有点提供值。
This behaviour can be realised by either providing 2D x,y, and z arrays to the function OR: provide 1D x and y arrays to the function and the function internally creates the 2D mesh from the x and y values with smth. like X,Y=np.meshgrid(x,y) but nevertheless z must be two dimensional.
这种行为可以通过向函数提供 2D x、y 和 z 数组来实现,或者:向函数提供 1D x 和 y 数组,函数在内部使用 smth 从 x 和 y 值创建 2D 网格。像 X,Y=np.meshgrid(x,y) 但 z 必须是二维的。
回答by rayryeng
Imagine that you want to plot a three-dimensional graph. You have a set of x
points and a set of y
points. The goal is to produce a value z
for each pair of x
and y
, or in other words you need a function f
such that it generates a value of z
so that z = f(x, y)
.
想象一下,您要绘制一个三维图形。你有一组x
点和一组y
点。目标是z
为每对x
and生成一个值y
,或者换句话说,您需要一个函数f
,以便它生成一个值z
so that z = f(x, y)
。
Here's a good example (taken from MathWorks):
这是一个很好的例子(取自 MathWorks):
The x
and y
coordinates are at the bottom right and bottom left respectively. You will have a function f
such that for each pair of x
and y
, we generate a z
value. Therefore, in the code you have provide, the numpy.meshgrid
call will generate two 2D arrays such that for each unique spatial location, we will observe the x
and y
value that are unique to that location.
在x
和y
坐标分别处于左底部右侧和底部。您将拥有一个函数f
,对于每对x
and y
,我们都会生成一个z
值。因此,在您提供的代码中,该numpy.meshgrid
调用将生成两个二维数组,以便对于每个唯一的空间位置,我们将观察该位置唯一的x
和y
值。
For example, let's use a very small example:
例如,让我们使用一个非常小的例子:
In [1]: import numpy as np
In [2]: x, y = np.meshgrid(np.linspace(-1, 1, 3), np.linspace(-1, 1, 3))
In [3]: x
Out[3]:
array([[-1., 0., 1.],
[-1., 0., 1.],
[-1., 0., 1.]])
In [4]: y
Out[4]:
array([[-1., -1., -1.],
[ 0., 0., 0.],
[ 1., 1., 1.]])
Take a look at row number 2 and column number 1 for example (I'm starting indexing at 0 btw). This means at this spatial location, we will have coordinate x = 0.
and y = 1
. numpy.meshgrid
gives us the x
and y
pair that is required to generate the value of z
at that particular coordinate. It's just split up into two 2D arrays for convenience.
例如,看看第 2 行和第 1 列(顺便说一下,我从 0 开始索引)。这意味着在这个空间位置,我们将有坐标x = 0.
和y = 1
。 numpy.meshgrid
为我们提供了在该特定坐标处生成 的值所需的x
和y
对z
。为方便起见,它只是分成两个二维数组。
Now what to finally put in your z
variable is that it should use the function f
and process what the output is for every value in x
and its corresponding y
.
现在最终要放入您的z
变量的是它应该使用该函数f
并处理输出中的每个值x
及其对应的y
.
Explicitly, you will need to formulate a z
array that is 2D such that:
明确地,您将需要制定一个z
二维数组,以便:
z = [f(-1, -1) f(0, -1) f(1, -1)]
[f(-1, 0) f(0, 0) f(1, 0)]
[f(-1, 1) f(0, 1) f(1, 1)]
Look very carefully at the spatial arrangement of x
and y
terms. We generate 9 unique values for each pair of x
and y
values. The x
values span from -1 to 1 and the same for y
. Once you generate this 2D array for z
, you can use contourf
to draw out level sets so that each contour line will give you the set of all possible x
and y
values that equal the same value of z
. In addition, in between each adjacent pair of distinct lines, we fill in the area in between by the same colour.
仔细观察x
和y
术语的空间排列。我们为每对x
和y
值生成 9 个唯一值。的x
值跨越从-1到1,并且在同一对y
。一旦你为 生成了这个二维数组z
,你就可以contourf
用来绘制水平集,这样每条等高线都会为你提供所有可能的x
和y
等于 的相同值的值的集合z
。此外,在每对相邻的不同线条之间,我们用相同的颜色填充它们之间的区域。
Let's finish this off with an actual example. Suppose we have the function f(x, y) = exp(-(x**2 + y**2) / 10)
. This is a 2D Gaussian with a standard deviation of sqrt(5)
.
让我们用一个实际的例子来结束这个。假设我们有函数f(x, y) = exp(-(x**2 + y**2) / 10)
。这是一个标准差为 的二维高斯sqrt(5)
。
Therefore, let's generate a grid of x
and y
values, use this to generate the z
values and draw a contourf
plot:
因此,让我们生成一个x
和y
值的网格,使用它来生成z
值并绘制一个contourf
图:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-1, 1, 101)
y = x
x, y = np.meshgrid(x, y)
z = np.exp(-(x**2 + y**2) / 10)
fig,ax2 = plt.subplots(1)
ax2.contourf(x,y,z)
plt.show()
We get:
我们得到:
回答by Wey Shi
Let me explain in a simple way, since I thought Z should not be 2D as well. contourf()
needs X and Y to build its own space, and the relation Z(X,Y) to build a complete space, rather than merely using several points with 1D X,Y,Z information.
让我用简单的方式解释一下,因为我认为 Z 也不应该是 2D 的。contourf()
需要X和Y来构建自己的空间,需要关系Z(X,Y)来构建一个完整的空间,而不是仅仅使用具有一维X,Y,Z信息的几个点。