[英]Pyplot - show x-axis labels according to y-axis value
I have 1min 20s long video record of 23.813 FPS.我有 23.813 FPS 的 1 分钟 20 秒长视频记录。 More precisely, I have 1923 frames in which I've been scanning desired features.更准确地说,我有 1923 帧,其中我一直在扫描所需的特征。 I've detected some specific behavior via neural network and using chosen metric I calculated a value for each frame.我通过神经网络检测到了一些特定的行为,并使用选定的指标为每一帧计算了一个值。
So, now, I have XY values to plot a graph:所以,现在,我有 XY 值来绘制图形:
X: time (each step of size 0,041993869s)
Y: a value measured by neural network
In the default state, the plot looks like this:在默认状态下,绘图如下所示:
So, I've tried to limit the number of bins in the faith that the bins will be spread over all my values.所以,我试图限制垃圾箱的数量,相信垃圾箱将分布在我的所有价值观上。 But they are not.但他们不是。 As you can see, only first fifteen x-values are rendered:如您所见,仅呈现前十五个 x 值:
pyplot.locator_params(axis='x', nbins=15)
But neither one is desired state.但两者都不是理想状态。 The desired state should render the labels of such x-bins with y-value higher than eg 1.2
.所需的状态应该呈现这样的 x-bins 的标签,其 y 值高于例如1.2
。 So, it should look like this:所以,它应该是这样的:
Is possible to achieve such result?有可能达到这样的结果吗?
Code:代码:
# draw plot
from pandas import read_csv
from matplotlib import pyplot
test_video_fps = 23.813
df = read_csv('/path/to/csv/file/file.csv', header=None)
df.columns = ['anomaly']
df['time'] = [round((i + 1) / test_video_fps, 2) for i in range(df.shape[0])]
axes = df.plot.bar(x='time', y='anomaly', rot='0')
# pyplot.locator_params(axis='x', nbins=15)
# axes.get_xaxis().set_visible(False)
fig = pyplot.gcf()
fig.set_size_inches(16, 10)
fig.savefig('/path/to/output/plot.png', dpi=100)
# pyplot.show()
Example:例子:
Simple example with a subset of original data.带有原始数据子集的简单示例。
0.379799
0.383786
0.345488
0.433286
0.469474
0.431993
0.474253
0.418843
0.491070
0.447778
0.384890
0.410994
0.898229
1.872756
2.907009
3.691382
4.685749
4.599612
3.738768
8.043357
7.660785
2.311198
1.956096
2.877326
3.467511
3.896339
4.250552
6.485533
7.452986
7.103761
2.684189
2.516134
1.512196
1.435303
0.852047
0.842551
0.957888
0.983085
0.990608
1.046679
1.082040
1.119655
0.962391
1.263255
1.371034
1.652812
2.160451
2.646674
1.460051
1.163745
0.938030
0.862976
0.734119
0.567076
0.417270
Desired plot:想要的剧情:
Your question has become a two-part problem, but it is interesting enough that I will answer both.你的问题已经变成了一个由两部分组成的问题,但很有趣,我会同时回答这两部分。
I will answer this in Matplotlib object oriented notation with numpy data rather than pandas.我将在 Matplotlib 面向对象的符号中使用 numpy 数据而不是 Pandas 来回答这个问题。 This will make things easier to explain, and can be easily generalized to pandas.这将使事情更容易解释,并且可以很容易地推广到熊猫。
I will assume that you have the following two data arrays:我假设您有以下两个数据数组:
dt = 0.041993869
x = np.arange(0.0, 15 * dt, dt)
y = np.array([1., 1.1, 1.3, 7.6, 2.4, 0.8, 0.7, 0.8, 1.0, 1.5, 10.0, 4.5, 3.2, 0.9, 0.7])
Part 1: Identifying the locations where you want labels第 1 部分:确定要放置标签的位置
The data can be masked to get the locations of the peaks:可以屏蔽数据以获得峰值的位置:
mask = y > 1.2
Consecutive peaks can be easily eliminated by computing the diff.通过计算差异可以轻松消除连续的峰值。 A diff of a boolean mask will be True
at the locations where the mask changes sense.在掩码改变意义的位置,布尔掩码的差异将为True
。 You will then have to take every other element to get the locations where it goes from False
to True
.然后,您将不得不采用其他所有元素来获取它从False
到True
。 The following code will capture all the corner cases where you start with a peak or end in the middle of a peak:以下代码将捕获从峰值开始或在峰值中间结束的所有极端情况:
d = np.flatnonzero(np.diff(mask))
if mask[d[0]]: # First diff is end of peak: True to False
d = np.concatenate(([0], d[1::2] + 1))
else:
d = d[::2] + 1
d
is now an array indices into x
and y
that represent the first element of each run of peaks. d
现在是x
和y
的数组索引,表示每次峰值运行的第一个元素。 You can get the last element by swapping the indices [1::2]
and [::2]
in the if-else
statement, and removing the + 1
in both cases.您可以通过交换if-else
语句中的索引[1::2]
和[::2]
来获取最后一个元素,并在两种情况下都删除+ 1
。
The locations of the labels are now simply x[d]
.标签的位置现在只是x[d]
。
Part 2: Locating and formatting the labels第 2 部分:定位和格式化标签
For this part, you will need to access Matplotlib's object oriented API via the Axes
object you are plotting on.对于这部分,您需要通过您正在绘图的Axes
对象访问 Matplotlib 的面向对象的 API。 You already have this in the pandas form, making the transfer easy.您已经在 Pandas 形式中拥有了它,从而使传输变得容易。 Here is a sample in raw Matplotlib:这是原始 Matplotlib 中的示例:
fig, axes = plt.subplots()
axes.plot(x, y)
Now use the ticker API to easily set the locations and labels.现在使用股票代码 API轻松设置位置和标签。 You actually set the locations directly (not with a Locator
) since you have a very fixed list of ticks:您实际上直接设置了位置(而不是使用Locator
),因为您有一个非常固定的刻度列表:
axes.set_xticks(x[d])
axes.xaxis.set_major_formatter(ticker.StrMethodFormatter('{x:0.01g}s'))
For the sample data show here, you get对于此处显示的示例数据,您将获得
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.