python处理数据与数据可视化遥感

Python实现彩色散点图绘制(利用色带对散点图进行颜色渲染)

2020-05-27  本文已影响0人  zengsk
image

接受自己的普通,然后全力以赴的出众,告诉自己要努力,但不要着急....

前言

数据组织

简单散点图绘制代码

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Name   : simple_scatter.py
# Author : zengsk in NanJing
# Created: 2019/12/14 17:16

"""
Details: 不带颜色渲染的散点图绘制 (包含多个子图)
"""

import numpy as np
import matplotlib.pyplot as plt


def draw_scatter(x, y, marker_size=1, savefig_name=""):
    # 创建画图窗口
    fig = plt.figure(1, figsize=(8, 8))
    # 将画图窗口分成2x2, 选择第一块区域作子图
    subplot1 = fig.add_subplot(2, 2, 1)
    # 画散点图
    subplot1.scatter(x, y, s=marker_size, c='k', marker='.')
    # 画参考线
    subplot1.plot((0, 300), (0, 300), linestyle="--", linewidth=0.8, color="b")
    # 调整坐标轴范围
    plt.xlim((0, 300))
    plt.ylim((0, 300))
    # 设置坐标轴刻度
    xticks = np.arange(0, 301, 50)
    yticks = np.arange(0, 301, 50)
    plt.xticks(xticks)
    plt.yticks(yticks)
    # 设置标题
    subplot1.set_title('Scatter Plot')
    # 设置坐标轴名称
    subplot1.set_xlabel('Observation')
    subplot1.set_ylabel('Estimate')
    # 添加网格线
    plt.grid(linestyle='--', color='grey')
    # 全局修改字体
    plt.rc('font', family='Times New Roman')

    # save figure
    fig.tight_layout()
    if "" != savefig_name.strip():
        plt.savefig(savefig_name, dpi=600)
    plt.show()


# 主模块
if __name__ == "__main__":
    # 加载数据
    url = r"E:\Scripts\Test\scatter\data\estimate3.csv"
    data = np.loadtxt(url, delimiter=',', skiprows=1)
    x = data[:, 1]
    y = data[:, 2]
    draw_scatter(x, y, savefig_name="E:\Scripts\Test\scatter\data\scatter.jpg")
image

当然, 这个结果并不是我真正想要的,Pass, 太丑了!

image

好吧,安排,我们先看下实现后的效果!

image

这个效果自然就比之前的好多了!

下面介绍一下实现的思路和细节(自己在写代码的时候还是发现了很多坑)

实现python散点图绘制需要用到matplotlib库,matplotlib库是专门用于可视化绘图的工具库;学习一个新的库当然看官方文档了:https://www.osgeo.cn/matplotlib/contents.html

实现思路:

image
散点密度计算如下:
def density_calc(x, y, radius):
    """
    散点密度计算(以便给散点图中的散点密度进行颜色渲染)
    :param x:
    :param y:
    :param radius:
    :return:  数据密度
    """
    res = np.empty(len(x), dtype=np.float32)
    for i in range(len(x)):
        print(i)
        res[i] = np.sum((x > (x[i] - radius)) & (x < (x[i] + radius))
                        & (y > (y[i] - radius)) & (y < (y[i] + radius)))
    return res

matplotlib.pyplot.scatter()函数是专门绘制散点图的函数:https://www.osgeo.cn/matplotlib/api/_as_gen/matplotlib.pyplot.scatter.html?highlight=scatter#matplotlib.pyplot.scatter

matplotlib.pyplot.scatter(x, y, s=None, c=None, marker=None, cmap=None, norm=None, vmin=None, vmax=None, alpha=None, linewidths=None, verts=None, edgecolors=None, ***, data=None, **kwargs) **

image image

当我们通过上面的density_calc()函数计算得到每个样本点的散点密度Z1时,就可以根据scatter函数进行彩色散点图的绘制,那么如何根据计算的散点密度与色带colormap的颜色进行一一映射呢,需要设置三个参数:c、cmap、norm,具体参数设置如下:

plt.scatter(observation, estimate, c=Z1, cmap=colormap, marker=".", s=marker_size, norm=colors.LogNorm(vmin=Z1.min(), vmax=0.5 * Z1.max()))
其中:
1、c参数为计算的散点密度;
2、cmap为色带(matplotlib里面自带了很多色带可供选择),参见:
https://www.osgeo.cn/matplotlib/gallery/color/colormap_reference.html
3、由于计算的散点密度数值大小分散,因此利用norm参数对散点密度Z1进行归一化处理(归一化方式很多,参见colors类),并给归一化方式设置色带刻度的最大最小值vmin和vmax(一般这两个参数就是指定散点密度的最小值和最大值),这样就建立起了密度与色带的映射关系。
https://matplotlib.org/tutorials/colors/colormapnorms.html

不知道我这个通俗的解释能否看懂,语言表达能力就这样了!!!

完整代码如下:(这里展示了同时绘制三个子图的写法)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Name   : scatter_render_main2.py
# Author : zengsk in NanJing
# Created: 2019/12/11 12:46

"""
Details:  散点图绘制
"""
import time
import numpy as np
import pandas as pd
import matplotlib.colors as colors
import matplotlib.pyplot as plt


def density_calc(x, y, radius):
    """
    散点密度计算(以便给散点图中的散点密度进行颜色渲染)
    :param x:
    :param y:
    :param radius:
    :return:  数据密度
    """
    res = np.empty(len(x), dtype=np.float32)
    for i in range(len(x)):
        print(i)
        res[i] = np.sum((x > (x[i] - radius)) & (x < (x[i] + radius))
                        & (y > (y[i] - radius)) & (y < (y[i] + radius)))
    return res


# Script Start...
start = time.process_time()

url_i = r"E:\Scripts\Test\scatter\data\estimate1.csv"
url_ii = r"E:\Scripts\Test\scatter\data\estimate2.csv"
url_iii = r"E:\Scripts\Test\scatter\data\estimate3.csv"
savefig_name = r"E:\Scripts\Test\scatter\data\scatter_render3.jpg"

# ------------ read data  -----------------
matrix_i = pd.read_csv(url_i).values
sevp_i = matrix_i[:, 1]   # 观测数据
estimate_i = matrix_i[:, 2]  # 预测数据

matrix_ii = pd.read_csv(url_ii).values
sevp_ii = matrix_ii[:, 1]
estimate_ii = matrix_ii[:, 2]

matrix_iii = pd.read_csv(url_iii).values
sevp_iii = matrix_iii[:, 1]
estimate_iii = matrix_iii[:, 2]

# ----------- Define Parameters ------------
radius = 3  # 半径
colormap = plt.get_cmap("jet")  # 色带
marker_size = 1  # 散点大小
xrange = [0, 350]
yrange = [0, 350]
xticks = np.linspace(0, 350, 8)
yticks = np.linspace(0, 350, 8)
xlabel = "Observation"
ylabel_i = "Estimate-1"
ylabel_ii = "Estimate-2"
ylabel_iii = "Estimate-3"
cbar_ticks = [10**0, 10**1, 10**2, 10**3, 10**4, 10**5]
font = {'family': 'Times New Roman',
        'weight': 'bold',
        'size': 7}

# -----------------  Plot Start  -----------------
fig = plt.figure(1, facecolor="grey")

# ---------------  sub plot no.1  ----------------
plt.subplot(1, 3, 1, aspect="equal")
Z1 = density_calc(sevp_i, estimate_i, radius)
plt.scatter(sevp_i, estimate_i, c=Z1, cmap=colormap, marker=".", s=marker_size,
            norm=colors.LogNorm(vmin=Z1.min(), vmax=0.5 * Z1.max()))
plt.xlim(xrange)
plt.ylim(yrange)
plt.xticks(xticks, fontproperties='Times New Roman', size=7)
plt.yticks(yticks, fontproperties='Times New Roman', size=7)
plt.xlabel(xlabel, fontdict=font)
plt.ylabel(ylabel_i, fontdict=font)
plt.grid(linestyle='--', color="grey")
plt.plot(xrange, yrange, color="k", linewidth=0.8, linestyle='--')
plt.rc('font', **font)
# color bar
cbar = plt.colorbar(orientation='horizontal', extend="both", pad=0.1)  # 显示色带
cbar.set_label("Scatter Density", fontdict=font)
cbar.set_ticks(cbar_ticks)
cbar.ax.tick_params(which="major", direction="in", length=2, labelsize=6)  # 主刻度
cbar.ax.tick_params(which="minor", direction="in", length=0)  # 副刻度

# ---------------  sub plot no.2  ----------------
plt.subplot(1, 3, 2, aspect="equal")
Z2 = density_calc(sevp_ii, estimate_ii, radius)
plt.scatter(sevp_ii, estimate_ii, c=Z2, cmap=colormap, marker=".", s=marker_size,
            norm=colors.LogNorm(vmin=Z2.min(), vmax=Z2.max()))
plt.xlim(xrange)
plt.ylim(yrange)
plt.xticks(xticks)
plt.yticks(yticks)
plt.xlabel(xlabel, fontsize=8)
plt.ylabel(ylabel_ii, fontsize=8)
plt.grid(linestyle='--', color="grey")
plt.plot(xrange, yrange, color="k", linewidth=0.8, linestyle='--')
plt.rc('font', **font)
# color bar
cbar = plt.colorbar(orientation='horizontal', extend="both", pad=0.1)  # 显示色带
cbar.set_label("Scatter Density", fontdict=font)
cbar.set_ticks(cbar_ticks)
cbar.ax.tick_params(which="major", direction="in", length=2, labelsize=6)  # 主刻度
cbar.ax.tick_params(which="minor", direction="in", length=0)  # 副刻度

# ---------------  sub plot no.3  ----------------
plt.subplot(1, 3, 3, aspect="equal")
Z3 = density_calc(sevp_iii, estimate_iii, radius)
plt.scatter(sevp_iii, estimate_iii, c=Z3, cmap=colormap, marker=".", s=marker_size,
            norm=colors.LogNorm(vmin=Z3.min(), vmax=Z3.max()))
plt.xlim(xrange)
plt.ylim(yrange)
plt.xticks(xticks)
plt.yticks(yticks)
plt.xlabel(xlabel, fontsize=8)
plt.ylabel(ylabel_iii, fontsize=8)
plt.grid(linestyle='--', color="grey")
plt.plot(xrange, yrange, color="k", linewidth=0.8, linestyle='--')
plt.rc('font', **font)

# color bar
cbar = plt.colorbar(orientation='horizontal', extend="both", pad=0.1)  # 显示色带
cbar.set_label("Scatter Density", fontdict=font)
cbar.set_ticks(cbar_ticks)
cbar.ax.tick_params(which="major", direction="in", length=2, labelsize=6)  # 主刻度
cbar.ax.tick_params(which="minor", direction="in", length=0)  # 副刻度

# save figure
fig.tight_layout()
plt.savefig(savefig_name, dpi=600)
plt.show()

elapsed = time.process_time() - start
print("This program totally costs {0} seconds!".format(elapsed))
print(" .... All is OK!!")

结果展示

(这里的结果与前面展示的相比改变了计算散点密度的半径:radius = 3以及绘制散点图的散点大小marksize)

image

作者能力水平有限,欢迎各位批评指正!

欢迎各位同行移步扫码关注作者公众号---ZENG同学,留言作者会给大家解读科研中自己爬过得坑!作者水平有限, 欢迎交流指正....

image
上一篇下一篇

猜你喜欢

热点阅读