如何在matplotlib中格式化热图的x轴?

huangapple go评论71阅读模式
英文:

How to format the x-axis of a heat map in matplotlib?

问题

I can help you translate the code-related portion. Here's the translated code:

我正在尝试自定义x轴上的标签/刻度使其看起来像我之前创建的另一个图表

import matplotlib as mplt
from matplotlib import dates, pyplot
from matplotlib.transforms import ScaledTranslation
import numpy as np
import pandas as pd
import datetime

s_names = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # 类别
dates_ = pd.date_range('2023/01/01', '2023/01/08', freq='3H', tz='utc') # 创建日期时间索引的列表。
matrix = pd.DataFrame(columns=s_names, index=dates_) # 初始化数据框。

matrix = matrix.applymap(lambda l: l if not np.isnan(l) else np.random.choice(range(1, 10))) # 用随机数替换数据框中的nan值。

matrix.sort_values(by=matrix.index[0], ascending=True, axis=1, inplace=True) # 按第一个日期(行)排序,列按从低到高排序。

params = {"ytick.color" : "b",
          "xtick.color" : "b",
          "axes.labelcolor" : "w",
          "axes.edgecolor" : "w"}

pyplot.rcParams.update(params)
fig, ax = pyplot.subplots(figsize = (14, 4))
ax = pyplot.gca();
extent = (0, matrix.shape[0], matrix.shape[1], 0)
ax.imshow(matrix.transpose(), cmap=pyplot.cm.RdYlGn)

ax.set_yticks(np.arange(len(s_names)), labels = list(matrix.columns))
ax.set_yticks(np.arange(-0.5, len(s_names),1), minor=True)
ax.set_xticks(np.arange(-0.5, len(dates_),1), minor=True)
pyplot.xticks(rotation=90)

ax.set_aspect(1)
ax.grid(color="w", linewidth=3, which='minor')

If you have any further questions or need additional translations, please let me know.

英文:

I'm trying to customize the labels / ticks on the x-axis here to look like another plot I had created:

import matplotlib as mplt
from matplotlib import dates, pyplot
from matplotlib.transforms import ScaledTranslation
import numpy as np
import pandas as pd
import datetime

s_names = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # categories
dates_ = pd.date_range('2023/01/01', '2023/01/08', freq='3H', tz='utc') # Creating a list of date time for index.
matrix = pd.DataFrame(columns=s_names, index=dates_) # initializing the df.

matrix = matrix.applymap(lambda l: l if not np.isnan(l) else np.random.choice(range(1, 10))) # replacing nan in the df with random number.

matrix.sort_values(by=matrix.index[0], ascending=True, axis=1, inplace=True) # Sorting by the first date (row), columns get ordered in from lowest to highest.

params = {"ytick.color" : "b",
          "xtick.color" : "b",
          "axes.labelcolor" : "w",
          "axes.edgecolor" : "w"}

pyplot.rcParams.update(params)
fig, ax = pyplot.subplots(figsize = (14, 4))
ax = pyplot.gca();
extent = (0, matrix.shape[0], matrix.shape[1], 0)
ax.imshow(matrix.transpose(), cmap=pyplot.cm.RdYlGn)

ax.set_yticks(np.arange(len(s_names)), labels = list(matrix.columns))
ax.set_yticks(np.arange(-0.5, len(s_names),1), minor=True)
ax.set_xticks(np.arange(-0.5, len(dates_),1), minor=True)
pyplot.xticks(rotation=90)


ax.set_aspect(1)
ax.grid(color="w", linewidth=3, which='minor')

This results in:
如何在matplotlib中格式化热图的x轴?

What I'm trying to get to for the x-axis:
如何在matplotlib中格式化热图的x轴?

答案1

得分: 1

以下是翻译好的代码部分:

import matplotlib as mplt
from matplotlib import dates, pyplot
from matplotlib.transforms import ScaledTranslation
import numpy as np
import pandas as pd
import datetime

s_names = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]  # 类别

# 为索引创建日期时间列表。
dates_ = pd.date_range('2023/01/01', '2023/01/08', freq='3H', tz='utc')
matrix = pd.DataFrame(columns=s_names, index=dates_)  # 初始化数据框。

# 用随机数替换数据框中的NaN值。
matrix = matrix.applymap(
    lambda l: l if not np.isnan(l) else np.random.choice(range(1, 10))
)

# 按照第一个日期(行)排序,列按从最低到最高的顺序排列。
matrix.sort_values(by=matrix.index[0], ascending=True, axis=1, inplace=True)

params = {"ytick.color": "b",
          "xtick.color": "b",
          "axes.labelcolor": "w",
          "axes.edgecolor": "w"}

pyplot.rcParams.update(params)

fig, ax = pyplot.subplots(figsize=(14, 4))

extent = (0, matrix.shape[0], matrix.shape[1], 0)

ax = pyplot.gca()
ax.imshow(matrix.transpose().sum().to_frame().T, cmap=pyplot.cm.RdYlGn)
# ax.set_yticks(np.arange(len(s_names)), labels=list(matrix.columns))
# ax.set_yticks(np.arange(-0.5, len(s_names), 1), minor=True)
ax.set_yticks([])
ax.set_xticks([])

pos = []
days = []
prev = None
days_labels = (
    dates_.to_series().dt.day.astype(str)
    + ' '
    + dates_.to_series().dt.month_name().str[:3]
).values

for i, dm in enumerate(days_labels):
    if dm != prev:
        pos.append(i)
        prev = dm
        days.append(prev)

pos.append(len(days_labels))
pos = np.array(pos) - 0.5

# 创建垂直线,以分隔每一天
ax.vlines(pos, 0, -1, color='blue', lw=0.8, clip_on=False,
          transform=ax.get_xaxis_transform())

hours_vlines = []
for day, pos0, pos1 in zip(days, pos[:-1], pos[1:]):
    # 添加日期标签
    ax.text((pos0 + pos1) / 2, -0.8, day, ha='center', clip_on=False,
            transform=ax.get_xaxis_transform(), color='blue', fontweight='bold')

    # pos1和pos0表示两个连续日期的x轴位置。
    # 我们希望为每一天创建3条垂直线,在6点、12点和18点。
    # 因此,我们需要在以下位置添加小时标签:
    # - 06:00:00 -> pos0 + (pos1 - pos0) / 24 * 6
    # - 12:00:00 -> pos0 + (pos1 - pos0) / 24 * 12
    # - 18:00:00 -> pos0 + (pos1 - pos0) / 24 * 18
    step = (pos1 - pos0) / 24

    for i, hour in enumerate(['06:00:00', '12:00:00', '18:00:00']):
        hp = pos0 + step * ((i + 1) * 6)
        hours_vlines.append(hp)
        ax.text(hp, -0.4, hour, ha='center', clip_on=False,
                transform=ax.get_xaxis_transform(), color='blue', fontsize='x-small')

# 在每一天的每个小时处创建x轴小时刻度,用于小时
# 06:00:00、12:00:00和18:00:00
ax.vlines(hours_vlines, 0, -0.1, color='blue', lw=0.8, clip_on=False,
          transform=ax.get_xaxis_transform())

ax.set_xlim(pos[0], pos[-1])

# 显示绘图
plt.tight_layout()
plt.show()

第二部分代码的翻译与第一部分相似,因此不再重复提供翻译。

英文:

Assuming your desired plot has only one row that equals the sum of all values for each given hour, you could use something like this:

import matplotlib as mplt
from matplotlib import dates, pyplot
from matplotlib.transforms import ScaledTranslation
import numpy as np
import pandas as pd
import datetime


s_names = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]  # categories

# Creating a list of date time for an index.
dates_ = pd.date_range('2023/01/01', '2023/01/08', freq='3H', tz='utc')
matrix = pd.DataFrame(columns=s_names, index=dates_)  # initializing the df.

# replacing nan in the df with a random number.
matrix = matrix.applymap(
    lambda l: l if not np.isnan(l) else np.random.choice(range(1, 10))
)

# Sorting by the first date (row), columns get ordered in from lowest to highest
matrix.sort_values(by=matrix.index[0], ascending=True, axis=1, inplace=True)

params = {"ytick.color": "b",
          "xtick.color": "b",
          "axes.labelcolor": "w",
          "axes.edgecolor": "w"}

pyplot.rcParams.update(params)

fig, ax = pyplot.subplots(figsize=(14, 4))

extent = (0, matrix.shape[0], matrix.shape[1], 0)

ax = pyplot.gca()
ax.imshow(matrix.transpose().sum().to_frame().T, cmap=pyplot.cm.RdYlGn)
# ax.set_yticks(np.arange(len(s_names)), labels=list(matrix.columns))
# ax.set_yticks(np.arange(-0.5, len(s_names), 1), minor=True)
ax.set_yticks([])
ax.set_xticks([])

pos = []
days = []
prev = None
days_labels = (
    dates_.to_series().dt.day.astype(str)
    + ' '
    + dates_.to_series().dt.month_name().str[:3]
).values

for i, dm in enumerate(days_labels):
    if dm != prev:
        pos.append(i)
        prev = dm
        days.append(prev)

pos.append(len(days_labels))
pos = np.array(pos) - 0.5

# Create the vertical lines, to separate days
ax.vlines(pos, 0, -1, color='blue', lw=0.8, clip_on=False,
          transform=ax.get_xaxis_transform())

hours_vlines = []
for day, pos0, pos1 in zip(days, pos[:-1], pos[1:]):
    # Add the day labels
    ax.text((pos0 + pos1) / 2, -0.8, day, ha='center', clip_on=False,
            transform=ax.get_xaxis_transform(), color='blue', fontweight='bold')

    # pos1 and pos0 represent the x-axis position of two consecutive days.
    # We want to create 3 vertical lines for each day, at 6, 12 and 18 hours.
    # So we need to add the hours' labels at:
    # - 06:00:00 -> pos0 + (pos1 - pos0) / 24 * 6
    # - 12:00:00 -> pos0 + (pos1 - pos0) / 24 * 12
    # - 18:00:00 -> pos0 + (pos1 - pos0) / 24 * 18
    step = (pos1 - pos0) / 24

    for i, hour in enumerate(['06:00:00', '12:00:00', '18:00:00']):
        hp = pos0 + step * ((i + 1) * 6)
        hours_vlines.append(hp)
        ax.text(hp, -0.4, hour, ha='center', clip_on=False,
                transform=ax.get_xaxis_transform(), color='blue', fontsize='x-small')

# Create the x-axis hours ticks at each day, for the hours
# 06:00:00, 12:00:00 and 18:00:00
ax.vlines(hours_vlines, 0, -0.1, color='blue', lw=0.8, clip_on=False,
          transform=ax.get_xaxis_transform())

ax.set_xlim(pos[0], pos[-1])

# Show the plot
plt.tight_layout()
plt.show()

Output:

如何在matplotlib中格式化热图的x轴?

If you're not trying to aggregate the values from each hour, and instead simply create a 2-level x-axis ticks, you could use something like:

import matplotlib as mplt
from matplotlib import dates, pyplot
from matplotlib.transforms import ScaledTranslation
import numpy as np
import pandas as pd
import datetime


s_names = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]  # categories

# Creating a list of date time for an index.
dates_ = pd.date_range('2023/01/01', '2023/01/08', freq='3H', tz='utc')
matrix = pd.DataFrame(columns=s_names, index=dates_)  # initializing the df.

# replacing nan in the df with a random number.
matrix = matrix.applymap(
    lambda l: l if not np.isnan(l) else np.random.choice(range(1, 10))
)

# Sorting by the first date (row), columns get ordered in from lowest to highest
matrix.sort_values(by=matrix.index[0], ascending=True, axis=1, inplace=True)

params = {"ytick.color": "b",
          "xtick.color": "b",
          "axes.labelcolor": "w",
          "axes.edgecolor": "w"}

pyplot.rcParams.update(params)

fig, ax = pyplot.subplots(figsize=(14, 4))

extent = (0, matrix.shape[0], matrix.shape[1], 0)

ax = pyplot.gca()
ax.imshow(matrix.transpose(), cmap=pyplot.cm.RdYlGn)
ax.set_yticks(np.arange(len(s_names)), labels=list(matrix.columns))
ax.set_yticks(np.arange(-0.5, len(s_names), 1), minor=True)
ax.set_xticks([])

pos = []
days = []
prev = None
days_labels = (
    dates_.to_series().dt.day.astype(str)
    + ' '
    + dates_.to_series().dt.month_name().str[:3]
).values

for i, dm in enumerate(days_labels):
    if dm != prev:
        pos.append(i)
        prev = dm
        days.append(prev)

pos.append(len(days_labels))
pos = np.array(pos) - 0.5

# Create the vertical lines, to separate days
ax.vlines(pos, 0, -0.15, color='blue', lw=0.8, clip_on=False,
          transform=ax.get_xaxis_transform())

hours_vlines = []
for day, pos0, pos1 in zip(days, pos[:-1], pos[1:]):
    # Add the day labels
    ax.text((pos0 + pos1) / 2, -0.12, day, ha='center', clip_on=False,
            transform=ax.get_xaxis_transform(), color='blue', fontweight='bold')

    # pos1 and pos0 represent the x-axis position of two consecutive days.
    # We want to create 3 vertical lines for each day, at 6, 12 and 18 hours.
    # So we need to add the hours' labels at:
    # - 06:00:00 -> pos0 + (pos1 - pos0) / 24 * 6
    # - 12:00:00 -> pos0 + (pos1 - pos0) / 24 * 12
    # - 18:00:00 -> pos0 + (pos1 - pos0) / 24 * 18
    step = (pos1 - pos0) / 24

    for i, hour in enumerate(['06:00:00', '12:00:00', '18:00:00']):
        hp = pos0 + step * ((i + 1) * 6)
        hours_vlines.append(hp)
        ax.text(hp, -0.06, hour, ha='center', clip_on=False,
                transform=ax.get_xaxis_transform(), color='blue', fontsize='x-small')

# Create the x-axis hours ticks at each day, for the hours
# 06:00:00, 12:00:00 and 18:00:00
ax.vlines(hours_vlines, 0, -0.01, color='blue', lw=0.8, clip_on=False,
          transform=ax.get_xaxis_transform())

ax.set_xlim(pos[0], pos[-1])

# Show the plot
plt.tight_layout()
plt.show()

Output:

如何在matplotlib中格式化热图的x轴?

Edit: Change vlines Position to the Centre of the Squares

To centralize the vlines and each square center, try this:

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


s_names = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]  # categories

# Creating a list of date time for an index.
dates_ = pd.date_range("2023/01/01", "2023/01/08", freq="3H", tz="utc")
matrix = pd.DataFrame(columns=s_names, index=dates_)  # initializing the df.

# replacing nan in the df with a random number.
matrix = matrix.applymap(
    lambda l: l if not np.isnan(l) else np.random.choice(range(1, 10))
)

# Sorting by the first date (row), columns get ordered in from lowest to highest
matrix.sort_values(by=matrix.index[0], ascending=True, axis=1, inplace=True)

params = {
    "ytick.color": "b",
    "xtick.color": "b",
    "axes.labelcolor": "w",
    "axes.edgecolor": "w",
}
pyplot.rcParams.update(params)

fig, ax = pyplot.subplots(figsize=(14, 4))

extent = (0, matrix.shape[0], matrix.shape[1], 0)
agg_matrix = matrix.transpose().sum().to_frame().T

ax = pyplot.gca()
ax.imshow(agg_matrix, cmap=pyplot.cm.RdYlGn)
ax.set_yticks([])
ax.set_xticks([])

days_vlines = []
hours_vlines = []
for i, dt in enumerate(agg_matrix.columns):
    if dt.hour in [6, 12, 18]:
        ax.text(
            i,
            -0.4,
            dt.strftime("%H:%M:%S"),
            ha="center",
            clip_on=False,
            transform=ax.get_xaxis_transform(),
            color="blue",
            fontsize="x-small",
        )
        hours_vlines.append(i)
    if dt.hour == 12:
        ax.text(
            i,
            -0.9,
            f"{dt.day} {dt.month_name()[:3]}",
            ha="center",
            clip_on=False,
            transform=ax.get_xaxis_transform(),
            color="blue",
            fontweight="bold",
        )
    if dt.hour == 0:
        days_vlines.append(i)

# Create the x-axis hours ticks at each day, for the hours
# 06:00:00, 12:00:00 and 18:00:00
ax.vlines(
    hours_vlines,
    0,
    -0.1,
    color="blue",
    lw=0.8,
    clip_on=False,
    transform=ax.get_xaxis_transform(),
)
ax.vlines(
    days_vlines, 0, -1, color="blue", lw=0.8, clip_on=False, transform=ax.get_xaxis_transform()
)

# Show the plot
plt.tight_layout()
plt.show()

Output:

如何在matplotlib中格式化热图的x轴?

For the first day:

如何在matplotlib中格式化热图的x轴?

huangapple
  • 本文由 发表于 2023年6月13日 13:32:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/76461924.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定