How to use pyplot to show data with no scale on xaxis and allow to pan (shift) via mouse

36 views Asked by At

So in the current matplotlib there is a pan button and zoom button and the plot show all data initially and scales it to fit in the visible window. To see the details, I have to zoom in and then pan.

What I want to do is to show the data in a detailed view as default and then I can pan it as needed.

For example, instead of this: https://th.bing.com/th/id/OIP.tMPfzJY6o0TY2Jupl-mPLAHaGA?rs=1&pid=ImgDetMain

I want this (by default):

enter image description here

Then I can pan it as needed.

I don't want to truncate the data because I need all data but just view them in parts. Any easier way out of this without manipulating the data as I pan it?

1

There are 1 answers

2
Ratislaus On BEST ANSWER

With Matplotlib you could use a Span Selector like in this example, to show your entire data on the top subplot, while showing the "zoomed" part of the data on the bottom subplot:

import matplotlib.pyplot as plt
import numpy as np
import mplfinance as mpf
import yfinance as yf
import pandas as pd

from matplotlib.widgets import SpanSelector

# get market data
df = yf.download("SPY", start="2024-02-04", end="2024-03-04", interval="1h")

# x data range
timestamps = list(df.index)
short_timestamps = [str(t)[0:16] for t in timestamps]
x = range(len(timestamps))

fig, (ax1, ax2) = plt.subplots(2)

# diagram to select a region from
mpf.plot(df,
         ax=ax1,
         type="candle"
    )

ax1.set_title('Press left mouse button and drag '
              'to select a region in the top graph')

# zoomed region
mpf.plot(df,
         ax=ax2,
         type="candle"
    )

# set initial range
ax2.set_xlim(x[short_timestamps.index('2024-02-05 09:30')], x[short_timestamps.index('2024-02-06 09:30')])

def onselect(xmin, xmax):
    indmin, indmax = np.searchsorted(x, (xmin, xmax))
    indmax = min(len(x) - 1, indmax)
    region_x = x[indmin:indmax]

    if len(region_x) >= 2:
        # plot the original diagram but with a different x range
        ax2.clear()
        mpf.plot(df,
                 ax=ax2,
                 type="candle"
            )
        ax2.set_xlim(region_x[0], region_x[-1])
        ax2.set_title('Zoomed')
        fig.canvas.draw_idle()

span = SpanSelector(
    ax1,
    onselect,
    "horizontal",
    useblit=True,
    interactive=True,
    drag_from_anywhere=True
)

fig.tight_layout()
plt.show()

In this way you can select the desired range on the top subplot:

enter image description here

But Plotly allows you to do something similar much easier, like in these examples:

import plotly.graph_objects as go
import pandas as pd

df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')

fig = go.Figure(data=[go.Candlestick(x=df['Date'],
                open=df['AAPL.Open'],
                high=df['AAPL.High'],
                low=df['AAPL.Low'],
                close=df['AAPL.Close'])])

# limit the x range to a required interval
fig.update_xaxes(range=['2016-01-01', '2016-02-01'])
fig.show()

In this case, you can see your entire data and select some part of it on the bottom subplot (called rangeslider), while seeing the selected part on the top subplot:

enter image description here