1

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.

0

2 Answers 2

3

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

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you very much for your quick response @Mr. T. Indeed, the values within each column can change over time and thus take on positive as well as negative values. Nevertheless, I was able to adapt your suggestion to fit my use case and hence solved the problem. You helped me out big time with that one - many thanks again! I'll post my particular solution right away.
My pleasure. If your code provides a better solution to your question, you are free to post and accept your own answer.
I would also be interested in a solution where a column can contain positive and negative values.
3

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

1 Comment

Nice. You should accept this as your answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.