策略模式(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)
网格和布局 — 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