0

In my plot, I am trying to annotate with multiple values at each point.

weights = [np.array([w, 1-w]) for w in np.linspace(0, 1, 5)]

mu = [0.5, 0.25]

def portfolio_return(weights, returns):
    return weights.T @ returns

rets = [portfolio_return(w, mu) for w in weights]

S = [[0.493, 0.11], [0.11, 0.16]]
def portfolio_vol(weights, cov):
    return (weights.T @ cov @ weights)**0.5

vols = [portfolio_vol(w, S) for w in weights]

import matplotlib.pyplot as plt
%matplotlib inline
%config InlineBackend.figure_format = 'svg'

markers_on = [1, 3]
fig = plt.figure()
ax = fig.add_subplot(111)
plt.plot(vols, rets, 'g-')

for marker in markers_on:
    plt.plot(vols[marker], rets[marker], 'bs')
    w1, w2 = weights[marker][0], weights[marker][1]
    ax.annotate(f'w = ({w1:.1f}, {w2:.1f})', (w1, w2), xy=(vols[marker]+.08, rets[marker]-.03))

plt.xlabel('Risk')
plt.ylabel('Return')
plt.show()

This returns error -

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-8-0e29da296b76> in <module>
     11     plt.plot(vols[marker], rets[marker], 'bs')
     12     w1, w2 = weights[marker][0], weights[marker][1]
---> 13     ax.annotate(f'w = ({w1:.1f}, {w2:.1f})', (w1, w2), xy=(vols[marker]+.08, rets[marker]-.03))

TypeError: annotate() got multiple values for argument 'xy'

New to Python plot. All I am trying to do is annotate two points on the plot, in each showing both the weights.

---------------------------------------------------------------------------

Note - made the following changes following @ewong's comment.

for marker in markers_on:
    plt.plot(vols[marker], rets[marker], 'bs')
    w1, w2 = weights[marker][0], weights[marker][1]
    ax.annotate(r'w = ({w1:%.2f}, {w2:%.2f})', (w1, w2))

No error, which is good. Unfortunately, although it marks two positions, does not show the weights.

Also there is a significant amount of white space before the plot shows up. I have to scroll down in jupyter notebook.

----------------------------------------------------------------------------------

Further changes made. Getting the plot with all three marker. But not the weights.

for marker in markers_on:
    plt.plot(vols[marker], rets[marker], 'bs')
    w1, w2 = weights[marker][0], weights[marker][1]
    text = f'w = ({w1:.2f}, {w2:.2f})', (w1, w2)
    ax.annotate(s = text, xy=(vols[marker]+.08, rets[marker]-.03))

deb
  • 331
  • 1
  • 4
  • 13
  • aiui, from https://matplotlib.org/3.1.0/api/_as_gen/matplotlib.pyplot.annotate.html , ```annotate()``` treats ```(w1, w2)``` as ```xy```, so specifying ```xy``` again is an error. – ewokx Aug 17 '20 at 02:24
  • Thanks @ewong Made the change you suggested. No error. Does not show the values. See the edited version of the question. – deb Aug 17 '20 at 03:37
  • You could assign `f'w = ({w1:.1f}, {w2:.1f})', (w1, w2)` to a temporary variable and use that temporary variable as text in `ax.annotate()`. – Ynjxsjmh Aug 17 '20 at 08:06
  • @Ynjxsjmh can you please show me how to do that? What would the code look like? – deb Aug 17 '20 at 15:14
  • `text = f'w = ({w1:.1f}, {w2:.1f})', (w1, w2) \n ax.annotate(text=text, xy=(vols[marker]+.08, rets[marker]-.03))`. You could refer [Axes.annotate()](https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.annotate.html) for the meaning of `text` argument. – Ynjxsjmh Aug 17 '20 at 16:20
  • @Ynjxsjmh outputs error. ```TypeError: annotate() missing 1 required positional argument: 's'``` – deb Aug 17 '20 at 20:59
  • Then try to replace `text` argument in `ax.annotate()` with `s`. It seems that newest Axes.annotate() and [older](https://matplotlib.org/3.2.1/api/_as_gen/matplotlib.axes.Axes.annotate.html) have a different api. – Ynjxsjmh Aug 18 '20 at 02:11
  • @Ynjxsjmh do mean ```text = s'w = ({w1:.1f}, {w2:.1f})', (w1, w2) ``` – deb Aug 18 '20 at 03:21
  • `text = f'w = ({w1:.1f}, {w2:.1f})', (w1, w2) \n ax.annotate(s=text, xy=(vols[marker]+.08, rets[marker]-.03))` – Ynjxsjmh Aug 18 '20 at 04:08
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/220041/discussion-between-deb-and-ynjxsjmh). – deb Aug 18 '20 at 14:27

1 Answers1

0

The reason why you didn't see the weight is because you adjust the text place with xy=(vols[marker]+.08, rets[marker]-.03). From your picture, I notice the x max is 0.0225. 0.08 is greater than 0.0225, so the text is out of bounds.

import numpy as np
import matplotlib.pyplot as plt

weights = [np.array([w, 1-w]) for w in np.linspace(0, 1, 5)]

mu = [0.5, 0.25]

def portfolio_return(weights, returns):
    return weights.T @ returns

rets = [portfolio_return(w, mu) for w in weights]

S = [[0.493, 0.11], [0.11, 0.16]]
def portfolio_vol(weights, cov):
    return (weights.T @ cov @ weights)**0.5

vols = [portfolio_vol(w, S) for w in weights]


markers_on = [1, 3]
fig = plt.figure()
ax = fig.add_subplot(111)
plt.plot(vols, rets, 'g-')

for marker in markers_on:
    plt.plot(vols[marker], rets[marker], 'bs')
    w1, w2 = weights[marker][0], weights[marker][1]
    text = f'w = ({w1:.1f}, {w2:.1f})'
    ax.annotate(text, xy=(vols[marker]+.005, rets[marker]-0.005))

plt.xlabel('Risk')
plt.ylabel('Return')
plt.show()

enter image description here

Ynjxsjmh
  • 28,441
  • 6
  • 34
  • 52