表面上的动画散点图(绘图)

问题描述 投票:0回答:1

我正在尝试使用plotly在固定表面上制作动画散点图。

这是我用来绘制表面的代码:

import plotly.graph_objects as go


def surface(x, y, z, opacity: float = 1.0) -> go.Figure:

    fig = go.Figure()

    fig.add_trace(
        go.Surface(
            x=x,
            y=y,
            z=z,
            contours_z=dict(
                show=True,
                usecolormap=True,
                project_z=True,
            ),
            opacity=opacity
        )
    )

    return fig

Surface plot

然后我试图在其上覆盖散点图。


def population(
    self,
    benchmark: CEC2013,
    batch_stats: BatchStats,
    filename: str = 'population'
):
    # Here I'm creating the surface figure using previous method
    surface = figure.surface.surface(*benchmark.surface, opacity=0.8)

    frames = []

    # Time to add some frames using Scatter 3D
    for population in batch_stats.population_history:
        x = [solution.genome[0] for solution in population.solutions]
        y = [solution.genome[1] for solution in population.solutions]
        fitness = population.fitness

        frame = go.Frame(
            data=[
                go.Scatter3d(
                    x=x,
                    y=y,
                    z=fitness,
                    mode='markers',
                    marker=dict(
                        size=6,
                        color='#52CA34',
                    )
                )
            ]
        )

        frames.append(frame)

    # Update frames to root figure
    surface.frames = frames

    # just a fancy display, to make it work in offline mode in html render from notebook
    pyo.iplot(
        surface,
        filename=filename,
        image_width=self.IMAGE_WIDTH,
        image_height=self.IMAGE_HEIGHT
    )

表面仅在第一帧中显示。散点图显示在后续帧中,但没有底面。

Scatter plot

代码位于dev分支上的here。根处有一个名为test_vis.ipynb的调试笔记本。感谢您的帮助<3

python plotly
1个回答
0
投票

我已将这个问题作为问题发布在plotly的repository

这是我收到的答案。

@ empet-谢谢<3

当您的fig.data仅包含一条迹线时,则假定每一帧都更新该迹线并且在动画过程中不再显示轨迹。这就是为什么您必须定义:

fig = go.Figure(
    data=[
        go.Scatter(
            y=y,
            x=x,
            mode="lines",
            ine_shape='spline'

         )
    ]*2
)

即在图数据中包含两次相同的迹线。同时修改框架定义,如下所示:

 frame = go.Frame(data=[scatter], traces=[1])

[traces = [1]通知plotly.js,每帧更新轨迹fig.data[1],而fig.data[0]在动画过程中保持不变。

这是一个如何在某些基础图上制作动画的完整示例。

import math
import numpy as np
import plotly.graph_objects as go
import plotly.io as pio
import plotly.offline as pyo


class Plot:

    def __init__(
        self,
        image_width: int = 1200,
        image_height: int = 900
    ) -> None:

        self.IMAGE_WIDTH = image_width
        self.IMAGE_HEIGHT = image_height

        pyo.init_notebook_mode(connected=False)
        pio.renderers.default = 'notebook'

    def population(self, filename: str = 'population'):

        x_spline = np.linspace(
            start=0,
            stop=20,
            num=100,
            endpoint=True
        )

        y_spline = np.array([math.sin(x_i) for x_i in x_spline])

        x_min = np.min(x_spline)
        x_max = np.max(x_spline)

        y_min = np.min(y_spline)
        y_max = np.max(y_spline)

        spline = go.Scatter(
            y=y_spline,
            x=x_spline,
            mode="lines",
            line_shape='spline'
        )

        fig = go.Figure(
            data=[spline] * 2
        )

        frames = []

        for i in range(50):
            x = np.random.random_sample(size=5)
            x *= x_max

            y = np.array([math.sin(x_i) for x_i in x])

            scatter = go.Scatter(
                x=x,
                y=y,
                mode='markers',
                marker=dict(
                    color='Green',
                    size=12,
                    line=dict(
                        color='Red',
                        width=2
                    )
                ),
            )
            frame = go.Frame(data=[scatter], traces=[1])
            frames.append(frame)

        fig.frames = frames

        fig.layout = go.Layout(
            xaxis=dict(
                range=[x_min, x_max],
                autorange=False
            ),
            yaxis=dict(
                range=[y_min, y_max],
                autorange=False
            ),
            title="Start Title",
            updatemenus=[
                dict(
                    type="buttons",
                    buttons=[
                        dict(
                            label="Play",
                            method="animate",
                            args=[None]
                        )
                    ]
                )
            ]
        )

        fig.update_layout(
            xaxis_title='x',
            yaxis_title='y',
            title='Fitness landscape',
            # autosize=True
        )

        pyo.iplot(
            fig,
            filename=filename,
            image_width=self.IMAGE_WIDTH,
            image_height=self.IMAGE_HEIGHT
        )

plot = Plot()
plot.population()
© www.soinside.com 2019 - 2024. All rights reserved.