I have a stacked bar chart for two variables.
ax = count[['new_category', "Count %", "Volume%"]].set_index('new_category').T.plot.bar(stacked=True)
plt.xticks(rotation = 360)
plt.show()
I want to connect the categories with lines, so my categories are connected with lines.
You could loop through each of the bar containers, and then through each of the bars. Connecting the bar tops should give the desired plot:
from matplotlib import pyplot as plt
import pandas as pd
count = pd.DataFrame({'new_category': ['Cat A', 'Cat B'],
'Count %': [20, 30],
'Volume%': [15, 40]})
ax = count[['new_category', "Count %", "Volume%"]].set_index('new_category').T.plot.bar(stacked=True)
for bars in ax.containers:
prev_x = None
prev_y = None
for bar in bars:
x, y = bar.get_xy()
w = bar.get_width()
h = bar.get_height()
if prev_x is not None:
ax.plot([prev_x, x], [prev_y, y + h], ls=':', color='k', lw=0.5)
prev_y = y + h
prev_x = x + w
ax.legend(loc='upper left', bbox_to_anchor=[1.01, 1.01])
ax.tick_params(axis='x', rotation=0)
plt.tight_layout()
plt.show()
Here is another example, using bars created by seaborn:
from matplotlib import pyplot as plt
import seaborn as sns
flights = sns.load_dataset('flights')
flights['year'] = flights['year'].astype(str)
fig, ax = plt.subplots(figsize=(12, 5))
sns.histplot(data=flights, x='year', hue='month', weights='passengers',
multiple='stack', palette='Set3', discrete=True, shrink=0.7, ax=ax)
for bars in ax.containers:
prev_x = None
prev_y = None
for bar in bars:
x, y = bar.get_xy()
w = bar.get_width()
h = bar.get_height()
if prev_x is not None:
ax.plot([prev_x, x], [prev_y, y + h], ls=':', color='k', lw=1)
prev_y = y + h
prev_x = x + w
sns.move_legend(ax, loc='upper left', bbox_to_anchor=[0.02, 1], ncol=2)
sns.despine()
ax.margins(x=0.01)
ax.set_ylabel('number of passengers')
ax.set_xlabel('')
plt.tight_layout()
plt.show()
Related
I saw this tutorial on how to make a scatter plot with a histogram for the x and y axes and I thought it would be neat to also tack on a colorbar for an extra dimension of information. To do this, I utilized "the make_axes_locatable" function, like so:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
# generating fake data
tx = np.random.randn(1000)
ty = np.random.randn(1000)
tz = np.random.randn(1000)
fig = plt.figure(figsize=(5, 5))
gs = fig.add_gridspec(2, 2, width_ratios=(4, 1), height_ratios=(1, 4),
left=0.1, right=0.9, bottom=0.1, top=0.9,
wspace=0.05, hspace=0.05)
# Create the Axes.
ax = fig.add_subplot(gs[1, 0])
ax_histx = fig.add_subplot(gs[0, 0], sharex=ax)
ax_histy = fig.add_subplot(gs[1, 1], sharey=ax)
def scatter_hist_and_colorbar(x, y, c, ax, ax_histx, ax_histy,label):
# no labels
ax_histx.tick_params(axis="x", labelbottom=False)
ax_histy.tick_params(axis="y", labelleft=False)
# the scatter plot:
sc=ax.scatter(x,y,marker='o',label=label,c=c)
# now determine nice limits by hand:
binwidth = 0.25
xlim = (int(np.max(np.abs(x))/binwidth) + 1) * binwidth
ylim = (int(np.max(np.abs(y))/binwidth) + 1) * binwidth
xbins = np.arange(-xlim, xlim + binwidth, binwidth)
ybins = np.arange(-ylim, ylim + binwidth, binwidth)
ax_histx.hist(x, bins=xbins)
ax_histy.hist(y, bins=ybins, orientation='horizontal')
return sc
sc1= scatter_hist_and_colorbar(tx,ty,tz, ax, ax_histx, ax_histy,label='data')
ax.set_ylabel('x data')
ax.set_xlabel('y data')
ax.legend()
divider = make_axes_locatable(ax)
cax = divider.append_axes('left', size='5%', pad=1)
cbar=fig.colorbar(sc1, cax=cax, orientation='vertical')
cbar.ax.set_ylabel('z data',rotation=90,labelpad=5)
cbar.ax.yaxis.set_ticks_position("left")
plt.savefig('example.png')
plt.show()][2]][2]
This almost works except the "ax_histx" axis is now stretched and doesn't properly line up due to the addition of the colorbar. Is there a way to resize the "ax_histx" axis or is there a better way to add a colorbar to the "ax" subplot so that it wouldn't affect the "ax_histx" or "ax_histy" axes?
After getting a suggestion form #r-beginners , I tried tweaking this code to place a colorbar in the upper right, perpendicular to the histogram axes. This way, it doesn't distort the width/heights of the other shared axes:
# some random data
tx = np.random.randn(1000)
ty = np.random.randn(1000)
tz = np.random.randn(1000)
fig = plt.figure(figsize=(5, 5))
gs = fig.add_gridspec(2, 2, width_ratios=(4, 1), height_ratios=(1, 4),
left=0.1, right=0.9, bottom=0.1, top=0.9,
wspace=0.05, hspace=0.05)
# Create the Axes.
ax0 = fig.add_subplot(gs[0, 1])
ax = fig.add_subplot(gs[1, 0])
ax_histx = fig.add_subplot(gs[0, 0], sharex=ax)
ax_histy = fig.add_subplot(gs[1, 1], sharey=ax)
def scatter_hist_and_colorbar(x, y, c, ax, ax_histx, ax_histy,label):
# no labels
ax_histx.tick_params(axis="x", labelbottom=False)
ax_histy.tick_params(axis="y", labelleft=False)
# the scatter plot:
sc=ax.scatter(x,y,marker='o',label=label,c=c)
# now determine nice limits by hand:
binwidth = 0.25
xymax = max(np.max(np.abs(x)), np.max(np.abs(y)))
lim = (int(xymax/binwidth) + 1) * binwidth
xlim = (int(np.max(np.abs(x))/binwidth) + 1) * binwidth
ylim = (int(np.max(np.abs(y))/binwidth) + 1) * binwidth
xbins = np.arange(-xlim, xlim + binwidth, binwidth)
ybins = np.arange(-ylim, ylim + binwidth, binwidth)
ax_histx.hist(x, bins=xbins)
ax_histy.hist(y, bins=ybins, orientation='horizontal')
return sc
sc1= scatter_hist_and_colorbar(tx,ty,tz, ax, ax_histx, ax_histy,label='data')
ax.set_ylabel('x data')
ax.set_xlabel('y data')
ax.legend()
divider = make_axes_locatable(ax)
divider = make_axes_locatable(ax0)
ca = divider.append_axes('left', size='50%')
ax0.axis('off')
cbar=fig.colorbar(sc1, cax=ca, orientation='vertical')
cbar.ax.set_ylabel('z data',rotation=270,labelpad=5)
cbar.ax.yaxis.set_ticks_position("right")
gs.tight_layout(fig,pad=1)
plt.savefig('example.png')
plt.show()
I have two working barplots about the sentiments of tweets (neutral, positive, negative). How can I merge them into one, side by side?
First bar:
plt.figure(figsize=(6,5))
plt.title('Classification of All tweets into sentiment categories',fontsize=15)
plt.ylabel('Percentage [%]',fontsize=18)
ax = (df_navalny.sentiment.value_counts()/len(df_navalny)*100).plot(kind="bar", rot=0,color=['#04407F','#0656AC','#0A73E1'])
ax.set_yticks(np.arange(0, 110, 10))
plt.grid(color='#95a5a6', linestyle='-.', linewidth=1, axis='y', alpha=0.7)
ax2 = ax.twinx()
ax2.set_yticks(np.arange(0, 110, 10)*len(df_navalny)/100)
for p in ax.patches:
ax.annotate('{:.2f}%'.format(p.get_height()), (p.get_x()+0.15, p.get_height()+1))
Second bar:
plt.figure(figsize=(6,5))
plt.title('Classification of All tweets into sentiment categories',fontsize=15)
plt.ylabel('Percentage [%]',fontsize=18)
ax = (df_putin.sentiment.value_counts()/len(df_putin)*100).plot(kind="bar", rot=0,color=['#04407F','#0656AC','#0A73E1'])
ax.set_yticks(np.arange(0, 110, 10))
plt.grid(color='#95a5a6', linestyle='-.', linewidth=1, axis='y', alpha=0.7)
ax2 = ax.twinx()
ax2.set_yticks(np.arange(0, 110, 10)*len(df_putin)/100)
for p in ax.patches:
ax.annotate('{:.2f}%'.format(p.get_height()), (p.get_x()+0.15, p.get_height()+1))
It's a bit complicated but Matplotlib site offers a demo and when you copy and past you have the following
Here it is the code
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import host_subplot
from mpl_toolkits import axisartist
# fake data
a = [2341, 5670, 4822]
b = [4290, 5205, 3966]
pca, pcb = [[round(100*x/sum(l),2) for x in l] for l in (a, b)]
# prepare all the vertical axes
ax = host_subplot(111, axes_class=axisartist.Axes)
plt.subplots_adjust(right=0.67)
axa = ax.twinx() ; axb = ax.twinx()
axb.axis['right'] = axb.new_fixed_axis(loc="right", offset=(60, 0))
axa.axis['right'].toggle(all=True)
axb.axis['right'].toggle(all=True)
# plot the bars PLUS invisible lines to represent the samples numerosities
x, w = np.array((1,2,3)), 0.30
ax.bar(x-w, pca, width=w, align='edge', label='a', zorder=1)
ax.bar(x-0, pcb, width=w, align='edge', label='b', zorder=1)
axa.plot((1,1),(0,sum(a)),lw=0)
axb.plot((1,1),(0,sum(b)),lw=0)
# fix xtics, xlabels, 'regular' yticks
plt.xticks((1,2,3)) ; ax.set_xticklabels('NO == YES'.split())
ax.set_yticks(range(0, 101, 10))
# all the ylabels
ax.set_ylabel('Percentages')
axa.set_ylabel('Numerosity of a')
axb.set_ylabel('Numerosity of b')
axa.set_ylim(bottom=0.0)
axb.set_ylim(bottom=0.0)
plt.legend()
plt.grid(zorder=0)
plt.show()
Could some help me to draw a circle using matplotlib or matplotlib and numpy. I have a set of points with x and y coordinates. set of points
Then I need to take from this set dots that will make a circle. The result should be something a circle
import numpy
import matplotlib.pyplot as plt
X = list(range(1, 101))
Y = list(range(1, 101))
x = numpy.array(X)
y = numpy.array(Y)
xgrid, ygrid = numpy.meshgrid(x, y)
plt.style.use('seaborn')
fig, ax = plt.subplots()
ax.scatter(xgrid, ygrid, s=5, color='green')
ax.set_title('net 100х100',
fontfamily = 'monospace',
fontstyle = 'normal',
fontweight = 'bold',
fontsize = 10)
ax.set_xlabel("X", fontsize=14)
ax.set_ylabel("Y", fontsize=14)
ax.tick_params(axis='both', which='major', labelsize=14)
ax.axis([0, 101, 0, 101])
plt.show()
All you need to do is collect the points that are in the circle.
import matplotlib.pyplot as plt
xgrid = []
ygrid = []
for x in range(100):
for y in range(100):
if (x-50)*(x-50)+(y-50)*(y-50) < 25*25:
xgrid.append(x)
ygrid.append(y)
plt.style.use('seaborn')
fig, ax = plt.subplots()
ax.scatter(xgrid, ygrid, s=5, color='green')
ax.tick_params(axis='both', which='major', labelsize=14)
ax.axis([0, 101, 0, 101])
plt.show()
I have a problem about putting a radar chart and bar graph in the subplot in Python.
I defined 1 row and 2 columns to put each one into each slot.
I tried to handle with this process but I couldn't.
How can I do that?
Here is my radar function shown below.
def radar_chart(values=[]):
labels=np.array(['Crew',
'Length',
'Wingspan',
'Height',
'WingArea'
]
)
angles=np.linspace(0, 2*np.pi, len(labels), endpoint=False)
#print(angles)
fig=plt.figure(figsize=(6,6))
#plt.suptitle(title, y=1.04)
for v in values:
stats=np.array(ww2aircraft_df[ww2aircraft_df["Name"]==v][labels])[0]
#print(stats)
ax = fig.add_subplot(111, polar=True)
ax.plot(angles, stats, 'o-', linewidth=2, label = v)
ax.fill(angles, stats, alpha=0.25)
ax.set_thetagrids(angles * 180/np.pi, labels)
ax.grid(True)
#plt.legend(loc="upper right",bbox_to_anchor=(1.2,1.0))
ax.legend(loc='upper center', bbox_to_anchor=(0.5, -0.10),
fancybox=True, shadow=True, ncol=1, fontsize=13)
Here is my code snippets shown below.
f,a = plt.subplots(1,2,figsize=(24,10))
radar_chart(values=ww2aircraft_df_top_5["Name"])
graph_1 = sns.barplot(data = ww2aircraft_df_top_5,
x = "MaxSpeed",
y = "Name" , ax = a[1])
show_values_on_bars(graph_1, "h", 0.3)
plt.suptitle('Top 5 fastest of WW2 warplane by their features',
fontsize=20,
fontweight="semibold",
)
plt.tight_layout()
plt.savefig('images/image10.png', bbox_inches = "tight")
plt.show()
Possible solution is the following:
The dataset can be found HERE
# pip install matplotlib
# pip install pandas
# pip install seaborn
import csv
import pandas as pd
import numpy as np
from math import pi
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
import seaborn as sns
# read csv to dataframe
df = pd.read_csv('ww2aircraft.csv', sep=';')
# select top-5 rows by 'MaxSpeed' column
df_top5_maxspeed = df.nlargest(5, 'MaxSpeed').reset_index(drop=True)
# convert column values to float type
df_top5_maxspeed['Length'] = df_top5_maxspeed['Length'].astype('float64')
df_top5_maxspeed['Wingspan'] = df_top5_maxspeed['Wingspan'].astype('float64')
# limit dataframe to required columns
df_top5_maxspeed_data = df_top5_maxspeed[["Name","Crew","Length","Wingspan","Height","WingArea","MaxSpeed"]]
df_top5_maxspeed_data
def create_radar_chart(df):
# limit data drame
df = df.iloc[:, :-1]
categories=list(df_top5_maxspeed_data)[1:-1]
N = len(categories)
angles = [n / float(N) * 2 * pi for n in range(N)]
angles += angles[:1]
ax = fig.add_subplot(gs[0, 0], polar=True)
ax.set_theta_offset(pi / 2)
ax.set_theta_direction(-1)
plt.xticks(angles[:-1], categories, size=10)
ax.set_rlabel_position(0)
plt.yticks([10,20,30,40], ["10","20","30","40"], color="grey", size=10)
plt.ylim(0,40)
for row in range(0, len(df.index)):
values=df.loc[row].drop(['Name']).values.flatten().tolist()
values+= values[:1]
ax.plot(angles, values, 'o-', linewidth=2, label = df.loc[row]["Name"])
ax.fill(angles, values, alpha=0.2)
ax.legend(loc='upper center', bbox_to_anchor=(0.5, -0.10),
fancybox=False, shadow=False, ncol=1, fontsize=10, frameon=False)
def create_bar_chart(df):
ax = fig.add_subplot(gs[0, 1])
df = df[['Name','MaxSpeed']]
df.plot.bar(x='Name', y='MaxSpeed', ax = ax, legend=False)
plt.xlabel("")
# create plots area
fig = plt.figure(figsize=(15, 5))
gs = GridSpec(nrows=1, ncols=2, width_ratios=[1, 1], wspace=0.1)
fig.suptitle('Top 5 fastest of WW2 warplane by their features', fontsize=16)
# add charts
create_radar_chart(df_top5_maxspeed_data)
create_bar_chart(df_top5_maxspeed_data)
# adjust space between title and charts
plt.subplots_adjust(top=0.85)
I have a dataset like:
I can't get the graph to print the 4 labels I'm plotting, the labels are the keys on this dictionary:
a = {'Pike':'red','Roach':'blue','Bream':'green','Perch':'orange'}
It will only print the first one:
from matplotlib.pyplot import plot, show, draw, figure, cm
from mpl_toolkits.mplot3d import Axes3D
sns.set_style("whitegrid", {'axes.grid' : False})
fig = plt.figure(figsize=(8,8))
ax = Axes3D(fig)
#ax = fig.add_subplot(111, projection='3d')
a = {'Pike':'red','Roach':'blue','Bream':'green','Perch':'orange'}
b = a.keys()
x = fish['Height']
y = fish['Width']
z = fish['Weight']
mp = ax.scatter(x, y, z, c=fish['Species'].apply(lambda x: a[x]), alpha=0.5, marker='o', s=50)
ax.view_init(azim=30)
ax.view_init(elev=15)
ax.set_xlabel('Height', fontweight ='bold')
ax.set_ylabel('Width', fontweight ='bold')
ax.set_zlabel('Weight', fontweight ='bold')
#ax.legend(a.keys(), bbox_to_anchor=(1.0, 1), loc=1)
legend = ax.legend(a.keys(), loc="upper left", title="Species", ncol=4)
ax.add_artist(legend)
plt.title('Fish Features 3d', fontweight ='bold', size=40)
plt.show()