如何沿 x 轴均匀地绘制日期数据?

Posted

技术标签:

【中文标题】如何沿 x 轴均匀地绘制日期数据?【英文标题】:How to plot date data evenly along x-axis? 【发布时间】:2018-01-23 21:38:36 【问题描述】:

我正在绘制 csv 文件中的数据,其中 y 轴上的值和 x 轴上的日期。我的数据集仅包含 15 年期间 6 月、7 月和 8 月的数据。但是,当我尝试绘制这些数据时,它会在整个期间的 x 轴上绘制所有日期,而不仅仅是 csv 文件中的夏季月份。下面是我的情节目前的样子

这是生成此图像的代码:

infile = r'data.csv'

with open(infile,'r') as f:
    data = list(reader(f))

date = [parser.parse(i[10]) for i in data[1:]] #3
date = mdates.date2num(date)
date = mdates.num2date(date)

value = [i[16] for i in data[1:]]

fig = plt.figure()
plt.plot(date, value, '.r')

基本上,我试图在没有每年数据之间的所有空格的情况下获得相同的图。

这是我的数据片段(从 2002 年到 2016 年)。日期列(L 列)由字符串组成。此数据来自刚刚在 Excel 中显示的 csv 文件。

【问题讨论】:

你可以设置xticks,但我认为你的情节会变得荒谬吗?您将在整个图表上出现大量偏离点,并且沿 x 轴到处都有不均匀的跳跃。从视觉上看,与您当前的图表相比,这对我来说毫无意义。 Of* 抱歉,您的问题是“沿 x 轴均匀分布”,这正是您已经拥有的。你的愿望似乎是有一个不均匀 x 轴,除非你打算用那个图做更多的事情,否则它真的会是我见过的最令人困惑的图表之一。你确定要这个吗? ...我也更喜欢你目前的表现形式。但是您可以使用 numpy.arange 或 range 创建一个数组或列表,并将其用于 x 轴参数,然后将 x 轴刻度标签更改为相应的日期。如果您查看the gallery 或example,您应该会找到does those things 的代码。 我认为您可能试图在一个情节中显示太多信息。你主要是想展示多年来的趋势,还是一年内的几个月?如果是前者,那么我会坚持使用与您已有的类似的东西。如果是后者,那么你可以做一些事情,比如沿着 x 轴设置几个月并绘制单独的线来代表每年。您可能还希望通过计算每年或每月的平均值/置信区间来汇总数据,具体取决于您要提出的观点。 您能提供一些示例数据吗?如果不是,数据的结构是什么?日期格式为 2014-07-01 的索引?还有多个类别(列)? 【参考方案1】:

我可以想象使用与日期范围一样多的子图可能是一种选择。为简单起见,您可以将所有数据绘制到所有子图中,但将每个子图限制在一个日期范围内。

import numpy as np; np.random.seed(24191)
import datetime
import matplotlib.pyplot as plt
import matplotlib.dates

## generate some data x and y
n= 1000
year = np.random.randint(2000,2009, size=n)
month = np.random.randint(6,9, size=n)
day = np.random.randint(1,32, size=n)
x = [datetime.date(y,m,d) for y,m,d in zip(year,month,day)]
y = np.abs(np.random.randn(n))

## define the ranges for the dates
drange = [[datetime.date(i,6,1),datetime.date(i,8,31)] for i in range(2000,2009)]

## create as many subplots as there are date ranges
fig, axes= plt.subplots(ncols=len(drange), sharey=True)
fig.subplots_adjust(bottom=0.3,wspace=0)

ymax = 1.1*y.max()
## loop over subplots and limit each to one date range
for i, ax in enumerate(axes):
    ax.set_xlim(drange[i][0],drange[i][1])
    ax.set_ylim(0,ymax)
    ax.scatter(x,y, s=4)
    loc = matplotlib.dates.MonthLocator([6,7,8])
    fmt =  matplotlib.dates.DateFormatter("%Y-%b")
    ax.xaxis.set_major_locator(loc)
    ax.xaxis.set_major_formatter(fmt)
    plt.setp(ax.get_xticklabels(), rotation=90)
    if i!=0:
        ax.tick_params(axis="y", which="both", length=0)

plt.show()

【讨论】:

那么这个答案是你想要的吗?如果没有,您可能想说明它在多大程度上没有帮助,或者您还想达到什么目标。只需查看问题中新添加的数据,在上面的代码中实现这似乎非常简单。 垂直线的添加对于该图是不可或缺的。我从没想过它会有意义,但我想通过简单的修改就可以了。 @roganjosh 你什么意思?你想要没有垂直线的情节吗? (它们在这里是免费的,而且非常方便,因为它们分割了情节,这样读者就不会被损坏的数据轴弄糊涂了。) 在我的主要问题下的 cmets 中,我设想了一个没有这些垂直线的情节。没有它们,x 轴上的不均匀跳跃让我觉得这将是多么荒谬的一团糟。垂直线使这个;我给你投了赞成票,证明这可以工作并证明我错了(我忽略了设想不同的界限):) 啊,我明白了。我完全同意某种边界是可取的。除了线条之外,还可以在背景中使用两种相同颜色的不同阴影或不同颜色的散点;我认为有很多选择。【参考方案2】:

听起来您只是想根据统一数组绘制数据,然后将刻度设置为日期,

import datetime as dt
import matplotlib.pyplot as plt
import numpy as np

dates = ['06/2015','07/2015','08/2015', '06/2016','07/2016','08/2016']
x = [dt.datetime.strptime(d,'%m/%Y').date() for d in dates]
y = range(len(x)) + np.random.random(len(x))

#Plot vs dates
fig, ax = plt.subplots(2,1)
ax[0].plot(x,y,'r.')

#Plot vs number and label
ax[1].plot(y,'r.')
ax[1].set_xticks(range(len(y)))
ax[1].set_xticklabels(dates)
plt.show()

看起来像这样,

【讨论】:

由于 OP 没有指定数据(还),这肯定是一个有效的答案。对于每月只有一个数据点的特殊情况,这是一个简单的解决方案。我目前不确定如何将其扩展到一般情况,您可能有任意数据点(例如来自my answer 的数据)。 @ImportanceOfBeingErnest 我添加了我的数据在 OP 中的样子的屏幕截图。 啊,我看到@ImportanceOfBeingErnest,我想您可以在刻度标签上添加一个跳过,set_xticklabels(dates[::10]) 以防止过度拥挤,但我同意这不是一般情况下的最佳解决方案。我赞成你的回答:)

以上是关于如何沿 x 轴均匀地绘制日期数据?的主要内容,如果未能解决你的问题,请参考以下文章

在 iOS 中沿路径均匀地绘制图像

如何使用 CGContext 方法清除旧数据的绘制?

在沿 x 轴定义的点处沿 y 轴插值数据

使用文件中的数据绘制日期和时间(x 轴)与值(y 轴)

使用文件中的数据绘制日期和时间(x 轴)与值(y 轴)

ipython plotly:无法将x轴绘制为日期时间