python - 在文本文件中记录标题并用后续数据绘制图表

标签 python text plot

我在解析用其他程序创建的文本文件时遇到问题。文本文件看起来像这样:

velocity 4
0 0
0.0800284750334461 0.0702333599787275
0.153911082737118 0.128537103048848
0.222539323234924 0.176328826156044
0.286621942300277 0.21464146333504
0.346732028739683 0.244229944930359
0.403339781262399 0.265638972071027
...
velocity 8
0 0
0.169153136373962 0.124121036173475
0.312016311613761 0.226778846267302
0.435889653693839 0.312371513797743
0.545354054604357 0.383832483710643
0.643486956562741 0.443203331839287
...

我想抓取与速度(标题)同一行的数字,并将其保存为后续数据图的标题。除标题之外的每隔一行代表射击球的 x 和 y 坐标。

因此,如果我有五个不同的标题,我希望在单个图表上看到五个不同的线条,并用图例显示不同的速度。

这是到目前为止我的 python 代码。我已经接近我想要的结果,但我缺少第一组数据(速度 = 4 m/s),并且图例上的颜色与线条颜色不匹配。

import matplotlib.pyplot as plt

xPoints = []
yPoints = []
fig, ax = plt.subplots()

with open('artilleryMotion.txt') as inf:

    for line in inf:
        column = line.split()

        if line.startswith("v"):
            velocity = column[1]
            ax.plot(xPoints, yPoints, label = '%s m/s' % velocity)
        else:
            xPoints.append(column[0])
            yPoints.append(column[1])

ax.legend()
plt.title("Ping-Pong Ball Artillery Motion")
plt.xlabel("distance")
plt.ylabel("height")
plt.ylim(ymin = 0)
ax.set_autoscaley_on(1)

我已经为此苦苦挣扎了一段时间。

Edit_1:这是我目前的输出:

Artillery motion plot

Edit_2:我删除了最后几行代码的缩进。颜色问题仍然出现。

Edit_3:我如何将每个速度的 x 和 y 点保存到新数组中?这可能会解决我的问题。

Edit_4:感谢 Charles Morris,我能够创建这些图。我现在只需要确定乒乓球在较高速度下的初始向上“弧形”运动是否代表物理现象,或者是我的代码的限制。

Artillery Motion Final

最佳答案

编辑:忽略旧信息,并查看下面已解决的解决方案:

以下代码适用于示例文本文件:input.txt

velocity 4
0 0
0.0800284750334461 0.0702333599787275
0.153911082737118 0.128537103048848
0.222539323234924 0.176328826156044
0.286621942300277 0.21464146333504
0.346732028739683 0.244229944930359
0.403339781262399 0.265638972071027
velocity 8
0 0
0.169153136373962 0.124121036173475
0.312016311613761 0.226778846267302
0.435889653693839 0.312371513797743
0.545354054604357 0.383832483710643
0.643486956562741 0.443203331839287

1) 导入我们的文本文件

我们使用 np.genfromtxt() 进行导入。在这种情况下,我们可以指定dtype = float。这会导致数字作为“Float”导入,因此字符串(在本例中为“Velocity”)作为 NaN 导入。

来源: https://docs.scipy.org/doc/numpy/user/basics.io.genfromtxt.html How to use numpy.genfromtxt when first column is string and the remaining columns are numbers?

from matplotlib import pyplot as plt
from itertools import groupby
from numpy import NaN as nan

A = np.genfromtxt('input.txt',dtype=float)


>>>
array([[        nan,  4.        ],
       [ 0.        ,  0.        ],
       [ 0.08002848,  0.07023336],
       [ 0.15391108,  0.1285371 ],
       [ 0.22253932,  0.17632883],
       [ 0.28662194,  0.21464146],
       [ 0.34673203,  0.24422994],
       [ 0.40333978,  0.26563897],
       [        nan,  8.        ],
       [ 0.        ,  0.        ],
       [ 0.16915314,  0.12412104],
       [ 0.31201631,  0.22677885],
       [ 0.43588965,  0.31237151],
       [ 0.54535405,  0.38383248],
       [ 0.64348696,  0.44320333]])

2) 对导入的数组进行切片 A

我们可以将这些数组分割成单独的 XY 数组来表示我们的 X 和 Y 值。在这里阅读 numpy 中的数组切片:https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html

在本例中,我们采用索引 = 0 (X) 的所有值和索引 1 (Y) 的所有值:

# x values
# y values   
X = A[:,0]
Y = A[:,1]    

>>> X = array([        nan,  0.        ,  0.08002848,  0.15391108,  0.22253932,
    0.28662194,  0.34673203,  0.40333978,         nan,  0.        ,
    0.16915314,  0.31201631,  0.43588965,  0.54535405,  0.64348696])

>>> Y = array([ 4.        ,  0.        ,  0.07023336,  0.1285371 ,  0.17632883,
    0.21464146,  0.24422994,  0.26563897,  8.        ,  0.        ,
    0.12412104,  0.22677885,  0.31237151,  0.38383248,  0.44320333])

3) 拆分每个速度的数据。

在这里,我们希望将 X 和 Y 值分成每个速度的值。我们的 X 值由 Nan 分隔,Y 值由 4,8,16... 分隔。

因此:对于 x,我们按 nan 进行分割。 nan 是 genfromtxt() 将 Velocity 解析为 float 并返回 nan 的结果。

来源: numpy: split 1D array of chunks separated by nans into a list of the chunks Split array at value in numpy

对于 y,我们将数组按照数字 4,8,16 等进行拆分。为此,我们排除了除以 4 后得到的值余数为零(使用 % Python 运算符)。

来源: Split array at value in numpy How to check if a float value is a whole number Split NumPy array according to values in the array (a condition) Find the division remainder of a number How do I use Python's itertools.groupby()?

XX = [list(v) for k,v in groupby(X,np.isfinite) if k]
YY = [list(v) for k,v in groupby(Y,lambda x: x % 4 != 0 or x == 0) if k]


>>> 
XX = [[0.0,
0.080028475033446095,
0.15391108273711801,
0.22253932323492401,
0.28662194230027699
0.34673202873968301,
0.403339781262399],
[0.0,
0.16915313637396201,
0.31201631161376098,
0.43588965369383897,
0.54535405460435704,
0.64348695656274102]]

>>> YY =
[[0.0,
0.070233359978727497,
0.12853710304884799,
0.17632882615604401,
0.21464146333504,
0.24422994493035899,
0.26563897207102699],
[0.0,
0.124121036173475,
0.22677884626730199,
0.31237151379774297,
0.38383248371064299,
0.44320333183928701]]

4)提取标签

使用与上面类似的技术,我们接受值=我们的速度4,8,16等。在这种情况下,我们只接受那些除以4时余数为0的数字、 和 都不为 0。然后我们将其转换为字符串并添加 m/s

Ylabels = [list(v) for k,v in groupby(Y,lambda x: x % 4 == 0 and x != 0) if k]
Velocities = [str(i[0]) + ' m/s' for i in Ylabels]

>>> Y labels = [[4.0], [8.0]]
>>> Velocities = ['4.0 m/s', '8.0 m/s']

5) 绘图

按索引绘制每个速度的值。

fig, ax = plt.subplots()
for i in range(0,len(XX)):
    plt.plot(XX[i],YY[i],label = Velocities[i])
ax.legend()
plt.title("Ping-Pong Ball Artillery Motion")
plt.xlabel("distance")
plt.ylabel("height")
plt.ylim(ymin = 0)
ax.set_autoscaley_on(1) 

Trajectories

代码总计:

import numpy as np
from matplotlib import pyplot as plt
from itertools import groupby
from numpy import NaN as nan

A = np.genfromtxt('input.txt',dtype=float)

X = A[:,0]
Y = A[:,1]    

Ylabels = [list(v) for k,v in groupby(Y,lambda x: x % 4 == 0 and x != 0) if k]
Velocities = [str(i[0]) + ' m/s' for i in Ylabels]

XX = [list(v) for k,v in groupby(X,np.isfinite) if k]
YY = [list(v) for k,v in groupby(Y,lambda x: x % 4 != 0 or x == 0) if k]

fig, ax = plt.subplots()
for i in range(0,len(XX)):
    plt.plot(XX[i],YY[i],label = Velocities[i])
ax.legend()
plt.title("Ping-Pong Ball Artillery Motion")
plt.xlabel("distance")
plt.ylabel("height")
plt.ylim(ymin = 0)
ax.set_autoscaley_on(1)  

Trajectories

旧答案:

第一次迭代文件中的所有行时,xPointsyPoints 数组为空。因此,当您尝试绘制 v = 4 的值时,您正在绘制一个空数组 - 因此您丢失了一行。

您需要先填充数组,然后绘制它们。目前,您正在标记为 v = 8 的行中绘制 v = 4 的值,对于 v = 8,绘制 v = 16 的值,依此类推。

忽略: 对于数组总体,请尝试以下操作:

xPoints = []
yPoints = []
with open('artilleryMotion.txt') as inf:
    # initialize placeholder velocity variable
    velocity = 0
    for line in inf:
        column = line.split()

        if line.startswith("v"):
            velocity = column[1]

        else:
            xPoints.append({velocity: column[0]})
            yPoints.append({velocity: column[1]})

在上面,您将数据保存为字典列表(x和y点分开),其中键等于最近读取的速度,值是x和y坐标.

当读入新的速度时,占位符变量 velocity 会更新,因此可以根据 x 和 y 值所拥有的键来识别它们。

这允许您通过字典键分离绘图(查找 D.iteritems() D.items() ),并且您可以单独绘制每组点。

关于python - 在文本文件中记录标题并用后续数据绘制图表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42044498/

相关文章:

python - 从字符串中提取带有空格的整数

Python:在文本文件中写入 pd.Series 的所有组合

Android 将文本绘制到中心的矩形中并根据需要裁剪

python - matplotlib中的移动轴指数

python - 以月为单位绘制 x 轴

python - 为什么 python 使用 matplotlib 绘图时不断崩溃?

python - 在 Python 中操作子列表

python - 交换字符串中的字符

python - 选择从 .txt 到 .csv 的数据列

python - 解析引号和转义字符 CSV 文件