Seaborn Countplot: Displaying the counts on bar - python-3.x

I have written the following code:
plt.figure(figsize=(12,6))
ax = sns.countplot(x='Region', data=data, order=data['Region'].value_counts().iloc[:15].index)
plt.xticks(rotation='vertical')
plt.xlabel('Regions', fontsize=14)
plt.ylabel('Total Restaurants', fontsize=14)
plt.title('Total Restaurnats present in Each Regions', fontsize=20, y=1.03, weight='bold')
My output:
Counting values
values = list(data['Region'].value_counts()[:15].values)
values
My output:
[203, 192, 177, 124, 113, 112, 99, 99, 94, 86, 82, 68, 67, 55, 53]
I want to show the respective values on each bar, like 203 on the first bar; 192 on the second and so on.
Is there any way to do this? I would be more than happy for your help.
Thanks in advance!

This is a version for vertical bars:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
N=11
t = np.linspace(0,0.5*np.pi,N) #---- generate data ----
df = pd.DataFrame({'A':10*np.sin(t),
'B':10*np.cos(t)} )
fig = plt.figure(figsize=(15,8)) #---- set up graphics ----
ax1 = fig.add_subplot(111)
width=0.9 #---- tuning parameters for the bar plot ----
dy = 0.2
df['A'].plot(kind='bar',width=width, color='b', alpha=0.3) #---- define the bar plot ----
for x,y in enumerate(df['A']): #---- annotate the bars ----
plt.annotate(str(np.around(y,decimals=3)), xy=(x+width/2, y+dy), va='center',ha='right', color='b', fontweight='bold', fontsize=16)
df['B'].plot(kind='bar',width=width, color='r', alpha=0.2) #---- define the bar plot ----
for x,y in enumerate(df['B']): #---- annotate the bars ----
plt.annotate(str(np.around(y,decimals=3)), xy=(x+width/2, y+dy), va='center',ha='right', color='r', fontweight='bold', fontsize=16)
plt.show()
pic_name='psc_annotaed_vertical_bars.png'
fig.savefig(pic_name, transparency=True)
And this is a version vor horizontal bars:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
N=11
t = np.linspace(0,0.5*np.pi,N)
df = pd.DataFrame({'A':10*np.sin(t),'B':10*np.cos(t)} )
fig = plt.figure(figsize=(15,8))
ax1 = fig.add_subplot(111)
df['A'].plot(kind='barh',width=0.9, color='b', alpha=0.3)
for y, x in enumerate(df['A']):
plt.annotate(str(np.around(x,decimals=3)), xy=(x-0.01, y), va='center',ha='right', color='b', fontweight='bold', fontsize=16)
df['B'].plot(kind='barh',width=0.9, color='r', alpha=0.2)
for y, x in enumerate(df['B']):
plt.annotate(str(np.around(x,decimals=3)), xy=(x-0.01, y), va='center',ha='right', color='r', fontweight='bold', fontsize=16)
plt.show()
pic_name='psc_annotaed_horizontal_bars.png'
fig.savefig(pic_name, transparency=True)

Related

sns.histplot legend colors not matching the output

I am creating a combo boxplot\histplot.
Everything runs and I get the output I am expecting except for one thing:
The line colors in the legend do not match the output.
Code:
def boxhist(dfx, x):
variable = dfx[x].values
np.array(variable).mean()
np.median(variable)
f, (ax_box, ax_hist) = plt.subplots(2, sharex=True, gridspec_kw={"height_ratios": (0.5, 2)})
mean = np.array(variable).mean()
median = np.median(variable)
sns.boxplot(variable, ax=ax_box)
ax_box.axvline(mean, color='orange', linestyle='--')
ax_box.axvline(median, color='black', linestyle='-')
sns.histplot(data=variable, ax=ax_hist, kde=True, binwidth=2, facecolor='green').lines[0].set_color('red')
ax_hist.axvline(mean, color='orange', linestyle='--')
ax_hist.axvline(median, color='black', linestyle='-')
plt.title(x, fontsize=10, loc='right')
plt.legend({'Mean': mean, 'Median': median})
ax_box.set(xlabel='')
plt.tight_layout()
plt.show()
Output:
The mean should be orange.
The median should be black.
Why is the legend showing the mean as red and the median as orange?
I want the legend colors to match the plot output. mean\orange, median\black.
You need to add a label in ax_hist.axvline(mean, ...., label='Mean') (and similar for the median). Then matplotlib should automatically add them to the legend (when called without parameters).
Here is some example code:
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
def boxhist(dfx, x):
variable = dfx[x].values
variable.mean()
np.median(variable)
f, (ax_box, ax_hist) = plt.subplots(2, sharex=True, gridspec_kw={"height_ratios": (0.5, 2)})
mean = variable.mean()
median = np.median(variable)
sns.boxplot(x=variable, ax=ax_box)
ax_box.axvline(mean, color='orange', linestyle='--')
ax_box.axvline(median, color='black', linestyle='-')
sns.histplot(x=variable, ax=ax_hist, kde=True, binwidth=2, facecolor='green')
ax_hist.lines[0].set_color('red')
ax_hist.axvline(mean, color='orange', linestyle='--', label='Mean')
ax_hist.axvline(median, color='black', linestyle='-', label='Median')
ax_hist.set_title(x, fontsize=10, loc='right')
ax_hist.legend()
# ax_box.set(xlabel='') # has no effect on shared x-axis
plt.tight_layout()
plt.show()
dfx = pd.DataFrame({'bmi': np.random.normal(30.2, 5, 100)})
boxhist(dfx, 'bmi')

How to change x,y in plt to lon, lat in cartopy?

I want to change x, y to lon, lat (Picture below yellow marker) when I click some point in map and get x, y.
How can I change it? Help me please...
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import numpy as np
import cartopy
def mouse_click(event):
x, y = event.xdata, event.ydata
print(x, y)
proj = ccrs.LambertConformal(central_longitude=125, central_latitude=35, false_easting=400000,false_northing=400000,
standard_parallels=(46, 49))
fig = plt.figure(figsize=(16.535433, 11.692913))
ax = fig.add_subplot(1,1,1, projection=proj)
ax.set_extent((79, 156, 10, 66))
gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=False, linewidth=0.2,color='black', alpha=0.5,
linestyle=(3, (20, 5)), xlocs=np.arange(-180, 200, 10), x_inline=False, y_inline=False)
#xlabel_style = {'rotation': 0},ylabel_style = {'rotation': 0})
ax.coastlines(resolution='50m', alpha=1, linewidth=0.5)
ax.add_feature(cartopy.feature.BORDERS, alpha=1,linewidth=0.5)
ax.add_feature(cartopy.feature.LAKES, alpha=0.4)
plt.connect('button_press_event', mouse_click)
plt.show()
I tried to find about it but It's hard to understanding.
I found some way.
Change the projection.
fig = plt.figure()
ax = fig.add_axes([0, 0, 1, 1], projection=ccrs.PlateCarree())
ax.add_feature(cartopy.feature.LAND, facecolor='black')
ax.set_global()
In LambertConformal,x,y is different with lon,lat. But in PlateCarree, they are same.

Secondary y-axis using seaborn

I am trying to plot a bar chart and a line chart as a single plot and inclined to use seaborn due to its nice formatting features. However, when I do df1.plot(kind='bar',...) followed by df1.plot(kind='line',..., secondary_y=True), I get similar outcome as below, i.e., no line chart but no error.
import seaborn as sns
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# Sample dataframe.
df1 = pd.DataFrame({'date':pd.date_range(datetime(2020,1,1), periods=699).tolist(), 'amount':range(1,700), 'balance':np.cumsum(range(1,700))})
df1.loc[:, 'month'] = df1['date'].dt.to_period("M")
df1.loc[:, 'month_str'] = df1['date'].dt.year.astype(str) + '-' + df1['date'].dt.month.astype(str)
df1.loc[:, 'month_dt'] = pd.to_datetime(df1.month.dt.year*10000+df1.month.dt.month*100+1,format='%Y%m%d')
# Case-1: This doesn't work.
df2 = df1.groupby(['month']).agg({'amount':'sum','balance':'sum'})
sns.barplot(x='month', y='amount', data=df2.reset_index(), palette="Blues_d")
ax2 = plt.twinx()
sns.lineplot(x='month', y='balance', data=df2.reset_index(), color='red', markers=True, ax=ax2)
# Case-2: This doesn't work (as intended, if months grow they will not auto-adjust max numbers to show and not sorted).
df2 = df1.groupby(['month_str']).agg({'amount':'sum','balance':'sum'})
sns.barplot(x='month_str', y='amount', data=df2.reset_index(), palette="Blues_d")
ax2 = plt.twinx()
sns.lineplot(x='month_str', y='balance', data=df2.reset_index(), color='red', markers=True, ax=ax2)
# Case-3: This doesn't work either.
df2 = df1.groupby(['month_dt']).agg({'amount':'sum','balance':'sum'})
sns.barplot(x='month_dt', y='amount', data=df2.reset_index(), palette="Blues_d")
ax2 = plt.twinx()
sns.lineplot(x='month_dt', y='balance', data=df2.reset_index(), color='red', markers=True, ax=ax2)
Case-1:
Traceback (most recent call last):
File "C:\...\lib\site-packages\seaborn\_decorators.py", line 46, in inner_f
return f(**kwargs)
File "C:\...\lib\site-packages\seaborn\relational.py", line 703, in lineplot
p.plot(ax, kwargs)
File "C:\...\lib\site-packages\seaborn\relational.py", line 529, in plot
line, = ax.plot(x, y, **kws)
File "C:\...\lib\site-packages\matplotlib\axes\_axes.py", line 1745, in plot
self.add_line(line)
File "C:\...\lib\site-packages\matplotlib\axes\_base.py", line 1964, in add_line
self._update_line_limits(line)
File "C:\...\lib\site-packages\matplotlib\axes\_base.py", line 1986, in _update_line_limits
path = line.get_path()
File "C:\...\lib\site-packages\matplotlib\lines.py", line 1011, in get_path
self.recache()
File "C:\...\lib\site-packages\matplotlib\lines.py", line 653, in recache
x = _to_unmasked_float_array(xconv).ravel()
File "C:\...\lib\site-packages\matplotlib\cbook\__init__.py", line 1289, in _to_unmasked_float_array
return np.asarray(x, float)
File "C:\...\lib\site-packages\numpy\core\_asarray.py", line 83, in asarray
return array(a, dtype, copy=False, order=order)
TypeError: float() argument must be a string or a number, not 'Period'
Case-2:
Case-3:
You can build a dummy x axis and replace the values with the month data after constructing the plot:
fig, ax = plt.subplots()
df2 = df1.groupby(['month']).agg({'amount':'sum','balance':'sum'})
# helper axis
data = df2.reset_index()
data['xaxis'] = range(len(data))
sns.barplot(x='xaxis', y='amount', data=data, palette="Blues_d", ax=ax)
ax2 = ax.twinx()
sns.lineplot(x='xaxis', y='balance', data=data, color='red', markers=True, ax=ax2)
# replace helper axis with actual data
ax.set_xticklabels(data['month'].values, rotation = 45, ha="right")
You don't need to create a dummy x axis. Try the following code:
import seaborn as sns
import pandas as pd
import numpy as np
# Sample dataframe.
df1 = pd.DataFrame({'date':pd.date_range(pd.datetime(2020,1,1), periods=699).tolist(), 'amount':range(1,700), 'balance':np.cumsum(range(1,700))})
df1.loc[:, 'month'] = df1['date'].dt.to_period("M")
df2 = df1.groupby(['month']).agg({'amount':'sum','balance':'sum'})
g = sns.barplot(x='month', y='amount', data=df2.reset_index(), palette="Blues_d")
g.set_xticklabels(g.get_xticklabels(), rotation=90)
sns.lineplot(x=range(len(df2.reset_index())), y='balance', data=df2.reset_index(), color='red', markers=True, ax=g.twinx())

Matplotlib- Add a color bar below a multi-colored line subplot as shown in the image

I am having a multicolored line plot and I want to add a color bar under it in the same figure like as shown in the image below, Is it possible?
I have attached a color bar image as a reference which I took from another code.
My intention here is to use the color bar like a legend for each segment of the line in the plot.
Edit-1: I want to have the color bar using a mappable object such as an image, So don't want to create a new subplot for the sole purpose of the color bar.
Any suggestion is welcome. Thanks in Advance.
This is the code for multicolored line plot
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
Segments=[[[3,1],[6,1]],[[6,2],[9,2]],[[9,3],[12,3]],[[12,4],[15,4]], [[12,4],[15,4]]]
Points_1 = np.concatenate([Segments[:-1], Segments[1:]], axis=1)
lc = LineCollection(Points_1, colors=['r','g','b','y'], linewidths=2)
fig, ax = plt.subplots()
ax.add_collection(lc)
ax.autoscale()
plt.show()
This is a workaround I'am using:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
import matplotlib.colorbar as mcolorbar
import matplotlib.colors as mcolors
Segments=[[[3,1],[6,1]],[[6,2],[9,2]],[[9,3],[12,3]],[[12,4],[15,4]], [[12,4],[15,4]]]
Points_1 = np.concatenate([Segments[:-1], Segments[1:]], axis=1)
lc = LineCollection(Points_1, colors=['r','g','b','y'], linewidths=2)
fig, ax = plt.subplots(2, 1, gridspec_kw={'height_ratios' : [5,1]})
ax[0].add_collection(lc)
bounds = np.linspace(0, 1, 5)[:-1]
labels = ['Action1', 'Action2', 'Action3', 'Action4']
ax[0].set_xlim([0, 15])
ax[0].set_ylim([0, 10])
cb2 = mcolorbar.ColorbarBase(ax = ax[1], cmap = cmap, orientation = 'horizontal', extendfrac='auto')
cb2.set_ticks(bounds)
cb2.set_ticklabels(labels)
plt.tight_layout()
plt.show()
If you specifically want to avoid subplots, you can use a scalar mappable:
fig, ax = plt.subplots()
ax.add_collection(lc)
ax.autoscale()
cmap = mcolors.ListedColormap(['r','g','b','y'])
sm = plt.cm.ScalarMappable(cmap=cmap)
sm.set_array([]) # this line may be ommitted for matplotlib >= 3.1
cbar = fig.colorbar(sm, ax=ax, orientation='horizontal',aspect=90)
bounds = np.linspace(0, 1, 5)[:-1]
labels = ['Action1', 'Action2', 'Action3', 'Action4']
ax.set_xlim([0, 15])
ax.set_ylim([0, 10])
cbar.set_ticks(bounds)
cbar.set_ticklabels(labels)
plt.tight_layout()
plt.show()
This helped me to get what I asked.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
from matplotlib.collections import LineCollection
Segments=[[[3,1],[6,1]],[[6,2],[9,2]],[[9,3],[12,3]],[[12,4],[15,4]], [[12,4],[15,4]]]
Points_1 = np.concatenate([Segments[:-1], Segments[1:]], axis=1)
lc = LineCollection(Points_1, colors=['r','g','b','y'], linewidths=2)
fig, ax = plt.subplots()
ax.add_collection(lc)
ax.autoscale()
c=[1,2,3,4,5]
labels = ['Action1', 'Action2', 'Action3', 'Action4']
cmap = mcolors.ListedColormap(['r','g','b','y'])
norm = mcolors.BoundaryNorm([1,2,3,4,5],4)
sm = plt.cm.ScalarMappable(norm=norm, cmap=cmap)
sm.set_array([]) # this line may be ommitted for matplotlib >= 3.1
cbar=fig.colorbar(sm, ticks=c, orientation='horizontal')
cbar.set_ticklabels(['Action1', 'Action2', 'Action3', 'Action4'])
plt.show()

How to plot vertical lines in plotly offline?

How would one plot a vertical line in plotly offline, using python? I want to add lines at x=20, x=40, and x=60, all in the same plot.
def graph_contracts(self):
trace1 = go.Scatter(
x=np.array(range(len(all_prices))),
y=np.array(all_prices), mode='markers', marker=dict(size=10, color='rgba(152, 0, 0, .8)'))
data = [trace1]
layout = go.Layout(title='Market Contracts by Period',
xaxis=dict(title='Contract #',
titlefont=dict(family='Courier New, monospace', size=18, color='#7f7f7f')),
yaxis=dict(title='Prices ($)',
titlefont=dict(family='Courier New, monospace', size=18, color='#7f7f7f')))
fig = go.Figure(data=data, layout=layout)
py.offline.plot(fig)
You can add lines via shape in layout, e.g.
import plotly
plotly.offline.init_notebook_mode()
import random
x=[i for i in range(100)]
trace = plotly.graph_objs.Scatter(x=x,
y=[random.random() for _ in x],
mode='markers')
shapes = list()
for i in (20, 40, 60):
shapes.append({'type': 'line',
'xref': 'x',
'yref': 'y',
'x0': i,
'y0': 0,
'x1': i,
'y1': 1})
layout = plotly.graph_objs.Layout(shapes=shapes)
fig = plotly.graph_objs.Figure(data=[trace],
layout=layout)
plotly.offline.plot(fig)
would give you
This is my example. The most important instruction is this.
fig.add_trace(go.Scatter(x=[12, 12], y=[-300,300], mode="lines", name="SIGNAL"))
The most important attribute is MODE='LINES'.
Actually this example is about a segment with x=12
EXAMPLE
import pandas as pd
import plotly.graph_objects as go
import matplotlib.pyplot as plt
import numpy as np
import plotly.tools as tls
df1 = pd.read_csv('./jnjw_f8.csv')
layout = go.Layout(
xaxis = go.layout.XAxis(
tickmode = 'linear',
tick0 = 1,
dtick = 3
),
yaxis = go.layout.YAxis(
tickmode = 'linear',
tick0 = -100,
dtick = 3
))
fig = go.Figure(layout = layout)
fig.add_trace(go.Scatter(x = df1['x'], y =
df1['y1'],name='JNJW_sqrt'))
fig.add_trace(go.Scatter(x=[12, 12], y=[-300,300],
mode="lines", name="SIGNAL"))
fig.show()
Look here too.
how to plot a vertical line with plotly
A feature for vertical and horizontal lines is implemented with Plotly.py 4.12 (released 11/20). It works for plotly express and graph objects. See here: https://community.plotly.com/t/announcing-plotly-py-4-12-horizontal-and-vertical-lines-and-rectangles/46783
Simple example:
import plotly.express as px
df = px.data.stocks(indexed=True)
fig = px.line(df)
fig.add_vline(x='2018-09-24')
fig.show()
fig.add_vline(x=2.5, line_width=3, line_dash="dash", line_color="green")

Resources