0

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!

broncomz1
  • 23
  • 3
  • Does this answer your question? [How to add a vertical line to a pandas bar plot of time-series data](https://stackoverflow.com/questions/61606615/how-to-add-a-vertical-line-to-a-pandas-bar-plot-of-time-series-data) – ouroboros1 Sep 18 '22 at 22:00
  • As per the suggested duplicate: `ax.axvline(df.index.searchsorted(385), color='red')`. – ouroboros1 Sep 18 '22 at 22:01

2 Answers2

0

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).

DomeQ
  • 9
  • 4
0

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

JohanC
  • 71,591
  • 8
  • 33
  • 66
  • Thanks, I think you are spot on, however I'm curious what will happen if I want to plot a line at say 387 in your example diagram, 387 doesn't fall on a major tick mark, and I'm assuming wouldn't have an internal index number associated, so would this work in that case? Or a number such as 385.50 for example... – broncomz1 Sep 22 '22 at 21:25
  • I added some code to interpolate positions. – JohanC Sep 23 '22 at 19:33