fig, ax = plt.subplots(figsize = (10,7))
sns.lineplot(data = dearborn_1111_groupby,
x = 'Date',
y = 'Rent',
hue = 'generic_type',
palette = 'husl',
ax = ax).set_title('1111 Dearborn Median In Place Rents (2018 - 2022)')
sns.lineplot(data = dearborn_1111_groupby,
x = 'Date',
y = 'Rent_apartlist',
color = 'black',
ax = ax)
ax.legend(bbox_to_anchor = (1.15, 0.95), title = 'Unit Type')
plt.show()
line plot
I'm trying to add a legend containing the black line. However the black line is a separate lineplot. How Do I include the black line into the existing legend or a separate legend?
You can to add a label to the line, via sns.lineplot(..., label=...).
Note that when using bbox_to_anchor for the legend, you also need to set loc=.... By default, loc='best', which change the anchor point depending on small changes in the plot or its parameters. plt.tight_layout() fits the legend and the labels nicely into the plot figure.
Here is some example code using Seaborn's flights dataset.
import matplotlib.pyplot as plt
import seaborn as sns
flights = sns.load_dataset('flights')
fig, ax = plt.subplots(figsize=(12, 5))
sns.lineplot(data=flights,
x='year',
y='passengers',
hue='month',
palette='husl',
ax=ax)
sns.lineplot(data=flights,
x='year',
y='passengers',
color='black',
label='Black Line',
ax=ax)
ax.legend(bbox_to_anchor=(1.02, 0.95), loc="upper left", title='Unit Type')
ax.margins(x=0)
plt.tight_layout()
plt.show()
Related
I'm trying to make a heatmap a heatmap with extensive y axis descriptions.
I would like to know if there is anyways to have a second and a third layer on the y tick labels.
fig, ax = plt.subplots(figsize=(20,25))
sns.set(style="darkgrid")
colName = [r'A', r'B', r'C', r'D', r'E']
colTitile = 'Test'
rowName = [r'a', r'b', r'c', r'd']
rowsName = [r'Vegetables', r'Fruits', r'Meats', r'Cheese',
r'Candy', r'Other']
rowTitile = 'Groups'
heatmapdata= np.arange(100).reshape(24,5)
sns.heatmap(heatmapdata,
cmap = 'turbo',
cbar = True,
vmin=0,
vmax=100,
ax=ax,
xticklabels = colName,
yticklabels = rowName)
for x in np.arange(0,len(ax.get_yticks()),4):
ax.axhline(x, color = 'white', lw=2)
Is there any way to do this? Which function should I use?
Thanks!
The labels for the rows can be set up in the graph settings, but other than that, I think the annotation function is the only way to handle this. the second level group names are set using the annotation function, and the coordinate criteria are set using the axis criteria. Axis labels are added using the text function with axis criteria.
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots(figsize=(10,10))
sns.set(style="darkgrid")
colName = [r'A', r'B', r'C', r'D', r'E']
colTitile = 'Test'
rowName = [r'a', r'b', r'c', r'd']
rowsName = [r'Vegetables', r'Fruits', r'Meats', r'Cheese',
r'Candy', r'Other']
rowTitle = 'Groups'
heatmapdata= np.arange(120).reshape(24,5)
sns.heatmap(heatmapdata,
cmap='turbo',
cbar=True,
vmin=0,
vmax=100,
ax=ax,
xticklabels=colName,
yticklabels=np.tile(rowName, 6))
for x in np.arange(0,ax.get_ylim()[0],4):
ax.axhline(x, color = 'white', lw=2)
for idx,g in enumerate(rowsName[::-1]):
ax.annotate(g, xy=(-100, idx*90+45), xycoords='axes points', size=14)
ax.text(x=-0.3, y=0.5, s=rowTitle, ha='center', transform=ax.transAxes, rotation=90, font=dict(size=16))
plt.show()
My colorbar is very far away from the bottom of my heatmap. Is there a way to move it closer?
My code is:
import seaborn as sns
Granger2 = Granger
Granger2.columns = Granger_colnames
Granger2.index = Granger_rownames
fig, ax = plt.subplots(figsize=(6,25))
sns.heatmap(Granger2, cmap=rvb, cbar=True, ax=ax,linewidths=.5,cbar_kws={"orientation": "horizontal"})
ax.xaxis.tick_top() # x axis on top
ax.xaxis.set_label_position('top')
#Remove ticks
ax.tick_params(axis='both', which='both', length=0)
# Drawing the frame
ax.axhline(y = 0, color='k',linewidth = 1)
ax.axhline(y = Granger2.shape[0], color = 'k',linewidth = 1)
ax.axvline(x = 0, color = 'k', linewidth = 1)
ax.axvline(x = Granger2.shape[1], color = 'k', linewidth = 1)
plt.show()
You can use e.g. cbar_kws={"orientation": "horizontal", "pad":0.02}. The padding is a fraction of the subplot height, so 0.02 is 2%. See the colorbar docs for more information about pad and other parameters.
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
sns.set_style('whitegrid')
flights = sns.load_dataset('flights')
flights = flights.pivot('year', 'month').droplevel(0, axis=1)
fig, ax = plt.subplots(figsize=(6, 20))
sns.heatmap(flights, cmap='Greens', cbar=True, ax=ax, linewidths=.5,
cbar_kws={"orientation": "horizontal", "pad": 0.02})
ax.xaxis.tick_top() # x axis on top
ax.xaxis.set_label_position('top')
# Remove ticks
ax.tick_params(axis='both', which='both', length=0)
# Drawing the frame
ax.patch.set_edgecolor('0.15')
ax.patch.set_linewidth(2)
plt.tight_layout()
plt.show()
I used the following code to create scatterplot (data is imported as an example). However, the plot was created without x and y axis, which looks weird. I would like to keep facecolor='white' as well.
import seaborn as sns
tips = sns.load_dataset("tips")
fig, ax = plt.subplots(figsize=(10, 8))
sns.scatterplot(
x='total_bill',
y='tip',
data=tips,
hue='total_bill',
edgecolor='black',
palette='rocket_r',
linewidth=0.5,
ax=ax
)
ax.set(
title='title',
xlabel='total_bill',
ylabel='tip',
facecolor='white'
);
Any suggestions? Thanks a lot.
You seem to have explicitly set the default seaborn theme. That has no border (so also no line for x and y axis), a grey facecolor and white grid lines. You can use sns.set_style("whitegrid") to have a white facecolor. You can also use sns.despine() to only show the x and y-axis but no "spines" at the top and right. See Controlling figure aesthetics for more information about fine-tuning how the plot looks like.
Here is a comparison. Note that the style should be set before the axes are created, so for demo-purposes plt.subplot creates the axes one at a time.
import matplotlib.pyplot as plt
import seaborn as sns
sns.set() # set the default style
# sns.set_style('white')
tips = sns.load_dataset("tips")
fig = plt.figure(figsize=(18, 6))
for subplot_ind in (1, 2, 3):
if subplot_ind >= 2:
sns.set_style('white')
ax = plt.subplot(1, 3, subplot_ind)
sns.scatterplot(
x='total_bill',
y='tip',
data=tips,
hue='total_bill',
edgecolor='black',
palette='rocket_r',
linewidth=0.5,
ax=ax
)
ax.set(
title={1: 'Default theme', 2: 'White style', 3: 'White style with despine'}[subplot_ind],
xlabel='total_bill',
ylabel='tip'
)
if subplot_ind == 3:
sns.despine(ax=ax)
plt.tight_layout()
plt.show()
This one used to work fine, but somehow it stopped working (I must have changed something mistakenly but I can't find the issue).
I'm plotting a set of 3 bars per date, plus a line that shows the accumulated value of one of them. But only one or another (either the bars or the line) is properly being plotted. If I left the code for the bars last, only the bars are plotted. If I left the code for the line last, only the line is plotted.
fig, ax = plt.subplots(figsize = (15,8))
df.groupby("date")["result"].sum().cumsum().plot(
ax=ax,
marker='D',
lw=2,
color="purple")
df.groupby("date")[selected_columns].sum().plot(
ax=ax,
kind="bar",
color=["blue", "red", "gold"])
ax.legend(["LINE", "X", "Y", "Z"])
Appreciate the help!
Pandas draws bar plots with the x-axis as categorical, so internally numbered 0, 1, 2, ... and then setting the label. The line plot uses dates as x-axis. To combine them, both need to be categorical. The easiest way is to drop the index from the line plot. Make sure that the line plot is draw first, enabling the labels to be set correctly by the bar plot.
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
df = pd.DataFrame({'date': pd.date_range('20210101', periods=10),
'earnings': np.random.randint(100, 600, 10),
'costs': np.random.randint(0, 200, 10)})
df['result'] = df['earnings'] - df['costs']
fig, ax = plt.subplots(figsize=(15, 8))
df.groupby("date")["result"].sum().cumsum().reset_index(drop=True).plot(
ax=ax,
marker='D',
lw=2,
color="purple")
df.groupby("date")[['earnings', 'costs', 'result']].sum().plot(
ax=ax,
kind="bar",
rot=0,
width=0.8,
color=["blue", "red", "gold"])
ax.legend(['Cumul.result', 'earnings', 'costs', 'result'])
# shorten the tick labels to only the date
ax.set_xticklabels([tick.get_text()[:10] for tick in ax.get_xticklabels()])
ax.set_ylim(ymin=0) # bar plots are nicer when bars start at zero
plt.tight_layout()
plt.show()
Here I post the solution:
import matplotlib.pyplot as plt
import matplotlib.ticker as mtick
a=[11.3,222,22, 63.8,9]
b=[0.12,-1.0,1.82,16.67,6.67]
l=[i for i in range(5)]
plt.rcParams['font.sans-serif']=['SimHei']
fmt='%.1f%%'
yticks = mtick.FormatStrFormatter(fmt)
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax1.plot(l, b,'og-',label=u'A')
ax1.yaxis.set_major_formatter(yticks)
for i,(_x,_y) in enumerate(zip(l,b)):
plt.text(_x,_y,b[i],color='black',fontsize=8,)
ax1.legend(loc=1)
ax1.set_ylim([-20, 30])
ax1.set_ylabel('ylabel')
plt.legend(prop={'family':'SimHei','size':8})
ax2 = ax1.twinx()
plt.bar(l,a,alpha=0.1,color='blue',label=u'label')
ax2.legend(loc=2)
plt.legend(prop={'family':'SimHei','size':8},loc="upper left")
plt.show()
The key to this is the command
ax2 = ax1.twinx()
i wanted to know how to make a plot with two y-axis so that my plot that looks like this :
to something more like this by adding another y-axis :
i'm only using this line of code from my plot in order to get the top 10 EngineVersions from my data frame :
sns.countplot(x='EngineVersion', data=train, order=train.EngineVersion.value_counts().iloc[:10].index);
I think you are looking for something like:
import matplotlib.pyplot as plt
x = [1,2,3,4,5]
y = [1000,2000,500,8000,3000]
y1 = [1050,3000,2000,4000,6000]
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax1.bar(x, y)
ax2.plot(x, y1, 'o-', color="red" )
ax1.set_xlabel('X data')
ax1.set_ylabel('Counts', color='g')
ax2.set_ylabel('Detection Rates', color='b')
plt.show()
Output:
#gdubs If you want to do this with Seaborn's library, this code set up worked for me. Instead of setting the ax assignment "outside" of the plot function in matplotlib, you do it "inside" of the plot function in Seaborn, where ax is the variable that stores the plot.
import seaborn as sns # Calls in seaborn
# These lines generate the data to be plotted
x = [1,2,3,4,5]
y = [1000,2000,500,8000,3000]
y1 = [1050,3000,2000,4000,6000]
fig, ax1 = plt.subplots() # initializes figure and plots
ax2 = ax1.twinx() # applies twinx to ax2, which is the second y axis.
sns.barplot(x = x, y = y, ax = ax1, color = 'blue') # plots the first set of data, and sets it to ax1.
sns.lineplot(x = x, y = y1, marker = 'o', color = 'red', ax = ax2) # plots the second set, and sets to ax2.
# these lines add the annotations for the plot.
ax1.set_xlabel('X data')
ax1.set_ylabel('Counts', color='g')
ax2.set_ylabel('Detection Rates', color='b')
plt.show(); # shows the plot.
Output:
Seaborn output example
You could try this code to obtain a very similar image to what you originally wanted.
import seaborn as sb
from matplotlib.lines import Line2D
from matplotlib.patches import Rectangle
x = ['1.1','1.2','1.2.1','2.0','2.1(beta)']
y = [1000,2000,500,8000,3000]
y1 = [3,4,1,8,5]
g = sb.barplot(x=x, y=y, color='blue')
g2 = sb.lineplot(x=range(len(x)), y=y1, color='orange', marker='o', ax=g.axes.twinx())
g.set_xticklabels(g.get_xticklabels(), rotation=-30)
g.set_xlabel('EngineVersion')
g.set_ylabel('Counts')
g2.set_ylabel('Detections rate')
g.legend(handles=[Rectangle((0,0), 0, 0, color='blue', label='Nontouch device counts'), Line2D([], [], marker='o', color='orange', label='Detections rate for nontouch devices')], loc=(1.1,0.8))