我在解析我用其他程序创建的文本文件时遇到问题。文本文件如下所示:
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
...
我想获取与velocity(标题)在同一行中的数字,并将其保存为后续数据的图表标题。除标题之外的每隔一行代表一个射击球的x和y坐标。
因此,如果我有五个不同的标题,我希望在一个图表上看到五个不同的行,其中一个图例显示不同的速度。
到目前为止,这是我的python代码。我接近我想要的,但我错过了第一组数据(速度= 4米/秒),而且我的图例上的颜色与线条颜色不匹配。
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:这是我目前的输出:
Edit_2:我删除了最后几行代码的缩进。颜色问题仍然存在。
Edit_3:我如何将x和y点保存到每个速度的新数组?这可以解决我的问题。
Edit_4:感谢Charles Morris,我能够创建这些图。我现在只需要确定乒乓球对于更高速度的初始向上“电弧”动作是否代表物理学或者是我的代码的限制。
答案 0 :(得分:0)
以下代码使用示例文本文件: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
我们使用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]])
A
我们可以将这些数组切割成表示X和Y值的单独X
和Y
数组。在这里阅读numpy中的数组切片:https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html
在这种情况下,我们采用index = 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])
这里我们希望将X和Y值分别为每个Velocity的值。我们的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,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']
按每个速度的索引绘制值。
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)
代码:
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)
旧答案:
第一次迭代文件中的所有行时,xPoints
和yPoints
数组为空。因此,当您尝试绘制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())来绘制图表,并且可以单独绘制每组点。