热图中的日期轴 seaborn

Posted

技术标签:

【中文标题】热图中的日期轴 seaborn【英文标题】:Date axis in heatmap 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']])

【问题讨论】:

【参考方案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-dT00: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_axisaxis')()
        
        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_axisticks')(ax_transformer.transform(dt_rng))
    getattr(ax, f'set_axisticklabels')(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).,所以不确定它是否完全正确...

以上是关于热图中的日期轴 seaborn的主要内容,如果未能解决你的问题,请参考以下文章

通过 geom_tile ggplot R 的热图 - 正确组织每月因子的 y 轴水平

基于非数字第三变量的热图轴重新排序 - ggplot2

更改seaborn热图的轴标签[重复]

seaborn热图y轴逆序

当x轴为时间格式(HH:MM)时,Highchart的热图图无法正确渲染

使用 Seaborn 和 Matplotlib 在热图和线图的共享子图中对齐 x 轴刻度