34.35.热图(heatmap)、创建带注释的热图、使用辅助函数的代码样式、图像显示、图像插值、将图像数据导入Numpy数组、将numpy数组绘制为图像

34.热图(heatmap)
34.1.创建带注释的热图
34.2.使用辅助函数的代码样式
35.图像显示
35.1.图像插值
35.2.将图像数据导入Numpy数组
35.3.将numpy数组绘制为图像

34.热图(heatmap)

34.1.创建带注释的热图

将依赖于两个自变量的数据显示为彩色图像图,通常称为热图。如果数据是分类的,则将其称为分类热图。 Matplotlib的imshow函数使这种绘图的制作特别容易。

以下示例显示了如何创建带有注释的热图。我们将从一个简单的分类热图开始。

我们可以从定义一些数据开始。我们需要一个2D列表或数组,用于将数据定义为颜色代码。然后,我们还需要两个列表或类别数组;当然,这些列表中的元素数量需要与各个轴上的数据匹配。

热图本身是一个imshow图,其标签设置为拥有的类别。请注意,必须同时设置刻度位置(set_xticks)和刻度标签(set_xticklabels),否则它们将变得不同步。位置只是升序的整数,而ticklabels是要显示的标签。最后,可以通过在每个单元格中创建一个显示该单元格值的文本来标记数据本身。

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

vegetables = ["cucumber", "tomato", "lettuce", "asparagus",
              "potato", "wheat", "barley"]
farmers = ["Farmer Joe", "Upland Bros.", "Smith Gardening",
           "Agrifun", "Organiculture", "BioGoods Ltd.", "Cornylee Corp."]

harvest = np.array([[0.8, 2.4, 2.5, 3.9, 0.0, 4.0, 0.0],
                    [2.4, 0.0, 4.0, 1.0, 2.7, 0.0, 0.0],
                    [1.1, 2.4, 0.8, 4.3, 1.9, 4.4, 0.0],
                    [0.6, 0.0, 0.3, 0.0, 3.1, 0.0, 0.0],
                    [0.7, 1.7, 0.6, 2.6, 2.2, 6.2, 0.0],
                    [1.3, 1.2, 0.0, 0.0, 0.0, 3.2, 5.1],
                    [0.1, 2.0, 0.0, 1.4, 0.0, 1.9, 6.3]])

plt.figure(figsize=(16,16))
fig, ax = plt.subplots()
im = ax.imshow(harvest)

# We want to show all ticks...
ax.set_xticks(np.arange(len(farmers)))
ax.set_yticks(np.arange(len(vegetables)))
# ... and label them with the respective list entries
ax.set_xticklabels(farmers)
ax.set_yticklabels(vegetables)

# Rotate the tick labels and set their alignment.
plt.setp(ax.get_xticklabels(), rotation=45, ha="right",
         rotation_mode="anchor")

# Loop over data dimensions and create text annotations.
for i in range(len(vegetables)):
    for j in range(len(farmers)):
        text = ax.text(j, i, harvest[i, j],
                       ha="center", va="center", color="w")

ax.set_title("Harvest of local farmers (in tons/year)")
#fig.tight_layout()
plt.show()

在这里插入图片描述

34.2.使用辅助函数的代码样式

人们可能想重用这种代码来为不同的输入数据和/或在不同的轴上创建某种热图。 我们创建一个函数,该函数将数据以及行和列标签作为输入,并允许使用用于自定义绘图的参数

在这里,除了上面的内容外,我们还希望创建一个颜色栏,并将标签放置在热图上方而不是其下方。 注释将根据阈值获得不同的颜色,以更好地与像素颜色形成对比。 最后,我们将周围的轴旋转并创建白线网格以分隔单元格。

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


def heatmap(data, row_labels, col_labels, ax=None,
            cbar_kw={}, cbarlabel="", **kwargs):
    """
    Create a heatmap from a numpy array and two lists of labels.

    Parameters
    ----------
    data
        A 2D numpy array of shape (N, M).
    row_labels
        A list or array of length N with the labels for the rows.
    col_labels
        A list or array of length M with the labels for the columns.
    ax
        A `matplotlib.axes.Axes` instance to which the heatmap is plotted.  If
        not provided, use current axes or create a new one.  Optional.
    cbar_kw
        A dictionary with arguments to `matplotlib.Figure.colorbar`.  Optional.
    cbarlabel
        The label for the colorbar.  Optional.
    **kwargs
        All other arguments are forwarded to `imshow`.
    """

    if not ax:
        ax = plt.gca()

    # Plot the heatmap
    im = ax.imshow(data, **kwargs)

    # Create colorbar
    cbar = ax.figure.colorbar(im, ax=ax, **cbar_kw)
    cbar.ax.set_ylabel(cbarlabel, rotation=-90, va="bottom")

    # We want to show all ticks...
    ax.set_xticks(np.arange(data.shape[1]))
    ax.set_yticks(np.arange(data.shape[0]))
    # ... and label them with the respective list entries.
    ax.set_xticklabels(col_labels)
    ax.set_yticklabels(row_labels)

    # Let the horizontal axes labeling appear on top.
    ax.tick_params(top=True, bottom=False,
                   labeltop=True, labelbottom=False)

    # Rotate the tick labels and set their alignment.
    plt.setp(ax.get_xticklabels(), rotation=-30, ha="right",
             rotation_mode="anchor")

    # Turn spines off and create white grid.
    for edge, spine in ax.spines.items():
        spine.set_visible(False)

    ax.set_xticks(np.arange(data.shape[1] + 1) - .5, minor=True)
    ax.set_yticks(np.arange(data.shape[0] + 1) - .5, minor=True)
    ax.grid(which="minor", color="w", linestyle='-', linewidth=3)
    ax.tick_params(which="minor", bottom=False, left=False)

    return im, cbar


def annotate_heatmap(im, data=None, valfmt="{x:.2f}",
                     textcolors=["black", "white"],
                     threshold=None, **textkw):
    """
    A function to annotate a heatmap.

    Parameters
    ----------
    im
        The AxesImage to be labeled.
    data
        Data used to annotate.  If None, the image's data is used.  Optional.
    valfmt
        The format of the annotations inside the heatmap.  This should either
        use the string format method, e.g. "$ {x:.2f}", or be a
        `matplotlib.ticker.Formatter`.  Optional.
    textcolors
        A list or array of two color specifications.  The first is used for
        values below a threshold, the second for those above.  Optional.
    threshold
        Value in data units according to which the colors from textcolors are
        applied.  If None (the default) uses the middle of the colormap as
        separation.  Optional.
    **kwargs
        All other arguments are forwarded to each call to `text` used to create
        the text labels.
    """

    if not isinstance(data, (list, np.ndarray)):
        data = im.get_array()

    # Normalize the threshold to the images color range.
    if threshold is not None:
        threshold = im.norm(threshold)
    else:
        threshold = im.norm(data.max()) / 2.

    # Set default alignment to center, but allow it to be
    # overwritten by textkw.
    kw = dict(horizontalalignment="center",
              verticalalignment="center")
    kw.update(textkw)

    # Get the formatter in case a string is supplied
    if isinstance(valfmt, str):
        valfmt = matplotlib.ticker.StrMethodFormatter(valfmt)

    # Loop over the data and create a `Text` for each "pixel".
    # Change the text's color depending on the data.
    texts = []
    for i in range(data.shape[0]):
        for j in range(data.shape[1]):
            kw.update(color=textcolors[int(im.norm(data[i, j]) > threshold)])
            text = im.axes.text(j, i, valfmt(data[i, j], None), **kw)
            texts.append(text)

    return texts


vegetables = ["cucumber", "tomato", "lettuce", "asparagus",
              "potato", "wheat", "barley"]
farmers = ["Farmer Joe", "Upland Bros.", "Smith Gardening",
           "Agrifun", "Organiculture", "BioGoods Ltd.", "Cornylee Corp."]

harvest = np.array([[0.8, 2.4, 2.5, 3.9, 0.0, 4.0, 0.0],
                    [2.4, 0.0, 4.0, 1.0, 2.7, 0.0, 0.0],
                    [1.1, 2.4, 0.8, 4.3, 1.9, 4.4, 0.0],
                    [0.6, 0.0, 0.3, 0.0, 3.1, 0.0, 0.0],
                    [0.7, 1.7, 0.6, 2.6, 2.2, 6.2, 0.0],
                    [1.3, 1.2, 0.0, 0.0, 0.0, 3.2, 5.1],
                    [0.1, 2.0, 0.0, 1.4, 0.0, 1.9, 6.3]])

fig, ax = plt.subplots()

im, cbar = heatmap(harvest, vegetables, farmers, ax=ax,
                   cmap="YlGn", cbarlabel="harvest [t/year]")
texts = annotate_heatmap(im, valfmt="{x:.1f} t")

fig.tight_layout()
plt.show()

在这里插入图片描述

35.图像显示

在Matplotlib中绘制图像的最常见的方法是使用imshow().

另外,PIL(Python Imaging Library)是Python常用的图像处理库,而Pillow是PIL的一个友好Fork,提供了广泛的文件格式支持,强大的图像处理能力,主要包括图像储存、图像显示、格式转换以及基本的图像处理操作等。

35.1.图像插值

在显示图像之前可以对图像进行插值。 在下面,我们将显示相同的数组,并使用三种不同的插值方法进行插值。

A[i,j]处的像素中心绘制在i + 0.5,i + 0.5处。 如果使用interpolation=‘nearest’,则由(i,j) 和 (i+1,j+1)界定的区域将具有相同的颜色。 如果使用插值,则像素中心的颜色将与最接近的颜色相同,但是其他像素将在相邻像素之间插值。

为了防止在进行插值时产生边缘效应,Matplotlib将输入数组的边缘填充相同的像素:如果有一个5x5数组,其颜色为a-y,如下所示:
在这里插入图片描述
Matplotlib计算插值并在填充数组上调整大小
在这里插入图片描述
然后提取结果的中心区域。

这种方法可以绘制一个数组的整个范围而没有边缘效应,例如,可以使用不同的插值方法将多个具有不同大小的图像相互层叠。 复杂的内插还意味着性能下降; 为了获得最佳性能或非常大的图像,建议使用插值interpolation=‘nearest’。

import numpy as np
import matplotlib.pyplot as plt

A = np.random.rand(5, 5)

fig, axs = plt.subplots(1, 3, figsize=(10, 3))
for ax, interp in zip(axs, ['nearest', 'bilinear', 'bicubic']):
    ax.imshow(A, interpolation=interp)
    ax.set_title(interp.capitalize())
    ax.grid(True)

plt.show()

在这里插入图片描述

35.2.将图像数据导入Numpy数组

Pillow库支持加载图像数据。

这是一个24位 RGB PNG图像(R,G,B分别为8比特)。 根据获取的数据位置,还有可能会遇到的其他类型的图像,如RGBA图像,该图像允许透明或单通道灰度(亮度)图像。

import matplotlib.image as mpimg

img = mpimg.imread('cat.png')
print(img)
输出结果:
[[[0. 0. 0. 0.]
  [0. 0. 0. 0.]
  [0. 0. 0. 0.]
  ...
  [0. 0. 0. 0.]
  [0. 0. 0. 0.]
  [0. 0. 0. 0.]]

 [[0. 0. 0. 0.]
  [0. 0. 0. 0.]
  [0. 0. 0. 0.]
  ...
  [0. 0. 0. 0.]
  [0. 0. 0. 0.]
  [0. 0. 0. 0.]]

 [[0. 0. 0. 0.]
  [0. 0. 0. 0.]
  [0. 0. 0. 0.]
  ...
  [0. 0. 0. 0.]
  [0. 0. 0. 0.]
  [0. 0. 0. 0.]]

 ...

 [[0. 0. 0. 0.]
  [0. 0. 0. 0.]
  [0. 0. 0. 0.]
  ...
  [0. 0. 0. 0.]
  [0. 0. 0. 0.]
  [0. 0. 0. 0.]]

 [[0. 0. 0. 0.]
  [0. 0. 0. 0.]
  [0. 0. 0. 0.]
  ...
  [0. 0. 0. 0.]
  [0. 0. 0. 0.]
  [0. 0. 0. 0.]]

 [[0. 0. 0. 0.]
  [0. 0. 0. 0.]
  [0. 0. 0. 0.]
  ...
  [0. 0. 0. 0.]
  [0. 0. 0. 0.]
  [0. 0. 0. 0.]]]

35.3.将numpy数组绘制为图像

将数据存储在numpy数组中(通过导入或生成), 然后渲染它。 在Matplotlib中,这是使用imshow()函数执行的。 在这里,我们使用了plot对象。

import matplotlib.pyplot as plt
import matplotlib.image as mpimg

img = mpimg.imread('cat.png')
print(img)

imgplot = plt.imshow(img)
plt.show()
from PIL import Image
import matplotlib.pyplot as plt
img = Image.open('cat.png')
# img = mping.imread('cat.png')
gray = img.convert('L')    # 其中img.convert指定一种色彩模式:L (8-bit pixels, black and white)
# 分离rgba
r, g, b, a  = img.split()
plt.figure("girl")

def setPlot(num, title):
    # subplot(nrows, ncols, plot_number)
    # 图表的整个绘图区域被等分为numRows行和numCols列,然后按照从左到右、从上到下的顺序对每个区域进行编号,左上区域的编号为1
    plt.subplot(2, 3, num)
    plt.title(title)
    plt.axis('off')

setPlot(1, 'origin')
plt.imshow(img)

setPlot(2, 'gray')
plt.imshow(gray, cmap='gray')

setPlot(3, 'gray')
plt.imshow(gray, cmap='gray')

setPlot(3,'rgba')
# 合并rgba
plt.imshow(Image.merge('RGBA', (r, g, b, a)))

setPlot(4, 'r')
plt.imshow(r)

setPlot(5, 'g')
plt.imshow(g)

setPlot(6, 'b')
plt.imshow(b)

plt.show()

在这里插入图片描述

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

涂作权的博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值