策略模式(Strategy Pattern):允许定义一系列算法,将它们封装起来,使得它们可以互换。
实现绘制不同类型的图表(如折线图、柱状图和饼图)功能。
下面是一个示例,展示如何传入横坐标和纵坐标内容,然后绘制不同类型的图表。
import matplotlib.pylab as plt
from abc import ABC, abstractmethod
class PlotStrategy(ABC):
# 抽象类:强制子类实现此方法
@abstractmethod
def plot(self, x_data, y_data, desc):
pass
class LinePlotStrategy(PlotStrategy):
def plot(self, x_data, y_data, desc):
print('折线图')
plt.plot(x_data,y_data,marker=0)
plt.title(desc[0])
plt.xlabel(desc[1])
plt.ylabel(desc[2])
plt.show()
class BarPlotStrategy(PlotStrategy):
def plot(self, x_data, y_data, desc):
print('柱状图')
plt.bar(x_data, y_data)
plt.title(desc[0])
plt.xlabel(desc[1])
plt.ylabel(desc[2])
plt.show()
class PiePlotStrategy(PlotStrategy):
def plot(self, x_data, y_data, desc):
print('饼图')
labels = x_data
sizes = y_data
plt.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=140)
plt.axis('equal') # 正圆形
plt.title(desc[0])
plt.show()
# Context类持有PlotStrategy的引用。可以通过set_strategy方法动态地更改策略
class Context:
def __int__(self, strategy: PlotStrategy):
# _ 开头的变量,表示这是一个受保护的变量
# 该变量只在类内部及其子类中使用,而不应在类外部直接访问
self._strategy = strategy
def set_strategy(self,strategy: PlotStrategy):
self._strategy = strategy
def execute_strategy(self, x_data, y_data, desc):
self._strategy.plot(x_data, y_data, desc)
x = ['A','B','C']
y = [2,3,6]
desc = ['title','x','y']
# line = LinePlotStrategy().plot(x, y, desc)
# bar = BarPlotStrategy().plot(x, y, desc)
# pie = PiePlotStrategy().plot(x, y, desc)
context = Context()
context.set_strategy(LinePlotStrategy())
context.execute_strategy(x, y, desc)
context.set_strategy(BarPlotStrategy())
context.execute_strategy(x, y, desc)
context.set_strategy(PiePlotStrategy())
context.execute_strategy(x, y, desc)
折线图
柱状图
饼图
import matplotlib.pylab as plt
from abc import ABC, abstractmethod
import seaborn as sns
import pandas as pd
import plotly.graph_objects as go
import plotly.io as pio
import altair as alt
from bokeh.plotting import figure, output_file, show
from bokeh.io import output_file,show
from bokeh.palettes import Category20c
from bokeh.plotting import figure, show
from bokeh.transform import cumsum
from math import pi
class PlotStrategy(ABC):
# 抽象类:强制子类实现此方法
@abstractmethod
def plot(self, x_data, y_data, desc):
pass
class LinePlotStrategy(PlotStrategy):
def plot(self, x_data, y_data, desc):
print('折线图')
plt.clf() # 清除当前图形内容
plt.plot(x_data,y_data,color='blue', linestyle='-', linewidth=2, marker='o', markersize=6, label='sin(x)')
plt.title(desc[0], fontsize=16)
plt.xlabel(desc[1], fontsize=14)
plt.ylabel(desc[2], fontsize=14)
plt.xticks(fontsize=12)
plt.yticks(fontsize=12)
plt.legend(fontsize=12) # 添加图例
plt.grid(True) # 添加网格
plt.tight_layout() # 自动调整布局
# plt.show()
plt.savefig('./line.png')
class BarPlotStrategy(PlotStrategy):
def plot(self, x_data, y_data, desc):
plt.clf() # 清除当前图形内容
print('柱状图')
bars = plt.bar(x_data, y_data,color='skyblue', edgecolor='grey')
plt.title(desc[0], fontsize=16)
plt.xlabel(desc[1], fontsize=14)
plt.ylabel(desc[2], fontsize=14)
# 添加数值标签
for bar in bars:
plt.text(bar.get_x() + bar.get_width() / 2, bar.get_height(),
round(bar.get_height(), 1), ha='center', va='bottom')
plt.xticks(fontsize=12)
plt.yticks(fontsize=12)
plt.tight_layout() # 自动调整布局
# plt.show()
plt.savefig('./bar.png')
class PiePlotStrategy(PlotStrategy):
def plot(self, x_data, y_data, desc):
plt.clf()# 清除当前图形内容
print('饼图')
labels = x_data
sizes = y_data
plt.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=140)
plt.axis('equal') # 正圆形
plt.title(desc[0])
# plt.show()
plt.savefig('./pie.png')
class SeabornPlotStrategy(PlotStrategy):
def plot(self, x_data, y_data, desc):
plt.clf() # 清除当前图形内容
print('Seaborn数据可视化库生成折线图')
# Seaborn 是基于 matplotlib 的数据可视化库,提供了更高层次的接口,使得统计数据可视化更加简单和美观
sns.lineplot(x = x_data,y = y_data)
# plt.show()
plt.savefig('./line_seaborn.png')
plt.clf() # 清除当前图形内容
print('Seaborn数据可视化库生成柱状图')
# 示例数据
data = {'Category': x_data,'Values': y_data}
# 创建一个 DataFrame
df = pd.DataFrame(data)
sns.barplot(x='Category', y='Values', data=df)
# plt.show()
plt.savefig('./bar_seaborn.png')
class PlotlyPlotStrategy(PlotStrategy):
def plot(self, x_data, y_data, desc):
print('使用 Plotly 画折线图')
# 使用 Plotly 画折线图,Plotly 是一个交互式可视化库,支持绘制高质量的动态图表和仪表板。它可以生成 HTML 文件或者在线展示
fig = go.Figure(data=go.Scatter(x=x_data, y=y_data))
# fig.show()
# 需要安装 kaleido 这个附加依赖,它是 Plotly 的推荐渲染引擎
# pio.write_image(fig, './line_plotly.png') # 执行失败,执行到此步骤 长时间无响应
# fig.write_image('./line_plotly.png') # 执行失败,执行到此步骤 长时间无响应
fig.write_html('./line_plotly.html')
print('使用 Plotly 画柱状图')
fig = go.Figure(data=go.Bar(x=x_data, y=y_data))
fig.update_layout(
title=desc[0],
xaxis=dict(title=desc[1]),
yaxis=dict(title=desc[2])
)
# fig.show()
fig.write_html('./bar_plotly.html')
print('使用 Plotly 画饼图')
fig = go.Figure(data=go.Pie(labels=x_data, values=y_data))
fig.update_layout(
title=desc[0]
)
# fig.show()
fig.write_html('./pie_plotly.html')
class AltairPlotStrategy(PlotStrategy):
def plot(self, x_data, y_data, desc):
# Altair 是一个 Python 可视化库,使用简洁的声明式语法创建交互式可视化
print('使用 Altair 画折线图')
# 创建示例数据
data = pd.DataFrame({
'x': x_data,
'y': y_data
})
# 创建折线图
line_chart = alt.Chart(data).mark_line().encode(
x='x',
y='y'
).properties(
title=desc[0]
)
# 显示折线图
line_chart.save('./line_altair.html')
print('使用 Altair 画柱状图')
# 创建示例数据
data = pd.DataFrame({
'x': x_data,
'y': y_data
})
# 创建柱状图
bar_chart = alt.Chart(data).mark_bar().encode(
x='x',
y='y'
).properties(
title=desc[0]
)
# 显示柱状图
bar_chart.save('./bar_altair.html')
print('使用 Altair 画饼图')
# 创建示例数据
data = pd.DataFrame({
'category': x_data,
'value': y_data
})
# 计算百分比
data['percent'] = (data['value'] / (data['value'].sum()) * 100).round(2)
# 创建饼图
pie_chart = alt.Chart(data).mark_arc(
size=200, # 设置饼图的大小
outerRadius=150 # 设置饼图半径
).encode(
theta='value:Q', # 角度根据value列的值来编码
color='category:N', # 颜色根据category列的值来编码
tooltip=['category', 'percent:Q'], # tooltip显示category和percent列
).properties(
width=300,
height=300,
title=desc[0]
)
# 显示饼图,Altair 不直接支持在每个扇区上显示两个不同的文本标签(值和百分比)
pie_chart.save('./pie_altair.html')
class BokehPlotStrategy(PlotStrategy):
def plot(self, x_data, y_data, desc):
# 使用 Bokeh 画折线图,Plotly 是一个交互式的可视化库,可以生成漂亮的图表,并支持与用户交互,例如缩放、悬停等操作
# 官方文档:https://docs.bokeh.org/en/latest/docs/user_guide/basic/lines.html
print('使用 Bokeh 画折线图')
# # 创建绘图对象
# output_file("./line_bokeh.html")
# p = figure(width=400, height=400)
#
# # add a line renderer
# p.line(x_data, y_data, line_width=2)
# # 显示图表
# show(p)
print('使用 Bokeh 画柱状图')
p = figure(x_range=x_data, height=350, title=desc[0],toolbar_location=None, tools="")
p.vbar(x=x_data, top=y_data, width=0.9)
p.xgrid.grid_line_color = None
p.y_range.start = 0
output_file("./bar_bokeh.html")
show(p)
print('使用 Bokeh 画饼图')
categories = x_data # 图例标签
values = y_data # 饼图的数值
# 计算起始和结束角度
start_angles = [2 * pi * i / sum(values) for i, _ in enumerate(values[:-1])]
end_angles = [2 * pi * (i + 1) / sum(values) for i, _ in enumerate(values)]
# 创建绘图对象
p = figure(title=desc[0], x_axis_type=None, y_axis_type=None, toolbar_location=None)
# 绘制饼图,确保legend_label是字符串
for i, (start, end, cat) in enumerate(zip(start_angles, end_angles, categories)):
p.wedge(x=0, y=1, radius=0.8,
start_angle=start, end_angle=end,
line_color="white", fill_color="blue", # 可以为每个扇形设置不同的颜色
legend_label=str(cat)) # 确保legend_label是字符串
# 添加图例
p.legend.location = "top_right"
p.legend.click_policy = "hide" # 可选:点击图例项来隐藏/显示对应的图形
# 显示图表
output_file("pie_bokeh.html")
show(p)
# Context类持有PlotStrategy的引用。可以通过set_strategy方法动态地更改策略
class Context:
def __int__(self, strategy: PlotStrategy):
# _ 开头的变量,表示这是一个受保护的变量
# 该变量只在类内部及其子类中使用,而不应在类外部直接访问
self._strategy = strategy
def set_strategy(self,strategy: PlotStrategy):
self._strategy = strategy
def execute_strategy(self, x_data, y_data, desc):
self._strategy.plot(x_data, y_data, desc)
x = ['A','B','C','D','E','F','G']
y = [2,3,6,1,4,4,3]
x1 = [1,2,3,4,5,6,7]
desc = ['title','x','y']
# line = LinePlotStrategy().plot(x, y, desc)
# bar = BarPlotStrategy().plot(x, y, desc)
# pie = PiePlotStrategy().plot(x, y, desc)
# seab = SeabornPlotStrategy().plot(x,y,desc)
context = Context()
context.set_strategy(LinePlotStrategy())
context.execute_strategy(x, y, desc)
context.set_strategy(BarPlotStrategy())
context.execute_strategy(x, y, desc)
context.set_strategy(PiePlotStrategy())
context.execute_strategy(x, y, desc)
context.set_strategy(SeabornPlotStrategy())
context.execute_strategy(x, y, desc)
context.set_strategy(PlotlyPlotStrategy())
context.execute_strategy(x, y, desc)
context.set_strategy(AltairPlotStrategy())
context.execute_strategy(x, y, desc)
context.set_strategy(BokehPlotStrategy())
context.execute_strategy(x, y, desc)
折线图
柱状图
饼图
Seaborn数据可视化库生成折线图
Seaborn数据可视化库生成柱状图
使用 Plotly 画折线图
使用 Plotly 画柱状图
使用 Plotly 画饼图
使用 Altair 画折线图
使用 Altair 画柱状图
使用 Altair 画饼图
使用 Bokeh 画折线图
使用 Bokeh 画柱状图
使用 Bokeh 画饼图
网格和布局 — Bokeh 3.4.1 文档
Specifying Data — Vega-Altair 5.3.0 documentation (altair-viz.github.io)
Plotly Python 图形库
Python API 参考 plotly — 5.22.0 文档
Seaborn:统计数据可视化 — Seaborn 0.13.2 文档 (pydata.org)
API reference — seaborn 0.13.2 documentation
User guide and tutorial — seaborn 0.13.2 documentation