Graph not showing in principal component analysis using python - python-3.x

How to show the graph image in my output for Principal Component Analysis?
import matplotlib.pyplot as plt
%matplotlib inline
fig = plt.figure(figsize = (8, 8))
ax = fig.add_subplot(1, 1, 1)
ax.set_xlabel('Principal Component 1', fontsize = 15)
ax.set_ylabel('Principal Component 2', fontsize = 15)
ax.set_title('2 Component PCA', fontsize = 20)
targets = ['Iris - setosa', 'Iris - versicolor', 'Iris - virginica']
colors = ['r', 'g', 'b']
for target, color in zip(targets, colors):
indicesToKeep = finalDF['target'] == target
ax.scatter(finalDF.loc[indicesToKeep, 'Principal Component 1'],
finalDF.loc[indicesToKeep, 'Principal Component 2'],
c = color, s = 50)
ax.legend(targets)
ax.grid()
ax.show()
Here is the error:
AttributeError Traceback (most recent call last)
<ipython-input-21-d87d089bc5f1> in <module>
16 ax.legend(targets)
17 ax.grid()
---> 18 ax.show()
AttributeError: 'AxesSubplot' object has no attribute 'show'
How to show the graph as there is no plots out there and show attribute is not working?

Only correction here is: in last line replace axis.show() by fig.show()
import matplotlib.pyplot as plt
%matplotlib inline
fig = plt.figure(figsize = (8, 8))
ax = fig.add_subplot(1, 1, 1)
ax.set_xlabel('Principal Component 1', fontsize = 15)
ax.set_ylabel('Principal Component 2', fontsize = 15)
ax.set_title('2 Component PCA', fontsize = 20)
targets = ['Iris - setosa', 'Iris - versicolor', 'Iris - virginica']
colors = ['r', 'g', 'b']
for target, color in zip(targets, colors):
indicesToKeep = finalDF['target'] == target
ax.scatter(finalDF.loc[indicesToKeep, 'Principal Component 1'],
finalDF.loc[indicesToKeep, 'Principal Component 2'],
c = color, s = 50)
ax.legend(targets)
ax.grid()
fig.show()

Related

Annotate Percentage of Group within a Seaborn CountPlot

The below code gets the percentage of all collisions. However, I want to get the percentage within a group. E.G. Mid-Block (not related to intersection) has 2 labels, a 1(red) or a 2(green/blue). Currently, the percentages next to those bars are percentages of the whole (bar count / all collisions), but I need to display the percentage within just one y-axis label. E.G. for Mid-block (not related to intersection), bar count / all collisions within mid-block (not related to intersection). I do not know how to do this, so if someone could point me in the right direction or give me some code that I could study to understand, I'd be very grateful.
Thank you so much for your time.
plt.style.use('ggplot')
plt.figure(figsize = (20, 15))
ax = sb.countplot(y = "JUNCTIONTYPE", hue = "SEVERITYCODE", data = dfm)
plt.title('Number of Persons vs. Number of Collisions by Severity', fontsize = 30)
plt.xlabel('Number of Collisions', fontsize = 24)
plt.ylabel('Number of Persons', fontsize = 24)
plt.tick_params(labelsize=18);
plt.legend(fontsize = 18, title = "Severity", loc = 'lower right')
plt.text(5, 6, "Figure 8: Number of persons plotted against the number of collisions grouped by severity", fontsize = 16)
# labels = [item.get_text() for item in ax.get_yticklabels()]
# labels[0] = 'No'
# labels[1] = 'Yes'
# ax.set_yticklabels(labels)
for p in ax.patches:
width = p.get_width()
height = p.get_height()
x, y = p.get_xy()
ax.annotate(int(width),
((x + width), y),
xytext = (30, -25),
fontsize = 18,
color = '#000000',
textcoords = 'offset points',
ha = 'right',
va = 'center')
for p in ax.patches:
width = p.get_width()
height = p.get_height()
x, y = p.get_xy()
totals = []
for i in ax.patches:
totals.append(i.get_width())
total = sum(totals)
ax.text(width + 0.3, y + 0.38,
str(
round((width/total) * 100, 2))
+ '%',
fontsize=18)
You could pre-calculate the per-group percentage points and use the order in which seaborn / matplotlib draws the bars to reference them.
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
titanic = sns.load_dataset('titanic')
# prepare the dataset
df = (titanic
.groupby(["embark_town", "survived"])
.size()
.reset_index()
.replace({"survived": {0:"no", 1:"yes"}})
.rename(columns={0:"count"}))
# calculate survival % per town of embarkation
df["percent"] = (df
.groupby("embark_town")
.apply(lambda x: x["count"] / x["count"].sum()).values)
# sort the dataframe to match the drawing order
df.sort_values(by=["survived", "embark_town"], inplace=True)
# visualisation
plt.style.use('ggplot')
fig = sns.catplot(
x="count", y="embark_town", hue="survived",
kind="bar", data=df, height=4, aspect=2)
for i, bar in enumerate(fig.ax.patches):
height = bar.get_height()
fig.ax.annotate(
# reference the pre-calculated row in the dataframe
f"{df.iloc[i, 3] :.0%}",
xycoords="data",
xytext=(20, -15),
textcoords="offset points",
xy=(bar.get_width(), bar.get_y()),
ha='center', va='center')
# make space for annonations
plt.margins(x=0.2)
plt.show()

How to add "copy id" button in matplot graph window

I am working on product sell analysis project and for that i have created one donut chart for different products.Now my question is,how to add copy id button near the legends(or anywhere in the graph window) of doughnut chart so that user can copy product id directly from there
Expected output
Code
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(6, 3), subplot_kw=dict(aspect="equal"))
products = ["id 11111",
"id 22222",
"id 33333",
"id 44444",
"id 55555",
"id 66666"]
data = [225, 90, 50, 60, 100, 5]
wedges, texts = ax.pie(data, wedgeprops=dict(width=0.5), startangle=-40)
bbox_props = dict(boxstyle="square,pad=0.3", fc="w", ec="k", lw=0.72)
kw = dict(arrowprops=dict(arrowstyle="-"),
bbox=bbox_props, zorder=0, va="center")
for i, p in enumerate(wedges):
ang = (p.theta2 - p.theta1)/2. + p.theta1
y = np.sin(np.deg2rad(ang))
x = np.cos(np.deg2rad(ang))
horizontalalignment = {-1: "right", 1: "left"}[int(np.sign(x))]
connectionstyle = "angle,angleA=0,angleB={}".format(ang)
kw["arrowprops"].update({"connectionstyle": connectionstyle})
ax.annotate(products[i], xy=(x, y), xytext=(1.35*np.sign(x), 1.4*y),
horizontalalignment=horizontalalignment, **kw)
ax.set_title("Matplotlib Products Sell: A donut")
plt.show()
output
The following code allows you to click on the annotation box and copies the content to the clipboard.
I use pandas.io.clipboard for doing so, as per this answer.
import numpy as np
import matplotlib.pyplot as plt
from pandas.io.clipboard import copy
def onclick(event):
copy(event.artist.get_text())
fig, ax = plt.subplots(figsize=(6, 3), subplot_kw=dict(aspect="equal"))
cid = fig.canvas.mpl_connect('pick_event', onclick)
products = ["id 11111",
"id 22222",
"id 33333",
"id 44444",
"id 55555",
"id 66666"]
annotations = []
data = [225, 90, 50, 60, 100, 5]
wedges, texts = ax.pie(data, wedgeprops=dict(width=0.5), startangle=-40)
bbox_props = dict(boxstyle="square,pad=0.3", fc="w", ec="k", lw=0.72)
kw = dict(arrowprops=dict(arrowstyle="-"),
bbox=bbox_props, zorder=0, va="center")
for i, p in enumerate(wedges):
ang = (p.theta2 - p.theta1) / 2. + p.theta1
y = np.sin(np.deg2rad(ang))
x = np.cos(np.deg2rad(ang))
horizontalalignment = {-1: "right", 1: "left"}[int(np.sign(x))]
connectionstyle = "angle,angleA=0,angleB={}".format(ang)
kw["arrowprops"].update({"connectionstyle": connectionstyle})
ax.annotate(products[i], xy=(x, y), xytext=(1.35 * np.sign(x), 1.4 * y),
horizontalalignment=horizontalalignment, picker=True, **kw)
ax.set_title("Matplotlib Products Sell: A donut")
plt.show()

Removing duplicate legend bar plot matplotlib

I want to edit my legend to make it only shows the labels once
I use for loop to create my bar graph. How can I remove the duplicate legend? It should only show week and month once
This code give me the graph below
fig, ax = plt.subplots(figsize = (10,6))
ax.set(xlim=(0,6))
ax.set(ylim=(0,150))
ax.set_xticklabels(edgeslist)
for i in range(6):
plt.bar(x = i, data = classw.iloc[:,i],
height = len(classw.iloc[:,i]) - classw.iloc[:,i].isna().sum(),
color = (0.91, 0.1, 0.4, 1), label = 'week',
align = 'edge', width = -0.4)
plt.bar(x = i, data = classm.iloc[:,i],
height = len(classm.iloc[:,i]) - classm.iloc[:,i].isna().sum(),
color = 'blue', label = 'month',
align = 'edge', width = 0.4)
plt.legend()
You can create a custom legend containing only the elements you want using the following code
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
r = Patch(facecolor=(0.91,0.1,0.4,1.0), label='week')
b = Patch(facecolor='blue', label='month')
plt.legend(handles=[r,b])
plt.show()
Which would give you a legend like this
Refer to this page for more on making custom legends.
Method 1 You can set the legend inside the loop only if a condition is met:
fig, ax = plt.subplots(figsize = (10,6))
ax.set(xlim=(0,6))
ax.set(ylim=(0,150))
ax.set_xticklabels(edgeslist)
for i in range(6):
plt.bar(x = i, data = classw.iloc[:,i],
height = len(classw.iloc[:,i]) - classw.iloc[:,i].isna().sum(),
color = (0.91, 0.1, 0.4, 1), label = 'week',
align = 'edge', width = -0.4)
plt.bar(x = i, data = classm.iloc[:,i],
height = len(classm.iloc[:,i]) - classm.iloc[:,i].isna().sum(),
color = 'blue', label = 'month',
align = 'edge', width = 0.4)
if i==0:
ax.legend()
Method 2
You can create a list with the label name. You will set as None but one value, then in the plot code, you index the label list this way.
fig, ax = plt.subplots(figsize = (10,6))
ax.set(xlim=(0,6))
ax.set(ylim=(0,150))
ax.set_xticklabels(edgeslist)
label_week = [None]*6
label_week[5] = 'week'
label_month = [None]*6
label_month[5] = 'month'
for i in range(6):
plt.bar(x = i, data = [1, 2, 5, 6, 0, 1],
height = 5,
color = (0.91, 0.1, 0.4, 1), label = label_week[i],
align = 'edge', width = -0.4)
plt.bar(x = i, data = [1, 2, 5, 6, 0, 1],
height = 6,
color = 'blue', label = label_month[i],
align = 'edge', width = 0.4)
plt.legend()
Hope it helps.

Scaling a PDF to show 100% at peak

I'm displaying a histogram of my data, with an overlaid PDF. My plots all look something like this:
and I'm trying to scale the red curve to show 100% at the peak.
My following toy code is identical to what I'm actually using, apart from the lines in between the two %:
%
import pandas as pd
import matplotlib.pyplot as plt
import scipy.stats as stats
import numpy as np
my_randoms = np.random.normal(0.5, 1, 50000)
dictOne = {"delta z":my_randoms}
df = pd.DataFrame(dictOne)
df = df[df['delta z'] > -999]
%
fig, ax = plt.subplots()
h, edges, _ = ax.hist(df['delta z'], alpha = 1, density = False, bins = 100)
param = stats.norm.fit(df['delta z'].dropna()) # Fit a normal distribution to the data
pdf_fitted = stats.norm.pdf(df['delta z'], *param)
x = np.linspace(*df['delta z'].agg([min, max]), 100) # x-values
binwidth = np.diff(edges).mean()
ax.plot(x, stats.norm.pdf(x, *param)*h.sum()*binwidth, color = 'r')
# Decorations
graph_title = 'U-B'
plt.grid(which = 'both')
plt.title(r'$\Delta z$ distribution for %s'%graph_title, fontsize = 25)
plt.xlabel(r'$\Delta z = z_{spec} - z_{photo}$', fontsize = 25)
plt.ylabel('Number', fontsize = 25)
plt.xticks(fontsize = 25)
plt.yticks(fontsize = 25)
xmin, xmax = min(df['delta z']), max(df['delta z'])
plt.xlim(xmin, xmax)
plt.annotate(
r'''$\mu_{\Delta z}$ = %.3f
$\sigma_{\Delta z}$ = %.3f'''%(param[0], param[1]),
fontsize = 25, color = 'r', xy=(0.85, 0.85), xycoords='axes fraction')
How would I define another axes object from 0 to 100 on the right-hand side and map the PDF to that?
Or is there a better way to do it?
This is kind of a follow-up to my previous question.
You can use density=True in plotting the histogram.
You use .twinx():
fig = plt.figure(figsize=(10, 8), dpi=72.0)
n_rows = 2
n_cols = 2
ax1 = fig.add_subplot(n_rows, n_cols, 1)
ax2 = fig.add_subplot(n_rows, n_cols, 2)
ax3 = ax1.twinx()
https://matplotlib.org/gallery/api/two_scales.html

Recreating price distribution chart

I'm trying to recreate following chart:
Currently I have no idea what should I do now, wondering if there is a possibility to merge these charts or plot everything in one chart code,
import numpy as np
import math
import matplotlib.pyplot as plt
from scipy.stats import norm
fig = plt.figure()
ax1 = plt.subplot2grid((6, 2), (0, 0), rowspan=6, colspan=1)
ax2 = plt.subplot2grid((6, 2), (0, 1), rowspan=6, colspan=1)
ax2.axes.get_xaxis().set_visible(False)
ax2.axes.get_yaxis().set_visible(False)
S = 5
T = 100
mu = 0
vol = 0.3
for i in range(10):
daily_returns = np.random.normal(mu / T, vol / math.sqrt(T), T) + 1
price_list = [S]
for x in daily_returns:
price_list.append(price_list[-1] * x)
ax1.plot(price_list)
ax1.set_ylim(0,10)
srange = np.arange(-4, 4, 0.01)
mean = 0
standard_deviation = 1
var = norm.pdf(srange, mean, standard_deviation)
ax2.plot(var,srange, color="grey")
plt.show()

Resources