Plot additional vertical line on a pandas pivot_table figure

Viewed 39

I have a pandas pivot_table that I am plotting using matplotlib and I am trying to also plot a vertical line at a certain x coordinate. The interesting thing is I'm able to plot a horizontal line at a y coordinate without problem, doing the same for a vertical line plot is not working.

Panda pivot_table looks like the following...

              Call Gamma     Put Gamma
    Strike                            
    340.0   8.630821e+05 -2.908180e+07
    345.0   3.740602e+05 -1.297854e+07
    350.0   2.680039e+06 -3.798996e+07
    355.0   1.733369e+06 -2.307662e+07
    360.0   1.858877e+06 -2.335522e+07
    365.0   2.475191e+06 -1.556776e+07
    370.0   5.372839e+06 -6.969699e+07
    372.0   2.453191e+06 -6.744016e+06
    374.0   1.359576e+06 -4.797525e+06
    375.0   1.258569e+07 -1.027296e+08
    376.0   6.172461e+06 -6.335903e+07
    377.0   6.433579e+06 -7.752972e+07
    378.0   7.030789e+06 -1.727623e+08
    379.0   4.256927e+06 -1.307386e+08

Here is the code I'm using to plot the pivot_table...

ax = mypivot.plot(figsize=(20, 5), kind='bar', stacked=True, title=name)

Here is the result of the above plot... pivot_table_plot

Now when I try to plot an additional vertical and horizontal line on top of the current figure, only the horizontal line works, here is the full code block...

ax = pivot.plot(figsize=(20, 5), kind='bar', stacked=True, title=name)
ax.axhline(y=-400000000, color='red')
ax.axvline(x=385, color='red')

pivot_plot_with_only_horizontal_line

I have a suspicion it's something to do with the Strike column in my pivot_table and indexing, but I can't figure it out for the life of me...please help...

Thanks!

2 Answers

The standard way to add vertical lines that will cover your entire plot window without you having to specify their actual height is plt.axvline

import matplotlib.pyplot as plt

plt.axvline(x=0.22058956)
plt.axvline(x=0.33088437)
plt.axvline(x=2.20589566)

OR

xcoords = [0.22058956, 0.33088437, 2.20589566]
for xc in xcoords:
    plt.axvline(x=xc)

You can use many of the keywords available for other plot commands (e.g. color, linestyle, linewidth ...). You can pass in keyword arguments ymin and ymax if you like in axes corrdinates (e.g. ymin=0.25, ymax=0.75 will cover the middle half of the plot). There are corresponding functions for horizontal lines (axhline) and rectangles (axvspan).

Here, the pandas bar plot uses a categorical x-axis, internally numbering the bars 0, 1, 2, .... To add a line at the position of the bar with label 385.0, you need to find the position of that bar, e.g. ax.axvline(x=19). You can use numpy's np.argmin on the index column to find that position.

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

mypivot = pd.DataFrame({'Strike': np.arange(340, 436, 5),
                        'Call Gamma': 1e8 ** np.random.rand(20),
                        'Put Gamma': -1e8 ** np.random.rand(20)
                        }).set_index('Strike')

ax = mypivot.plot(figsize=(20, 5), kind='bar', stacked=True, color=['cornflowerblue', 'salmon'])
ax.axhline(-40000000, color='red')
ax.axvline(np.argmin(np.abs(mypivot.index - 385)), color='red')

plt.tight_layout()
plt.show()

vertical line at a pandas bar plot

If you want a line in between two bar positions, supposing the x's are sorted ascending, you could work with interpolation:

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

mypivot = pd.DataFrame({'Strike': np.arange(340, 436, 5),
                        'Call Gamma': 1e8 ** np.random.rand(20),
                        'Put Gamma': -1e8 ** np.random.rand(20)
                        }).set_index('Strike')
ax = mypivot.plot(figsize=(20, 5), kind='bar', stacked=True, color=['limegreen', 'tomato'], rot=0)
ax.axhline(-40000000, color='red')
xline = 387
xs = mypivot.index.to_numpy()
ind0 = np.argmax(np.where(xs <= xline, xs, -np.inf))
ind1 = np.argmin(np.where(xs >= xline, xs, np.inf))
ax.axvline(np.interp(xline, [xs[ind0], xs[ind1]], [ind0, ind1]), color='red')

plt.tight_layout()
plt.show()

vertical line between bars at an interpolated position

Related