Legend not showing when plotting multiple seaborn plots - matplotlib

I typically don't have problems with matplotlib legend, but this is the first time I am using it with multiple seaborn plots, and the following does not work.
fig = plt.figure(figsize=(10,6))
a =sns.regplot(x='VarX', y='VarY1', data=data)
b = sns.regplot(x='VarX', y='VarY2', data=data)
c = sns.regplot(x='VarX', y='VarY3', data=data)
fig.legend(handles=[a, b, c],labels=['First','Second','Third'])
fig.show()
What am I doing wrong?

seaborn.regplot returns an axes. You cannot create a legend proxy handle from an axes. However this is not even necessary. Remove the handles from the legend and it should give the desired plot.
import matplotlib.pyplot as plt
import numpy as np; np.random.seed(1)
import pandas as pd
import seaborn as sns
data=pd.DataFrame({"VarX" : np.arange(10),
'VarY1': np.random.rand(10),
'VarY2': np.random.rand(10),
'VarY3': np.random.rand(10)})
fig = plt.figure(figsize=(10,6))
sns.regplot(x='VarX', y='VarY1', data=data)
sns.regplot(x='VarX', y='VarY2', data=data)
sns.regplot(x='VarX', y='VarY3', data=data)
fig.legend(labels=['First','Second','Third'])
plt.show()

Related

How to plot multiple graphs stacked above each other

I need to plot a set of 9 or more data sets with a common x-axis. I was able to do it for 2 of them but the rest of them just don't appear. They have to be stacked one above the other. with a common x axis. I have attached the image of what I have been able to do so far.
stack of plot
I have used the following code
import numpy as np
import pandas as pd
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
import matplotlib.gridspec as gridspec
from matplotlib.lines import Line2D
import matplotlib.lines as mlines
file1 = '1.dat'
file2 = '10.dat'
data1 = pd.read_csv(file1, delimiter='\s+', header=None, engine='python')
data1.columns = ['M','B','C']
data2 = pd.read_csv(file2, delimiter='\s+', header=None, engine='python')
data2.columns = ['N','A','D']
def fit_data():
fig = plt.figure(1,figsize=(12,11))
ax1= fig.add_subplot(211,)
ax1.plot(data1['M'], data1['B'], color='cornflowerblue', linestyle= '-', lw=0.5)
ax1.scatter(data1['M'], data1['B'], marker='o', color='red', s=25)
ax1.errorbar(data1['M'], data1['B'], data1['C'], fmt='.', ecolor='red',color='red', elinewidth=1,capsize=3)
ax2 = fig.add_subplot(211, sharex=ax1 )
ax2.plot(data2['N'], data2['A'], color='cornflowerblue', linestyle= '-', lw=0.5)
ax2.scatter(data2['N'], data2['A'], marker='o', color='blue', s=25)
ax2.errorbar(data2['N'], data2['A'], data2['D'], fmt='.', ecolor='blue',color='blue', elinewidth=1,capsize=3)
plt.setp(ax1.get_xticklabels(), visible=False) # hide labels
fig.subplots_adjust(hspace=0)
ax1.tick_params(axis='both',which='minor',length=5,width=2,labelsize=18)
ax1.tick_params(axis='both',which='major',length=8,width=2,labelsize=18)
plt.savefig("1.pdf")
#fig.set_size_inches(w=13,h=10)
plt.show()
plt.close()
fit_data()
I read through stacking of plots but wasn't able to apply the same here.
I modified the code to this but this is what I get. modified code.
I need the stacking to be done to do a comparative study. Something like this image. comparative study
This is the part of the code I have modified and used.
plt.setp(ax1.get_xticklabels(), visible=False) # hide labels
fig.subplots_adjust(hspace=0.0) # remove vertical space between subplots
Should it be done seperately for ax1, ax2 and so on?
plt.subplots_adjust(hspace=0.0) removes the space between them.
You can have as many plots as you want:
from matplotlib import pyplot as plt
import numpy as np
numer_of_plots = 9
X = np.random.random((numer_of_plots, 50))
fig, axs = plt.subplots(nrows=numer_of_plots, ncols=1)
for ax, x in zip(axs, X):
ax.plot(range(50), x)
plt.subplots_adjust(hspace=0.0)
plt.show()

Understanding plt.show() in Matplotlib

import numpy as np
import os.path
from skimage.io import imread
from skimage import data_dir
img = imread(os.path.join(data_dir, 'checker_bilevel.png'))
import matplotlib.pyplot as plt
#plt.imshow(img, cmap='Blues')
#plt.show()
imgT = img.T
plt.figure(1)
plt.imshow(imgT,cmap='Greys')
#plt.show()
imgR = img.reshape(20,5)
plt.figure(2)
plt.imshow(imgR,cmap='Blues')
plt.show(1)
I read that plt.figure() will create or assign the image a new ID if not explicitly given one. So here, I have given the two figures, ID 1 & 2 respectively. Now I wish to see only one one of the image.
I tried plt.show(1) epecting ONLY the first image will be displayed but both of them are.
What should I write to get only one?
plt.clf() will clear the figure
import matplotlib.pyplot as plt
plt.plot(range(10), 'r')
plt.clf()
plt.plot(range(12), 'g--')
plt.show()
plt.show will show all the figures created. The argument you forces the figure to be shown in a non-blocking way. If you only want to show a particular figure you can write a wrapper function.
import matplotlib.pyplot as plt
figures = [plt.subplots() for i in range(5)]
def show(figNum, figures):
if plt.fignum_exists(figNum):
fig = [f[0] for f in figures if f[0].number == figNum][0]
fig.show()
else:
print('figure not found')

matplotlib different size of unit along x-axis

everyone. I want to generate a x-axis like the picture showing below.
Except make several different-sized subplots then merged to a single one.
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
axes=[]
ax1 = plt.subplot2grid((1,10),(0,0),colspan=4,rowspan=1)
ax1.plot([0,1],[2,3])
ax2 = plt.subplot2grid((1,10),(0,4),colspan=1,rowspan=1)
ax2.plot([1,2],[3,4])
ax3 = plt.subplot2grid((1,10),(0,5),colspan=3,rowspan=1)
ax3.plot([2,3],[4,5])
ax4 = plt.subplot2grid((1,10),(0,8),colspan=2,rowspan=1)
ax4.plot([3,4],[5,6])
axes=[ax1,ax2,ax3,ax4]
ax1.spines['right'].set_visible(False)
ax1.set_xticks([0,1])
ax1.set_xticklabels(['0','1'])
ax2.spines['right'].set_visible(False)
ax2.spines['left'].set_visible(False)
ax2.yaxis.set_major_locator(ticker.NullLocator())
ax2.set_xticks([2])
ax2.set_xticklabels(['2'])
ax3.spines['right'].set_visible(False)
ax3.spines['left'].set_visible(False)
ax3.yaxis.set_major_locator(ticker.NullLocator())
ax3.set_xticks([3])
ax3.set_xticklabels(['3'])
ax4.spines['left'].set_visible(False)
ax4.yaxis.set_major_locator(ticker.NullLocator())
ax4.set_xticks([4])
ax4.set_xticklabels(['4'])
[plt.setp(axes[i],xlim=[i+0,i+1]) for i in range(4)]
[plt.setp(axes[i],ylim=[2,6]) for i in range(4)]
plt.subplots_adjust(wspace=0,)
plt.savefig('xx.png',format='png',dpi=300)
I wonder is there other way to do this?

Arrange two plots horizontally

As an exercise, I'm reproducing a plot from The Economist with matplotlib
So far, I can generate a random data and produce two plots independently. I'm struggling now with putting them next to each other horizontally.
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
df1 = pd.DataFrame({"broadcast": np.random.randint(110, 150,size=8),
"cable": np.random.randint(100, 250, size=8),
"streaming" : np.random.randint(10, 50, size=8)},
index=pd.Series(np.arange(2009,2017),name='year'))
df1.plot.bar(stacked=True)
df2 = pd.DataFrame({'usage': np.sort(np.random.randint(1,50,size=7)),
'avg_hour': np.sort(np.random.randint(0,3, size=7) + np.random.ranf(size=7))},
index=pd.Series(np.arange(2009,2016),name='year'))
plt.figure()
fig, ax1 = plt.subplots()
ax1.plot(df2['avg_hour'])
ax2 = ax1.twinx()
ax2.bar(left=range(2009,2016),height=df2['usage'])
plt.show()
You should try using subplots. First you create a figure by plt.figure(). Then add one subplot(121) where 1 is number of rows, 2 is number of columns and last 1 is your first plot. Then you plot the first dataframe, note that you should use the created axis ax1. Then add the second subplot(122) and repeat for the second dataframe. I changed your axis ax2 to ax3 since now you have three axis on one figure. The code below produces what I believe you are looking for. You can then work on aesthetics of each plot separately.
%matplotlib inline
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
df1 = pd.DataFrame({"broadcast": np.random.randint(110, 150,size=8),
"cable": np.random.randint(100, 250, size=8),
"streaming" : np.random.randint(10, 50, size=8)},
index=pd.Series(np.arange(2009,2017),name='year'))
ax1 = fig.add_subplot(121)
df1.plot.bar(stacked=True,ax=ax1)
df2 = pd.DataFrame({'usage': np.sort(np.random.randint(1,50,size=7)),
'avg_hour': np.sort(np.random.randint(0,3, size=7) + np.random.ranf(size=7))},
index=pd.Series(np.arange(2009,2016),name='year'))
ax2 = fig.add_subplot(122)
ax2.plot(df2['avg_hour'])
ax3 = ax2.twinx()
ax3.bar(left=range(2009,2016),height=df2['usage'])
plt.show()

Annotate labels in pandas scatter plot

I saw this method from an older post but can't get the plot I want.
To start
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import string
df = pd.DataFrame({'x':np.random.rand(10),'y':np.random.rand(10)},
index=list(string.ascii_lowercase[:10]))
scatter plot
ax = df.plot('x','y', kind='scatter', s=50)
Then define a function to iterate the rows to annotate
def annotate_df(row):
ax.annotate(row.name, row.values,
xytext=(10,-5),
textcoords='offset points',
size=18,
color='darkslategrey')
Last apply to get annotation
ab= df.apply(annotate_df, axis=1)
Somehow I just get a series ab instead of the scatter plot I want. Where is wrong? Thank you!
Your code works, you just need plt.show() at the end.
Your full code:
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import string
df = pd.DataFrame({'x':np.random.rand(10),'y':np.random.rand(10)},
index=list(string.ascii_lowercase[:10]))
ax = df.plot('x','y', kind='scatter', s=50)
def annotate_df(row):
ax.annotate(row.name, row.values,
xytext=(10,-5),
textcoords='offset points',
size=18,
color='darkslategrey')
ab= df.apply(annotate_df, axis=1)
plt.show()
Looks like that this doesn't work any more, however the solution is easy: convert row.values from numpy.ndarray to list:
list(row.values)