8000 Add new example for plotting a confidence_ellipse · matplotlib/matplotlib@9661375 · GitHub
[go: up one dir, main page]

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 9661375

Browse files
author
Carsten
committed
Add new example for plotting a confidence_ellipse
1 parent a06ed93 commit 9661375

File tree

1 file changed

+206
-0
lines changed

1 file changed

+206
-0
lines changed
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
"""
2+
======================================================
3+
Plot a confidence ellipse of a two-dimensional dataset
4+
======================================================
5+
6+
This example shows how to plot a confidence ellipse of a
7+
two-dimensional dataset, using its pearson correlation coefficient.
8+
9+
The approach that is used to obtain the correct geometry is
10+
explained and proved here:
11+
12+
https://carstenschelp.github.io/2018/09/14/Plot_Confidence_Ellipse_001.html
13+
"""
14+
15+
import numpy as np
16+
import matplotlib.pyplot as plt
17+
from matplotlib.patches import Ellipse
18+
import matplotlib.transforms as transforms
19+
20+
21+
def confidence_ellipse(x, y, ax, n_std=3.0, **kwargs):
22+
"""
23+
Create a plot of the covariance confidence ellipse of `x` and `y`
24+
25+
Parameters
26+
----------
27+
x, y : array_like, shape (n, )
28+
Input data
29+
30+
ax : matplotlib.axes object to the ellipse into
31+
32+
n_std : number of standard deviations to determine the ellipse's radiuses
33+
34+
Returns
35+
-------
36+
None
37+
38+
Other parameters
39+
----------------
40+
kwargs : `~matplotlib.patches.Patch` properties
41+
42+
author : Carsten Schelp
43+
license: GNU General Public License v3.0 (https://github.com/CarstenSchelp/CarstenSchelp.github.io/blob/master/LICENSE)
44+
"""
45+
if x.size != y.size:
46+
raise ValueError("x and y must be the same size")
47+
48+
cov = np.cov(x, y)
49+
pearson = cov[0, 1]/np.sqrt(cov[0, 0] * cov[1,1])
50+
# Using a special case to obtain the eigenvalues of this two-dimensionl dataset.
51+
ell_radius_x = np.sqrt(1 + pearson)
52+
ell_radius_y = np.sqrt(1 - pearson)
53+
ellipse = Ellipse((0,0), width=ell_radius_x * 2, height=ell_radius_y * 2, **kwargs)
54+
55+
# Calculating the stdandard deviation of x from the squareroot of the variance
56+
# and multiplying with the given number of standard deviations.
57+
scale_x = np.sqrt(cov[0, 0]) * n_std
58+
mean_x = np.mean(x)
59+
60+
# calculating the stdandard deviation of y ...
61+
scale_y = np.sqrt(cov[1, 1]) * n_std
62+
mean_y = np.mean(y)
63+
64+
transf = transforms.Affine2D() \
65+
.rotate_deg(45) \
66+
.scale(scale_x, scale_y) \
67+
.translate(mean_x, mean_y)
68+
69+
ellipse.set_transform(transf + ax.transData)
70+
ax.add_patch(ellipse)
71+
72+
73+
def get_correlated_dataset(n, dependency, mu, scale):
74+
latent = np.random.randn(n, 2)
75+
dependent = latent.dot(dependency)
76+
scaled = dependent * scale
77+
scaled_with_offset = scaled + mu
78+
# return x and y of the new, correlated dataset
79+
return scaled_with_offset[:,0],scaled_with_offset[:,1]
80+
81+
fig, ((ax_pos, ax_neg, ax_uncorrel), (ax_nstd1, ax_nstd2, ax_kwargs)) = plt.subplots(nrows=2, ncols=3, figsize=(9, 6), sharex=True, sharey=True)
82+
np.random.seed(1234)
83+
84+
# Demo top left: positive correlation
85+
86+
# Create a matrix that transforms the independent "latent" dataset
87+
# into a dataset where x and y are correlated - positive correlation, in this case.
88+
dependency_pos = np.array([
89+
[0.85, 0.35],
90+
[0.15, -0.65]
91+
])
92+
mu_pos = np.array([2, 4]).T
93+
scale_pos = np.array([3, 5]).T
94+
95+
# Indicate the x- and y-axis
96+
ax_pos.axvline(c='grey', lw=1)
97+
ax_pos.axhline(c='grey', lw=1)
98+
99+
x, y = get_correlated_dataset(500, dependency_pos, mu_pos, scale_pos)
100+
confidence_ellipse(x, y, ax_pos, facecolor='none', edgecolor='red')
101+
102+
# Also plot the dataset itself, for reference
103+
ax_pos.scatter(x, y, s=0.5)
104+
# Mark the mean ("mu")
105+
ax_pos.scatter([mu_pos[0]], [mu_pos[1]],c='red', s=3)
106+
ax_pos.set_title(f'Positive correlation')
107+
108+
# Demo top middle: negative correlation
109+
dependency_neg = np.array([
110+
[0.9, -0.4],
111+
[0.1, -0.6]
112+
])
113+
mu = np.array([2, 4]).T
114+
scale = np.array([3, 5]).T
115+
116+
# Indicate the x- and y-axes
117+
ax_neg.axvline(c='grey', lw=1)
118+
ax_neg.axhline(c='grey', lw=1)
119+
120+
x, y = get_correlated_dataset(500, dependency_neg, mu, scale)
121+
confidence_ellipse(x, y, ax_neg, facecolor='none', edgecolor='red')
122+
# Again, plot the dataset itself, for reference
123+
ax_neg.scatter(x, y, s=0.5)
124+
# Mark the mean ("mu")
125+
ax_neg.scatter([mu[0]], [mu[1]],c='red', s=3)
126+
ax_neg.set_title(f'Negative correlation')
127+
128+
# Demo top right: uncorrelated dataset
129+
# This uncorrelated plot (bottom left) is not a circle since x and y
130+
# are differently scaled. However, the fact that x and y are uncorrelated
131+
# is shown however by the ellipse being aligned with the x- and y-axis.
132+
133+
in_dependency = np.array([
134+
[1, 0],
135+
[0, 1]
136+
])
137+
mu = np.array([2, 4]).T
138+
scale = np.array([5, 3]).T
139+
140+
ax_uncorrel.axvline(c='grey', lw=1)
141+
ax_uncorrel.axhline(c='grey', lw=1)
142+
143+
x, y = get_correlated_dataset(500, in_dependency, mu, scale)
144+
confidence_ellipse(x, y, ax_uncorrel, facecolor='none', edgecolor='red')
145+
ax_uncorrel.scatter(x, y, s=0.5)
146+
ax_uncorrel.scatter([mu[0]], [mu[1]],c='red', s=3)
147+
ax_uncorrel.set_title(f'Weak correlation')
148+
149+
# Demo bottom left and middle: ellipse two standard deviations wide
150+
# In the confidence_ellipse function the default of the number
151+
# of standard deviations is 3, which makes the ellipse enclose
152+
# 99.7% of the points when the data is normally distributed.
153+
# This demo shows a two plots of the same dataset with different
154+
# values for "n_std".
155+
dependency_nstd_1 = np.array([
156+
[0.8, 0.75],
157+
[-0.2, 0.35]
158+
])
159+
mu = np.array([0, 0]).T
160+
scale = np.array([8, 5]).T
161+
162+
ax_kwargs.axvline(c='grey', lw=1)
163+
ax_kwargs.axhline(c='grey', lw=1)
164+
165+
x, y = get_correlated_dataset(500, dependency_nstd_1, mu, scale)
166+
# Onde standard deviation
167+
# Now plot the dataset first ("under" the ellipse) in order to
168+
# demonstrate the transparency of the ellipse (alpha).
169+
ax_nstd1.scatter(x, y, s=0.5)
170+
confidence_ellipse(x, y, ax_nstd1, n_std=1, facecolor='none', edgecolor='red')
171+
confidence_ellipse(x, y, ax_nstd1, n_std=3, facecolor='none', edgecolor='gray', linestyle='--')
172+
173+
ax_nstd1.scatter([mu[0]], [mu[1]],c='red', s=3)
174+
ax_nstd1.set_title(f'One standard deviation')
175+
176+
# Two standard deviations
177+
ax_nstd2.scatter(x, y, s=0.5)
178+
confidence_ellipse(x, y, ax_nstd2, n_std=2, facecolor='none', edgecolor='red')
179+
confidence_ellipse(x, y, ax_nstd2, n_std=3, facecolor='none', edgecolor='gray', linestyle='--')
180+
181+
ax_nstd2.scatter([mu[0]], [mu[1]],c='red', s=3)
182+
ax_nstd2.set_title(f'Two standard deviations')
183+
184+
185+
# Demo bottom right: Using kwargs
186+
dependency_kwargs = np.array([
187+
[-0.8, 0.5],
188+
[-0.2, 0.5]
189+
])
190+
mu = np.array([2, -3]).T
191+
scale = np.array([6, 5]).T
192+
193+
ax_kwargs.axvline(c='grey', lw=1)
194+
ax_kwargs.axhline(c='grey', lw=1)
195+
196+
x, y = get_correlated_dataset(500, dependency_kwargs, mu, scale)
197+
# Now plot the dataset first ("under" the ellipse) in order to
198+
# demonstrate the transparency of the ellipse (alpha).
199+
ax_kwargs.scatter(x, y, s=0.5)
200+
confidence_ellipse(x, y, ax_kwargs, alpha=0.5, facecolor='pink', edgecolor='purple')
201+
202+
ax_kwargs.scatter([mu[0]], [mu[1]],c='red', s=3)
203+
ax_kwargs.set_title(f'Using kwargs')
204+
205+
fig.subplots_adjust(hspace=0.25)
206+
plt.show()

0 commit comments

Comments
 (0)
0