像Google那样观察折线图上的值和百分比变化

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

如果您在 Google 上搜索 Apple 股票,您将被带到此页面。在图表上,您可以左键单击并按住并向右或向左移动。如果这样做,您会得到百分比的变化以及值的变化,当您四处移动时会显示这些变化。

问题

是否可以完全按照 Python 中的描述创建上述功能?我尝试使用 Plotly 包但无法做到。

我想在下图上做:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(0)
x = np.random.randn(2000)
y = np.cumsum(x)
df = pd.DataFrame(y, columns=['value'])
fig, ax = plt.subplots(figsize=(20, 4))
df['value'].plot(ax=ax)
plt.show()

在下面的评论部分,Joseph 建议使用 PyQtgraph 示例池,但这是我第一次使用这个包,我不知道该怎么做。

python visualization graph-visualization
2个回答
1
投票

在不确切知道您要寻找什么的情况下,这是一个使用 PyQtgraph 的示例。这将创建一个带有数据光标的简单股票图表。当您左键单击并按住图表并向左或向右移动时,数据光标将跟随您的鼠标光标并显示该点股价的百分比变化。

import numpy as np
import pyqtgraph as pg

class StockChart(pg.PlotWidget):
    def __init__(self):
        super().__init__()

        # Create a plot curve
        self.plot_curve = self.plot()

        # Set the plot range
        self.setXRange(0, 2000)
        self.setYRange(0, 10000)

        # Create a data cursor
        self.data_cursor = pg.LinearRegionItem()
        self.addItem(self.data_cursor)

        # Bind the data cursor to the plot curve
        self.data_cursor.sigRegionChanged.connect(self.on_data_cursor_changed)

    def on_data_cursor_changed(self):
        # Get the x and y values of the data cursor
        x, y = self.data_cursor.getRegion()

        # Calculate the percentage change
        percentage_change = (y - self.plot_curve.getData(x)[0]) / self.plot_curve.getData(x)[0] * 100

        # Display the percentage change
        print(f"Percentage change: {percentage_change:.2f}%")

if __name__ == "__main__":
    # Create a StockChart object
    stock_chart = StockChart()

    # Generate some random data
    x = np.random.randn(2000)
    y = np.cumsum(x)

    # Set the data for the plot curve
    stock_chart.plot_curve.setData(x, y)

    # Show the plot
    stock_chart.show()

0
投票

这是一个将

matplotlib
与鼠标事件结合使用的解决方案。它提供原始股票图的移动/单击和拖动行为,在图例中显示结果:

  • 移动鼠标而不点击:在x值处显示y值。
  • 单击并拖动:显示覆盖的 x 范围内最左边和最右边 y 值之间的总差和百分比差。

它确实绘制原始库存图中的垂直线和阴影区域。虽然这也是可能的,但可能会有点太长了。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

def set_text_for(x_start, event):
    if event.xdata is not None:  # Are we inside the graph?
        x_current = int(np.round(event.xdata))
        y_current = df["value"].at[x_current]
        if x_start is None:  # No click and drag: show y value and x value
            value_str = f"{y_current:.2f} at {x_current})"
        else:  # Click and drag: show y value change and x value range
            y_start = df["value"].at[x_start]
            if x_current < x_start:  # Swap start and current if we drag to the left
                x_start, x_current, y_start, y_current = x_current, x_start, y_current, y_start
            y_diff = y_current - y_start
            y_diff_percent = np.nan if y_start == 0 else abs(100 * y_diff / y_start)
            arrow = " " if y_diff == 0 else ("↑" if y_diff > 0 else "↓")
            value_str = f"{y_diff:+.2f} ({y_diff_percent:.2f} %) {arrow} at {x_start}-{x_current}"
        leg.texts[0].set_text(f"{line_label}: {value_str}")
        fig.canvas.draw_idle()

class PlotState:
    def __init__(self):
        self.x_start = None

    def on_press(self, event):
        if event.xdata is not None:
            self.x_start = int(np.round(event.xdata))

    def on_release(self, event):
        self.x_start = None
        set_text_for(self.x_start, event)
        
    def on_move(self, event):
        set_text_for(self.x_start, event)
        
if __name__ == "__main__":
    # Initialize data
    np.random.seed(0)
    df = pd.DataFrame(np.cumsum(np.random.randn(2000)), columns=["value"])
    # Initialize plotting
    fig, ax = plt.subplots(figsize=(20, 4))
    df["value"].plot(ax=ax)
    leg = plt.legend()
    line_label = leg.texts[0].get_text()
    # Initialize event handling
    state = PlotState()
    fig.canvas.mpl_connect("button_press_event", state.on_press)
    fig.canvas.mpl_connect("button_release_event", state.on_release)
    fig.canvas.mpl_connect("motion_notify_event", state.on_move)
    
    plt.show()

代码上的一些注释:

  • 使用
    PlotState
    ,我们可以跟踪是否仅移动鼠标(
    self.x_start
    None
    )还是单击并拖动,并提供相应的事件处理。
  • 通过
    mpl_connect()
    连接到必要的事件(“button_press_event”、“button_release_event”、“motion_notify_event”)来初始化事件处理。
  • 我们需要对浮点值
    event.xdata
    (光标下绘图的 x 坐标)进行舍入,以从数据框中获取最接近的 x 值。
© www.soinside.com 2019 - 2024. All rights reserved.