I have created a confidence interval plot which is working exactly how I want:
month = ['Nov-20', 'Dec-20', 'Jan-21', 'Feb-21', 'Mar-21', 'Apr-21', 'May-21', 'Jun-21', 'Jul-21', 'Aug-21', 'Sep-21', 'Oct-21']
x = [0.85704744, 0.74785299, 0.68103776, 0.69793547, 0.8396294 ,
0.25560889, 0.37400785, 0.00742866, 0.84700224, 0.95142221,
0.08544432, 0.09068883]
y = [0.09448781, 0.69683102, 0.96261431, 0.93635227, 0.31503366,
0.38335671, 0.24244469, 0.36712811, 0.22270387, 0.01506295,
0.78433 , 0.38408096]
z = [0.84585527, 0.59615266, 0.60263581, 0.26366399, 0.42948978,
0.18138516, 0.54841131, 0.65201558, 0.03089001, 0.20581638,
0.57586628, 0.33622286]
fig, ax = plt.subplots(figsize=(17,8))
ax.plot(month, z)
ax.fill_between(month, x, y, color='b', alpha=.3)
ax.hlines(y=0.50, xmin=0, xmax=(len(month)), colors='orange', linestyles='--', lw=2, label="Target: 50%")
plt.xlabel('Month')
plt.ylabel('Target %')
plt.rcParams["font.size"] = "20"
plt.ylim((0.1, 1.0))
plt.legend(bbox_to_anchor=(1.04,0.5), loc="center left", borderaxespad=0)
plt.title("Target Forecast Nov20 - Nov21")
plt.show()
plt.close()
However, I want to add the following to the legend:
An indicator that the blue line is the "probable forecast"
An indicator that the blue fill_between is the confidence interval
I did read this matplotlib documentation, and so I tried:
fig, ax = plt.subplots(figsize=(17,8))
prob, = ax.plot(month, z)
btwn, = ax.fill_between(month, x, y, color='b', alpha=.3)
tgt, = ax.hlines(y=0.50, xmin=0, xmax=(len(month)), colors='orange', linestyles='--', lw=2, label="Target: 50%")
plt.xlabel('Month')
plt.ylabel('Target %')
plt.rcParams["font.size"] = "20"
plt.ylim((0.1, 1.0))
plt.legend([prob, btwn, tgt], ['Probable', 'Confidence Interval', 'Target'])
plt.title("Target Forecast Nov20 - Nov21")
plt.show()
plt.close()
But it ends in a TypeError:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-61-3ef952c0fc7f> in <module>
1 fig, ax = plt.subplots(figsize=(17,8))
2 prob, = ax.plot(month, z)
----> 3 btwn, = ax.fill_between(month, x, y, color='b', alpha=.3)
4 tgt, = ax.hlines(y=0.50, xmin=0, xmax=(len(month)), colors='orange', linestyles='--', lw=2, label="Target: 50%")
5 plt.xlabel('Month')
TypeError: 'PolyCollection' object is not iterable
How can I add these things to the legend?
The matplotlib documentation often suggests to use proxy artists.
Otherwise, in your case, you can just add the label argument and name it the way you want, and the legend should be updated automatically.
In your case:
ax.plot(month, z, label="Probable Forecast")
ax.fill_between(month, x, y, color='b', alpha=.3, label="Confidence Interval")
should work.
Related
I have been using fill between to color the area in this chart, but there seems to always be a negative line by 0 which doesn't correspond to the data, does anyone know why this is happening or how to fix it?
The chart is based on the below
grid = np.linspace(-0.25, 0.25)
kdea = stats.gaussian_kde(x1)
kdeb = stats.gaussian_kde(y1)
kde_diff = kdea(grid)-kdeb(grid)
kde_diff_down = np.where(kde_diff>=0, 0, kde_diff)
kde_diff_up = np.where(kde_diff<=0, 0, kde_diff)
grid_positive = np.where(grid<=-0, -0, grid)
grid_negative =np.where(grid>=0, 0, grid)
plt.plot(grid, kdea(grid), color='y', label="Fund")
plt.plot(grid, kdeb(grid), color='b', label="Benchmark")
plt.plot(grid, kde_diff, color='k', label="Difference")
plt.fill_between(grid_negative, kde_diff_down, alpha=0.4,
color='g')
plt.fill_between(grid_negative, kde_diff_up, alpha=0.4, color='r')
plt.fill_between(grid_positive, kde_diff_down, alpha=0.4, color='r')
plt.fill_between(grid_positive, kde_diff_up, alpha=0.4, color='g')
I have a graph with 2 lines and used the check button to make visible/invisible lines. However, I could not manage to make the same thing to annotations. I wanna when I check label2 make visible/invisible annotations too. I couldn't find any solution from here or web. Any idea?
Here is example of my code :
import matplotlib.pyplot as plt
from matplotlib.widgets import CheckButtons
kansekeri=[333, 111, 111]
inshiz=[3.0, 3.0, 2.5]
zaman=['01-04-2021 04:02', '01-04-2021 04:02', '01-04-2021 04:02']
fig = plt.figure(figsize=(10, 5))
fig.canvas.set_window_title('-')
ax1 = fig.add_subplot()
l0,=ax1.plot(zaman, inshiz, color='tab:blue', marker='.', label='İnsülin Hızı')
ax1.set_xlabel('Tarih - Saat')
ax1.set_ylabel('İnsülin Hızı (u/h)', color='tab:blue')
ax1.tick_params(axis='y',labelcolor='tab:blue')
ax1.tick_params(axis='x', labelsize=7)
ax2 = ax1.twinx()
l1,=ax2.plot(zaman, kansekeri, color='tab:red', marker='.', label="Kan Şekeri")
ax2.set_ylabel('Kan Şekeri',color='tab:red')
ax2.tick_params(labelcolor='tab:red')
for x,y in zip(zaman,kansekeri):
label = "{:.1f}".format(y)
ann=plt.annotate(label, # this is the text
(x,y),
textcoords="offset points",
xytext=(0,7),
ha='center',fontsize=7)
lines = [l0, l1]
rax = plt.axes([0.05, 0.7, 0.1, 0.15])
labels = [str(line.get_label()) for line in lines]
visibility = [line.get_visible() for line in lines]
check = CheckButtons(rax, labels, visibility)
def func(label):
index = labels.index(label)
lines[index].set_visible(not lines[index].get_visible())
plt.draw()
check.on_clicked(func)
plt.subplots_adjust(left=0.2)
plt.grid()
plt.show()
You could also save the annotations in a list: annotations = [plt.annotate(f"{y:.1f}", (x, y), ...) for x, y in zip(zaman, kansekeri)] and then do something similar as with the lines.
Here is some example code:
import matplotlib.pyplot as plt
from matplotlib.widgets import CheckButtons
kansekeri = [333, 111, 111]
inshiz = [3.0, 3.0, 2.5]
zaman = ['01-04-2021 04:02', '01-04-2021 04:02', '01-04-2021 04:02']
fig = plt.figure(figsize=(10, 5))
fig.canvas.set_window_title('-')
ax1 = fig.add_subplot()
l0, = ax1.plot(zaman, inshiz, color='tab:blue', marker='.', label='İnsülin Hızı')
ax1.set_xlabel('Tarih - Saat')
ax1.set_ylabel('İnsülin Hızı (u/h)', color='tab:blue')
ax1.tick_params(axis='y', labelcolor='tab:blue')
ax1.tick_params(axis='x', labelsize=7)
ax2 = ax1.twinx()
l1, = ax2.plot(zaman, kansekeri, color='tab:red', marker='.', label="Kan Şekeri")
ax2.set_ylabel('Kan Şekeri', color='tab:red')
ax2.tick_params(labelcolor='tab:red')
annotations = [plt.annotate(f"{y:.1f}",
(x, y),
textcoords="offset points",
xytext=(0, 7),
ha='center', fontsize=7)
for x, y in zip(zaman, kansekeri)]
lines = [l0, l1]
rax = plt.axes([0.05, 0.7, 0.1, 0.15])
labels = [str(line.get_label()) for line in lines]
visibility = [line.get_visible() for line in lines]
check = CheckButtons(rax, labels, visibility)
def func(label):
index = labels.index(label)
new_line_visibility = not lines[index].get_visible()
lines[index].set_visible(new_line_visibility)
if index == 1:
for ann in annotations:
ann.set_visible(new_line_visibility)
plt.draw()
check.on_clicked(func)
plt.subplots_adjust(left=0.2)
plt.grid()
plt.show()
I have two data sets:
short_data_test.csv:
Item,Current,Forecast
Test1,19.7,49.7
Test2,6.94,12.4
Test3,0.4147,3.1
Test4,27.9,74.03
And short_data_interest_test.csv
Item,Current,Forecast
Test1,0,8.8
Test2,0,7.6
Test3,0,33.5
Test4,0,17.65
When I plot them in two subplots, the output looks like this:
You can see that all of the data, and the labels, are in the second, plot and only the points are in the first plot. Why is all of the data, and labels, only appearing on the second plot and not the first? Can someone show me how to edit the code to fix this? This is the code:
from matplotlib.pylab import plt
import matplotlib.lines as mlines
import numpy as np
# Import Data
import pandas as pd
df = pd.read_csv("short_data_test.csv",sep=',')
left_label = [str(c) + ', '+ str(round(y)) for c, y in zip(df['Item'], df['Current'])]
right_label = [str(c) + ', '+ str(round(y)) for c, y in zip(df['Item'], df['Forecast'])]
klass = ['red' if (y1-y2) < 0 else 'green' for y1, y2 in zip(df['Current'], df['Forecast'])]
# draw line
def newline(p1, p2, color='black'):
ax1 = plt.gca()
l = mlines.Line2D([p1[0],p2[0]], [p1[1],p2[1]], color='red' if p2[1] > 70000 else 'green', marker='o', markersize=6)
ax1.add_line(l)
return l
fig, (ax1,ax2) = plt.subplots(1,2,figsize=(14,14), dpi= 80)
# Vertical Lines
ax1.vlines(x=1, ymin=0, ymax=75, color='black', alpha=0.7, linewidth=1, linestyles='dotted')
ax1.vlines(x=3, ymin=0, ymax=75, color='black', alpha=0.7, linewidth=1, linestyles='dotted')
# Points
ax1.scatter(y=df['Current'], x=np.repeat(1, df.shape[0]), s=10, color='black', alpha=0.7)
ax1.scatter(y=df['Forecast'], x=np.repeat(3, df.shape[0]), s=10, color='black', alpha=0.7)
# Line Segmentsand Annotation
for p1, p2, c in zip(df['Current'], df['Forecast'], df['Item']):
newline([1,p1], [3,p2])
ax1.text(1-0.05, p1, c, horizontalalignment='right', verticalalignment='center', fontdict={'size':14})
ax1.text(3+0.05, p2, c, horizontalalignment='left', verticalalignment='center', fontdict={'size':14})
ax1.text(1-0.05, 75, 'BEFORE',horizontalalignment='right', verticalalignment='center',fontdict={'size':0.001, 'weight':700})
ax1.text(3+0.05, 75, 'AFTER',horizontalalignment='left', verticalalignment='center', fontdict={'size':0.0001, 'weight':700})
# Decoration
ax1.set_title("Comparison1", fontdict={'size':18},weight='bold')
ax1.set(xlim=(0,4))
plt.ylabel('Rate1',fontsize=14,weight='bold')
ax1.set_xticks([1,3])
plt.tick_params(labelsize=14)
ax1.set_xticklabels(["Time1", "Time2"],weight='bold')
df2 = pd.read_csv("short_data_interest_test.csv",sep=',')
left_label2 = [str(c) + ', '+ str(round(y)) for c, y in zip(df2['Item'], df2['Current'])]
right_label2 = [str(c) + ', '+ str(round(y)) for c, y in zip(df2['Item'], df2['Forecast'])]
klass2 = ['red' if (y1-y2) < 0 else 'green' for y1, y2 in zip(df2['Current'], df2['Forecast'])]
# draw line
def newline(p1, p2, color='black'):
ax2 = plt.gca()
l2 = mlines.Line2D([p1[0],p2[0]], [p1[1],p2[1]], color='red' if p2[1] > 70000 else 'green', marker='o', markersize=6)
ax2.add_line(l2)
return l2
# Vertical Lines
ax2.vlines(x=1, ymin=0, ymax=75, color='black', alpha=0.7, linewidth=1, linestyles='dotted')
ax2.vlines(x=3, ymin=0, ymax=75, color='black', alpha=0.7, linewidth=1, linestyles='dotted')
# Points
ax2.scatter(y=df2['Current'], x=np.repeat(1, df2.shape[0]), s=10, color='black', alpha=0.7)
ax2.scatter(y=df2['Forecast'], x=np.repeat(3, df2.shape[0]), s=10, color='black', alpha=0.7)
# Line Segmentsand Annotation
for p1, p2, c in zip(df2['Current'], df2['Forecast'], df2['Item']):
newline([1,p1], [3,p2])
ax2.text(1-0.05, p1, c, horizontalalignment='right', verticalalignment='center', fontdict={'size':14})
ax2.text(3+0.05, p2, c, horizontalalignment='left', verticalalignment='center', fontdict={'size':14})
ax2.text(1-0.05, 75, 'BEFORE',horizontalalignment='right', verticalalignment='center',fontdict={'size':0.001, 'weight':700})
ax2.text(3+0.05, 75, 'AFTER',horizontalalignment='left', verticalalignment='center', fontdict={'size':0.0001, 'weight':700})
# Decoration
ax2.set_title("Comparison2", fontdict={'size':18},weight='bold')
ax2.set(xlim=(0,4))
plt.ylabel('Rate2',fontsize=14,weight='bold')
ax2.set_xticks([1,3])
plt.tick_params(labelsize=14)
ax2.set_xticklabels(["Time1", "Time2"],weight='bold')
plt.show()
plt.savefig('slopechart.png')
I am using python to plot and my codes are:
import matplotlib.pyplot as plt
import numpy as np
# these are the data to be plot
x = [1,2,3,4,5,6,7,8,9,10,11,12,13,14]
x_test = ['grid50', 'grid100', 'grid150', 'grid250', 'grid500', 'grid750', 'NN5', 'NN10', 'NN15', 'NN20', 'NN50', 'NN100', 'CB', 'CBG']
clf = [0.58502, 0.60799, 0.60342, 0.59629, 0.56464, 0.53757, 0.62567, 0.63429, 0.63583, 0.63239, 0.63315, 0.63156, 0.60630, 0.52755]
hitrate = [0.80544, 0.89422, 0.94029, 0.98379, 0.99413, 0.99921, 0.99478, 0.99961, 0.99997, 0.99980, 0.99899, 0.99991, 0.88435, 1.0]
level = [23.04527, 9.90955, 4.35757, 1.46438, 0.51277, 0.15071, 1.30057, 0.00016, 0.00001, 0.00021, 0.00005, 0.00004, 6.38019, 0]
fig = plt.figure(figsize=(20,7))
ax = fig.add_subplot(111)
fig.subplots_adjust(right=0.8)
# this is the function to put annotation on bars
def autolabel(rects):
# attach some text labels
for ii,rect in enumerate(rects):
height = rect.get_height()
plt. text(rect.get_x()+rect.get_width()/2., 1.02*height, '%s'% (clf[ii]),ha='center', va='bottom')
plt.xticks(x,x_test)
# this part is to plot the red bar charts
ins1 = ax.bar(x,clf,color='Red', align='center',label='classification results')
ax.set_ylabel('classification results', color='Red')
ax.tick_params(axis='y',colors='Red')
ax.set_ylim(0,1.5)
autolabel(ins1)
# this part is to plot the green hitrate and the for-loop is to put annotation next to the line
ax2 = ax.twinx()
ins2, = ax2.plot(x,hitrate,marker='o',color='Green', linewidth=3.0, label='hitrate')
ax2.set_ylabel('hitrate', color='Green')
ax2.tick_params(axis='y',colors='Green')
ax2.set_ylim(0,1.5)
for i,j in zip(x, hitrate):
ax2.annotate(str(j),xy=(i,j+0.02))
# this part is to plot the blue level, forloop same as that of hitrate
ax3 = ax.twinx()
axes = [ax, ax2, ax3]
ax3.spines['right'].set_position(('axes', 1.1))
ax3.set_frame_on(True)
ax3.patch.set_visible(False)
ins3, = ax3.plot(x,level,marker='^', color='Blue', linewidth=3.0, label='obfuscation level')
ax3.set_ylabel('obfuscation level', color='Blue')
ax3.tick_params(axis='y',colors='Blue')
ax3.set_ylim(0,25)
for i,j in zip(x, level):
ax3.annotate(str(j),xy=(i,j+0.02))
ax.set_xlabel('Cell Configurations')
ax.set_xlim(0,15)
ax.set_title('benchmark')
ax.legend([ins1,ins2,ins3],['clf', 'hit', 'level'])
plt.grid()
plt.show()
And I got a figure like :
The problem is that, some numbers are not put in a good place so to be read clearly, but I don't know whether there is a method to put the annotation naturally at a blank area. Any ideas?
No matter what I seem to do, or whichever past questions I seem to look up - I seem unable to change simple properties of tick labels.
This code:
from mpl_toolkits.axes_grid.axislines import SubplotZero
from matplotlib.transforms import BlendedGenericTransform
import matplotlib.pyplot as plt
import numpy
if 1:
fig = plt.figure(1)
ax = SubplotZero(fig, 111)
fig.add_subplot(ax)
# thicken the axis lines
ax.axhline(linewidth=1.7, color="k")
ax.axvline(linewidth=1.7, color="k")
plt.xticks([-numpy.pi/2, -numpy.pi/4, 0, numpy.pi/4, numpy.pi/2], [r'$-\pi$', r'$-\pi/2$', r'$O$', r'$\pi/2$', r'$\pi$'], rotation=30)
plt.yticks([])
#ax.set_xticklabels([r'$-\pi$', r'$-\pi/2$', r'$0$', r'$\pi/2$', r'$\pi$'], rotation=40, ha='left')
# end-of-axis arrows
ax.text(0, 1.05, r'$y$', transform=BlendedGenericTransform(ax.transData, ax.transAxes), ha='center')
ax.text(1.03, 0, r'$x$', transform=BlendedGenericTransform(ax.transAxes, ax.transData), va='center')
plt.ylim(-5, 5)
plt.xlim(-numpy.pi/2, numpy.pi/2)
x_width = (abs(plt.xlim()[0]) + abs(plt.xlim()[1])) / 2
y_width = (abs(plt.ylim()[0]) + abs(plt.ylim()[1])) / 2
# end-of-axis arrows
plt.arrow(plt.xlim()[1], -0.003, x_width*0.01, 0,
width=x_width*0.0015, color="k", clip_on=False,
head_width=y_width*0.24/7, head_length=x_width*0.024)
plt.arrow(0.003, plt.ylim()[1], 0, y_width*0.01,
width=y_width*0.0015, color="k", clip_on=False,
head_width=x_width*0.24/7, head_length=y_width*0.024)
for direction in ["xzero", "yzero"]:
ax.axis[direction].set_visible(True)
for direction in ["left", "right", "bottom", "top"]:
ax.axis[direction].set_visible(False)
x = numpy.linspace(-numpy.pi/2, numpy.pi/2, 2500)
yy = numpy.tan(2*(x - numpy.pi/2))
threshold = 1000
yy[yy > threshold] = numpy.inf
yy[yy < -threshold] = numpy.inf
ax.plot(x, yy, linewidth=1.2, color="black")
ax.axvline(x=-3*numpy.pi/4, linewidth=1.0, color="k", linestyle="--")
ax.axvline(x=-numpy.pi/4, linewidth=1.0, color="k", linestyle="--")
ax.axvline(x=numpy.pi/4, linewidth=1.0, color="k", linestyle="--")
ax.axvline(x=3*numpy.pi/4, linewidth=1.0, color="k", linestyle="--")
plt.savefig('MC6.png')
with particular note of this line:
plt.xticks([-numpy.pi/2, -numpy.pi/4, 0, numpy.pi/4, numpy.pi/2], [r'$-\pi$', r'$-\pi/2$', r'$O$', r'$\pi/2$', r'$\pi$'], rotation=30)
does not rotate the labels by 30 degrees. Likewise if I do other workarounds to change the font-size, the labels always stay the same.
Am I missing something super simple about matplotlib???
Add this line:
ax.axis["xzero"].major_ticklabels.set_rotation(30)
For the reference, here's a mailing list item where this comes from: http://matplotlib.1069221.n5.nabble.com/rotating-x-tick-labels-bold-labels-with-axislines-toolkit-td7661.html
As to why what you do has no effect, I can only guess. A wild guess would be that the state machine (which works under the hood when you call functions from the pyplot namespace) assumes that plt.xticks relate to the bottom spine, which you've explicitly set to be invisible.