• Python使用策略模式实现绘图功能


    策略模式(Strategy Pattern):允许定义一系列算法,将它们封装起来,使得它们可以互换。

    实现绘制不同类型的图表(如折线图、柱状图和饼图)功能。

    下面是一个示例,展示如何传入横坐标和纵坐标内容,然后绘制不同类型的图表。

    1. import matplotlib.pylab as plt
    2. from abc import ABC, abstractmethod
    3. class PlotStrategy(ABC):
    4. # 抽象类:强制子类实现此方法
    5. @abstractmethod
    6. def plot(self, x_data, y_data, desc):
    7. pass
    8. class LinePlotStrategy(PlotStrategy):
    9. def plot(self, x_data, y_data, desc):
    10. print('折线图')
    11. plt.plot(x_data,y_data,marker=0)
    12. plt.title(desc[0])
    13. plt.xlabel(desc[1])
    14. plt.ylabel(desc[2])
    15. plt.show()
    16. class BarPlotStrategy(PlotStrategy):
    17. def plot(self, x_data, y_data, desc):
    18. print('柱状图')
    19. plt.bar(x_data, y_data)
    20. plt.title(desc[0])
    21. plt.xlabel(desc[1])
    22. plt.ylabel(desc[2])
    23. plt.show()
    24. class PiePlotStrategy(PlotStrategy):
    25. def plot(self, x_data, y_data, desc):
    26. print('饼图')
    27. labels = x_data
    28. sizes = y_data
    29. plt.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=140)
    30. plt.axis('equal') # 正圆形
    31. plt.title(desc[0])
    32. plt.show()
    33. # Context类持有PlotStrategy的引用。可以通过set_strategy方法动态地更改策略
    34. class Context:
    35. def __int__(self, strategy: PlotStrategy):
    36. # _ 开头的变量,表示这是一个受保护的变量
    37. # 该变量只在类内部及其子类中使用,而不应在类外部直接访问
    38. self._strategy = strategy
    39. def set_strategy(self,strategy: PlotStrategy):
    40. self._strategy = strategy
    41. def execute_strategy(self, x_data, y_data, desc):
    42. self._strategy.plot(x_data, y_data, desc)
    43. x = ['A','B','C']
    44. y = [2,3,6]
    45. desc = ['title','x','y']
    46. # line = LinePlotStrategy().plot(x, y, desc)
    47. # bar = BarPlotStrategy().plot(x, y, desc)
    48. # pie = PiePlotStrategy().plot(x, y, desc)
    49. context = Context()
    50. context.set_strategy(LinePlotStrategy())
    51. context.execute_strategy(x, y, desc)
    52. context.set_strategy(BarPlotStrategy())
    53. context.execute_strategy(x, y, desc)
    54. context.set_strategy(PiePlotStrategy())
    55. context.execute_strategy(x, y, desc)

    折线图
    柱状图
    饼图

    1. import matplotlib.pylab as plt
    2. from abc import ABC, abstractmethod
    3. import seaborn as sns
    4. import pandas as pd
    5. import plotly.graph_objects as go
    6. import plotly.io as pio
    7. import altair as alt
    8. from bokeh.plotting import figure, output_file, show
    9. from bokeh.io import output_file,show
    10. from bokeh.palettes import Category20c
    11. from bokeh.plotting import figure, show
    12. from bokeh.transform import cumsum
    13. from math import pi
    14. class PlotStrategy(ABC):
    15. # 抽象类:强制子类实现此方法
    16. @abstractmethod
    17. def plot(self, x_data, y_data, desc):
    18. pass
    19. class LinePlotStrategy(PlotStrategy):
    20. def plot(self, x_data, y_data, desc):
    21. print('折线图')
    22. plt.clf() # 清除当前图形内容
    23. plt.plot(x_data,y_data,color='blue', linestyle='-', linewidth=2, marker='o', markersize=6, label='sin(x)')
    24. plt.title(desc[0], fontsize=16)
    25. plt.xlabel(desc[1], fontsize=14)
    26. plt.ylabel(desc[2], fontsize=14)
    27. plt.xticks(fontsize=12)
    28. plt.yticks(fontsize=12)
    29. plt.legend(fontsize=12) # 添加图例
    30. plt.grid(True) # 添加网格
    31. plt.tight_layout() # 自动调整布局
    32. # plt.show()
    33. plt.savefig('./line.png')
    34. class BarPlotStrategy(PlotStrategy):
    35. def plot(self, x_data, y_data, desc):
    36. plt.clf() # 清除当前图形内容
    37. print('柱状图')
    38. bars = plt.bar(x_data, y_data,color='skyblue', edgecolor='grey')
    39. plt.title(desc[0], fontsize=16)
    40. plt.xlabel(desc[1], fontsize=14)
    41. plt.ylabel(desc[2], fontsize=14)
    42. # 添加数值标签
    43. for bar in bars:
    44. plt.text(bar.get_x() + bar.get_width() / 2, bar.get_height(),
    45. round(bar.get_height(), 1), ha='center', va='bottom')
    46. plt.xticks(fontsize=12)
    47. plt.yticks(fontsize=12)
    48. plt.tight_layout() # 自动调整布局
    49. # plt.show()
    50. plt.savefig('./bar.png')
    51. class PiePlotStrategy(PlotStrategy):
    52. def plot(self, x_data, y_data, desc):
    53. plt.clf()# 清除当前图形内容
    54. print('饼图')
    55. labels = x_data
    56. sizes = y_data
    57. plt.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=140)
    58. plt.axis('equal') # 正圆形
    59. plt.title(desc[0])
    60. # plt.show()
    61. plt.savefig('./pie.png')
    62. class SeabornPlotStrategy(PlotStrategy):
    63. def plot(self, x_data, y_data, desc):
    64. plt.clf() # 清除当前图形内容
    65. print('Seaborn数据可视化库生成折线图')
    66. # Seaborn 是基于 matplotlib 的数据可视化库,提供了更高层次的接口,使得统计数据可视化更加简单和美观
    67. sns.lineplot(x = x_data,y = y_data)
    68. # plt.show()
    69. plt.savefig('./line_seaborn.png')
    70. plt.clf() # 清除当前图形内容
    71. print('Seaborn数据可视化库生成柱状图')
    72. # 示例数据
    73. data = {'Category': x_data,'Values': y_data}
    74. # 创建一个 DataFrame
    75. df = pd.DataFrame(data)
    76. sns.barplot(x='Category', y='Values', data=df)
    77. # plt.show()
    78. plt.savefig('./bar_seaborn.png')
    79. class PlotlyPlotStrategy(PlotStrategy):
    80. def plot(self, x_data, y_data, desc):
    81. print('使用 Plotly 画折线图')
    82. # 使用 Plotly 画折线图,Plotly 是一个交互式可视化库,支持绘制高质量的动态图表和仪表板。它可以生成 HTML 文件或者在线展示
    83. fig = go.Figure(data=go.Scatter(x=x_data, y=y_data))
    84. # fig.show()
    85. # 需要安装 kaleido 这个附加依赖,它是 Plotly 的推荐渲染引擎
    86. # pio.write_image(fig, './line_plotly.png') # 执行失败,执行到此步骤 长时间无响应
    87. # fig.write_image('./line_plotly.png') # 执行失败,执行到此步骤 长时间无响应
    88. fig.write_html('./line_plotly.html')
    89. print('使用 Plotly 画柱状图')
    90. fig = go.Figure(data=go.Bar(x=x_data, y=y_data))
    91. fig.update_layout(
    92. title=desc[0],
    93. xaxis=dict(title=desc[1]),
    94. yaxis=dict(title=desc[2])
    95. )
    96. # fig.show()
    97. fig.write_html('./bar_plotly.html')
    98. print('使用 Plotly 画饼图')
    99. fig = go.Figure(data=go.Pie(labels=x_data, values=y_data))
    100. fig.update_layout(
    101. title=desc[0]
    102. )
    103. # fig.show()
    104. fig.write_html('./pie_plotly.html')
    105. class AltairPlotStrategy(PlotStrategy):
    106. def plot(self, x_data, y_data, desc):
    107. # Altair 是一个 Python 可视化库,使用简洁的声明式语法创建交互式可视化
    108. print('使用 Altair 画折线图')
    109. # 创建示例数据
    110. data = pd.DataFrame({
    111. 'x': x_data,
    112. 'y': y_data
    113. })
    114. # 创建折线图
    115. line_chart = alt.Chart(data).mark_line().encode(
    116. x='x',
    117. y='y'
    118. ).properties(
    119. title=desc[0]
    120. )
    121. # 显示折线图
    122. line_chart.save('./line_altair.html')
    123. print('使用 Altair 画柱状图')
    124. # 创建示例数据
    125. data = pd.DataFrame({
    126. 'x': x_data,
    127. 'y': y_data
    128. })
    129. # 创建柱状图
    130. bar_chart = alt.Chart(data).mark_bar().encode(
    131. x='x',
    132. y='y'
    133. ).properties(
    134. title=desc[0]
    135. )
    136. # 显示柱状图
    137. bar_chart.save('./bar_altair.html')
    138. print('使用 Altair 画饼图')
    139. # 创建示例数据
    140. data = pd.DataFrame({
    141. 'category': x_data,
    142. 'value': y_data
    143. })
    144. # 计算百分比
    145. data['percent'] = (data['value'] / (data['value'].sum()) * 100).round(2)
    146. # 创建饼图
    147. pie_chart = alt.Chart(data).mark_arc(
    148. size=200, # 设置饼图的大小
    149. outerRadius=150 # 设置饼图半径
    150. ).encode(
    151. theta='value:Q', # 角度根据value列的值来编码
    152. color='category:N', # 颜色根据category列的值来编码
    153. tooltip=['category', 'percent:Q'], # tooltip显示category和percent列
    154. ).properties(
    155. width=300,
    156. height=300,
    157. title=desc[0]
    158. )
    159. # 显示饼图,Altair 不直接支持在每个扇区上显示两个不同的文本标签(值和百分比)
    160. pie_chart.save('./pie_altair.html')
    161. class BokehPlotStrategy(PlotStrategy):
    162. def plot(self, x_data, y_data, desc):
    163. # 使用 Bokeh 画折线图,Plotly 是一个交互式的可视化库,可以生成漂亮的图表,并支持与用户交互,例如缩放、悬停等操作
    164. # 官方文档:https://docs.bokeh.org/en/latest/docs/user_guide/basic/lines.html
    165. print('使用 Bokeh 画折线图')
    166. # # 创建绘图对象
    167. # output_file("./line_bokeh.html")
    168. # p = figure(width=400, height=400)
    169. #
    170. # # add a line renderer
    171. # p.line(x_data, y_data, line_width=2)
    172. # # 显示图表
    173. # show(p)
    174. print('使用 Bokeh 画柱状图')
    175. p = figure(x_range=x_data, height=350, title=desc[0],toolbar_location=None, tools="")
    176. p.vbar(x=x_data, top=y_data, width=0.9)
    177. p.xgrid.grid_line_color = None
    178. p.y_range.start = 0
    179. output_file("./bar_bokeh.html")
    180. show(p)
    181. print('使用 Bokeh 画饼图')
    182. categories = x_data # 图例标签
    183. values = y_data # 饼图的数值
    184. # 计算起始和结束角度
    185. start_angles = [2 * pi * i / sum(values) for i, _ in enumerate(values[:-1])]
    186. end_angles = [2 * pi * (i + 1) / sum(values) for i, _ in enumerate(values)]
    187. # 创建绘图对象
    188. p = figure(title=desc[0], x_axis_type=None, y_axis_type=None, toolbar_location=None)
    189. # 绘制饼图,确保legend_label是字符串
    190. for i, (start, end, cat) in enumerate(zip(start_angles, end_angles, categories)):
    191. p.wedge(x=0, y=1, radius=0.8,
    192. start_angle=start, end_angle=end,
    193. line_color="white", fill_color="blue", # 可以为每个扇形设置不同的颜色
    194. legend_label=str(cat)) # 确保legend_label是字符串
    195. # 添加图例
    196. p.legend.location = "top_right"
    197. p.legend.click_policy = "hide" # 可选:点击图例项来隐藏/显示对应的图形
    198. # 显示图表
    199. output_file("pie_bokeh.html")
    200. show(p)
    201. # Context类持有PlotStrategy的引用。可以通过set_strategy方法动态地更改策略
    202. class Context:
    203. def __int__(self, strategy: PlotStrategy):
    204. # _ 开头的变量,表示这是一个受保护的变量
    205. # 该变量只在类内部及其子类中使用,而不应在类外部直接访问
    206. self._strategy = strategy
    207. def set_strategy(self,strategy: PlotStrategy):
    208. self._strategy = strategy
    209. def execute_strategy(self, x_data, y_data, desc):
    210. self._strategy.plot(x_data, y_data, desc)
    211. x = ['A','B','C','D','E','F','G']
    212. y = [2,3,6,1,4,4,3]
    213. x1 = [1,2,3,4,5,6,7]
    214. desc = ['title','x','y']
    215. # line = LinePlotStrategy().plot(x, y, desc)
    216. # bar = BarPlotStrategy().plot(x, y, desc)
    217. # pie = PiePlotStrategy().plot(x, y, desc)
    218. # seab = SeabornPlotStrategy().plot(x,y,desc)
    219. context = Context()
    220. context.set_strategy(LinePlotStrategy())
    221. context.execute_strategy(x, y, desc)
    222. context.set_strategy(BarPlotStrategy())
    223. context.execute_strategy(x, y, desc)
    224. context.set_strategy(PiePlotStrategy())
    225. context.execute_strategy(x, y, desc)
    226. context.set_strategy(SeabornPlotStrategy())
    227. context.execute_strategy(x, y, desc)
    228. context.set_strategy(PlotlyPlotStrategy())
    229. context.execute_strategy(x, y, desc)
    230. context.set_strategy(AltairPlotStrategy())
    231. context.execute_strategy(x, y, desc)
    232. context.set_strategy(BokehPlotStrategy())
    233. 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

  • 相关阅读:
    10 索引优化与查询优化
    用Java写PTA 7-7 较为复杂情况下的求和
    Java从入门到精通-类和对象(二)
    使用R语言自带数据“USArrests”,利用K-means进行聚类分析。建议按照如下步骤进行
    【云原生之Docker实战】使用Docker部署Ubooquity个人漫画服务器
    Linux操作系统——linux 系统-备份与恢复
    Backbone 网络-ResNet v2 详解
    Qt:信号与槽机制
    B_QuRT_User_Guide(27)
    ES6+知识点总结
  • 原文地址:https://blog.csdn.net/songpeiying/article/details/139681065