dominikmeyer95
dominikmeyer95

Reputation: 81

How to display negative values in matplotlib's stackplot?

I´d like to create a stacked barplot of asset weights representing a financial portfolio over time. I tried several approaches for that one, but got the most pleasing results with matplotlib's stackplot function. However, I am not able to display negative asset weights in my stackplot, thus receiving wrong figures. I am using Python (3.8.3) and Matplotlib (3.3.2).

The following displays the head of the asset weights dataframe to plot:

w_minvar1nc.head()

              SMACAP    GROWTH    MOMTUM    MINVOL   QUALITY
Date                                                        
2015-02-20  0.012942  0.584273 -0.114441  0.387773  0.129454
2015-02-23  0.013129  0.584528 -0.115836  0.386448  0.131732
2015-02-24  0.013487  0.584404 -0.116585  0.386364  0.132330
2015-02-25  0.015145  0.572256 -0.117796  0.387583  0.142811
2015-02-26  0.015113  0.567198 -0.114580  0.387807  0.144462

The following displays a simple code snippet of my current approach to the stackplot:

# initialize stackplot
fig, ax = plt.subplots(nrows=1, ncols=1, facecolor="#F0F0F0")
# create and format stackplot
ax.stackplot(w_minvar1nc.index, w_minvar1nc.SMACAP, w_minvar1nc.GROWTH, w_minvar1nc.MOMTUM, w_minvar1nc.MINVOL, w_minvar1nc.QUALITY)
ax.set_xlabel("Time")
ax.set_ylabel("Weight")
ax.set_ylim(bottom=-0.5, top=1.5)
ax.grid(which="major", color="grey", linestyle="--", linewidth=0.5)
# save stackplot
fig.savefig(fname=(plotpath + "test.png"))
plt.clf()
plt.close()

And here comes the corresponding stackplot itself in which you can see that the negative asset weights don't show up:

enter image description here

Does anyone know how to deal with that problem? Any ideas would be much appreciated.

PS: Of course I've already tried other approaches such as stacking the data manually and then create a regular barplot etc. And in this case the positive and negative asset weights are actually displayed correctly, but this approach also leads to even bigger problems regarding the formatting of the x-axis because of the daily data.

Upvotes: 1

Views: 3432

Answers (2)

dominikmeyer95
dominikmeyer95

Reputation: 81

Enclosed the solution to the problem with huge credit to @Mr. T:

# split data into negative and positive values
w_minvar1nc_pos = w_minvar1nc[w_minvar1nc >= 0].fillna(0)
w_minvar1nc_neg = w_minvar1nc[w_minvar1nc < 0].fillna(0)
# initialize stackplot
fig, ax = plt.subplots(nrows=1, ncols=1, facecolor="#F0F0F0")
# create and format stackplot
ax.stackplot(w_minvar1nc_pos.index, w_minvar1nc_pos.SMACAP, w_minvar1nc_pos.GROWTH, w_minvar1nc_pos.MOMTUM, w_minvar1nc_pos.MINVOL, w_minvar1nc_pos.QUALITY)
ax.stackplot(w_minvar1nc_neg.index, w_minvar1nc_neg.SMACAP, w_minvar1nc_neg.GROWTH, w_minvar1nc_neg.MOMTUM, w_minvar1nc_neg.MINVOL, w_minvar1nc_neg.QUALITY)
ax.set_xlabel("Time")
ax.set_ylabel("Weight")
ax.set_ylim(bottom=-0.5, top=1.5)
ax.grid(which="major", color="grey", linestyle="--", linewidth=0.5)
# save stackplot
fig.savefig(fname=(plotpath + "test.png"))
plt.clf()
plt.close()

enter image description here

Upvotes: 3

Mr. T
Mr. T

Reputation: 12410

If the columns are separated into positive and negative weights, you can plot them separately:

from matplotlib import pyplot as plt
import pandas as pd

#fake data
import numpy as np
np.random.seed(123)
n = 100
df = pd.DataFrame({"Dates": pd.date_range("20180101", periods=n, freq="10d"), 
                   "A": 0.2 + np.random.random(n)/10, 
                   "B": -np.random.random(n)/10,
                   "C": -0.1-np.random.random(n)/10, 
                   "D": 0.3+ np.random.random(n)/10})
df.set_index("Dates", inplace=True)
df["E"] = 1 - df.A - df.D - df.B - df.C

fig, ax = plt.subplots(nrows=1, ncols=1, facecolor="#F0F0F0")
ax.stackplot(df.index, df.A, df.D, df.E)
ax.stackplot(df.index, df.B, df.C)
ax.set_xlabel("Time")
ax.set_ylabel("Weight")
ax.set_ylim(bottom=-0.5, top=1.5)
ax.grid(which="major", color="grey", linestyle="--", linewidth=0.5)

plt.show()

Sample output:

enter image description here

Upvotes: 3

Related Questions