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

8
我正在绘制一份包含Y轴数值和X轴日期的CSV文件数据,我的数据集仅涵盖了15年内六月、七月和八月的数据。但是,当我尝试绘制这些数据时,它会绘制出整个时间段内的所有日期,而不仅仅是CSV文件中的夏季月份。下面是我目前绘制的图形:

enter image description here

下面是产生此图像的代码:
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列)由字符串组成。这些数据来自csv文件,只是在Excel中显示。 enter image description here

1
你可以设置 xticks,但我认为你的图表会变得毫无意义。你会在整个图表上看到大量的点和不均匀的跳跃,这在视觉上对我来说与你当前的图表相比是没有意义的。 - roganjosh
1
抱歉,您的问题中提到“沿x轴均匀分布”,这正是您已经拥有的。您似乎希望拥有一个不均匀的x轴,除非您计划在该图中做更多的事情,否则它真的将是我见过的最令人困惑的图表之一。您确定要这样吗? - roganjosh
1
我也喜欢你目前的表示方式。但是你可以使用numpy.arange或range创建一个数组或列表,并将其用作x轴参数,然后将x轴刻度标签更改为相应的日期。如果您浏览画廊示例,您应该会找到代码来完成这些事情 - wwii
1
我认为你可能试图在一个单一的图中展示过多的信息。你主要是想展示多年的趋势还是一年中每个月的趋势?如果是前者,那么我建议你继续使用类似于你已经有的东西。如果是后者,那么你可以将月份放在x轴上,并绘制不同的线来代表每一年。你可能还需要聚合你的数据,计算每年或每月的平均值/置信区间,具体取决于你想要表达的观点。 - ali_m
1
你能提供一些样本数据吗?如果不能,那么数据的结构是什么?日期格式为2014-07-01的索引?还有多个类别(列)吗? - vestland
显示剩余2条评论
2个回答

5

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

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()

enter image description here


那么这个答案是否符合您的要求呢?如果不是,您可能需要说明它在哪些方面没有帮助或者您想要实现什么其他功能。仅仅看一下问题中新增的数据,似乎在上述代码中实现起来非常简单明了。 - ImportanceOfBeingErnest
添加垂直线对于这个图形非常重要。我从来没有想过这样的修改会使它有意义,但是我猜它确实可以。 - roganjosh
@roganjosh 你的意思是什么?你想要没有竖线的图吗?(这里免费提供,非常方便,因为它们会将图形分割,使读者不会被断裂的数据轴所困扰。) - ImportanceOfBeingErnest
在我对主要问题的评论中,我构想了一个没有那些垂直线的情节。没有它们,x轴上不均匀的跳跃让我想到这将是一团毫无意义的混乱。垂直线使得这成为可能;我给你点赞是因为你证明了这可以行得通,并证明了我的错误(我忽略了构想出明显的边界) :) - roganjosh
啊,我明白了。我完全同意需要某种边界。除了线条之外,也可以在背景中使用两种不同的相同颜色的阴影或不同颜色的散点;我认为有很多选择。 - ImportanceOfBeingErnest
@ImportanceOfBeingErnest 这就是我在寻找的。谢谢! - glayne

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()

这看起来像这样:

在此输入图像描述


这段内容与IT技术有关。

由于 OP 尚未指定数据,因此这肯定是一个有效的答案。这是一个简单的解决方案,适用于每个月恰好有一个数据点的特殊情况。我目前不确定如何将其扩展到一般情况,即您可能拥有任意数据点的情况(例如来自我的答案中的数据)。 - ImportanceOfBeingErnest
@ImportanceOfBeingErnest 我在 OP 中添加了一个屏幕截图,展示我的数据长什么样子。 - glayne
啊,我明白了@ImportanceOfBeingErnest,我想你可以在刻度标签上添加跳过,set_xticklabels(dates[::10])以防止拥挤,但我同意这不是一般情况下的最佳解决方案。我已经为你的答案点赞 :) - Ed Smith

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接