gpt4 book ai didi

datetime - Matplotlib:光标捕捉到带有日期时间轴的绘图数据

转载 作者:行者123 更新时间:2023-12-04 15:13:17 25 4
gpt4 key购买 nike

我有 3 个数据集的图,这些数据集在 x 轴上有日期时间对象。
我想要一个光标捕捉数据并显示精确的 x 和 y 值。

我已经有一个“对齐光标”,但这仅适用于标量 x 轴。
任何人都可以帮我修改对齐光标,使其也适用于日期时间 x 轴吗?

这是我的数据图:
enter image description here

import numpy as np
import matplotlib.pyplot as plot
import matplotlib.ticker as mticker
import matplotlib.dates as dates
import datetime
import Helpers

fig = plot.figure(1)
DAU = ( 2, 20, 25, 60, 190, 210, 18, 196, 212)
WAU = ( 50, 160, 412, 403, 308, 379, 345, 299, 258)
MAU = (760, 620, 487, 751, 612, 601, 546, 409, 457)

firstDay = datetime.datetime(2012,1,15)

#create an array with len(DAU) entries from given starting day
dayArray = [firstDay + datetime.timedelta(days = i) for i in xrange(len(DAU))]

line1 = plot.plot(dayArray, DAU, 'o-', color = '#336699')
line2 = plot.plot(dayArray, WAU, 'o-', color = '#993333')
line3 = plot.plot(dayArray, MAU, 'o-', color = '#89a54e')

ax = plot.subplot(111)
dateLocator = mticker.MultipleLocator(2)
dateFormatter = dates.DateFormatter('%d.%m.%Y')
ax.xaxis.set_major_locator(dateLocator)
ax.xaxis.set_major_formatter(dateFormatter)
fig.autofmt_xdate(rotation = 90, ha = 'center')

yMax = max(np.max(DAU), np.max(WAU), np.max(MAU))
yLimit = 100 - (yMax % 100) + yMax
plot.yticks(np.arange(0, yLimit + 1, 100))

plot.title('Active users', weight = 'bold')
plot.grid(True, axis = 'both')
plot.subplots_adjust(bottom = 0.2)
plot.subplots_adjust(right = 0.82)

legend = plot.legend((line1[0], line2[0], line3[0]),
('DAU',
'WAU',
'MAU'),
'upper left',
bbox_to_anchor = [1, 1],
shadow = True)

frame = legend.get_frame()
frame.set_facecolor('0.80')
for t in legend.get_texts():
t.set_fontsize('small')

#THIS DOES NOT WORK
cursor = Helpers.SnaptoCursor(ax, dayArray, DAU, 'euro daily')
plot.connect('motion_notify_event', cursor.mouse_move)

plot.show()

这是我的模块“Helper”,其中包含“SnaptoCursor”类:
(我从其他地方获得了基本的 SnaptoCursor 类并对其进行了一些修改)
from __future__ import print_function
import numpy as np
import matplotlib.pyplot as plot

def minsec(sec, unused):
"""
Returns a string of the input seconds formatted as mm'ss''.
"""
minutes = sec // 60
sec = sec - minutes * 60
return '{0:02d}\'{1:02d}\'\''.format(int(minutes), int(sec))

class SnaptoCursor():
"""
A cursor with crosshair snaps to the nearest x point.
For simplicity, I'm assuming x is sorted.
"""
def __init__(self, ax, x, y, formatting, z = None):
"""
ax: plot axis
x: plot spacing
y: plot data
formatting: string flag for desired formatting
z: optional second plot data
"""
self.ax = ax
self.lx = ax.axhline(color = 'k') #the horiz line
self.ly = ax.axvline(color = 'k') #the vert line
self.x = x
self.y = y
self.z = z
# text location in axes coords
self.txt = ax.text(0.6, 0.9, '', transform = ax.transAxes)
self.formatting = formatting

def format(self, x, y):
if self.formatting == 'minsec':
return 'x={0:d}, y='.format(x) + minsec(y, 0)

elif self.formatting == 'daily euro':
return u'day {0:d}: {1:.2f}€'.format(x, y)

def mouse_move(self, event):
if not event.inaxes: return

mouseX, mouseY = event.xdata, event.ydata

#searchsorted: returns an index or indices that suggest where x should be inserted
#so that the order of the list self.x would be preserved
indx = np.searchsorted(self.x, [mouseX])[0]

mouseX = self.x[indx]
#if z wasn't defined
if self.z == None:
mouseY = self.y[indx]
#if z was defined: compare the distance between mouse and the two plots y and z
#and use the nearest one
elif abs(mouseY - self.y[indx]) < abs(mouseY - self.z[indx]):
mouseY = self.y[indx]
else:
mouseY = self.z[indx]

#update the line positions
self.lx.set_ydata(mouseY)
self.ly.set_xdata(mouseX)

self.txt.set_text(self.format(mouseX, mouseY))
plot.draw()

当然这不起作用,因为我使用日期时间数组“dayArray”调用 SnaptoCursor,稍后应该将其与鼠标坐标进行比较。而且这些数据类型没有可比性。

最佳答案

我得到了它!!!

这两行中的问题初始化 SnaptoCursor 类的方法:

self.lx = ax.axhline(color = 'k')  #the horiz line
self.ly = ax.axvline(color = 'k') #the vert line

他们以某种方式弄乱了日期时间 x 轴(例如,序数高达 730,000),因此您只需初始化线条的坐标:
self.lx = ax.axhline(y = min(y), color = 'k')  #the horiz line
self.ly = ax.axvline(x = min(x), color = 'k') #the vert line

然后它工作得很好!

现在我将发布我的完整 SnaptoCursor 类,因为我已经修改了它,因此它可以接受单独的格式字符串,并且它最多可以占用 3 个输入数据图 - 根据您的鼠标位置捕捉到。
def percent(x, unused):
"""
Returns a string of the float number x formatted as %.
"""
return '{0:1.2f}%'.format(x * 100)

def minsec(sec, unused):
"""
Returns a string of the input seconds formatted as mm'ss''.
"""
minutes = sec // 60
sec = sec - minutes * 60
return '{0:02d}\'{1:02d}\'\''.format(int(minutes), int(sec))

class SnaptoCursor():
"""
A cursor with crosshair snaps to the nearest x point.
For simplicity, I'm assuming x is sorted.
"""
def __init__(self, ax, x, y, formatting, y2 = None, y3 = None):
"""
ax: plot axis
x: plot spacing
y: plot data
formatting: string flag for desired formatting
y2: optional second plot data
y3: optional third plot data
"""
self.ax = ax
self.lx = ax.axhline(y = min(y), color = 'k') #the horiz line
self.ly = ax.axvline(x = min(x), color = 'k') #the vert line
self.x = x
self.y = y
self.y2 = y2
self.y3 = y3
# text location in axes coords
self.txt = ax.text(0.6, 0.9, '', transform = ax.transAxes)
self.formatting = formatting

def format(self, x, y):
if self.formatting == 'minsec':
return 'x={0:d}, y='.format(x) + minsec(y, 0)

if self.formatting == 'decimal':
return 'x={0:d}, y={1:d}'.format(x, int(y))

elif self.formatting == 'date decimal':
return 'x={0:%d.%m.%Y}, y={1:d}'.format(x, int(y))

elif self.formatting == 'decimal percent':
return 'x={0:d}, y={1:d}%'.format(x, int(y * 100))

elif self.formatting == 'float':
return 'x={0:d}, y={1:.2f}'.format(x, y)

elif self.formatting == 'float percent':
return 'x={0:d}, y='.format(x) + percent(y, 0)

elif self.formatting == 'daily euro':
return u'day {0:d}: {1:.2f}€'.format(x, y)

def mouse_move(self, event):
if not event.inaxes:
return

mouseX, mouseY = event.xdata, event.ydata
if type(self.x[0]) == datetime.datetime:
mouseX = dates.num2date(int(mouseX)).replace(tzinfo = None)

#searchsorted: returns an index or indices that suggest where mouseX should be inserted
#so that the order of the list self.x would be preserved
indx = np.searchsorted(self.x, [mouseX])[0]

#if indx is out of bounds
if indx >= len(self.x):
indx = len(self.x) - 1

#if y2 wasn't defined
if self.y2 == None:
mouseY = self.y[indx]

#if y2 was defined AND y3 wasn't defined
elif self.y3 == None:
if abs(mouseY - self.y[indx]) < abs(mouseY - self.y2[indx]):
mouseY = self.y[indx]
else:
mouseY = self.y2[indx]

#if y2 AND y3 were defined
elif abs(mouseY - self.y2[indx]) < abs(mouseY - self.y[indx]):
if abs(mouseY - self.y2[indx]) < abs(mouseY - self.y3[indx]):
mouseY = self.y2[indx]
else:
mouseY = self.y3[indx]
#lastly, compare y with y3
elif abs(mouseY - self.y[indx]) < abs(mouseY - self.y3[indx]):
mouseY = self.y[indx]
else:
mouseY = self.y3[indx]

#update the line positions
self.lx.set_ydata(mouseY)
self.ly.set_xdata(mouseX)

self.txt.set_text(self.format(mouseX, mouseY))
plot.draw()

关于datetime - Matplotlib:光标捕捉到带有日期时间轴的绘图数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14338051/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com