I am trying to figure out the alignment of Markers in "ax.plot" . Apart from plotting 2 bar graphs, I also need to plot 2 points, one per bar graph. Here's what I am looking for -:
Centering/alignment of markers ('o' and '' here, in the center of each bar, rather than at the edge of the bar graph. "o" should come at the center of the 1st bar graph and "" should come at the center of the 2nd bar graph, their individual heights will differ though, as on the scale "Performance" -the "o" and "" are "Performance" objects (right hand side scale, as in the figure) - centering, thus means, overlay of the markers("o" and "" against its respective stacked graph.
Removing the duplicate marker symbols, with 'o' and '*' in the legend on the upper right corner. And, understanding why that happens for par2.plot , but not for ax.bar object. Could I have done this without using ax.twinx(), which generates two scales (one for "#candidates" and other for "Performance" - and if this double entry of legend is related to using the 2 scales ? (I hope not)
For (2), I also used plt.legend(numpoints=1) just before the last line, plt,show()
according to the answer here, multiple markers in legend , but that didn't seem to remove the "duplicate markers" in this context.
Also attached is the graph, with (1) and (2) highlighted
Tip -: Ignore the looping constructs, they are a part of the larger piece, and did not want to change that while pasting, focus on this snippet of the entire code (IMO, this should narrow the problem?)
rects1 = ax.bar(ind, Current_Period, width, color=colors)
rects2 = ax.bar(ind+width, Next_Period, width, color='c')
lines_1=par1.plot(perform_1,linestyle='', marker='H', markerfacecolor ='k')
lines_2=par1.plot(perform_2,linestyle='', marker='*',markerfacecolor ='m')
ax.legend((rects1[0], rects2[0],lines_1[0],lines_2[0]), ('Current time period', 'Next time Period','Current Period Performance', 'Next Period Performance'),prop=dict(size=10) )
Here is the complete code that I used -:
#Final plotting file
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rc
#placing anchored text within the figure
from mpl_toolkits.axes_grid.anchored_artists import AnchoredText
rc('mathtext', default='regular')
history_P=[[1.4155322812819471, 4.9723842851306213, 3.6831354714462456, 3.0345047089322521, 5.3355879766963819], [2.3240101637275856, 4.7804345245879354, 7.0829471987293973, 6.1050663075245852, 3.6087166298399973], [3.5770722538162265, 3.4516290562530587, 4.4851829512197678, 5.1158026103364733, 3.7873662329909235], [4.7137003352158136, 5.0792119756378593, 4.4624078437179504, 3.1790266221827754, 4.8711126648436895], [4.8043291762010414, 5.6979872315568576, 3.4869780377350339, 3.892755123606721, 3.8142509389863095], [4.8072846135271492, 4.2055137431209033, 5.0441056822018417, 4.1014759291893306, 5.327936039526822]]
history_C=[[14000, 14000, 14000, 14000, 14000], [5373, 18874, 13981, 11519, 20253], [6806, 14001, 20744, 17880, 10569], [12264, 11834, 15377, 17540, 12985], [14793, 15940, 14004, 9977, 15286], [15500, 18384, 11250, 12559, 12307]]
N = 5
ind = np.arange(N) # the x locations for the groups
width = 0.35
def make_patch_spines_invisible(ax):
ax.set_frame_on(True)
ax.patch.set_visible(False)
for sp in ax.spines.itervalues():
sp.set_visible(False)
def autolabel(rects):
# attach some text labels
for rect in rects:
height = rect.get_height()
ax.text(rect.get_x()+rect.get_width()/2., 1.05*height, '%d'%int(height),ha='center', va='bottom')
alphab = ['M1', 'M2', 'M3', 'M4', 'M5', 'M6']
for k in range(0,5):
colors=[]
Current_Period=history_C[k]
Next_Period = history_C[k+1]
perform_1=history_P[k]
perform_2=history_P[k+1]
for i in range(0,5):
if perform_1[i]==max(perform_1) :
colors.append('g')
best=i
elif perform_1[i]==min(perform_1):
colors.append('r')
worst=i
elif (perform_1[i] != min(perform_1) or perform_1[i] != max(perform_1)):
colors.append('b')
fig, ax = plt.subplots()
fig.subplots_adjust(right=0.75)
par1 = ax.twinx()
make_patch_spines_invisible(par1)
rects1 = ax.bar(ind, Current_Period, width, color=colors)
rects2 = ax.bar(ind+width, Next_Period, width, color='c')
lines_1=par1.plot(perform_1,linestyle='', marker='H', markerfacecolor ='k')
lines_2=par1.plot(perform_2,linestyle='', marker='*',markerfacecolor ='m')
ax.set_xlabel("Model #",style='italic',size='large')
ax.set_ylabel("Candidate #",style='italic',size='large')
par1.set_ylabel("Performance",style='italic',size='large')
ax.set_title('Aggregated Performace Rolled out to candidates, per period',style='italic')
#fontdict=dict('fontsize':rcParams['axes.titlesize'],'verticalalignment': 'baseline', 'horizontalalignment': loc)
ax.set_xticks(ind+width)
ax.set_xticklabels( ('M1', 'M2', 'M3', 'M4', 'M5') )
ax.annotate('Worst Performer', xy=(worst,0), xycoords='data',xytext=(-30, 30), textcoords='offset points',size=12, va="center", ha="center",arrowprops=dict(arrowstyle="simple", connectionstyle="arc3,rad=-0.2"))
ax.annotate('Best Performer', xy=(best,0), xycoords='data',xytext=(-30, 30), textcoords='offset points',size=12, va="center", ha="center",arrowprops=dict(arrowstyle="simple", connectionstyle="arc3,rad=-0.2"))
ax.legend((rects1[0], rects2[0],lines_1[0],lines_2[0]), ('Current time period', 'Next time Period','Current Period Performance', 'Next Period Performance'),prop=dict(size=10) )
#placing anchored text within the figure, per Period
at = AnchoredText("Time Period :"+str(k+1),prop=dict(size=10), frameon=True,loc=2,)
at.patch.set_boxstyle("round,pad=0.,rounding_size=0.2")
ax.add_artist(at)
par1.set_ylim(0, 10)
autolabel(rects1)
autolabel(rects2)
plt.show()
You have to provide the plot
method with x-coordinate arguments. If given only one list-like object, matplotlib will use this list as the y-coordinates and use x = np.arange(len(y))
(where y
are the given y-coordinates).
You should not call the legend
method several times for each Axes
; include the numpoints
kwarg in your original legend
call.
In other words, replace the lines
lines_1=par1.plot(perform_1,linestyle='', marker='H', markerfacecolor ='k')
lines_2=par1.plot(perform_2,linestyle='', marker='*',markerfacecolor ='m')
ax.legend((rects1[0], rects2[0],lines_1[0],lines_2[0]), ('Current time period', 'Next time Period','Current Period Performance', 'Next Period Performance'),prop=dict(size=10) )
with
lines_1=par1.plot(ind + 0.5*width, perform_1,linestyle='', marker='H', markerfacecolor ='k')
lines_2=par1.plot(ind + 1.5*width, perform_2,linestyle='', marker='*',markerfacecolor ='m')
ax.legend((rects1[0], rects2[0],lines_1[0],lines_2[0]), ('Current time period', 'Next time Period','Current Period Performance', 'Next Period Performance'),prop=dict(size=10), numpoints=1 )
This gives the desire output: