在强度图中绘制不等大小或 x 向量的数据
Plotting data of unequal size or x-vector in an intensity plot
假设您有以下数据:
x1_Length = 100
x1 = np.linspace(10,100,num=x1_Length)
y1 = np.linspace(0, 1.3, num=x1_Length)
x2_Length = 200
x2 = np.linspace(50, 200, num=x2_Length)
y2 = np.exp(np.linspace(0, 1, num=x2_Length))
如果你想绘制这个,那就很简单了:
fig, ax = plt.subplots()
ax.plot(x1,y1, ".g")
ax.plot(x2,y2, "--r")
这给出了预期的结果,即使绘制的阵列具有不同的长度并且不共享 x 数据。
现在,假设您想在强度图中绘制相同的数据。这会导致一些问题:
据我了解,强度图(例如 imshow
)绘制二维阵列,因此没有 x 轴刻度或 y 轴刻度的直接概念。数据根据其在数组中的索引显示。在这里,这将是一个问题,因为两个数组的第一个元素不对应于相同的 x 值。
所有 rows/columns 需要在二维数组中具有相同的长度。这是两个问题中的次要问题,因为我总能找出最长的数据集并用例如 NaN 填充所有较短的数据集,如下所示:
dataset = [x1_data, x2_data]
max_Length = np.max([array[0,:].shape[0] for array in dataset ])
data_array = np.nan * np.ones((2*len(dataset), max_Length))
for i, spectrum_array2D in enumerate(dataset):
length = spectrum_array2D[0,:].shape[0]
firstRowOfInsertion = 2*i
data_array[[firstRowOfInsertion, firstRowOfInsertion+1], :length] = spectrum_array2D
我没有看到任何技术限制,为什么不能像 plt.plot()
那样将多个不同数据阵列绘制成强度图。理想情况下,我需要的是告诉它可以预期的强度图,在这个例子中,2 个水平数据切片,然后提供 x 数据(绘制在 x 轴上),y 数据(绘制在colorbar) 对于该图应该进入的切片的每个索引。您知道实现此目的的方法或任何能够做到这一点的软件包吗?
编辑:最终,我想要一个看起来像这样的图,它是从下面的@wtw 建议中采纳的(这个图中的数据是随机的,我需要它是我的 y1 和 y2 数组):
据我了解,您知道,这两个数据集不能相互交叉。这是第一个重要条件。如果 to 值将占据 meshgrid 中的相同像素,将选择哪一个?
但即使数据不相交,当两个轴具有不同的采样 rates/distances 时,也可能会出现问题。在您可以将它们都绘制在同一图像甚至网格中之前,您必须 resample/interpolate 两个阵列都位于相同的网格上。这很快就变得非常棘手并且容易出错。
如果我要尝试这个,我会首先创建单独的颜色贴图,使用相同的颜色代码,但两个独立的网格。下一步是将一个图形放在另一个图形之上并移动它以使轴对齐;基本上是一个插图。我想在 matplotlib 中有一些最佳实践。
matplotlib 的一个选项是 pcolormesh
:https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.pcolormesh.html
它接受坐标和值。在这种情况下,您有一个二维网格,因此您需要一个二维数组作为 x 坐标,一个二维数组作为 y 坐标,一个二维数组作为值。
您可以绘制不同的数据集,但如果它们的坐标重叠,您将不得不考虑如何显示这些数据集。一种选择是使第二个数据集稍微透明,以便您可以透过它看到第一个数据集。
import numpy as np
import matplotlib.pyplot as plt
# Create the first set of coordinates
X1, Y1 = np.meshgrid(np.arange(0, 10, 1), np.arange(0, 5, 0.5))
C1 = np.random.uniform(size=np.shape(X1))
# Second set of coordinates with smaller cells, slightly overlapping the first
X2, Y2 = np.meshgrid(np.arange(8, 12, 0.1), np.arange(4, 6, 0.1))
C2 = np.random.uniform(size=np.shape(X2))
# Plotting:
fig, ax = plt.subplots(1)
ax.pcolormesh(X1, Y1, C1)
ax.pcolormesh(X2, Y2, C2, alpha=0.25)
工作 wtw 的第一个答案我想出了一个方法,有点 hacky...
使用他们的方法我无法绘制我的一维数组,所以我通过将 2 个相同的数组堆叠在一起使它们成为二维的。然后,我指定应绘制的 y 轴值。这是我的最终代码:
import numpy as np
import matplotlib.pyplot as plt
x1_Length = 100
x1 = np.linspace(10,100,num=x1_Length)
z1 = np.linspace(0, 1.3, num=x1_Length)
x1_data = np.stack([x1,z1])
x2_Length = 200
x2 = np.linspace(50, 200, num=x2_Length)
z2 = np.exp(np.linspace(0, 4, num=x2_Length))
x2_data = np.stack([x2,z2])
x3_Length = 30
x3 = np.linspace(50, 150, num=x3_Length)
z3 = np.sin(np.linspace(0, 4, num=x3_Length))
x3_data = np.stack([x3,z3])
y_data = [-1, 5, 12]
stepsize = np.min(np.abs(np.diff(y_data)))
dataset = [x1_data, x2_data, x3_data]
fig, ax = plt.subplots(1)
for i, spectrum_array2D in enumerate(dataset):
X, Y = np.meshgrid(spectrum_array2D[0,:], [y_data[i]-stepsize/4, y_data[i]+stepsize/4]); print(f"X has shape {X.shape}, Y has shape {Y.shape}")
Z = np.vstack( [spectrum_array2D[1,:], spectrum_array2D[1,:]] ); print(f"Z has shape {Z.shape}")
ax.pcolormesh(X, Y, Z)
ax.set_yticks(y_data)
ax.set_xlabel("x")
ax.set_ylabel("y")
产生下图:
经过讨论,我认为需要的是一条用 x
点和颜色值绘制的线,每次可能具有不同的 y
值。
对这里的答案稍作修改(只是为了传递绘图变量):
import matplotlib.cm as cm
import matplotlib.pyplot as plt
import numpy as np
def plot_colourline(x,y,c, **xargs):
c = cm.viridis((c-np.min(c))/(np.max(c)-np.min(c)))
ax = plt.gca()
for i in np.arange(len(x)-1):
ax.plot([x[i],x[i+1]], [y[i],y[i+1]], c=c[i], **xargs)
return
# First data set
x1 = np.arange(0, 10, 1)
y1 = np.zeros(len(x1)) # use 0 as the y value for all points
c1 = np.random.uniform(size=len(x1))
# Second dataset, different number of points, x values and y value
x2 = np.arange(8, 12, 0.1)
y2 = np.ones(len(x2)) # Use 1 as the y value for all points
c2 = np.random.uniform(size=len(x2))
fig, ax = plt.subplots(1)
plot_colourline(x1, y1, c1, linewidth=5)
plot_colourline(x2, y2, c2, linewidth=5, alpha=0.5)
假设您有以下数据:
x1_Length = 100
x1 = np.linspace(10,100,num=x1_Length)
y1 = np.linspace(0, 1.3, num=x1_Length)
x2_Length = 200
x2 = np.linspace(50, 200, num=x2_Length)
y2 = np.exp(np.linspace(0, 1, num=x2_Length))
如果你想绘制这个,那就很简单了:
fig, ax = plt.subplots()
ax.plot(x1,y1, ".g")
ax.plot(x2,y2, "--r")
这给出了预期的结果,即使绘制的阵列具有不同的长度并且不共享 x 数据。
现在,假设您想在强度图中绘制相同的数据。这会导致一些问题:
据我了解,强度图(例如
imshow
)绘制二维阵列,因此没有 x 轴刻度或 y 轴刻度的直接概念。数据根据其在数组中的索引显示。在这里,这将是一个问题,因为两个数组的第一个元素不对应于相同的 x 值。所有 rows/columns 需要在二维数组中具有相同的长度。这是两个问题中的次要问题,因为我总能找出最长的数据集并用例如 NaN 填充所有较短的数据集,如下所示:
dataset = [x1_data, x2_data] max_Length = np.max([array[0,:].shape[0] for array in dataset ]) data_array = np.nan * np.ones((2*len(dataset), max_Length)) for i, spectrum_array2D in enumerate(dataset): length = spectrum_array2D[0,:].shape[0] firstRowOfInsertion = 2*i data_array[[firstRowOfInsertion, firstRowOfInsertion+1], :length] = spectrum_array2D
我没有看到任何技术限制,为什么不能像 plt.plot()
那样将多个不同数据阵列绘制成强度图。理想情况下,我需要的是告诉它可以预期的强度图,在这个例子中,2 个水平数据切片,然后提供 x 数据(绘制在 x 轴上),y 数据(绘制在colorbar) 对于该图应该进入的切片的每个索引。您知道实现此目的的方法或任何能够做到这一点的软件包吗?
编辑:最终,我想要一个看起来像这样的图,它是从下面的@wtw 建议中采纳的(这个图中的数据是随机的,我需要它是我的 y1 和 y2 数组):
据我了解,您知道,这两个数据集不能相互交叉。这是第一个重要条件。如果 to 值将占据 meshgrid 中的相同像素,将选择哪一个? 但即使数据不相交,当两个轴具有不同的采样 rates/distances 时,也可能会出现问题。在您可以将它们都绘制在同一图像甚至网格中之前,您必须 resample/interpolate 两个阵列都位于相同的网格上。这很快就变得非常棘手并且容易出错。 如果我要尝试这个,我会首先创建单独的颜色贴图,使用相同的颜色代码,但两个独立的网格。下一步是将一个图形放在另一个图形之上并移动它以使轴对齐;基本上是一个插图。我想在 matplotlib 中有一些最佳实践。
matplotlib 的一个选项是 pcolormesh
:https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.pcolormesh.html
它接受坐标和值。在这种情况下,您有一个二维网格,因此您需要一个二维数组作为 x 坐标,一个二维数组作为 y 坐标,一个二维数组作为值。
您可以绘制不同的数据集,但如果它们的坐标重叠,您将不得不考虑如何显示这些数据集。一种选择是使第二个数据集稍微透明,以便您可以透过它看到第一个数据集。
import numpy as np
import matplotlib.pyplot as plt
# Create the first set of coordinates
X1, Y1 = np.meshgrid(np.arange(0, 10, 1), np.arange(0, 5, 0.5))
C1 = np.random.uniform(size=np.shape(X1))
# Second set of coordinates with smaller cells, slightly overlapping the first
X2, Y2 = np.meshgrid(np.arange(8, 12, 0.1), np.arange(4, 6, 0.1))
C2 = np.random.uniform(size=np.shape(X2))
# Plotting:
fig, ax = plt.subplots(1)
ax.pcolormesh(X1, Y1, C1)
ax.pcolormesh(X2, Y2, C2, alpha=0.25)
工作 wtw 的第一个答案我想出了一个方法,有点 hacky... 使用他们的方法我无法绘制我的一维数组,所以我通过将 2 个相同的数组堆叠在一起使它们成为二维的。然后,我指定应绘制的 y 轴值。这是我的最终代码:
import numpy as np
import matplotlib.pyplot as plt
x1_Length = 100
x1 = np.linspace(10,100,num=x1_Length)
z1 = np.linspace(0, 1.3, num=x1_Length)
x1_data = np.stack([x1,z1])
x2_Length = 200
x2 = np.linspace(50, 200, num=x2_Length)
z2 = np.exp(np.linspace(0, 4, num=x2_Length))
x2_data = np.stack([x2,z2])
x3_Length = 30
x3 = np.linspace(50, 150, num=x3_Length)
z3 = np.sin(np.linspace(0, 4, num=x3_Length))
x3_data = np.stack([x3,z3])
y_data = [-1, 5, 12]
stepsize = np.min(np.abs(np.diff(y_data)))
dataset = [x1_data, x2_data, x3_data]
fig, ax = plt.subplots(1)
for i, spectrum_array2D in enumerate(dataset):
X, Y = np.meshgrid(spectrum_array2D[0,:], [y_data[i]-stepsize/4, y_data[i]+stepsize/4]); print(f"X has shape {X.shape}, Y has shape {Y.shape}")
Z = np.vstack( [spectrum_array2D[1,:], spectrum_array2D[1,:]] ); print(f"Z has shape {Z.shape}")
ax.pcolormesh(X, Y, Z)
ax.set_yticks(y_data)
ax.set_xlabel("x")
ax.set_ylabel("y")
产生下图:
经过讨论,我认为需要的是一条用 x
点和颜色值绘制的线,每次可能具有不同的 y
值。
对这里的答案稍作修改(只是为了传递绘图变量):
import matplotlib.cm as cm
import matplotlib.pyplot as plt
import numpy as np
def plot_colourline(x,y,c, **xargs):
c = cm.viridis((c-np.min(c))/(np.max(c)-np.min(c)))
ax = plt.gca()
for i in np.arange(len(x)-1):
ax.plot([x[i],x[i+1]], [y[i],y[i+1]], c=c[i], **xargs)
return
# First data set
x1 = np.arange(0, 10, 1)
y1 = np.zeros(len(x1)) # use 0 as the y value for all points
c1 = np.random.uniform(size=len(x1))
# Second dataset, different number of points, x values and y value
x2 = np.arange(8, 12, 0.1)
y2 = np.ones(len(x2)) # Use 1 as the y value for all points
c2 = np.random.uniform(size=len(x2))
fig, ax = plt.subplots(1)
plot_colourline(x1, y1, c1, linewidth=5)
plot_colourline(x2, y2, c2, linewidth=5, alpha=0.5)