Search code examples
pythonmatplotlibaxis-labels

Skipping certain values in Python with Matplotlib


I am currently working on an intra-day stock chart using the Alpha Vantage API. The data frame contains values from 4:00 to 20:00. In my matplotlib.pyplot chart however, the x-Axis also includes values from 20:00 to 4:00 over night. I dont want this as it messes up the aesthetics and also the Volume subplot.

Q: Is there any way to skip x-Axis values which dont exist in the actual Data Frame (the values from 20:00 to 04:00)?

As you can see, the Data Frame clearly jumps from 20:00 to 04:00

However in the Matplotlib chart, the x-Axis contains the values from 20:00 to 4:00, messing with the chart

Code so far. I believe so far everything is right:

import pandas as pd
import matplotlib.pyplot as plt
from alpha_vantage.timeseries import TimeSeries
import time
import datetime as dt
from datetime import timedelta as td 
from dateutil.relativedelta import relativedelta

#Accessing and Preparing API
ts = TimeSeries(key=api_key, output_format='pandas')

ticker_input = "TSLA"
interval_input = "15min"
df, meta_data = ts.get_intraday(symbol = ticker_input, interval = interval_input, outputsize = 'full')
slice_date = 16*4*5
df = df[0:slice_date]
df = df.iloc[::-1]
df["100ma"] = df["4. close"].rolling(window = 50, min_periods = 0).mean()
df["Close"] = df["4. close"]
df["Date"] = df.index

#Plotting all as 2 different subplots
ax1 = plt.subplot2grid((7,1), (0,0), rowspan = 5, colspan = 1)
ax1.plot(df["Date"], df['Close'])
ax1.plot(df["Date"], df["100ma"], linewidth = 0.5)
plt.xticks(rotation=45)
ax2 = plt.subplot2grid((6,1), (5,0), rowspan = 2, colspan = 2, sharex = ax1)
ax2.bar(df["Date"], df["5. volume"])
ax2.axes.xaxis.set_visible(False)
plt.tight_layout()
plt.show()

It would be great if anybody could help. Im still a complete beginner and only started Python 2 weeks ago.


Solution

  • I fixed it using matplotlib.ticker.formatter.

    I first created a class and using:

    class MyFormatter(Formatter):
        def __init__(self, dates, fmt='%Y-%m-%d %H:%M'):
            self.dates = dates
            self.fmt = fmt
    
        def __call__(self, x, pos=0):
            'Return the label for time x at position pos'
            ind = int(np.round(x))
        if ind >= len(self.dates) or ind < 0:
            return ''
        return self.dates[ind].strftime(self.fmt)
    
    formatter = MyFormatter(df.index)
    ax1 = plt.subplot2grid((7,1), (0,0), rowspan = 5, colspan = 1)
    ax1.xaxis.set_major_formatter(formatter)
    ax1.plot(np.arange(len(df)), df["Close"])
    ax1.plot(np.arange(len(df)), df["100ma"], linewidth = 0.5)
    ax1.xticks(rotation=45)
    ax1.axis([xmin,xmax,ymin,ymax])
    ax2 = plt.subplot2grid((6,1), (5,0), rowspan = 2, colspan = 2, sharex = ax1)
    ax2.bar(np.arange(len(df)), df["5. volume"])
    
    plt.show()
    

    This gave me a smoother graph than the one before and also that recommended by r-beginner. THis is the result

    The only issue that I have is that if I zoom in the x-axis doesnt really change. it always has teh year, month, date, hour, and minute. Obviously I only want hour and minute when Im zoomed in further. I am yet to figure out how to do that