Python数据可视化

 基于asciichartpy

import asciichartpy

data = [1, 2, 3, 4, 5, 4, 3, 2, 1]
chart = asciichartpy.plot(data)
print(chart)

 

基于sparklines

import sparklines

data = [1, 2, 3, 4, 5, 4, 3, 2, 1]
sparkline_str = ''.join(sparklines.sparklines(data))
print(sparkline_str)

 

基于sparkline-nb将曲线插入dataframe

import io
import base64
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from IPython.display import display, HTML


def sparkline(data, figsize=(4, 0.25), **kwargs):
    """
    Returns an HTML image tag containing a base64 encoded sparkline style plot
    """
    data = list(data)
    
    fig, ax = plt.subplots(1, 1, figsize=figsize, **kwargs)
    ax.plot(data)
    for k, v in ax.spines.items():
        v.set_visible(False)
    ax.set_xticks([])
    ax.set_yticks([])

    plt.plot(len(data) - 1, data[len(data) - 1], 'r.')

    ax.fill_between(range(len(data)), data, [min(data)]*len(data), alpha=0.1)
    
    img = io.BytesIO()
    plt.savefig(img, format='png')
    img.seek(0)
    plt.close()
    
    # Encode the image in base64
    img_base64 = base64.b64encode(img.read()).decode('utf-8')
    
    return f'<img src="data:image/png;base64,{img_base64}"/>'


if __name__ == "__main__":

    n = 4
    data = [
        ('rand',        np.random.rand(n)), 
        ('randn',       np.random.randn(n)), 
        ('beta',        np.random.beta(2, 1, size=n)),
        ('binomial',    np.random.binomial(3.4, 0.22, size=n)),
        ('exponential', np.random.exponential(size=n)),
        ('geometric',   np.random.geometric(0.5, size=n)),
        ('laplace',     np.random.laplace(size=n))
    ]
    spark = pd.DataFrame(data, columns=['func', 'data'])
    print(spark)

    # map the sparkline function over the data column
    # and store back in the column sparklines
    spark['sparklines'] = spark.data.map(sparkline)
    # _repr_html_ escapes HTML so manually handle the rendering
    HTML(spark.to_html(escape=False))

 

基于xlsxwriter在Excel里插入曲线

import xlsxwriter

wb = xlsxwriter.Workbook('hello.xlsx')
ws = wb.add_worksheet()

data=[12,23,9,17,31,3,7,21,10,15]
ws.write_row('A1', data)
ws.set_column('K:K', 40)
ws.set_row(0, 30)

data=[1,1,-1,-1,-1,1,1,1,-1,-1]
ws.write_row('A5', data)
ws.set_column('K:K', 40)
ws.set_row(4, 30)
ws.add_sparkline('K1', {'range':'Sheet1!A1:J1', 'markers':True})
ws.add_sparkline('K5', {'range':'Sheet1!A5:J5', 'type':'win_loss',
'negative_points':True})

wb.close()
# 更多参数
ws.add_sparkline(idx + 1, offset - 1, {
        'range': data_sheet_loc, 
        'markers': False, 
        'markers_color': 'purple',
        'series_color': 'blue', 
        'high_point': 'red', 
        'high_color': 'red',
        'low_point': 'green', 
        'low_color': 'green'
    }
)

 

基于matplotlib.pyplot先生成png,然后再插入Excel的方法

import os
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
from matplotlib import font_manager
from openpyxl import load_workbook
from openpyxl.drawing.image import Image

def insert_pic(excel_path, pic_path, height):
    if not os.path.exists(excel_path):
        log.error("failed to insert pic because of missing {}".format(excel_path))
        return
    if not os.path.exists(pic_path):
        log.error("failed to insert pic because of missing {}".format(pic_path))
        return
    print(excel_path, pic_path)
    xl = load_workbook(excel_path)
    xl_sheet = xl[xl.sheetnames[0]]
    pos = "B" + str(xl_sheet.max_row + height + 5)
    img = Image(pic_path)
    xl_sheet.add_image(img, pos)
    xl.save(excel_path)
    xl.close()

 

matplotlib.pyplot画图示例

# X 轴数据
dis = pd.date_range(start='2025-01-17 09:20:00', end='2025-01-20 09:20:00', freq="5min", closed="left")

# 创建figure绘图
plt.figure(figsize=(15, 6))
plt.title("Test Title")
plt.plot(dis, vals, label='PV')
plt.axvline(x=xxx, color='r', linestyle='--', linewidth=0.7, label='调整时间点')

# 去掉左右的空隙,设置X轴范围
plt.xlim(dis.min(), dis.max())
# 定义日期格式化器, 获取当前 Axes 对象, 设置 X 轴刻度标签的格式
date_format = DateFormatter('%Y-%m-%d %H:%M:%S')
ax = plt.gca()
ax.xaxis.set_major_formatter(date_format)
# 设置 X 轴刻度,使第一个和最后一个坐标也被标识出来
num_ticks = 12
xticks = pd.date_range(start=dis.min(), end=dis.max(), periods=num_ticks)
plt.xticks(xticks, rotation=45)

plt.xlabel('时间')
plt.ylabel('人数')
plt.legend()
plt.grid()
plt.show()

补充示例:

import os
import json
import time
import datetime
import traceback
import pandas as pd
import matplotlib.ticker as mticker
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from matplotlib import font_manager
fname="/usr/local/python3.6/lib/python3.6/site-packages/matplotlib/mpl-data/fonts/ttf/simhei.ttf"
zhfont = font_manager.FontProperties(fname=fname)


dis = pd.date_range(start=stime, end=etime, freq="5min", closed="left")
total_tss = [ int(di.tz_localize("Asia/Shanghai").timestamp()) for di in dis.to_list() ]


plt.figure(figsize=(15, 6))
plt.title("任务执行耗时变化情况")
# plt.plot(dis, spent_lst, label='耗时(秒)')
plt.scatter(dis, spent_lst, alpha=0.5, s=10)  # 数据较多时候使用散点图

# 去掉左右的空隙,设置X轴范围
plt.xlim(dis.min(), dis.max())
# 定义日期格式化器, 获取当前 Axes 对象, 设置 X 轴刻度标签的格式
date_format = mdates.DateFormatter('%m-%d %H:%M')
ax = plt.gca()
ax.xaxis.set_major_formatter(date_format)
# 设置 X 轴刻度,使第一个和最后一个坐标也被标识出来
num_ticks = 24
xticks = pd.date_range(start=dis.min(), end=dis.max(), periods=num_ticks)
plt.xticks(xticks, rotation=45)

plt.xlabel('时间')
plt.ylabel('任务执行耗时')
plt.legend()
plt.grid()
plt.show()

精细化控制时间显示:

# 确保timestamp是datetime类型(已经是北京时间,无需转换)
df['timestamp'] = pd.to_datetime(df['timestamp'])
# # 如果timestamp没有时区信息,假设它是UTC时间,然后转换为北京时间
# if df['timestamp'].dt.tz is None:
#     # 假设数据是UTC时间,转换为北京时间(UTC+8)
#     df['timestamp'] = df['timestamp'].dt.tz_localize('UTC').dt.tz_convert('Asia/Shanghai')
# else:
#     # 如果已有时区信息,直接转换
#     df['timestamp'] = df['timestamp'].dt.tz_convert('Asia/Shanghai')

# ========== 图1: 带宽数据单独一张图 ==========
fig, ax = plt.subplots(figsize=(14, 6))
ax.plot(df['timestamp'], df['bandwidth_mbps'], linewidth=1, color='#2E86AB', marker='o', markersize=1)
ax.set_title('Bandwidth Over Time', fontsize=16, fontweight='bold')
ax.set_xlabel('Time', fontsize=12)
ax.set_ylabel('Bandwidth (Mbps)', fontsize=12)
ax.grid(True, alpha=0.3)
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d %H:%M'))
ax.xaxis.set_major_locator(mdates.HourLocator(interval=6))
ax.tick_params(axis='x', rotation=45)
plt.tight_layout()
plt.show()

 

支持中文显示问题

######################## 设置全局字体 ########################
import matplotlib
from matplotlib import font_manager

# 1. 先注册字体文件(告诉matplotlib字体文件的位置)
font_path = "/usr/local/python3.6/lib/python3.6/site-packages/matplotlib/mpl-data/fonts/ttf/simhei.ttf"
font_manager.fontManager.addfont(font_path)

# 2. 获取字体名称(从字体文件中读取)
prop = font_manager.FontProperties(fname=font_path)
font_name = prop.get_name()  # 获取字体名称,通常是 'SimHei'

# 3. 全局设置中文字体
matplotlib.rcParams['font.sans-serif'] = [font_name]
matplotlib.rcParams['axes.unicode_minus'] = False    # 解决负号显示问题



######################## 设置局部字体 ########################
import matplotlib.pyplot as plt
from matplotlib import font_manager
zhfont = font_manager.FontProperties(fname="/usr/local/python3.6/lib/python3.6/site-packages/matplotlib/mpl-data/fonts/ttf/simhei.ttf")

plt.title('中文标题', fontsize=12, fontproperties=zhfont)  # 指定中文字体
plt.annotate(
    "中文annotate",
    xy=(x_95_point, y_95_point),
    fontproperties=zhfont  # 指定中文字体
)
plt.plot(x_5min, vals, label="中文label")
plt.legend(prop=zhfont)  # 指定中文字体

 

 

...

 

posted @ 2024-07-01 19:01  马贡多在下雨  阅读(75)  评论(0)    收藏  举报