利用日历热力图可以方便的查看站点水质全年的变化情况。
接口获取站点数据
这一步根据自己实际情况,也可以读取excel、MySQL读取数据。这里把API地址已隐去。
import numpy as np
import calendar
import requests
import json
import pandas as pd
import time
from datetime import date, datetime, timedelta
import matplotlib.pyplot as plt
from matplotlib.pylab import style # 自定义图表风格
# style.use('ggplot')
# 解决中文乱码问题
plt.rcParams['font.sans-serif'] = ['Simhei']# 解决坐标轴刻度负号乱码
plt.rcParams['axes.unicode_minus'] = False
connect_table =pd.read_excel("设备因子对照.xls")
# 根据时间、站点名称参数获取API url
def url_ask(beginTime,endTime,mn,period):# beginTime 要拉取的数据开始时间节点(yyyy-MM-dd HH:mm:ss)# endTime = "2023-10-30 00:00:00" #前闭后开# mn 设备编码# page当前页码# 原始接口中包括page和pagesize 默认1和10000 # 这里需要注意 不宜太大,暂内存,二是如果查询内容过大则会超过1页,需要查询total page 字段的数字,并判断# period 时间周期,实时为空,但要带这个请求参数,1小时为h1,4小时为h4,天数据为d1 page ="1"pageSize ="10000"mianurl = " "ip_port = " " url =ip_port + mianurl+"beginTime="+beginTime+"&endTime="+endTime +"&mn="+mn +"&page="+page +"&period=" +period +"&pageSize="+pageSize# 发起API请求获取JSON数据return(url)
# 根据站点名称求编码
def seak_mn(ask_station):mn_text = connect_table.loc[connect_table['设备名称'] ==ask_station] mn = mn_text.mn.unique()[0]return(mn)period = "h4"
ask_station = '湾凼'
mn = seak_mn(ask_station)
url =url_ask('2023-01-01 00:00:00','2023-11-20 00:00:00',mn,period)# 根据URL 获取站点监测数据 未经降维
def mn_value(url):response = requests.get(url)response_data = response.json()data =response_data["data"]titles =data["titles"]titles= pd.DataFrame(titles)factor_code = titles["identifier"]factor_name = titles["name"]# 查询监测数据df_value =data["items"]df_value = pd.DataFrame(df_value,columns=factor_code)df_value.columns= factor_namedf_value.rename(columns={'上报时间': '监测时间'}, inplace=True)return(df_value)
df_value =mn_value(url)
df_value.tail()
输出数据结构如下:
进行站点等级评价
选择 '氨氮', '高锰酸盐指数', '总磷',作为评价因子,以地表水评价导则判断各因子的评价等级,
再按照因子评价等级最高的最为站点评价等级。
df = df_value[['氨氮', '高锰酸盐指数', '总磷', '监测时间']]
# 数据清洗
df = df.replace(0, np.nan) # 将0替换为NaN
df = df.dropna(axis=0, how='any') # 删除包含NaN的行
# 将监测时间转换为日期,并计算日平均值
df['监测时间'] = pd.to_datetime(df['监测时间'])
df['日期'] = df['监测时间'].dt.date
df = df.groupby('日期').mean().reset_index()# 数据评价
def evaluate_index(value, limits):for i, limit in enumerate(limits):if value <= limit:return i + 1return len(limits) + 1# 设置各因子的标准限值
limits = {'高锰酸盐指数': [2, 4, 6, 10, 15],'氨氮': [0.15, 0.5, 1, 1.5, 2.0],'总磷': [0.02, 0.1, 0.2, 0.3, 0.4]
}# 计算评价等级
for factor, limit in limits.items():df[f'{factor}评价等级'] = df[factor].apply(lambda x: evaluate_index(x, limit))# 计算站点评价等级
df['站点评价等级'] = df[['高锰酸盐指数评价等级', '氨氮评价等级', '总磷评价等级']].max(axis=1)
最后的结果如下图
日历热力图的绘制
通过简单查询可以知道这个点位的等级范围为2-6类(Ⅱ类到劣Ⅴ类)
第一种方式 calmap库
import pandas as pd
import calmap
import matplotlib.pyplot as plt
import matplotlib.dates as mdates# 将日期列转换为日期类型
df['日期'] = pd.to_datetime(df['日期'])# 确保站点评价等级是数值类型
df['站点评价等级'] = pd.to_numeric(df['站点评价等级'])# 创建日历热力图
fig, ax = plt.subplots(figsize=(20, 6), dpi=300)
calmap.yearplot(df.set_index('日期')['站点评价等级'], year=2023, cmap='RdYlGn_r', linewidth=0.01, linecolor='grey', monthticks=5, monthlabels='none')# 添加颜色条
cmap = plt.cm.get_cmap('RdYlGn_r', 6) # 选择颜色映射,这里假设我们将颜色分为7个区间
bounds = [0.5, 1.5, 2.5, 3.5, 4.5, 5.5] # 设置颜色条的分割点
norm = plt.cm.colors.BoundaryNorm(bounds, cmap.N) # 根据分割点创建颜色映射
sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
sm.set_array([])
cbar = plt.colorbar(sm, orientation='horizontal', ticks=[1, 2, 3, 4, 5], shrink=0.4) # 设置颜色条的标记位置
cbar.ax.set_xticklabels(['Ⅱ类', 'Ⅲ类', 'Ⅳ类', 'Ⅴ类', '劣Ⅴ类'])
cbar.set_label('水质等级', fontsize=14)# 自定义月份显示为中文
plt.gca().set_xticklabels(['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'])# 调整图形布局
plt.subplots_adjust(left=0.05, right=0.95, top=0.95, bottom=0.2)# 设置图形标题
label_name = ask_station + "2023年水质等级日历热力图"
plt.title(label_name, fontsize=16)
# 保存图形到本地
# plt.savefig("calendar_heatmap.png")
# 显示图形
plt.show()
缺点比较明显 不能交互,且月份之间间隔不明显。
第一种方式 pyecharts库
代码更简洁,效果还可以,输出格式为html,可交互,逻辑更清晰。
import pandas as pd
from pyecharts import options as opts
from pyecharts.charts import Calendar# 将日期列转换为日期类型
df['日期'] = pd.to_datetime(df['日期'])# 确保站点评价等级是数值类型
df['站点评价等级'] = pd.to_numeric(df['站点评价等级'])# 获取日期和评价等级数据
data = df[['日期', '站点评价等级']].values.tolist()# 创建日历热力图
calendar = (Calendar().add("", data, calendar_opts=opts.CalendarOpts(range_='2023')).set_global_opts(title_opts=opts.TitleOpts(title=ask_station + "2023年水质等级日历热力图"),visualmap_opts=opts.VisualMapOpts(max_=5,min_=1,orient="horizontal",pos_top="230px",pos_left="center",is_piecewise=True,pieces=[{"min": 1, "max": 2, "label": "Ⅱ类", "color": "#00E500"},{"min": 2, "max": 3, "label": "Ⅲ类", "color": "blue"},{"min": 3, "max": 4, "label": "Ⅳ类", "color": "#FFA500"},{"min": 4, "max": 5, "label": "Ⅴ类", "color": "#FF0000"},{"min": 5, "max": 6, "label": "劣Ⅴ类", "color": "#800080"},], ),).render("calendar_heatmap.html")
)# 还是有改进的地方,比如根据等级的上下限自动匹配色块
小结
从图中可以看到该站点4-10月水质较差,其他月份水质为Ⅲ类及以下。