Search code examples
matplotlib

How to create candlestick chart using matplotlib only


I have a problem with displaying vlines in the place where the body of the candle is very small. Maybe someone has already solved a similar problem.

fig, axs = plt.subplots(1)

fig.set_size_inches(12.0, 6.0)

axs.vlines(df.index, df['Start_g'], df['End_g'], color='green', linestyle='-', lw=10)
axs.vlines(df.index, df['Start_r'], df['End_r'], color='red', linestyle='-', lw=10)

axs.vlines(df.index, df['Low_g'], df['High_g'], color='green', linestyle='-', lw=1)
axs.vlines(df.index, df['Low_r'], df['High_r'], color='red', linestyle='-', lw=1)

plt.show()

Here is a image of the output

I tried setting dpi to 200 fig.set_dpi(200), it helps but the candles overlap each other

Here is a image of the output


Solution

  • To display the body of the candle I used a Rectangle and to display Low and High I used Line2D

    Input data should be pandas.DataFrame with columns Open High Low Close

    df = df[['Open', 'High', 'Low', 'Close']]
    
    
    import numpy as np
    import matplotlib.patches as mpatches
    from matplotlib.collections import PatchCollection
    import matplotlib.lines as mlines
    import matplotlib.pyplot as plt
    
    
    def create_collection(df):
        
        l = len(df)
    
        grid = []
        height = []
        colors = []
        
        for i in range(l):
            if df.loc[i, 'Close'] > df.loc[i, 'Open']:
                grid.append([i, df.loc[i, 'Open']])
                height.append(df.loc[i, 'Close'] - df.loc[i, 'Open'])
                colors.append('green')
            elif df.loc[i, 'Close'] < df.loc[i, 'Open']:
                grid.append([i, df.loc[i, 'Close']])
                height.append(df.loc[i, 'Open'] - df.loc[i, 'Close'])
                colors.append('red')
        grid = np.array(grid)
    
        patches = []
        lines = []
        width = 0.5
        
        for i in range(l):
            
            rect = mpatches.Rectangle(grid[i]-[width/2, 0.0], width, height[i])
            patches.append(rect)
            line = mlines.Line2D([i, i], [df.loc[i, 'Low'], df.loc[i, 'High']], lw=0.75, color=colors[i])
            lines.append(line)
    
        collection = PatchCollection(patches, cmap=plt.cm.hsv)
        collection.set_facecolors([colors[i] for i in range(l)])
        collection.set_linewidth(1.0)
        collection.set_edgecolors([colors[i] for i in range(l)])
        
        return collection, lines
    
    collection, lines = create_collection(df)
    
    fig, axs = plt.subplots()
    fig.set_figwidth(640)
    fig.set_figheight(320)
    fig.set_size_inches(12.0, 6.0)
    
    axs.add_collection(collection)
    [axs.add_line(lines[i]) for i in range(len(df))]
    
    plt.axis('auto')
    plt.show()
    

    output here