【问题标题】:How to make a histogram from this nc file?如何从此 nc 文件制作直方图?
【发布时间】:2015-04-21 12:47:26
【问题描述】:

我是一名研究助理,最近开始学习 python 来解释 netCDF 文件格式的模型输出。让我简要介绍一下我的问题的背景:

我已经使用 netCDF4 模块搜索了 netCDF 文件的某个网格区域并存储了一个时间数组,然后我使用 netCDF4 的 num2date 功能将其转换为日期列表。我在下面显示了我的代码。请注意,restrictedrange 是 nc 文件中变量的子集,rmduplicates() 未显示。

import netCDF4 as nc
import numpy as np
import matplotlib.pyplot as pyp
import matplotlib as mpl
import datetime as dtm
flor = nc.Dataset('FLOR.slp_subset1.nc','r')    

times = []
timecounter = .25
for i in restrictedrange:
     for j in np.nditer(i):
         if(j <= 975):
              times.append(timecounter)
    timecounter += .25
uniquetimes = rmduplicates(times)
dates = nc.num2date(uniquetimes,'days since 0001-01-01 00:00:00','julian')

stacked_dates = []
for date in dates:
    stacked_dates.append(date.replace(year=0001))
stacked_dates = mpl.dates.date2num(stacked_dates)

fig = pyp.figure()
ax = pyp.subplot(111)
ax.xaxis.set_major_locator(mpl.dates.MonthLocator())
format = mpl.dates.DateFormatter('%m/%d')
ax.xaxis.set_major_formatter(format)

ax.hist(stacked_dates)

pyp.xticks(rotation='vertical')

pyp.show()

现在我有一个格式为“(y)yy-mm-dd hh:mm:ss”的日期列表。我现在想按月获取这些日期并制作直方图(可能使用 matplotlib 或最适合此的方法)。因此,条形 = 频率,分档是月。 另外,如果我的格式不清楚,有些年份有三个数字,有些只有两个,但实际上没有一个有 1。

再次重申,我对 python 还很陌生,所以我很感激任何帮助,如果这个问题的格式不正确,我深表歉意,因为我从未使用过这个网站。

谢谢!

【问题讨论】:

  • 不清楚你到底想要什么......我觉得这个问题的大部分开头实际上是无关紧要的。只是你有一个字符串日期列表并想得到一个直方图吗?
  • 我只是把它放在那里,以防有必要查看我如何生成输出(例如,使用 netCDF4 而不是 matplotlib 用于 num2date)。但是,您是对的,我有一个字符串日期列表,并且想要一个基于每月频率的直方图。

标签: python date matplotlib histogram


【解决方案1】:

我不知道你有什么数据,但这里有一个模拟示例,说明如何在 x 轴上制作月\天的直方图。

我只能假设您从日期时间对象列表开始,但我无法弄清楚 nc 是什么(是 matplotlib.date 模块吗?)次。所以通常这是方法。

您将需要和使用这些模块。

import matplotlib as mpl
import matplotlib.pyplot as plt
import datetime

这些是我使用的模拟日期。对于这个例子。那里只有 11 个月,所以大多数垃圾箱最终都会是 1。

for i in range(1, 12):
    dates.append(datetime.datetime(i*5+1960, i, i, i, i, i))

[datetime.datetime(1965, 1, 1, 1, 1, 1), datetime.datetime(1970, 2, 2, 2, 2, 2), datetime.datetime(1975, 3, 3, 3, 3, 3), datetime.datetime(1980, 4, 4, 4, 4, 4), datetime.datetime(1985, 5, 5, 5, 5, 5), datetime.datetime(1990, 6, 6, 6, 6, 6), datetime.datetime(1995, 7, 7, 7, 7, 7), datetime.datetime(2000, 8, 8, 8, 8, 8), datetime.datetime(2005, 9, 9, 9, 9, 9), datetime.datetime(2010, 10, 10, 10, 10, 10), datetime.datetime(2015, 11, 11, 11, 11, 11)]

如果像上面的例子一样,你要处理不同的年份,你将不得不自己“堆叠”它们。否则我稍后将使用的date2num 函数将产生截然不同的数字。将它们“堆叠”意味着将它们转换为好像它们都发生在同一年一样。

stacked_dates = []
for date in dates:
    stacked_dates.append( date.replace(year=2000)  )

>>> stacked_dates
[datetime.datetime(2000, 1, 1, 1, 1, 1), datetime.datetime(2000, 2, 2, 2, 2, 2), datetime.datetime(2000, 3, 3, 3, 3, 3), datetime.datetime(2000, 4, 4, 4, 4, 4), datetime.datetime(2000, 5, 5, 5, 5, 5), datetime.datetime(2000, 6, 6, 6, 6, 6), datetime.datetime(2000, 7, 7, 7, 7, 7), datetime.datetime(2000, 8, 8, 8, 8, 8), datetime.datetime(2000, 9, 9, 9, 9, 9), datetime.datetime(2000, 10, 10, 10, 10, 10), datetime.datetime(2000, 11, 11, 11, 11, 11)]

好的。现在我们可以使用date2num 函数来得到mpl 真正理解的东西。 (顺便说一句,如果您只想绘制这些数据,您可以使用 plt.plot_dates 函数,该函数可以理解日期时间对象)

stacked_dates = mpl.dates.date2num(stacked_dates)

>>> stacked_dates
array([ 730120.04237269,  730152.08474537,  730182.12711806,
        730214.16949074,  730245.21186343,  730277.25423611,
        730308.2966088 ,  730340.33898148,  730372.38135417,
        730403.42372685,  730435.46609954])

现在可以进行绘图了。 mpl 可以理解这些数字,但它不会自动假定它们是日期。它会将它们视为正常数字。这就是为什么我们必须告诉 x 轴它们实际上是日期。使用 major_axis_formatterset_major_locator 来做到这一点

fig = plt.figure()
ax = plt.subplot(111)
ax.xaxis.set_major_locator(mpl.dates.MonthLocator())
format = mpl.dates.DateFormatter('%m/%d') #explore other options of display
ax.xaxis.set_major_formatter(format)

ax.hist(stacked_dates) #plot the damned thing

plt.xticks(rotation='vertical') #avoid overlapping numbers
                           #make sure you do this AFTER .hist function

plt.show()

此代码生成以下图表:

请注意,您有可能无法在原始图表上看到日期,因为它们会超出屏幕(此类格式可能很长,并且不适合图表)。在这种情况下,按下“配置子图”按钮并调整“底部”的值。在脚本中,您可以通过 plt.subplots_adjust(bottom=.3) 或其他值来执行此操作。

您还应该注意在ax.hist(stacked_dates, bins=12) 中指定有 12 个 bin,因为默认值为 10,并且看起来像我的图表一样时髦。

还有一个更简单的,虽然不太可修改/可个性化的等......通过使用条形图而不是直方图的可能性。阅读它HERE 但这真的取决于你拥有什么样的信息。如果有很多日期,让hist 函数计算箱高可能比自己计算更容易。 如果是其他信息,则值得考虑使用条形图。

完整的脚本类似于:

import matplotlib as mpl
import matplotlib.pyplot as plt
import datetime

stacked_dates = []
for date in dates:
    stacked_dates.append( date.replace(year=2000)  )

stacked_dates = mpl.dates.date2num(stacked_dates)

fig = plt.figure()
ax = plt.subplot(111)
ax.xaxis.set_major_locator(mpl.dates.MonthLocator())
format = mpl.dates.DateFormatter('%m/%d')
ax.xaxis.set_major_formatter(format)

ax.hist(stacked_dates)

plt.xticks(rotation='vertical')  
plt.show()

【讨论】:

  • 感谢您的帮助。我应该把 nc 是什么(再次,我是新人,所以我很抱歉)。我在我的代码中将 netCDF4 模块作为 nc 导入,并使用 netCDF4 的 num2date 函数执行此操作。我使用这个的原因是因为这个文件使用的日历是儒略而不是公历(就像 mpl 使用的那样)。有没有一种方法可以使用 mpl 而不会因为日历差异而在一天左右的时间内歪曲日期?
  • 只是一个快速的跟进,我认为日历差异阻止我超越堆叠步骤,因为即使使用 mpl 将我的时间转换为日期,我仍然收到错误“ValueError:day is超出一个月的范围。”
  • @LonelyHeartsClub 啊,我不知道 nc 有同样的功能。至于你的第一个问题,是的。贴一些代码,让我看看你是如何转换它的。据我所知,netcdftime 模块只是一个包装好的日期时间模块。我建议明确地进行转换,例如 for date in ncdate: list.append(datetime(year=date.year .... day=date.day-1) 这使您可以选择使用 if 条件等来准确控制转换的发生方式。我看到的唯一问题是 1500 年之前的日期。但是,如果您不使用旧信息,没问题。
  • 当然,我会准确地发布我为实现此列表所做的工作。此外,我确实在 1500 年之前有几年,因为这是假设数据(随机生成的模型输出)所以我的年份从第一年开始。import netCDF4 as nc; import numpy as np;flor = nc.Dataset('FLOR.slp_subset1.nc','r')times = []; timecounter = .25for i in restrictedrange: for j in np.nditer(i):if(j &lt;= 975):times.append(timecounter) timecounter += .25 uniquetimes = rmduplicates(times) Times 是一个值列表,例如 .25,.50,对应于 0001 年 1 月 1 日之后的天数
  • @LonelyHeartsClub 请相应地编辑您的原始帖子,cmets 没有相同的编辑权限。此外,这似乎与您在原始问题中发布的代码完全相同。我也想知道nc.num2dates 的类型是什么,希望它是一个浮点数。如果是这样,你可以做我所做的一切,除了你必须确保你使用nc.datetime 模块来堆叠日期并使用date2num 将它们转换为数字。 nc 应该自己进行更正,最终结果是浮动,mpl 解释得很好。 1/2
猜你喜欢
  • 2012-02-03
  • 1970-01-01
  • 2020-02-16
  • 1970-01-01
  • 2021-12-09
  • 2020-10-24
  • 2016-07-22
  • 2017-10-17
  • 1970-01-01
相关资源
最近更新 更多