python - x 轴上时间戳的格式

标签 python matplotlib formatting unix-timestamp

我正在尝试格式化我的天气数据图中的 x 轴。我对 y 轴很满意,但我为使 x 轴成为一种体面的、人类可读的格式所做的所有尝试到目前为止都没有奏效。因此,经过几个小时的反复试验,我希望得到您的帮助。

ugly x-axis

我要实现的目标

最后,我希望每 30 分钟有一个刻度线,每小时有一条垂直的虚线网格,时间写为 HH:MM,另外还有每晚 00:00 写的日期。像这样的东西(注意,前面有糟糕的 ASCII 艺术!):

     :         :         :
     :         :         :
     :         :         :
     :         :         :
     :         :         :
|====|====|====|====|====|====|====
   23:00     00:00     01:00
            09JAN18

所有时间均为 UTC,这将是终极豪华版。但我的问题开始得更早。

我的代码片段

一开始,我试图将它变成一种可读的格式。我想到了

locator = mdates.AutoDateLocator()
plt.gca().xaxis.set_major_locator(locator)
plt.gca().xaxis.set_major_formatter(mdates.AutoDateFormatter(locator))

并希望我能摆脱 exp

结果

输出不是我所希望的:

pi@raspi3b:~/wx-logging $ python plot.py
[( 15.94,  57.86,  992.65,  1019.99, 1515460740)
 ( 15.96,  57.8 ,  992.65,  1019.99, 1515460745)
 ( 15.99,  57.79,  992.68,  1020.02, 1515460750) ...,
 ( 13.25,  55.7 ,  990.16,  1017.43, 1515496060)
 ( 13.31,  56.  ,  990.14,  1017.41, 1515496065)
 ( 13.34,  56.32,  990.13,  1017.4 , 1515496070)]
Traceback (most recent call last):
  File "plot.py", line 123, in <module>
    plt.savefig("plot.png", dpi=150)
  File "/usr/lib/python2.7/dist-packages/matplotlib/pyplot.py", line 697, in savefig
    res = fig.savefig(*args, **kwargs)
  File "/usr/lib/python2.7/dist-packages/matplotlib/figure.py", line 1572, in savefig
    self.canvas.print_figure(*args, **kwargs)
  File "/usr/lib/python2.7/dist-packages/matplotlib/backend_bases.py", line 2244, in print_figure
    **kwargs)
  File "/usr/lib/python2.7/dist-packages/matplotlib/backends/backend_agg.py", line 545, in print_png
    FigureCanvasAgg.draw(self)
  File "/usr/lib/python2.7/dist-packages/matplotlib/backends/backend_agg.py", line 464, in draw
    self.figure.draw(self.renderer)
  File "/usr/lib/python2.7/dist-packages/matplotlib/artist.py", line 63, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "/usr/lib/python2.7/dist-packages/matplotlib/figure.py", line 1143, in draw
    renderer, self, dsu, self.suppressComposite)
  File "/usr/lib/python2.7/dist-packages/matplotlib/image.py", line 139, in _draw_list_compositing_images
    a.draw(renderer)
  File "/usr/lib/python2.7/dist-packages/mpl_toolkits/axes_grid1/parasite_axes.py", line 295, in draw
    self._get_base_axes_attr("draw")(self, renderer)
  File "/usr/lib/python2.7/dist-packages/mpl_toolkits/axisartist/axislines.py", line 778, in draw
    super(Axes, self).draw(renderer, inframe)
  File "/usr/lib/python2.7/dist-packages/matplotlib/artist.py", line 63, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "/usr/lib/python2.7/dist-packages/matplotlib/axes/_base.py", line 2409, in draw
    mimage._draw_list_compositing_images(renderer, self, dsu)
  File "/usr/lib/python2.7/dist-packages/matplotlib/image.py", line 139, in _draw_list_compositing_images
    a.draw(renderer)
  File "/usr/lib/python2.7/dist-packages/mpl_toolkits/axisartist/axis_artist.py", line 915, in draw
    gl = self._grid_helper.get_gridlines(self._which, self._axis)
  File "/usr/lib/python2.7/dist-packages/mpl_toolkits/axisartist/axislines.py", line 546, in get_gridlines
    locs.extend(self.axes.xaxis.major.locator())
  File "/usr/lib/python2.7/dist-packages/matplotlib/dates.py", line 983, in __call__
    self.refresh()
  File "/usr/lib/python2.7/dist-packages/matplotlib/dates.py", line 1003, in refresh
    dmin, dmax = self.viewlim_to_dt()
  File "/usr/lib/python2.7/dist-packages/matplotlib/dates.py", line 760, in viewlim_to_dt
    return num2date(vmin, self.tz), num2date(vmax, self.tz)
  File "/usr/lib/python2.7/dist-packages/matplotlib/dates.py", line 401, in num2date
    return _from_ordinalf(x, tz)
  File "/usr/lib/python2.7/dist-packages/matplotlib/dates.py", line 254, in _from_ordinalf
    dt = datetime.datetime.fromordinal(ix).replace(tzinfo=UTC)
ValueError: year is out of range
pi@raspi3b:~/wx-logging $

不太有希望。我不明白为什么它说 ValueError: year is out of range 因为它是一个 unix 纪元时间戳。

我做错了什么?我怎样才能达到上面概述的预期结果?我真的很感激在正确的方向轻推。感谢您的帮助!

祝一切顺利, 克里斯

完整脚本

到目前为止,我的完整脚本在这里为您提供一些背景信息。

#!/usr/bin/python
# -*- coding: utf-8 -*-

import matplotlib
matplotlib.use('AGG')
from mpl_toolkits.axes_grid1 import host_subplot
import mpl_toolkits.axisartist as aa
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from matplotlib.ticker import FuncFormatter
import numpy as np
from numpy import vectorize
import datetime
import shutil
import math

# Dewpoint calculation
def dewpoint(tempC, rlHum):

    r  = 8314.3
    mw = 18.016

    if tempC >= 0:
        a = 7.5
        b = 237.3
    # over water:
    # elif tempC < 0:
    #     a = 7.6
    #     b = 240.7
    #
    # over ice:
    elif tempC < 0:
        a = 9.5
        b = 265.5

    saettDampfDruck = 6.1078 * 10**((a*tempC)/(b+tempC))
    dampfDruck = rlHum / 100.0 * saettDampfDruck
    v = math.log10(dampfDruck/6.1078)
    dewpC = b*v/(a-v)

    return dewpC

# translate cm into inches
def cm2inch(*tupl):
    inch = 2.54
    if isinstance(tupl[0], tuple):
        return tuple(i/inch for i in tupl[0])
    else:
        return tuple(i/inch for i in tupl)

vdewpoint = vectorize(dewpoint)

convertDate = lambda x: datetime.datetime.utcfromtimestamp(x)

data = np.genfromtxt('/home/pi/wx-logging/wx-log2.txt', 
                    delimiter=';', 
                    usecols=(1, 2, 3, 5, 6), 
                    names=['temp', 'humidity', 'press', 'slp', 'time'], 
                    converters={'6': convertDate}, 
                    dtype='float, float, float, float, int')

print data

plt.figure(figsize=cm2inch(29.7, 21))

host = host_subplot(111, axes_class=aa.Axes)
plt.subplots_adjust(right=0.75)
par1 = host.twinx()
par2 = host.twinx()

offset = 70 # offset of detached axis
new_fixed_axis = par2.get_grid_helper().new_fixed_axis
par2.axis["right"] = par2.get_grid_helper().new_fixed_axis(loc="right", 
                                                            axes=par2, 
                                                            offset=(offset, 0))

par1.axis["right"].toggle(all=True)
par2.axis["right"].toggle(all=True)

host.set_title("Weather Station")
host.set_xlabel("Time")
host.set_ylabel("Temperature & Dewpoint [" + u'\u00b0'+ "C]")
par1.set_ylabel("Sealevel Pressure [hPa]")
par2.set_ylabel("relative Humidity [%]")

host.set_ylim([-20, 40]) # temperature range -20C ... +40C
par1.set_ylim([980, 1040]) # slp range 980hPa ... 1040hPa
par2.set_ylim([0, 100]) # percent


p1, = host.plot(data['time'],
                data['temp'],
                label="Temperature",
                color="red",
                linewidth=2)
p2, = host.plot(data['time'],
                vdewpoint(data['temp'],
                data['humidity']),
                label="Dewpoint",
                color="salmon",
                linewidth=0.75)
p3, = par1.plot(data['time'],
                data['slp'],
                label="Sealevel Pressure",
                color="blue",
                linewidth=0.75)
p4, = par2.plot(data['time'],
                data['humidity'],
                label="rel. Humidity",
                color="grey",
                linewidth=0.5)

locator = mdates.AutoDateLocator()
plt.gca().xaxis.set_major_locator(locator)
plt.gca().xaxis.set_major_formatter(mdates.AutoDateFormatter(locator))


plt.legend(bbox_to_anchor=(0.05, 0.05), 
           loc=3,
           ncol=2, 
           borderaxespad=0.)

plt.savefig("plot.png", dpi=150)

shutil.copyfile('/home/pi/wx-logging/plot.png', '/var/www/html/plot.png')

编辑1:您可以下载wx-log2.txt (~58KB) 包含用于试验脚本的示例数据。由 tiago 正确建议

最佳答案

您的代码有一些问题。首先,在 converters={'6': 中使用引号中的列意味着永远不会应用转换函数。使用不带引号的列号:

converters={6: convertDate},

另一个问题是您需要将字符串转换为整数,否则您的日期时间转换将不起作用:

convertDate = lambda x: datetime.datetime.utcfromtimestamp(int(x))

最后,time 字段的数据类型必须是 numpy.datatype64(并以微秒为单位指定,因为这是 utcfromtimestamp 返回的内容).在 np.genfromtxt 调用中分配数据类型的正确方法如下:

data = np.genfromtxt('wx-log2.txt',  
                     delimiter=';',
                     converters={6: convertDate},
                     usecols=(1,2,3,5,6), 
                     dtype=[('temp', 'f'), ('humidity', 'f'), ('press', 'f'), 
                            ('slp', 'f'), ('time', 'datetime64[us]')])

通过以上内容,您应该如何以 plt.plot_date 可以理解的格式设置时间。

对于日期格式,您可以通过将次要刻度标记标签设置为 HH:MM 并将主要刻度标签设置为一年中的某一天来实现与您试图实现的类似的效果,但我不知道每 30 分钟有一个额外的未标记刻度线的方法。

这是一个简单的示例,它具有适当的时间数组并以与您想要的格式类似的格式绘制。为简单起见,每 4 小时只写一次刻度线,但您可以更改它。

import numpy as np
import matplotlib.dates as dates
import matplotlib.pyplot as plt 

fig, ax = plt.subplots()
idx = pd.date_range('2018-01-07', '2018-01-09', freq='10min')
# generate a time range series with 10 min intervals
idx = np.arange('2018-01-07T00', '2018-01-09T02', 10, dtype='datetime64[m]')
# some random data
y = np.sin(np.arange(idx.shape[0]) / 0.01)

ax.plot_date(idx, y, '-')

ax.xaxis.set_minor_locator(dates.HourLocator(interval=4))   # every 4 hours
ax.xaxis.set_minor_formatter(dates.DateFormatter('%H:%M'))  # hours and minutes
ax.xaxis.set_major_locator(dates.DayLocator(interval=1))    # every day
ax.xaxis.set_major_formatter(dates.DateFormatter('\n%d-%m-%Y')) 

output image

关于python - x 轴上时间戳的格式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48167835/

相关文章:

python - 仅访问嵌套字典列表中的一个键并使用 matplotlib 绘制它

python - 如何使用 cartopy 和 matplotlib 屏蔽海洋中出现的数据

c - 是否有 "null"printf 代码不打印任何内容,用于跳过参数?

python格式化字符串以忽略缩进空格

python - 有没有办法遍历列表并将所有内容转换为整数?

python - 编码字符串

python - 使用 Matplotlib 在一张条形图中绘制两个字典

android - 如果 ScrollView 仅支持一个直接子级,我应该如何使整个布局可滚动?

python - 国际化django模板中的多个复数变量

python - Pandas:使用列值的随机采样替换 NaN