【问题标题】:Date axis in heatmap seaborn热图中的日期轴 seaborn
【发布时间】:2017-04-16 23:10:44
【问题描述】:

一点信息:我对编程很陌生,这是我第一个脚本的一小部分。这个特定部分的目标是显示一个海洋热图,其中 y 轴为垂直深度,x 轴为时间,科学测量的强度作为热函数。

如果这个问题已经在别处得到解答,我想道歉,但我的搜索能力一定让我失望了。

sns.set()
nametag = 'Well_4_all_depths_capf'
Dp = D[D.well == 'well4']
print(Dp.date)


heat = Dp.pivot("depth",  "date", "capf")
### depth, date and capf are all columns of a pandas dataframe 

plt.title(nametag)

sns.heatmap(heat,  linewidths=.25)

plt.savefig('%s%s.png' % (pathheatcapf, nametag), dpi = 600)

这是从 ' print(Dp.date) ' 打印的内容 所以我很确定数据框的格式是我想要的格式,特别是年、日、月。

0    2016-08-09
1    2016-08-09
2    2016-08-09
3    2016-08-09
4    2016-08-09
5    2016-08-09
6    2016-08-09
         ...    

但是,当我运行它时,日期轴总是打印出我不想要的空白时间(00:00 等)。 有没有办法从日期轴中删除这些?

问题是我在上面的一个单元格中使用此功能扫描文件名并用日期制作一列吗???使用 datetime 而不是仅使用 date 函数是错误的吗?

D['date']=pd.to_datetime(['%s-%s-%s' %(f[0:4],f[4:6],f[6:8]) for f in             
D['filename']])

【问题讨论】:

    标签: python datetime matplotlib seaborn heatmap


    【解决方案1】:
    • 首先,'date' 列必须用pandas.to_datetime 转换为datetime dtype
    • 如果想要的结果是只有日期(没有时间),那么最简单的解决方案是使用.dt accessor 提取.date 组件。或者,使用dt.strftime 设置特定的字符串格式。
      • strftime() and strptime() Format Codes
      • df.date.dt.strftime('%H:%M') 会将小时和分钟提取到像 '14:29' 这样的字符串中
      • 在下面的示例中,将提取的日期分配给同一列,但也可以将值分配为新列。
    • pandas.DataFrame.pivot_table 用于聚合一个函数,如果每个 index 的列中有多个值,如果只有一个值,则应使用 pandas.DataFrame.pivot
      • 这比 .groupby 好,因为数据框的形状正确,易于绘制。
    • python 3.8.11pandas 1.3.2matplotlib 3.4.3seaborn 0.11.2 中测试
    import pandas as pd
    import numpy as np
    import seaborn as sns
    
    # create sample data
    dates = [f'2016-08-{d}T00:00:00.000000000' for d in range(9, 26, 2)] + ['2016-09-09T00:00:00.000000000']
    depths = np.arange(1.25, 5.80, 0.25)
    np.random.seed(365)
    p1 = np.random.dirichlet(np.ones(10), size=1)[0]  # random probabilities for random.choice
    p2 = np.random.dirichlet(np.ones(19), size=1)[0]  # random probabilities for random.choice
    data = {'date': np.random.choice(dates, size=1000, p=p1), 'depth': np.random.choice(depths, size=1000, p=p2), 'capf': np.random.normal(0.3, 0.05, size=1000)}
    df = pd.DataFrame(data)
    
    # display(df.head())
                                date  depth      capf
    0  2016-08-19T00:00:00.000000000   4.75  0.339233
    1  2016-08-19T00:00:00.000000000   3.00  0.370395
    2  2016-08-21T00:00:00.000000000   5.75  0.332895
    3  2016-08-23T00:00:00.000000000   1.75  0.237543
    4  2016-08-23T00:00:00.000000000   5.75  0.272067
    
    # make sure the date column is converted to a datetime dtype
    df.date = pd.to_datetime(df.date)
    
    # extract only the date component of the date column
    df.date = df.date.dt.date
    
    # reshape the data for heatmap; if there's no need to aggregate a function, then use .pivot(...)
    dfp = df.pivot_table(index='depth', columns='date', values='capf', aggfunc='mean')
    
    # display(dfp.head())
    date   2016-08-09  2016-08-11  2016-08-13  2016-08-15  2016-08-17  2016-08-19  2016-08-21  2016-08-23  2016-08-25  2016-09-09
    depth                                                                                                                        
    1.50     0.334661         NaN         NaN    0.302670    0.314186    0.325257    0.313645    0.263135         NaN         NaN
    1.75     0.305488    0.303005    0.410124    0.299095    0.313899    0.280732    0.275758    0.260641         NaN    0.318099
    2.00     0.322312    0.274105         NaN    0.319606    0.268984    0.368449    0.311517    0.309923         NaN    0.306162
    2.25     0.289959    0.315081         NaN    0.302202    0.306286    0.339809    0.292546    0.314225    0.263875         NaN
    2.50     0.314227    0.296968         NaN    0.312705    0.333797    0.299556    0.327187    0.326958         NaN         NaN
    
    # plot
    sns.heatmap(dfp, cmap='GnBu')
    

    【讨论】:

      【解决方案2】:

      标准热图日期时间标签示例

      import pandas as pd
      import seaborn as sns
      
      dates = pd.date_range('2019-01-01', '2020-12-01')
      
      df = pd.DataFrame(np.random.randint(0, 100, size=(len(dates), 4)), index=dates)
      
      sns.heatmap(df)
      

      我们可以创建一些辅助类/函数来获得更好看的标签和位置。 AxTransformer 支持从数据坐标到刻度位置的转换,set_date_ticks 允许将自定义日期范围应用于绘图。

      import numpy as np
      import pandas as pd
      import matplotlib.pyplot as plt
      from collections.abc import Iterable
      from sklearn import linear_model
      
      class AxTransformer:
          def __init__(self, datetime_vals=False):
              self.datetime_vals = datetime_vals
              self.lr = linear_model.LinearRegression()
              
              return
          
          def process_tick_vals(self, tick_vals):
              if not isinstance(tick_vals, Iterable) or isinstance(tick_vals, str):
                  tick_vals = [tick_vals]
                  
              if self.datetime_vals == True:
                  tick_vals = pd.to_datetime(tick_vals).astype(int).values
                  
              tick_vals = np.array(tick_vals)
                  
              return tick_vals
          
          def fit(self, ax, axis='x'):
              axis = getattr(ax, f'get_{axis}axis')()
              
              tick_locs = axis.get_ticklocs()
              tick_vals = self.process_tick_vals([label._text for label in axis.get_ticklabels()])
              
              self.lr.fit(tick_vals.reshape(-1, 1), tick_locs)
              
              return
          
          def transform(self, tick_vals):        
              tick_vals = self.process_tick_vals(tick_vals)
              tick_locs = self.lr.predict(np.array(tick_vals).reshape(-1, 1))
              
              return tick_locs
          
      def set_date_ticks(ax, start_date, end_date, axis='y', date_format='%Y-%m-%d', **date_range_kwargs):
          dt_rng = pd.date_range(start_date, end_date, **date_range_kwargs)
      
          ax_transformer = AxTransformer(datetime_vals=True)
          ax_transformer.fit(ax, axis=axis)
          
          getattr(ax, f'set_{axis}ticks')(ax_transformer.transform(dt_rng))
          getattr(ax, f'set_{axis}ticklabels')(dt_rng.strftime(date_format))
      
          ax.tick_params(axis=axis, which='both', bottom=True, top=False, labelbottom=True)
          
          return ax
      

      这些为我们提供了很大的灵活性,例如

      fig, ax = plt.subplots(dpi=150)
      
      sns.heatmap(df, ax=ax)
      
      set_date_ticks(ax, '2019-01-01', '2020-12-01', freq='3MS')
      

      或者如果你真的想变得奇怪,你可以做类似的事情

      fig, ax = plt.subplots(dpi=150)
      
      sns.heatmap(df, ax=ax)
      
      set_date_ticks(ax, '2019-06-01', '2020-06-01', freq='2MS', date_format='%b `%y')
      

      对于您的具体示例,您必须将axis='x' 传递给set_date_ticks

      【讨论】:

        【解决方案3】:

        我有类似的问题,但日期是索引。我刚刚在绘图之前将日期转换为字符串(pandas 1.0),它对我有用。

        heat['date'] = heat.date.astype('string')
        

        【讨论】:

          【解决方案4】:

          您必须对数据框的日期系列使用 strftime 函数才能正确绘制 xtick 标签:

          import numpy as np
          import pandas as pd
          import matplotlib.pyplot as plt
          import seaborn as sns
          from datetime import datetime, timedelta
          import random
          
          dates = [datetime.today() - timedelta(days=x * random.getrandbits(1)) for x in xrange(25)]
          df = pd.DataFrame({'depth': [0.1,0.05, 0.01, 0.005, 0.001, 0.1, 0.05, 0.01, 0.005, 0.001, 0.1, 0.05, 0.01, 0.005, 0.001, 0.1, 0.05, 0.01, 0.005, 0.001, 0.1, 0.05, 0.01, 0.005, 0.001],\
           'date': dates,\
           'value': [-4.1808639999999997, -9.1753490000000006, -11.408113999999999, -10.50245, -8.0274750000000008, -0.72260200000000008, -6.9963940000000004, -10.536339999999999, -9.5440649999999998, -7.1964070000000007, -0.39225599999999999, -6.6216390000000001, -9.5518009999999993, -9.2924690000000005, -6.7605589999999998, -0.65214700000000003, -6.8852289999999989, -9.4557760000000002, -8.9364629999999998, -6.4736289999999999, -0.96481800000000006, -6.051482, -9.7846860000000007, -8.5710630000000005, -6.1461209999999999]})
          pivot = df.pivot(index='depth', columns='date', values='value')
          
          sns.set()
          ax = sns.heatmap(pivot)
          ax.set_xticklabels(df['date'].dt.strftime('%d-%m-%Y'))
          plt.xticks(rotation=-90)
          
          plt.show()
          

          【讨论】:

          • 现在给出ValueError: The number of FixedLocator locations (13), usually from a call to set_ticks, does not match the number of ticklabels (25).,所以不确定它是否完全正确...
          猜你喜欢
          • 2021-04-07
          • 2018-08-10
          • 1970-01-01
          • 2016-03-17
          • 2021-08-03
          • 2018-01-02
          • 1970-01-01
          • 2021-03-10
          相关资源
          最近更新 更多