how to add matplotlib figure number to facetgrid object? - python

so I have a canvas with a figure in matplotlib and I would like to add the plot output of a seaborn facetgrid object to it. the seaborn catplot function (which I need) returns me a facetgrid but how can I add the ax to the matplotlib.pyplot.figure ? It would be also fine if I could specify the figure_id (=num) for facetgrid.fig. (normally I would just call sns.swarmplot() and the figure is added)
thanks in advance !!
example code with approaches I tried:
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
### example data
test_data = {'sample': ['id_1', 'id_2', 'id_1','id_2'],
'val': [1, 2, 3, 2],
'cond':['cond_1','cond_1','cond_2','cond_2']}
df = pd.DataFrame(data = test_data)
figure_id = 17
fig = plt.figure(num=figure_id)
fg = sns.catplot(x="cond", y="val", hue="sample", kind="point", data = df) # returns facetgrid
### draw fg.ax on figure with num 17
### tried out different ways to copy it into the subplot or ax object
# fig, ax = plt.subplots(1,1, num=figure_id)
# ax = fg.ax # => shows coordinates but no data
# fig.axes.append(fg.ax) # also do not work
# fig.add_subplot(fg.subplots)

Related

Why are my subplots plotting only to the last ax?

So in Spyder IPython and in Jupyter notebook, the following code is failing to create subplots:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
mydict = {'a': [1,2,3,4], 'b':[2,3,4,5], 'c':[3,4,5,6]}
df = pd.DataFrame(mydict)
fig, axes = plt.subplots(3,1)
axes[0] = plt.plot(df.a)
axes[1] = plt.plot(df.b)
axes[2] = plt.plot(df.c)
plt.show(fig)
and it gives back the following plot:
this also happens when I copy-c copy-vd the example code from the matplotlib webpage
what I would like is the three columns in the three different subplots to be plotted
If you create your axes using plt.subplots you are using the object oriented approach in matplotlib. Then you have to call plot() on the axes object, so axes[0].plot(df.a), not plt.plot.
What you are doing is a weird hybrid between the procedural and object oriented approach and you also overwrite the axes objects that you created when you write axes[0] = plt.plot(....
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
mydict = {'a': [1,2,3,4], 'b':[2,3,4,5], 'c':[3,4,5,6]}
df = pd.DataFrame(mydict)
fig, axes = plt.subplots(3,1)
axes[0].plot(df.a)
axes[1].plot(df.b)
axes[2].plot(df.c)
plt.show()

Seaborn - Display Last Value / Label

I would like create an plot with to display the last value on line. But i can not create the plot with the last value on chart. Do you have an idea for to resolve my problem, thanks you !
Input :
DataFrame
Plot
Output :
Cross = Last Value In columns
Output Final
# import eikon as ek
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
import os
import seaborn as sns; sns.set()
import pylab
from scipy import *
from pylab import *
fichier = "P:/GESTION_RPSE/GES - Gestion Epargne Salariale/Dvp Python/Florian/Absolute
Performance/PLOT.csv"
df = pd.read_csv(fichier)
df = df.drop(columns=['Unnamed: 0'])
# sns.set()
plt.figure(figsize=(16, 10))
df = df.melt('Date', var_name='Company', value_name='Value')
#palette = sns.color_palette("husl",12)
ax = sns.lineplot(x="Date", y="Value", hue='Company', data=df).set_title("LaLaLa")
plt.show()
Do you just want to put an 'X' at the end of your lines?
If so, you could pass markerevery=[-1] to the call to lineplot(). However there are a few caveats:
You have to use style= instead of hue= otherwise, there are no markers drawn
Filled markers work better than unfilled markers (like "x"). You can just use markers=True to use the default markers, or pass a list markers=['s','d','o',etc...]
code:
fmri = sns.load_dataset("fmri")
fig, ax = plt.subplots()
ax = sns.lineplot(x="timepoint", y="signal",
style="event", data=fmri, ci=None, markers=True, markevery=[-1], markersize=10)

Adding a legend to a Pandas DataFrame boxplot

I am plotting a series of boxplots on the same axes and want to adda legend to identify them.
Very simplified, my script looks like this:
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
df={}
bp={}
positions = [1,2,3,4]
df[0]= pd.DataFrame (np.random.rand(4,4),columns =['A','B','C','D'])
df[1]= pd.DataFrame (np.random.rand(4,4),columns =['A','B','C','D'])
colour=['red','blue']
fig, ax = plt.subplots()
for i in [0,1]:
bp[i] = df[i].plot.box(ax=ax,
positions = positions,
color={'whiskers': colour[i],
'caps': colour[i],
'medians': colour[i],
'boxes': colour[i]}
)
plt.legend([bp[i] for i in [0,1]], ['first plot', 'second plot'])
fig.show()
The plot is fine, but the legend is not drawn and I get this warning
UserWarning: Legend does not support <matplotlib.axes._subplots.AxesSubplot object at 0x000000000A7830F0> instances.
A proxy artist may be used instead.
(I have had this warning before when adding a legend to a scatter plot, but the legend was still drawn, so i could ignore it. )
Here is a link to a description of proxy artists, but it is not clear how to apply this to my script. Any suggestions?
'pandas' plots return AxesSubplot objects which can not be used for generating legends. You must generate you own legend using proxy artist instead. I have modified your code:
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.patches as mpatches
df={}
bp={}
positions = [1,2,3,4]
df[0]= pd.DataFrame (np.random.rand(4,4),columns =['A','B','C','D'])
df[1]= pd.DataFrame (np.random.rand(4,4),columns =['A','B','C','D'])
colour=['red','blue']
fig, ax = plt.subplots()
for i in [0,1]:
bp[i] = df[i].plot.box(ax=ax,
positions = positions,
color={'whiskers': colour[i],
'caps': colour[i],
'medians': colour[i],
'boxes': colour[i]}
)
red_patch = mpatches.Patch(color='red', label='The red data')
blue_patch = mpatches.Patch(color='blue', label='The blue data')
plt.legend(handles=[red_patch, blue_patch])
plt.show()
The results are shown below:

Scatter plot from multiple columns of a pandas dataframe

I have a pandas dataframe that looks as below:
Filename GalCer(18:1/12:0)_IS GalCer(d18:1/16:0) GalCer(d18:1/18:0)
0 A-1-1 15.0 1.299366 40.662458 0.242658 6.891069 0.180315
1 A-1-2 15.0 1.341638 50.237734 0.270351 8.367316 0.233468
2 A-1-3 15.0 1.583500 47.039423 0.241681 7.902761 0.201153
3 A-1-4 15.0 1.635365 53.139610 0.322680 9.578195 0.345681
4 B-1-10 15.0 2.370330 80.209846 0.463770 13.729810 0.395355
I am trying to plot a scatter sub-plots with a shared x-axis with the first column "Filename" on the x-axis. While I am able to generate barplots, the following code gives me a key error for a scatter plot:
import matplotlib.pyplot as plt
colnames = list (qqq.columns)
qqq.plot.scatter(x=qqq.Filename, y=colnames[1:], legend=False, subplots = True, sharex = True, figsize = (10,50))
KeyError: "['A-1-1' 'A-1-2' 'A-1-3' 'A-1-4' 'B-1-10' ] not in index"
The following code for barplots works fine. Do I need to specify something differently for the scatterplots?
import matplotlib.pyplot as plt
colnames = list (qqq.columns)
qqq.plot(x=qqq.Filename, y=colnames[1:], kind = 'bar', legend=False, subplots = True, sharex = True, figsize = (10,30))
A scatter plot will require numeric values for both axes. In this case you can use the index as x values,
df.reset_index().plot(x="index", y="other column")
The problem is now that you cannot plot several columns at once using the scatter plot wrapper in pandas. Depending on what the reason for using a scatter plot are, you may decide to use a line plot instead, just without lines. I.e. you may specify linestyle="none" and marker="o" to the plot, such that points appear on the plot.
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
fn = ["{}_{}".format(i,j) for i in list("ABCD") for j in range(4)]
df = pd.DataFrame(np.random.rand(len(fn), 4), columns=list("ZXYQ"))
df.insert(0,"Filename",pd.Series(fn))
colnames = list (df.columns)
df.reset_index().plot(x="index", y=colnames[1:], kind = 'line', legend=False,
subplots = True, sharex = True, figsize = (5.5,4), ls="none", marker="o")
plt.show()
In case you absolutely need a scatter plot, you may create a subplots grid first and then iterate over the columns and axes to plot one scatter plot at a time to the respective axes.
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
fn = ["{}_{}".format(i,j) for i in list("ABCD") for j in range(4)]
df = pd.DataFrame(np.random.rand(len(fn), 4), columns=list("ZXYQ"))
df.insert(0,"Filename",pd.Series(fn))
colnames = list (df.columns)
fig, axes = plt.subplots(nrows=len(colnames)-1, sharex = True,figsize = (5.5,4),)
for i, ax in enumerate(axes):
df.reset_index().plot(x="index", y=colnames[i+1], kind = 'scatter', legend=False,
ax=ax, c=colnames[i+1], cmap="inferno")
plt.show()

Change the facecolor of boxplot in pandas

I need to change the colors of the boxplot drawn using pandas utility function. I can change most properties using the color argument but can't figure out how to change the facecolor of the box. Someone knows how to do it?
import pandas as pd
import numpy as np
data = np.random.randn(100, 4)
labels = list("ABCD")
df = pd.DataFrame(data, columns=labels)
props = dict(boxes="DarkGreen", whiskers="DarkOrange", medians="DarkBlue", caps="Gray")
df.plot.box(color=props)
While I still recommend seaborn and raw matplotlib over the plotting interface in pandas, it turns out that you can pass patch_artist=True as a kwarg to df.plot.box, which will pass it as a kwarg to df.plot, which will pass is as a kwarg to matplotlib.Axes.boxplot.
import pandas as pd
import numpy as np
data = np.random.randn(100, 4)
labels = list("ABCD")
df = pd.DataFrame(data, columns=labels)
props = dict(boxes="DarkGreen", whiskers="DarkOrange", medians="DarkBlue", caps="Gray")
df.plot.box(color=props, patch_artist=True)
As suggested, I ended up creating a function to plot this, using raw matplotlib.
def plot_boxplot(data, ax):
bp = ax.boxplot(data.values, patch_artist=True)
for box in bp['boxes']:
box.set(color='DarkGreen')
box.set(facecolor='DarkGreen')
for whisker in bp['whiskers']:
whisker.set(color="DarkOrange")
for cap in bp['caps']:
cap.set(color="Gray")
for median in bp['medians']:
median.set(color="white")
ax.axhline(0, color="DarkBlue", linestyle=":")
ax.set_xticklabels(data.columns)
I suggest using df.plot.box with patch_artist=True and return_type='both' (which returns the matplotlib axes the boxplot is drawn on and a dictionary whose values are the matplotlib Lines of the boxplot) in order to have the best customization possibilities.
For example, given this data:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame(
data=np.random.randn(100, 4),
columns=list("ABCD")
)
you can set a specific color for all the boxes:
fig,ax = plt.subplots(figsize=(9,6))
ax,props = df.plot.box(patch_artist=True, return_type='both', ax=ax)
for patch in props['boxes']:
patch.set_facecolor('lime')
plt.show()
you can set a specific color for each box:
colors = ['green','blue','yellow','red']
fig,ax = plt.subplots(figsize=(9,6))
ax,props = df.plot.box(patch_artist=True, return_type='both', ax=ax)
for patch,color in zip(props['boxes'],colors):
patch.set_facecolor(color)
plt.show()
you can easily integrate a colormap:
colors = np.random.randint(0,10, 4)
cm = plt.cm.get_cmap('rainbow')
colors_cm = [cm((c-colors.min())/(colors.max()-colors.min())) for c in colors]
fig,ax = plt.subplots(figsize=(9,6))
ax,props = df.plot.box(patch_artist=True, return_type='both', ax=ax)
for patch,color in zip(props['boxes'],colors_cm):
patch.set_facecolor(color)
# to add colorbar
fig.colorbar(plt.cm.ScalarMappable(
plt.cm.colors.Normalize(min(colors),max(colors)),
cmap='rainbow'
), ax=ax, cmap='rainbow')
plt.show()

Categories

Resources