Related
Here is the output of the code :
array = [[64,7,5],
[9,195,1],
[6,17,2]]
df_cm = pd.DataFrame(array, range(3), range(3))
sn.set(font_scale=1.4) # for l)abel size
sn.heatmap(df_cm, annot=True, annot_kws={"size": 16}, cmap='Blues', fmt='g') # font size
class_names = ['dog','cat','bear']
plt.gca().xaxis.tick_top()
plt.gca().xaxis.set_label_position('top')
tick_marks = np.arange(len(class_names))
plt.xticks(tick_marks, class_names, rotation=45, rotation_mode='anchor')
plt.yticks(tick_marks, class_names, rotation='horizontal')# rotation='horizontal', ha='right', rotation_mode='anchor'
plt.tight_layout()
plt.ylabel('True label',size=14)
plt.xlabel('Predicted label',size=14)
plt.show()
I would like to align labels of x and y with center position, So please how can I change the above
With tick_marks = np.arange(len(class_names)) you're setting new tick marks. Just get the existing ones with ax.get_xticks()/ax.get_yticks():
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sn
array = [[64,7,5],
[9,195,1],
[6,17,2]]
df_cm = pd.DataFrame(array, range(3), range(3))
sn.set(font_scale=1.4) # for l)abel size
fig, ax = plt.subplots()
sn.heatmap(df_cm, annot_kws={"size": 16}, cmap='Blues', fmt='g') # font size
class_names = ['dog','cat','bear']
plt.gca().xaxis.tick_top()
plt.gca().xaxis.set_label_position('top')
plt.xticks(ax.get_xticks(), class_names, rotation=45, rotation_mode='anchor')
plt.yticks(ax.get_yticks(), class_names, rotation='horizontal')# rotation='horizontal', ha='right', rotation_mode='anchor'
plt.tight_layout()
plt.ylabel('True label',size=14)
plt.xlabel('Predicted label',size=14)
plt.show()
Output:
Edit: you'll achieve the same result by replacing your plt.xticks(...) and plt.yticks(...) with the following:
plt.gca().set_xticklabels(class_names, rotation=45, rotation_mode='anchor')
plt.gca().set_yticklabels(class_names, rotation='horizontal')
I am generating a subplot in Matplotlib that features four subplots stacked in a vertical orientation. The plot looks as follows:
In order to generate the subplots, I am currently utilizing GridSpec to govern whitespace between the plots and overall layout of each plot. I have included gs.update(wspace=0.00, hspace=0.00), however this has not removed whitespace in between the top three subplots as I anticipated. The expanded code is as follows, please note that I've only included the key pieces for simplicity:
fig, ax = plt.subplots(figsize=(14,8), sharex=True, sharey=True)
gs = gridspec.GridSpec(4, 1, height_ratios=[1, 1, 1, 11.5])
gs.update(wspace=0.00, hspace=0.00)
bar_width = 0.40
botax = plt.subplot(gs[0])
im = plt.imshow(clds_arr, cmap='Blues', vmin=0, vmax=100, interpolation='nearest')
for i in range(len(clds_arr)):
for k,j in zip(clds,range(len(objects_temps))):
if k in list(range(0,51)):
text = plt.text(j, i, clds_arr[i, j], ha="center", va="center", color="k", fontsize=11)
else:
text = plt.text(j, i, clds_arr[i, j], ha="center", va="center", color="w", fontsize=11)
midax = plt.subplot(gs[1], sharex=botax)
im = plt.imshow(temps_arr, cmap=cmap, norm=norm, interpolation='nearest')
for i in range(len(temps_arr)):
for k,j in zip(temps,range(len(objects_temps))):
if k in list(range(-10,5)) + list(range(15,25)) + list(range(88,99)):
text = plt.text(j, i, temps_arr[i, j], ha="center", va="center", color="w", fontsize=11)
else:
text = plt.text(j, i, temps_arr[i, j], ha="center", va="center", color="k", fontsize=11)
upperax = plt.subplot(gs[2], sharex=botax)
im = plt.imshow(dpts_arr, cmap=cmap, norm=norm, interpolation='nearest')
for i in range(len(dpts_arr)):
for k,j in zip(dpts,range(len(objects_temps))):
if k in list(range(-10,5)) + list(range(15,25)) + list(range(88,99)):
text = plt.text(j, i, dpts_arr[i, j], ha="center", va="center", color="w", fontsize=11)
else:
text = plt.text(j, i, dpts_arr[i, j], ha="center", va="center", color="k", fontsize=11)
topax = plt.subplot(gs[3], sharex=botax)
rectstop = plt.bar(ymax_pos, height=highheight, width=0.65, bottom=min_highhght, color='#1e90ff', edgecolor='black', linewidth=2, zorder=3)
for rect in rectstop:
y_value = rect.get_height()+min_highhght
x_value = rect.get_x() + rect.get_width() / 2
space = 2
va = 'bottom'
label = y_value
plttxt = plt.annotate(label, (x_value, y_value), xytext=(0, space), textcoords="offset points", ha='center', va=va)
plttxt.set_fontsize(13)
plttxt.set_weight('semibold')
What additional code is required to remove the additional whitespace in between the top three subplots? Thanks!
I can't run your code as you present it since there are so many undefined variables.
However, when I run a minimal version, I get what you seem to want:
from matplotlib import pyplot, gridspec
fig, ax = pyplot.subplots(figsize=(14,8), sharex=True, sharey=True)
gs = gridspec.GridSpec(4, 1, height_ratios=[1, 1, 1, 11.5])
botax = fig.add_subplot(gs[0])
midax = fig.add_subplot(gs[1], sharex=botax)
upperax = fig.add_subplot(gs[2], sharex=botax)
topax = fig.add_subplot(gs[3], sharex=botax)
gs.update(wspace=0.00, hspace=0.00)
I have tried a number of different things to fix my chart, from zorder on the plots to plt.rcParams.
I feel that this is such a simple problem but I just dont know where I have gone wrong. As you can see the bottom annotation in cyan blue is unreadable and mashed with the y label.
Ideally, the annotation sits over the y label to a point where text inside annotation is readable.
If possible just for the annotation to sit on top and still overlay the y label..something like this
Any help on this would be greatly appreciated.
ax = df.plot(x=df.columns[0], y=df.columns[1], legend=False, zorder=0, linewidth=1)
y1 =df.loc[:, df.columns[2]].tail(1)
y2= df.loc[:, df.columns[1]].tail(1)
colors = plt.rcParams["axes.prop_cycle"].by_key()["color"]
print(colors)
for var in (y1, y2):
plt.annotate('%0.2f' % var.max(), xy=(1, var.max()), zorder=1, xytext=(8, 0),
xycoords=('axes fraction', 'data'),
textcoords='offset points',
bbox=dict(boxstyle="round", fc=colors[0], ec=colors[0],))
ax2 = ax.twinx()
df.plot(x=df.columns[0], y=df.columns[2], ax=ax2, legend=False, color='#fa8174', zorder=0,linewidth=1)
ax.figure.legend(prop=subtitle_font)
ax.grid(True, color="white",alpha=0.2)
pack = [df.columns[1], df.columns[2], freq[0]]
plt.text(0.01, 0.95,'{0} v {1} - ({2})'.format(df.columns[1], df.columns[2], freq[0]),
horizontalalignment='left',
verticalalignment='center',
transform = ax.transAxes,
zorder=10,
fontproperties=subtitle_font)
ax.text(0.01,0.02,"Sources: FRED, Quandl, #Paul92s",
color="white",fontsize=10,
horizontalalignment='left',
transform = ax.transAxes,
verticalalignment='center',
zorder=20,
fontproperties=subtitle_font)
ax.xaxis.set_major_locator(matplotlib.dates.YearLocator())
ax.xaxis.set_minor_locator(matplotlib.dates.MonthLocator((4,7,10)))
ax.xaxis.set_major_formatter(matplotlib.dates.DateFormatter("%Y"))
ax.xaxis.set_minor_formatter(ticker.NullFormatter()) # matplotlib.dates.DateFormatter("%m")
plt.setp(ax.get_xticklabels(), rotation=0, ha="center", zorder=-1)
plt.setp(ax2.get_yticklabels(), rotation=0, zorder=-1)
plt.setp(ax.get_yticklabels(), rotation=0, zorder=-1)
plt.gcf().set_size_inches(14,7)
ax.set_xlabel('Data as of; {0}'.format(df['Date'].max().strftime("%B %d, %Y")), fontproperties=subtitle_font)
y1 =df.loc[:, df.columns[2]].tail(1)
y2= df.loc[:, df.columns[1]].tail(1)
for var in (y1, y2):
plt.annotate('%0.2f' % var.max(), xy=(1, var.max()), zorder=1,xytext=(8, 0),
xycoords=('axes fraction', 'data'),
textcoords='offset points',
bbox=dict(boxstyle="round", fc="#fa8174", ec="#fa8174"))
plt.title('{0}'.format("FRED Velocity of M2 Money Stock v Trade Weighted U.S. Dollar Index: Broad"),fontproperties=heading_font)
ax.texts.append(ax.texts.pop())
ax.set_facecolor('#181818')
ax.figure.set_facecolor('#181818')
plt.rcParams['axes.axisbelow'] = True
I don't figure out why zorder doesn't work, but you can directly set the label style of tick labels:
import matplotlib.pyplot as plt
import numpy as np
from numpy.random import rand
import matplotlib.patches as mpatches
fig, ax = plt.subplots(1, 1)
ax.plot(rand(100), '^', color='r')
for label in ax.get_xticklabels():
label.set_bbox(dict(facecolor='orange'))
ax1 = ax.twinx()
ax1.plot(rand(100), 'o', color='b')
index_to_add_bbox = [2, 4]
ax1_labels = ax1.get_yticklabels()
for i in index_to_add_bbox:
ax1_labels[i].set_bbox(dict(boxstyle='Circle', facecolor='orange'))
plt.show()
I'm trying to display a confusion matrix and can't for the life of my figure out why it refuses to display in an appropriate manner. Here's my code:
import numpy as np
import itertools
from sklearn.metrics import confusion_matrix
def plot_confusion_matrix(cm, classes,
normalize=False,
title='Confusion matrix',
cmap=plt.cm.winter):
if normalize:
cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
plt.imshow(cm, interpolation='nearest', cmap=cmap)
plt.title(title, fontsize=30)
plt.colorbar()
tick_marks = np.arange(len(classes))
plt.xticks(tick_marks, classes, fontsize=20)
plt.yticks(tick_marks, classes, fontsize=20)
fmt = '.2f' if normalize else 'd'
thresh = cm.max() / 2.
for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
plt.text(j, i, format(cm[i, j], fmt), horizontalalignment="center",
color="white" if cm[i, j] < thresh else "black", fontsize=40)
plt.tight_layout()
plt.ylabel('True label', fontsize=30)
plt.xlabel('Predicted label', fontsize=30)
return plt
cm = confusion_matrix(y_test, y_predicted_counts)
fig = plt.figure(figsize=(10, 10))
plot = plot_confusion_matrix(cm, classes=['Unsure','No','Yes'], normalize=False, title='Confusion matrix')
plt.show()
print(cm)
And this is what is displayed:
Any help would be appreciated. Thanks in advance.
For the call to imshow you need to specify origin='lower' (the default is 'upper'; they probably changed this at some time and the scikit-learn docs didn't update their example). So the following should do the trick:
plt.imshow(cm, interpolation='nearest', cmap=cmap, origin='lower')
# ^
# |
# added origin='lower' ------------------------------
Using Matplotlib
If you want to keep your matplotlib implementation, just add plt.ylim(-0.5,2.5) at the end of your plot_confusion_matrix function:
def plot_confusion_matrix(cm, classes,
normalize=False,
title='Confusion matrix',
cmap=plt.cm.winter):
if normalize:
cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
plt.imshow(cm, interpolation='nearest', cmap=cmap)
plt.title(title, fontsize=30)
plt.colorbar()
tick_marks = np.arange(len(classes))
plt.xticks(tick_marks, classes, fontsize=20)
plt.yticks(tick_marks, classes, fontsize=20)
fmt = '.2f' if normalize else 'd'
thresh = cm.max() / 2.
for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
plt.text(j, i, format(cm[i, j], fmt), horizontalalignment="center",
color="white" if cm[i, j] < thresh else "black", fontsize=40)
plt.tight_layout()
plt.ylabel('True label', fontsize=30)
plt.xlabel('Predicted label', fontsize=30)
plt.ylim(-0.5, 2.5) # <-- SOLUTION
return plt
Using Seaborn
you can try the seaborn package for plotting heatmaps:
from sklearn.metrics import confusion_matrix
import pandas as pd
import seaborn as sn
import matplotlib.pyplot as plt
def plot_confusion_matrix(cm, classes,
normalize=False,
title='Confusion matrix',
cmap=plt.cm.winter):
cm_df = pd.DataFrame(cm, columns=classes, index = classes)
cm_df.index.name = 'Actual'
cm_df.columns.name = 'Predicted'
plt.figure(figsize = (10,7))
sn.set(font_scale=1.4)#for label size
ax =sn.heatmap(cm_df, cmap=cmap, annot=True,annot_kws={"size": 16},fmt="d")# font size
plt.title(title)
bottom, top = ax.get_ylim()
ax.set_ylim(bottom + 0.5, top - 0.5)
plt.show()
plot_confusion_matrix(cm, classes=['Unsure','No','Yes'], normalize=False, title='Confusion matrix')
Confusion Matrix Result
Hope this works for you!
It's likely that you're using matplotlib 3.1.1 which broke the tick default behaviour. Upgrade to 3.1.2 or downgrade to 3.1.0 to fix the issue.
How do we draw an average line (horizontal) for a histogram in using matplotlib?
Right now, I'm able to draw the histogram without any issues.
Here is the code I'm using:
## necessary variables
ind = np.arange(N) # the x locations for the groups
width = 0.2 # the width of the bars
plt.tick_params(axis='both', which='major', labelsize=30)
plt.tick_params(axis='both', which='minor', labelsize=30)
ax2 = ax.twinx()
## the bars
rects1 = ax.bar(ind, PAAE1, width,
color='0.2',
error_kw=dict(elinewidth=2,ecolor='red'),
label='PAAE1')
rects2 = ax.bar(ind+width, PAAE2, width,
color='0.3',
error_kw=dict(elinewidth=2,ecolor='black'),
label='PAAE2')
rects3 = ax2.bar(ind+width+width, AAE1, width,
color='0.4',
error_kw=dict(elinewidth=2,ecolor='red'),
label='AAE1')
rects4 = ax2.bar(ind+3*width, AAE2, width,
color='0.5',
error_kw=dict(elinewidth=2,ecolor='black'),
label='AAE3')
maxi = max(dataset[2])
maxi1 = max(dataset[4])
f_max = max(maxi, maxi1)
lns = [rects1,rects2,rects3,rects4]
labs = [l.get_label() for l in lns]
ax.legend(lns, labs, loc='upper center', ncol=4)
# axes and labels
ax.set_xlim(-width,len(ind)+width)
ax.set_ylim(0, 100)
ax.set_ylabel('PAAE', fontsize=25)
ax2.set_ylim(0, f_max+500)
ax2.set_ylabel('AAE (mW)', fontsize=25)
xTickMarks = dataset[0]
ax.set_xticks(ind+width)
xtickNames = ax.set_xticklabels(xTickMarks)
plt.setp(xtickNames, rotation=90, fontsize=25)
I want to plot the average line for PAAE 1, 2 and AAE 1, 2.
What should I be using to plot the average line?
If you'd like a vertical line to denote the mean use axvline(x_value). This will place a vertical line that always spans the full (or specified fraction of) y-axis. There's also axhline for horizontal lines.
In other works, you might have something like this:
ax.axvline(data1.mean(), color='blue', linewidth=2)
ax.axvline(data2.mean(), color='green', linewidth=2)
As a more complete, but unnecessarily complex example (most of this is nicely annotating the means with curved arrows):
import numpy as np
import matplotlib.pyplot as plt
data1 = np.random.normal(0, 1, 1000)
data2 = np.random.normal(-2, 1.5, 1000)
fig, ax = plt.subplots()
bins = np.linspace(-10, 5, 50)
ax.hist(data1, bins=bins, color='blue', label='Dataset 1',
alpha=0.5, histtype='stepfilled')
ax.hist(data2, bins=bins, color='green', label='Dataset 2',
alpha=0.5, histtype='stepfilled')
ax.axvline(data1.mean(), color='blue', linewidth=2)
ax.axvline(data2.mean(), color='green', linewidth=2)
# Add arrows annotating the means:
for dat, xoff in zip([data1, data2], [15, -15]):
x0 = dat.mean()
align = 'left' if xoff > 0 else 'right'
ax.annotate('Mean: {:0.2f}'.format(x0), xy=(x0, 1), xytext=(xoff, 15),
xycoords=('data', 'axes fraction'), textcoords='offset points',
horizontalalignment=align, verticalalignment='center',
arrowprops=dict(arrowstyle='-|>', fc='black', shrinkA=0, shrinkB=0,
connectionstyle='angle,angleA=0,angleB=90,rad=10'),
)
ax.legend(loc='upper left')
ax.margins(0.05)
plt.show()