Python matplotlib stepped axis label

huangapple go评论78阅读模式
英文:

Python matplotlib stepped axis label

问题

我正在使用Matplotlib在Tkinter应用程序中生成图像。 数据提供了针对时间存储的值(真实应用程序数据是每秒开放的会话以显示负载)。 我试图在x轴上显示时间,y轴上显示会话。

然而,我在格式化x轴上的标签方面遇到了一些困难。 如果您看到图像Test 1,如果我将整数分配给x轴,那么尽管数据是0-19,Matplotlib会自动显示0,5,10,15,以保持轴的整洁。

如果我只分配标签给它,那么会显示前4个标签,而不是每5个标签显示一个。 如果我重置刻度和标签,那么会得到每个刻度和每个标签(虽然在这里刚好合适,但在我的真实应用程序中数据太多了)。

我的解决方案是手动计算每个第N个刻度和第N个标签,然后分配这些值,这个方法已经起作用,但似乎应该有一些内置功能来处理这种类型的数据,就像对整数一样。

我的代码是:

import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg)
import datetime
import tkinter

def main():

    x_labels = []
    x = []
    y = []

    dt_now = datetime.datetime.now()
    entries = 20
    for i in range(0, entries):
        newtime=(dt_now + datetime.timedelta(seconds=i)).strftime("%H:%M:%S")
        x.append(i)
        y.append(i/2)
        x_labels.append(newtime)

    root = tkinter.Tk()
    fig = plt.figure(figsize=(8,8))
    canvas = FigureCanvasTkAgg(fig, master=root) 
    canvas.draw()

    ax1 = fig.add_subplot(221)
    ax1.plot(x,y)
    ax1.set_title('Test 1 - Original Values')
    ax1.set_xlabel('Entry ID')
    ax1.set_ylabel('Sessions')

    ax2 = fig.add_subplot(222)
    ax2.plot(x,y)
    ax2.set_title('Test 2 - Labels 0,1,2,3\nExpecting labels 0,5,10,15')
    ax2.set_xlabel('Entry Time')
    ax2.set_ylabel('Sessions')
    ax2.set_xticklabels(x_labels, rotation=90, ha='center')

    ax3 = fig.add_subplot(223)
    ax3.plot(x_labels,y)
    ax3.set_title('Test 3 - Every label')
    ax3.set_xlabel('Entry Time')
    ax3.set_ylabel('Sessions')
    ax3.set_xticklabels(x_labels, rotation = 90)

    major_ticks = []
    major_tick_labels = []
    for i in range(0,entries,int(entries/5)):
        major_ticks.append(x[i])
        major_tick_labels.append(x_labels[i])

    ax4 = fig.add_subplot(224)
    ax4.plot(x,y)
    ax4.set_title('Test 4 - What I\'m expecting\nbut hard coded')
    ax4.set_xlabel('Entry Time')
    ax4.set_ylabel('Sessions')
    ax4.set_xticks(major_ticks)
    ax4.set_xticklabels(major_tick_labels, rotation=90, ha='center')

    plt.subplots_adjust(hspace = 0.75, bottom = 0.2)
    canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=1)

    tkinter.mainloop()

if __name__ == '__main__':
    main()

生成以下结果:

Python matplotlib stepped axis label

这是实现要求的唯一方法吗,还是有其他我可能遗漏的方法? 我已阅读了文档,但在那里找不到任何相关的内容(除了确保我同时设置刻度和标签)。 我希望这个过程尽可能自动化,因为时间范围将由用户驱动,所以最好有4个刻度、5个刻度、10个刻度等。 Matplotlib似乎很好地处理了整数范围的要求,我只想关联相同的标签。

英文:

I am using matplotlib to generate an image in a tkinter application. The data provides a value stored against a time (real app data is open sessions by second to show load). I am trying to display this with time across the x axis, and sessions up the y axis.

I am having some difficulty however with formatting the labels on the x axis. If you see image Test 1, if i assign integers to the x axis, then although data is 0-19, matplotlib automatically displays 0,5,10,15, to keep the axis tidy.

If I just assign labels to this, then the first 4 labels are shown rather than every 5th label. If I reset the tciks and labels, I get every tick and every label (which just about fits here but in my real app theres too much data).

My solution has been to manually calculate every Nth tick and Nth label and assign those values which has worked but seems like there should be some built in functionality that handles this sort of data, the same way as it does for integers.

My code is:

import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg)
import datetime
import tkinter
def main():
x_labels = []
x = []
y = []
dt_now = datetime.datetime.now()
entries = 20
for i in range(0, entries):
newtime=(dt_now + datetime.timedelta(seconds=i)).strftime("%H:%M:%S")
x.append(i)
y.append(i/2)
x_labels.append(newtime)
root = tkinter.Tk()
fig = plt.figure(figsize=(8,8))
canvas = FigureCanvasTkAgg(fig, master=root) 
canvas.draw()
ax1 = fig.add_subplot(221)
ax1.plot(x,y)
ax1.set_title('Test 1 - Original Values')
ax1.set_xlabel('Entry ID')
ax1.set_ylabel('Sessions')
ax2 = fig.add_subplot(222)
ax2.plot(x,y)
ax2.set_title('Test 2 - Labels 0,1,2,3\nExpecting labels 0,5,10,15')
ax2.set_xlabel('Entry Time')
ax2.set_ylabel('Sessions')
ax2.set_xticklabels(x_labels, rotation=90, ha='center')
ax3 = fig.add_subplot(223)
ax3.plot(x_labels,y)
ax3.set_title('Test 3 - Every label')
ax3.set_xlabel('Entry Time')
ax3.set_ylabel('Sessions')
ax3.set_xticklabels(x_labels, rotation = 90)
major_ticks = []
major_tick_labels = []
for i in range(0,entries,int(entries/5)):
major_ticks.append(x[i])
major_tick_labels.append(x_labels[i])
ax4 = fig.add_subplot(224)
ax4.plot(x,y)
ax4.set_title('Test 4 - What I''m expecting\nbut hard coded')
ax4.set_xlabel('Entry Time')
ax4.set_ylabel('Sessions')
ax4.set_xticks(major_ticks)
ax4.set_xticklabels(major_tick_labels, rotation=90, ha='center')
plt.subplots_adjust(hspace = 0.75, bottom = 0.2)
canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=1)
tkinter.mainloop()
if __name__ == '__main__':
main()

Which generates the following:
Python matplotlib stepped axis label

Is this the only way to achieve the requirement or is there something available that I am missing. I have read the documentation, but couldn't see anything relevant in there (past making sure I set ticks and labels together). I'd like the process to be as automated as possible, as the time frame will be user driven, so may be best with 4 ticks, 5 ticks 10 ticks, etc. Matplotlib seems to handle this requirement well the a defined range of integers, I just want to associate the same labels.

答案1

得分: 1

你可以使用matplotlib.dates。请注意,为了使其工作,你需要保持x_labels的格式为日期时间(我删除了你对.strftime的调用)。

import datetime
import matplotlib.pyplot as plt
import matplotlib.dates as mdates

x_labels = []
x = []
y = []

dt_now = datetime.datetime.now()
entries = 20
for i in range(0, entries):
    newtime = (dt_now + datetime.timedelta(seconds=i))
    x.append(i)
    y.append(i/2)
    x_labels.append(newtime)

fig = plt.figure(figsize=(8,8))

ax4 = fig.add_subplot(224)
ax4.plot(x_labels, y)
ax4.set_title('一个可能的解决方案')
ax4.set_xlabel('进入时间')
ax4.set_ylabel('会话')
ax4.xaxis.set_major_locator(mdates.SecondLocator(interval=4))
ax4.tick_params(axis="x", rotation=90)

这将给你:

Python matplotlib stepped axis label

英文:

You could use matplotlib.dates. Note that you need to keep the x_labels formatted as datetimes for this to work (I removed your call to .strftime)

import datetime
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
x_labels = []
x = []
y = []
dt_now = datetime.datetime.now()
entries = 20
for i in range(0, entries):
newtime=(dt_now + datetime.timedelta(seconds=i))
x.append(i)
y.append(i/2)
x_labels.append(newtime)
fig = plt.figure(figsize=(8,8))
ax4 = fig.add_subplot(224)
ax4.plot(x_labels,y)
ax4.set_title('One possible solution')
ax4.set_xlabel('Entry Time')
ax4.set_ylabel('Sessions')
ax4.xaxis.set_major_locator(mdates.SecondLocator(interval=4))
ax4.tick_params(axis="x", rotation=90)

This will give you

Python matplotlib stepped axis label

huangapple
  • 本文由 发表于 2020年1月3日 17:01:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/59575662.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定