使用 Python 的 USGS 水文数据甘特图?

Posted

技术标签:

【中文标题】使用 Python 的 USGS 水文数据甘特图?【英文标题】:Gantt Chart for USGS Hydrology Data with Python? 【发布时间】:2020-05-22 18:44:27 【问题描述】:

我已经编译了一个数据框,其中包含几个不同的流量仪表的 USGS 流量数据。现在我想创建一个类似于this 的甘特图。目前,我的数据将列作为站点名称,将日期索引作为行。

这是我的data 的示例。

我链接的甘特图示例的问题是我的数据在通常定义水平时间线的开始日期和结束日期之间存在间隔。我发现的许多示例仅说明了开始日期和结束日期,而不是可能介于两者之间的缺失值。对于某些网站,我如何解释没有数据(值的这些插槽中的空白或 nan)的空白?

首先,我有一个图表来显示缺失数据的位置。

import missingno as msno
msno.bar(dfp)

现在,我想要 x 轴上的时间和 y 轴上的水平线,用于跟踪网站何时包含这些时间的数据。我知道如何以蛮力方式执行此操作,这意味着手动选择有有效数据的开始日期和结束日期(我在下面编写)。

from datetime import datetime
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as dt

df=[('RIO GRANDE AT EMBUDO, NM','2015-7-22','2015-12-7'),
('RIO GRANDE AT EMBUDO, NM','2016-1-22','2016-8-5'),
('RIO GRANDE DEL RANCHO NEAR TALPA, NM','2014-12-10','2015-12-14'),
('RIO GRANDE DEL RANCHO NEAR TALPA, NM','2017-1-10','2017-11-25'),
('RIO GRANDE AT OTOWI BRIDGE, NM','2015-8-17','2017-8-21'),
('RIO GRANDE BLW TAOS JUNCTION BRIDGE NEAR TAOS, NM','2015-9-1','2016-6-1'),
('RIO GRANDE NEAR CERRO, NM','2016-1-2','2016-3-15'),
] 
df=pd.DataFrame(data=df)
df.columns = ['A', 'Beg', 'End']
df['Beg'] = pd.to_datetime(df['Beg'])
df['End'] = pd.to_datetime(df['End'])

fig = plt.figure(figsize=(10,8))
ax = fig.add_subplot(111)
ax = ax.xaxis_date()
ax = plt.hlines(df['A'], dt.date2num(df['Beg']), dt.date2num(df['End']))

如何使用我提供的数据框作为示例制作一个图形(如上图所示)?理想情况下,我想避免使用蛮力方法。

请注意:零值被视为有效数据点。

提前感谢您的反馈!

【问题讨论】:

您能否编辑您的答案以包括您迄今为止尝试过的内容、获得的输出并描述与您想要的结果有何不同?这里有一些关于如何提出好问题的提示。 Link 好点,我应该包括我到目前为止所做的。我现在已经更新了这个问题,以包括我到目前为止所做的事情。谢谢! 您的数据是否总是每天采样? 对于这个数据集,每天编译一次。 【参考方案1】:

查找非空数据的日期范围

2020-02-12 编辑以澄清循环中的逻辑

df = pd.read_excel('Downloads/output.xlsx', index_col='date')

确保日期顺序:

df.sort_index(inplace=True)

遍历数据并找到良好数据范围的边缘。获取相应的索引值和仪表的名称,并将它们全部收集到一个列表中:

# Looping feels like defeat. However, I'm not clever enough to avoid it 
good_ranges = []
for i in df:
    col = df[i]
    gauge_name = col.name

    # Start of good data block defined by a number preceeded by a NaN
    start_mark = (col.notnull() & col.shift().isnull())
    start = col[start_mark].index

    # End of good data block defined by a number followed by a Nan
    end_mark = (col.notnull() & col.shift(-1).isnull())
    end = col[end_mark].index

    for s, e in zip(start, end):
        good_ranges.append((gauge_name, s, e))

good_ranges = pd.DataFrame(good_ranges, columns=['gauge', 'start', 'end'])

绘图

这里没有什么新鲜事。几乎直接从您的问题中复制:

fig = plt.figure(figsize=(10,8))
ax = fig.add_subplot(111)
ax = ax.xaxis_date()
ax = plt.hlines(good_ranges['gauge'], 
                dt.date2num(good_ranges['start']), 
                dt.date2num(good_ranges['end']))
fig.tight_layout()

【讨论】:

抱歉,我已经出城了一段时间。感谢您的答复;我认为这对我来说很有意义。我必须一点一点地检查你的代码,以确保我了解事情是如何工作的。一个问题只是为了澄清:本质上,在每一端添加一个额外的日期(带有关联的 nan 值)使得当我们找到数据从有效到 nan 值的位置时,一旦我们不会丢失有效数据点使用 .shift() 调用? 既然您指出了这一点,这里不需要扩展索引,因为shift 将提供NaNs。我已经编辑了我的答案。那个索引扩展的东西是在解决逆问题时遗留下来的——找到仪表何时离线,即 NaN 组。 太好了,这对我来说更有意义。谢谢你的澄清!【参考方案2】:

这是您可以使用的一种方法,它有点老套,所以也许其他一些方法会产生更好的解决方案,但它应该会产生您想要的输出。首先使用pd.where 将非 NaN 值替换为一个整数,该整数稍后将确定 y 轴上线条的位置,我逐行执行此操作,以便属于一起的所有数据都处于相同的高度。如果你想增加甘特图线条之间的间距,可以在i 中添加一个数字,我在下面代码块中的 cmets 中提供了一个示例。

y 标签及其位置是在数据修改步骤中生成的,因此无论列数如何,此方法都可以工作,并且在您更改上述间距时会正确定位标签。

此方法返回 matplotlib.pyplot.axesmatplotlib.pyplot.Figure 对象,因此您可以调整图表的美感以适合您的目的(即更改线条的粗细、颜色等)。 Link to docs.

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

df = pd.read_excel('output.xlsx')
dates = pd.to_datetime(df.date)
df.index = dates
df = df.drop('date', axis=1)

new_rows = [df[s].where(df[s].isna(), i) for i, s in enumerate(df, 1)]
# To increase spacing between lines add a number to i, eg. below:
# [df[s].where(df[s].isna(), i+3) for i, s in enumerate(df, 1)]
new_df = pd.DataFrame(new_rows)

### Plotting ###

fig, ax = plt.subplots() # Create axes object to pass to pandas df.plot()
ax = new_df.transpose().plot(figsize=(40,10), ax=ax, legend=False, fontsize=20)
list_of_sites = new_df.transpose().columns.to_list() # For y tick labels
x_tick_location = new_df.iloc[:, 0].values # For y tick positions
ax.set_yticks(x_tick_location) # Place ticks in correct positions
ax.set_yticklabels(list_of_sites) # Update labels to site names

【讨论】:

以上是关于使用 Python 的 USGS 水文数据甘特图?的主要内容,如果未能解决你的问题,请参考以下文章

无标题CSDN发布模板水文

无标题CSDN发布模板水文

无标题CSDN发布模板水文

如何使用 Python Pandas 绘制堆叠事件持续时间(甘特图)

如何在python中为相同的并行机器创建甘特图?

Python:用于绘制甘特图的模块