使用python读取.dat文件

时间:2016-06-28 17:20:18

标签: python matplotlib plot

我使用 MITgcm 进行了内部波浪和水中移动粒子的模拟。每个时间步的输出都是这样的:

   -9999 0.0000000000000000000  #Time step (0.00000000000000 seconds)
 1308.2021183321899       -14.999709364517091 # Particle 1 (X,Z)
 1308.2020142528656       -24.999521595698688 # Particle 2 (X,Z)
 1308.2018600072618       -34.999345597877536 # .
 1308.2016593336587       -44.999185870669805 # .
 1308.2014165588744       -54.999046508237896 # .
 1308.2011370083103       -64.998931076248894
 1308.2008269116873       -74.998842490305705
 1308.2004933548124       -84.998782925797485
 1308.2001441978532       -94.998753764086956
 1308.1997879652938       -104.99875557384759
 1308.1994336881464       -114.99878812280582
 1308.1990906721119       -124.99885041328211
 1308.1987681881285       -134.99894073461562
 1308.1984750963150       -144.99905672694641
 1308.1982194336249       -154.99919545294702
 1308.1980080134056       -164.99935347476733
 1308.1978461242272       -174.99952693694112
 1308.1977378137256       -184.99971163492469
 1308.2000000000000       -195.00000000000000
 5232.8000000000002       -15.000038916290352
 5232.8000000000002       -25.000064153684303
 5232.8000000000002       -35.000089286157163
 5232.8000000000002       -45.000114270293523
 5232.8000000000002       -55.000139061712051 # Particle 57

其中-9999 #number是时间步长(以秒为单位),左列是X位置,右列是Z位置(以米为单位);并且每一行都是不同的粒子(-9999除外)。因此,对于每个时间步和每个粒子,我们都会有大量的线条。

我想绘制粒子位置的时间演变。我该怎么做?如果这太难了,我会对所有粒子位置的不同时间步长的静态图表感到满意。

非常感谢你。

Edit1:我试图做的是这个,但我以前没有表现出来,因为它远非正确:

 from matplotlib import numpy
 import matplotlib.pyplot as plot
 plot.plot(*np.loadtxt('data.dat',unpack=True), linewidth=2.0)

或者这个:

 plot.plotfile('data.dat', delimiter=' ', cols=(0, 1), names=('col1', 'col2'), marker='o')

1 个答案:

答案 0 :(得分:5)

我会使用numpy.loadtxt来读取输入,但这只是因为后处理也需要numpy。您可以将所有数据读取到内存中,然后找到分隔线,然后重新整形其余数据以适合您的粒子数。以下假设没有任何粒子达到完全 x=-9999,这应该是一个合理的(尽管不是万无一失的)假设。

import numpy as np
filename = 'input.dat'
indata = np.loadtxt(filename, usecols=(0,1)) # make sure the rest is ignored
tlines_bool = indata[:,0]==-9999
Nparticles = np.diff(np.where(tlines_bool)[0][:2])[0] - 1
# TODO: error handling: diff(np.where(tlines_bool)) should be constant
times = indata[tlines_bool,1]
positions = indata[np.logical_not(tlines_bool),:].reshape(-1,Nparticles,2)

以上代码为每个粒子在每个时间步的2d位置生成Nt - 元素数组times和形状position的数组(Nt,Nparticles,2)。通过计算粒子数量,我们可以让numpy确定第一个维度的大小(这就是-1reshape()索引的含义)。

对于绘图,您只需要切入positions数组以提取您确切需要的内容。如果是2d x数据和2d y数据,matplotlib.pyplot.plot()将自动尝试将输入数组的列绘制为彼此的函数。以下是使用实际输入数据进行可视化的示例:

import matplotlib.pyplot as plt
t_indices = slice(None,None,500)  # every 500th time step
particle_indices = slice(None)    # every particle
#particle_indices = slice(None,5)   # first 5 particles
#particle_indices = slice(-5,None)  # last 5 particles

plt.figure()
_ = plt.plot(times[myslice],positions[myslice,particle_indices,0])
plt.xlabel('t')
plt.ylabel('x')

plt.figure()
_ = plt.plot(times[myslice],positions[myslice,particle_indices,1])
plt.xlabel('t')
plt.ylabel('z')

plt.figure()
_ = plt.plot(positions[myslice,particle_indices,0],positions[myslice,particle_indices,1])
plt.xlabel('x')
plt.ylabel('z')
plt.show()

x(t) plot z(t) plot z(x) plot

每条线对应一个粒子。前两个图分别显示xz分量的时间演变,第三个图显示z(x)轨迹。请注意,数据中有很多粒子根本不会移动:

>>> sum([~np.diff(positions[:,k,:],axis=0).any() for k in range(positions.shape[1])])
15

(这计算每个粒子的两个坐标的时间差,一个接一个地计算,并计算两个维度中每个差异为0的粒子数,即粒子不移动。)。这解释了前两个图中的所有水平线;在第三个图中,这些静止粒子根本不会出现(因为它们的轨迹是单个点)。

我故意引入了一些花哨的索引,这样可以更轻松地使用您的数据。正如您所看到的,索引如下所示:times[myslice]positions[myslice,particle_indices,0],其中两个切片都是根据......井,slice定义的。您应该查看文档,但简短的故事是arr[slice(from,to,stride)]等同于arr[from:to:stride],如果任何变量是None,则相应的索引为空:{{1相当于arr[slice(-5,None)],即它会切割数组的最后5个元素。

因此,如果您使用减少数量的轨迹进行绘图(因为57很多),您可以考虑添加图例(只有matplotlib的默认颜色循环可以区分粒子,这才有意义)否则你必须设置手动颜色或更改轴的默认颜色周期。为此,您必须保留从arr[-5:]返回的句柄:

plot

example with legend

相关问题