Related
I want to have a 3x3 grid of subplots to visualize each Series individually.
I first created some toy data:
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
sns.set(style='whitegrid', rc={"figure.figsize":(14,6)})
rs = np.random.RandomState(444)
dates = pd.date_range(start="2009-01-01", end='2019-12-31', freq='1D')
values = rs.randn(4017,12).cumsum(axis=0)
data = pd.DataFrame(values, dates, columns =['a','b','c','d','e','f','h','i','j','k','l','m'])
Here is the first code I wrote:
fig, ax = plt.subplots(3, 3, sharex=True, sharey=True)
for col in n_cols:
ax = data[col].plot()
With these lines of code the problem is that I get the 3x3 grid but all the columns have been plotten on the same subplotsAxes, in the bottom right corner.
Bottom Right Corner with all Lines
Here is the second thing I tried:
n_cols = ['a', 'b', 'c', 'd', 'e', 'f', 'h', 'i', 'j']
fig, ax = plt.subplots(3, 3, sharex=True, sharey=True)
for col in n_cols:
for i in range(3):
for j in range(3):
ax[i,j].plot(data[col])
But now I get all the columns plotted on every single subplotAxes.
All AxesSubplot with same lines
And if I try something like this:
fig, ax = plt.subplots(sharex=True, sharey=True)
for col in n_cols:
for i in range(3):
for j in range(3):
ax[i,j].add_subplot(data[col])
But I get:
TypeError: 'AxesSubplot' object is not subscriptable
I am sorry but can't figure out what to do.
Currently you're plotting each series in each of the subplots:
for col in n_cols:
for i in range(3):
for j in range(3):
ax[i,j].plot(data[col])
Following your example code, here is a way to only plot a single series per subplot:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
rs = np.random.RandomState(444)
dates = pd.date_range(start="2009-01-01", end='2019-12-31', freq='1D')
values = rs.randn(4017,12).cumsum(axis=0)
data = pd.DataFrame(values, dates, columns =['a','b','c','d','e','f','h','i','j','k','l','m'])
n_cols = ['a', 'b', 'c', 'd', 'e', 'f', 'h', 'i', 'j']
fig, ax = plt.subplots(3, 3, sharex=True, sharey=True)
for i in range(3):
for j in range(3):
col_name = n_cols[i*3+j]
ax[i,j].plot(data[col_name])
plt.show()
I'd like to create a categorical plot of two pandas DataFrame columns a and b in the same figure with shared x and different y axis:
import pandas as pd
import seaborn as sns
example = [
('exp1','f0', 0.25, 2),
('exp1','f1', 0.5, 3),
('exp1','f2', 0.75, 4),
('exp2','f1', -0.25, 1),
('exp2','f2', 1, 2),
('exp2','f3', 0, 3)
]
df = pd.DataFrame(example, columns=['exp', 'split', 'a', 'b'])
mean_df = df.groupby('exp')['a'].mean()
g = sns.catplot(x='exp', y='a', data=df, jitter=False)
ax2 = plt.twinx()
sns.catplot(x='exp', y='b', data=df, jitter=False, ax=ax2)
In this implementation I have the problem that the colors are different for categories (x-values), not for the columns. Can I sole this or do I have to change the data structure?
I would also like to connect the means of the categorical values like in the image like this:
You may want to melt your data first:
data = df.melt(id_vars='exp', value_vars=['a','b'])
fig, ax = plt.subplots()
sns.scatterplot(data=data,
x='exp',
hue='variable',
y='value',
ax=ax)
(data.groupby(['exp','variable'])['value']
.mean()
.unstack('variable')
.plot(ax=ax, legend=False)
)
ax.set_xlim(-0.5, 1.5);
Output:
df = pd.DataFrame(example, columns=['exp', 'split', 'a', 'b'])
mean_df = df.groupby('exp').mean().reset_index()
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
sns.scatterplot(x='exp', y='a', data=df, color='C0', ax=ax1)
sns.scatterplot(x='exp', y='b', data=df, color='C1', ax=ax2)
sns.lineplot(x='exp',y='a', data=mean_df, color='C0', ax=ax1)
sns.lineplot(x='exp',y='b', data=mean_df, color='C1', ax=ax2)
I have a dataframe as shown in the code and I generated a barh chart for each row using a loop. I am trying to plot a single legend for all the charts on the bottom-right corner but without success. I tried the lines of codes such as the ones below - and many others found online - inside the plotting loop and outside without success. Kindly suggest a solution that could work.
#handles, labels = bars.get_legend_handles_labels()
#bars.legend(handles, labels)
#bars.legend(loc='bottom right', ncol=9)
import pandas as pd
import matplotlib.pyplot as plt
import io
lines=['Business Category,Not_sure!,Performance_of_certain_applications,DNS_Resolution_Time,User’s_perception_of_your_network_(QoE),Routing_stability,Packet_loss/Jitter,Network_utilisation,Reachability,Latency,Bandwidth/Throughput\n'
'Academic
Institution,0.0,18.0,16.0,19.0,17.0,17.0,22.0,24.0,26.0,33.0\n'
'Civil society,0.0,5.0,2.0,2.0,1.0,1.0,2.0,4.0,4.0,6.0\n'
'End-user (Home/Mobile broadband),0.0,5.0,7.0,5.0,5.0,6.0,7.0,6.0,9.0,9.0\n'
'Internet Service Provider (ISP),1.0,20.0,22.0,22.0,27.0,31.0,20.0,25.0,32.0,32.0\n'
'Internet eXchange Point (IXP),0.0,2.0,3.0,2.0,7.0,6.0,5.0,5.0,8.0,7.0\n'
'Other,1.0,7.0,8.0,9.0,10.0,9.0,17.0,13.0,16.0,19.0\n'
'Regulator/Government Agency,0.0,1.0,1.0,2.0,1.0,0.0,2.0,1.0,4.0,5.0\n'
'Total,2.0,58.0,59.0,61.0,68.0,70.0,75.0,78.0,99.0,111.0\n']
df3 = pd.read_csv(pd.compat.StringIO("\n".join(lines)), sep=",").set_index('Business Category')
i = j = roundcounter = 0
patterns = ['\\', '|', '/', '+', 'x', 'o', 'O', '.', '*', '-']
color=['orange', 'darkseagreen', 'maroon', 'mediumpurple', 'saddlebrown', 'orchid', 'indianred',
'tomato', 'dimgrey', 'aquamarine']
fig, axes = plt.subplots(3,3, sharex=False, sharey=True)
print("\nWhich of these performance indicators/metrics are important for your organisation/network?\n\n")
for col in df3[:-1].index:
bars = df3.loc[col].plot.barh(width=.9, figsize=(15, 10), color=color, title=df3.loc[col].name,
ax=axes[i, j])
for spine in axes[i, j].spines:
axes[i, j].spines[spine].set_visible(False)
for bar, pattern in zip(bars.patches, patterns):
bar.set_hatch(pattern)
fig.tight_layout()
if j==2:
if roundcounter==0:
roundcounter+=1
i=1
j=0
elif roundcounter==1:
roundcounter+=1
j=0
i=2
elif roundcounter==2:
i=2
j=0
elif j==1 or j==0:
j+=1
axes[2, 1].axis('off')
axes[2, 2].axis('off')
bars.legend()
plt.savefig('figures/metrics.png')
plt.show()
As a new user I cannot post image yet but it is available here: https://drive.google.com/open?id=1c46FOZnA9aBtDb62kJg8h5bxePoTThrI
I am able to fix the problem after trying a number of solutions. See code below. There is an additional 'import matplotlib as mpl' to the libraries in the original question.
#Adding 'Total' row and column to use for sorting.
df3.loc['Total',:]= df3.sum(axis=0)
df3=df3[df3.iloc[-1,:].sort_values(ascending=False).index]
df3['Total'] = df3.sum(axis=1)
df3 = df3.sort_values(by='Total', ascending=False)
i = j = roundcounter = 0
patterns = ['\\', '|', '/', '+', 'x', 'o', 'O', '.', '*', '-']
color=['orange', 'darkseagreen', 'maroon', 'mediumpurple', 'saddlebrown', 'orchid', 'indianred',
'tomato', 'dimgrey', 'aquamarine']
fig, axes = plt.subplots(3,3, sharex=False, sharey=True)
print("\nWhich of these performance indicators/metrics are important for your organisation/network?\n\n")
#Plot the graphs
for col in df3[1:].index:
bars = df3.loc[col].drop(['Total']).plot.barh(width=.9, figsize=(22, 18), color=color, ax=axes[i, j])
axes[i, j].set_title(df3.loc[col].name, fontdict={'fontsize': 25, 'fontweight': 'medium'})
axes[i, j].get_yaxis().set_ticklabels([])
for tick in axes[i, j].xaxis.get_major_ticks():
tick.label.set_fontsize(25)
for spine in axes[i, j].spines:
axes[i, j].spines[spine].set_visible(False)
for bar, pattern in zip(bars.patches, patterns):
bar.set_hatch(pattern)
if j==2:
if roundcounter==0:
roundcounter+=1
i=1
j=0
elif roundcounter==1:
roundcounter+=1
j=0
i=2
elif roundcounter==2:
i=2
j=0
elif j==1 or j==0:
j+=1
axes[0, 2].set_xticks([0, 4, 8, 12, 16, 20], minor=False)
axes[2, 1].axis('off')
axes[2, 2].axis('off')
labels = df3.loc['Academic Institution'].drop(['Total']).index.tolist()
handles = [rect for rect in bars.get_children() if isinstance(rect, mpl.patches.Rectangle)]
legend = fig.legend(handles, labels, loc=4, fontsize=25)
legend.set_title('Metric/Options Selected',prop={'size':26})
plt.savefig('figures/metrics.png', bbox_inches="tight")
fig.tight_layout()
plt.show()
I have a pyplot code.
Since I want to group multiple bars, I am trying to write text in the graph using plt.annotate.
However, as you can see in the picture, the word 'Something' in left bottom gets cropped. Does anyone know How I can fix this?
Here is my code
#!/usr/bin/python
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import operator as o
import numpy as np
n_groups = 5
means_men = (20, 35, 30, 35, 27)
std_men = (2, 3, 4, 1, 2)
means_women = (25, 32, 34, 20, 25)
std_women = (3, 5, 2, 3, 3)
fig, ax = plt.subplots()
index = np.arange(n_groups)
bar_width = 0.35
opacity = 0.4
error_config = {'ecolor': '0.3'}
rects1 = plt.bar(index, means_men, bar_width, alpha=opacity, color='b', yerr=std_men, error_kw=error_config, label='Men')
rects2 = plt.bar(index + bar_width, means_women, bar_width,
alpha=opacity,
color='r',
yerr=std_women,
error_kw=error_config,
label='Women')
#plt.xlabel('Group')
plt.ylabel('Scores')
plt.title('Scores by group and gender')
plt.annotate('Something', (0,0), (50,-40), xycoords = 'axes fraction', textcoords='offset points', va='top');
plt.annotate('Something', (0,0), (200,-20), xycoords = 'axes fraction', textcoords='offset points', va='top');
plt.xticks(index + bar_width, ('A', 'B', 'C', 'D', 'E'))
plt.legend()
plt.savefig('barchart_3.png')
For some reason, matplotlib sometimes clips too aggressively. If you add bbox_inches='tight' to save fig this should include the figure correctly,
plt.savefig('barchart_3.png', bbox_inches='tight')
More generally, you can adjust your main figure with something like,
plt.subplots_adjust(bottom=0.1)
I have a following code which produces a graph -
# imports specific to the plots in this example
import sys
import numpy as np
from matplotlib import cm
import matplotlib.pyplot as plt
resultsDirectory='results'
outputFile=resultsDirectory+".pdf"
axisLabelFontSize=16
borderWidth=0.0
# Twice as wide as it is tall.
fig = plt.figure(figsize=plt.figaspect(0.5))
ax = fig.add_subplot(111)
# Set up the Grid
[i.set_linewidth(borderWidth) for i in ax.spines.itervalues()]
unsatX=[680,2775,3821,680,4073,941,1202,1463]
unsatY=[1,1,1,4,1,2,2,2]
paretoX=[680, 1203, 1726, 4870]
paretoY=[10,7, 4,1]
satX=[4870,680,1727,1726,1203,680]
satY=[1,13,7,4,7,10]
typeX=[680, 1727]
typeY=[13, 7]
leftX=[680]
leftY=[12]
c = np.rec.fromarrays([paretoX, paretoY], names='x,y')
c.sort()
paretoX=c.x
paretoY=c.y
markrsz=8
l4, = plt.plot(paretoX, paretoY, '#000000', lw=2, label='Pareto Curve(unfolding, period locality)',markersize=markrsz,zorder = 10)
l1, = plt.plot(satX, satY, 'bo', label='Sat Points',markersize=markrsz,zorder = 10)
l2, = plt.plot(unsatX, unsatY, 'ro',marker='s',label='Unsat Points',markersize=markrsz,zorder = 10)
l5, = plt.plot(leftX, leftY, 'gp',label='Proc. count pareto points',markersize=markrsz)
l6, = plt.plot(typeX, typeY, 'w*',label='Modulo pareto points',markersize=markrsz,zorder=10)
leg=plt.legend(bbox_to_anchor=(0.,-0.200, 1., 1.102), loc=3, numpoints=1,
ncol=3, mode="expand", borderaxespad=0., fancybox=True, shadow=True,prop={'size':axisLabelFontSize})
rect = leg.get_frame()
rect.set_facecolor('#cccccc') # a grayscale intensity
#leg.set_frame_on(False)
latency=[680,2775,4870, 680,3821,4868, 680,1727,4341,4864, 680,1203,1726,1203, 680,4073,4334,4595,4856, 941,1202,1463,1724]
processor=[1, 1, 1,13, 1, 1, 7, 7, 1, 1, 4, 4, 4, 7,10,1, 1, 1, 1, 2, 2, 2, 2]
ax.set_xlabel('Period',size=axisLabelFontSize,labelpad=10)
ax.set_ylabel('Processors',size=axisLabelFontSize,labelpad=10)
ax.set_xlim(0, max(latency)+100)
ax.set_ylim(0, max(processor)+1)
# Set Border width zero
[i.set_linewidth(0) for i in ax.spines.itervalues()]
gridLineWidth=0.1
ax.set_axisbelow(False)
gridlines = ax.get_xgridlines()+ax.get_ygridlines()
#ax.set_axisbelow(True)
plt.setp(gridlines, 'zorder', 5)
ax.yaxis.grid(True, linewidth=gridLineWidth, linestyle='-', color='0.6',alpha='0.3')
ax.xaxis.grid(False)
ax.xaxis.set_ticks_position('none')
ax.yaxis.set_ticks_position('none')
fig.savefig(outputFile, format="pdf", bbox_inches='tight')
The legends in the plot get messed up.
Could someone tell me how do i fix a long legend entry which overwrites into area of other entry? What would be ideal if, I could do 3 legend entries in first row and two legend entries in the second row.
Besides the workaround found by the question author, a possibility is to add new lines for long labels:
...
l4, = plt.plot(paretoX, paretoY, '#000000', lw=2,
label='Pareto Curve \n(unfolding, period locality)',markersize=markrsz,zorder = 10)
...
The following modification to the code also solved my problem -
leg=plt.legend(bbox_to_anchor=(0.,-0.350, 1., 1.102), loc=3, numpoints=1, ncol=2 , borderaxespad=0., fancybox=True, shadow=True,prop={'size':axisLabelFontSize})