python用plotly实现绘制局部放大图

作者:Eloik 时间:2021-06-13 06:30:44 

最终效果展示

python用plotly实现绘制局部放大图

实现思路

在绘图区域插入一个嵌入图,嵌入图与原图的绘画保持一致,通过限制嵌入图的x轴和y轴的显示范围,达到缩放的效果,并在原图上绘画一个矩形框,以凸显缩放的区域,最后通过两条直线凸显缩放关系。

导入库

import plotly.io as pio
import plotly.graph_objects as go
import pandas as pd
import numpy as np

# 设置plotly默认主题,白色主题
pio.templates.default = 'plotly_white'

随机生成一些数据

# x坐标
x = np.arange(1, 1001)

# 生成y轴数据,并添加随机波动
y1 = np.log(x)
indexs = np.random.randint(0, 1000, 800)
for index in indexs:
   y1[index] += np.random.rand() - 0.5
y1 = y1 + 0.2

y2 = np.log(x)
indexs = np.random.randint(0, 1000, 800)
for index in indexs:
   y2[index] += np.random.rand() - 0.5

y3 = np.log(x)
indexs = np.random.randint(0, 1000, 800)
for index in indexs:
   y3[index] += np.random.rand() - 0.5
y3 = y3 - 0.2

封装绘图代码

class LocalZoomPlot:
   def __init__(self, x, y, colors, x_range, scale=0.):
       """
       :param x: x轴坐标,列表类型
       :param y: y轴坐标,二维列表类型,例如 [y1, y2, y3]
       :param colors: 每个曲线的颜色,必须与 len(y) 相等
       :param x_range: 需要缩放区域的x轴范围
       :param scale: 详见 getRangeMinMaxValue 函数
       """
       self.x = x
       self.y = y
       self.colors = colors
       self.x_range = x_range
       self.y_range = self.getRangeMinMaxValue(x_range, scale)

def getRangeMinMaxValue(self, x_range, scale=0.):
       """
       获取指定x轴范围内,所有y数据的最大值和最小值

:param x_range: 期望局部放大的x轴范围
       :param scale: 将最大值和最小值向两侧延伸一定距离
       """
       min_value = np.min([np.min(arr[x_range[0]:x_range[1]]) for arr in self.y])
       max_value = np.max([np.max(arr[x_range[0]:x_range[1]]) for arr in self.y])
       # 按一定比例缩放
       min_value = min_value - (max_value - min_value) * scale
       max_value = max_value + (max_value - min_value) * scale
       # 返回缩放后的结果
       return min_value, max_value

def originPlot(self, fig, **kwargs):
       """
       根据 y 数据绘制初始折线图

:param fig: go.Figure实例
       """
       fig.add_traces([
           go.Scatter(x=self.x, y=arr, opacity=0.7, marker_color=self.colors[i], **kwargs)
           for i, arr in enumerate(self.y)
       ])
       return fig

def insetPlot(self, fig, inset_axes):
       """
       在原始图像上插入嵌入图

:param fig: go.Figure对象实例
       :param inset_axes: 嵌入图的位置和大小 [左下角的x轴位置, 左下角的y轴位置, 宽度, 高度]
         所有坐标都是绝对坐标(0~1之间)
       """
       # 使用创建子图中的嵌入图参数,创建一个嵌入图
       fig = fig.set_subplots(insets=[dict(
           type='xy',
           l=inset_axes[0], b=inset_axes[1],
           w=inset_axes[2], h=inset_axes[3],
       )])
   # 嵌入图与原始图的绘画一致,需要指定 xaxis 和 yaxis 参数确保是在嵌入图上绘画的
       fig = self.originPlot(fig, xaxis='x2', yaxis='y2', showlegend=False)
       # 将嵌入图的坐标轴范围限定在指定范围
       fig.update_layout(
           xaxis2=dict(range=self.x_range),
           yaxis2=dict(range=self.y_range)
       )
       return fig

def rectOriginArea(self, fig):
       """
       将放大的区域框起来

:param fig: go.Figure实例
       """
       fig.add_trace(go.Scatter(
       # 从左上角开始,顺时针连线
           x=np.array(self.x_range)[[0, 1, 1, 0, 0]],
           y=np.array(self.y_range)[[1, 1, 0, 0, 1]],
           mode='lines',
           line={'color': '#737473', 'dash': 'dash', 'width': 3},
           showlegend=False
       ))
       return fig

def addConnectLine(self, fig, area_point_num, point):
       """
       从放大区域指定点连线

:param fig: go.Figure实例
       :param area_point_num: 放大区域的锚点,例如:(0, 0)表示放大区域的左下角坐标,(0, 1)表示左上角坐标,
         (1, 0)表示右下角坐标,(1, 1)表示右上角坐标,只能取这四种情况
       :param point: 要进行连线的另一个点,通常位于嵌入图附近,根据美观程度自行指定
       """
       fig.add_shape(type='line',
           x0=self.x_range[area_point_num[0]],
           y0=self.y_range[area_point_num[1]],
           x1=point[0], y1=point[1],
           line={'color': '#737473', 'dash': 'dash', 'width': 1},
       )
       return fig

开始绘制

plot = LocalZoomPlot(x, [y1, y2, y3], ['#f0bc94', '#7fe2b3', '#cba0e6'], (100, 150), 0.)
fig = go.Figure()

fig = plot.originPlot(fig)
fig = plot.insetPlot(fig, (0.4, 0.2, 0.4, 0.3))
fig = plot.rectOriginArea(fig)
fig = plot.addConnectLine(fig, (0, 0), (420, -0.7))
fig = plot.addConnectLine(fig, (1, 1), (900, 2.7))

# 额外对图片进行设置
fig.update_layout(
   width=800, height=600,
   xaxis=dict(
       rangemode='tozero',
       showgrid=False,
       zeroline=False,
   ),
   xaxis2=dict(
       showgrid=False,
       zeroline=False
   ),
)

fig.show()

来源:https://blog.csdn.net/weixin_45826022/article/details/122894413

标签:Python,Plotly
0
投稿

猜你喜欢

  • 在阿里云服务器上配置CentOS+Nginx+Python+Flask环境

    2023-07-26 09:47:46
  • Python绘制百分比堆叠柱状图并填充图案

    2023-01-25 00:49:06
  • 如何使用表单发送电子邮件?

    2010-05-16 15:13:00
  • Python入门教程(四十)Python的NumPy数组创建

    2023-11-14 08:36:32
  • 详解 PyTorch Lightning模型部署到生产服务中

    2021-10-23 01:17:25
  • python 名称空间与作用域详情

    2021-06-10 23:12:38
  • 使用Python和xlwt向Excel文件中写入中文的实例

    2023-08-27 19:18:08
  • asp 随机字符串函数

    2011-04-04 11:01:00
  • 如何在Flask中实现数据分组流程详解

    2021-11-15 06:53:59
  • python 实现提取PPT中所有的文字

    2023-05-01 04:21:35
  • ASP Google的translate API代码

    2011-04-03 11:16:00
  • 2010怎么就宅了——我们是设计星球的阿凡达

    2010-03-09 13:26:00
  • Python利器openpyxl之操作excel表格

    2022-11-16 18:46:58
  • python 判断参数为Nonetype类型或空的实例

    2021-03-21 07:15:17
  • 有感用户体验规划与系统实现

    2009-11-27 18:33:00
  • 在js中的replace方法详解

    2007-08-21 15:47:00
  • 可能是最全面的 Python 字符串拼接总结【收藏】

    2023-10-06 14:29:20
  • Oracle字符集修改查看方法

    2009-11-05 21:45:00
  • Python嵌套函数,作用域与偏函数用法实例分析

    2022-12-03 08:46:15
  • 详解php中反射的应用

    2023-11-15 01:26:56
  • asp之家 网络编程 m.aspxhome.com