12
12
https://carstenschelp.github.io/2018/09/14/Plot_Confidence_Ellipse_001.html
13
13
"""
14
14
15
+ #############################################################################
16
+ #
17
+ # The plotting function itself
18
+ # """"""""""""""""""""""""""""
19
+ #
20
+ # This function plots the confidence ellipse of the covariance of the given
21
+ # array-like variables x and y. The ellipse is plotted into the given
22
+ # axes-object ax.
23
+ #
24
+ # The radiuses of the ellipse can be controlled by n_std which is the number
25
+ # of standard deviations. The default value is 3 which makes the ellipse
26
+ # enclose 99.7% of the points (given the data is normally distributed
27
+ # like in these examples).
28
+
15
29
import numpy as np
16
30
import matplotlib .pyplot as plt
17
31
from matplotlib .patches import Ellipse
@@ -72,6 +86,16 @@ def confidence_ellipse(x, y, ax, n_std=3.0, **kwargs):
72
86
ax .add_patch (ellipse )
73
87
74
88
89
+ #############################################################################
90
+ #
91
+ # A helper function to create a correlated dataset
92
+ # """"""""""""""""""""""""""""""""""""""""""""""""
93
+ #
94
+ # Creates a random two-dimesional dataset with the specified
95
+ # two-dimensional mean (mu) and dimensions (scale).
96
+ # The correlation can be controlled by the param 'dependency',
97
+ # a 2x2 matrix.
98
+
75
99
def get_correlated_dataset (n , dependency , mu , scale ):
76
100
latent = np .random .randn (n , 2 )
77
101
dependent = latent .dot (dependency )
@@ -80,60 +104,76 @@ def get_correlated_dataset(n, dependency, mu, scale):
80
104
# return x and y of the new, correlated dataset
81
105
return scaled_with_offset [:, 0 ], scaled_with_offset [:, 1 ]
82
106
83
- fig , ((ax_pos , ax_neg , ax_uncorrel ), (ax_nstd1 , ax_nstd2 , ax_kwargs ))\
84
- = plt .subplots (nrows = 2 , ncols = 3 , figsize = (9 , 6 ),
85
- sharex = True , sharey = True )
86
- np .random .seed (1234 )
87
107
88
- # Demo top left: positive correlation
108
+ #############################################################################
109
+ #
110
+ # Positive correlation
111
+ # """"""""""""""""""""
112
+ #
113
+
114
+ fig , ax_pos = plt .subplots (figsize = (6 , 6 ))
115
+ np .random .seed (1234 )
89
116
90
- # Create a matrix that transforms the independent
91
- # "latent" dataset into a dataset where x and y are
92
- # correlated - positive correlation, in this case.
93
117
dependency_pos = np .array ([
94
118
[0.85 , 0.35 ],
95
119
[0.15 , - 0.65 ]
96
120
])
97
- mu_pos = np .array ([2 , 4 ]).T
98
- scale_pos = np .array ([3 , 5 ]).T
121
+ mu = np .array ([2 , 4 ]).T
122
+ scale = np .array ([3 , 5 ]).T
99
123
100
124
# Indicate the x- and y-axis
101
125
ax_pos .axvline (c = 'grey' , lw = 1 )
102
126
ax_pos .axhline (c = 'grey' , lw = 1 )
103
127
104
- x , y = get_correlated_dataset (500 , dependency_pos , mu_pos , scale_pos )
128
+ x , y = get_correlated_dataset (500 , dependency_pos , mu , scale )
105
129
confidence_ellipse (x , y , ax_pos , facecolor = 'none' , edgecolor = 'red' )
106
130
107
131
# Also plot the dataset itself, for reference
108
132
ax_pos .scatter (x , y , s = 0.5 )
109
133
# Mark the mean ("mu")
110
- ax_pos .scatter ([mu_pos [0 ]], [mu_pos [1 ]], c = 'red' , s = 3 )
134
+ ax_pos .scatter ([mu [0 ]], [mu [1 ]], c = 'red' , s = 3 )
111
135
ax_pos .set_title (f'Positive correlation' )
136
+ plt .show ()
137
+
112
138
113
- # Demo top middle: negative correlation
139
+ #############################################################################
140
+ #
141
+ # Negative correlation
142
+ # """"""""""""""""""""
143
+ #
144
+
145
+ fig , ax_neg = plt .subplots (figsize = (6 , 6 ))
114
146
dependency_neg = np .array ([
115
147
[0.9 , - 0.4 ],
116
148
[0.1 , - 0.6 ]
117
149
])
118
150
mu = np .array ([2 , 4 ]).T
119
151
scale = np .array ([3 , 5 ]).T
120
152
121
- # Indicate the x- and y-axes
122
153
ax_neg .axvline (c = 'grey' , lw = 1 )
123
154
ax_neg .axhline (c = 'grey' , lw = 1 )
124
155
125
156
x , y = get_correlated_dataset (500 , dependency_neg , mu , scale )
126
157
confidence_ellipse (x , y , ax_neg , facecolor = 'none' , edgecolor = 'red' )
127
- # Again, plot the dataset itself, for reference
158
+
128
159
ax_neg .scatter (x , y , s = 0.5 )
129
- # Mark the mean ("mu")
160
+
130
161
ax_neg .scatter ([mu [0 ]], [mu [1 ]], c = 'red' , s = 3 )
131
162
ax_neg .set_title (f'Negative correlation' )
163
+ plt .show ()
132
164
133
- # Demo top right: uncorrelated dataset
134
- # This uncorrelated plot (bottom left) is not a circle since x and y
165
+
166
+ #############################################################################
167
+ #
168
+ # Weak correlation
169
+ # """"""""""""""""
170
+ #
171
+ # This is still an ellipse, not a circle because x and y
135
172
# are differently scaled. However, the fact that x and y are uncorrelated
136
- # is shown however by the ellipse being aligned with the x- and y-axis.
173
+ # is shown by the axes of the ellipse being aligned with the x- and y-axis
174
+ # of the coordinate system.
175
+
176
+ fig , ax_uncorrel = plt .subplots (figsize = (6 , 6 ))
137
177
138
178
in_dependency = np .array ([
139
179
[1 , 0 ],
@@ -151,47 +191,50 @@ def get_correlated_dataset(n, dependency, mu, scale):
151
191
ax_uncorrel .scatter ([mu [0 ]], [mu [1 ]], c = 'red' , s = 3 )
152
192
ax_uncorrel .set_title (f'Weak correlation' )
153
193
154
- # Demo bottom left and middle: ellipse two standard deviations wide
155
- # In the confidence_ellipse function the default of the number
156
- # of standard deviations is 3, which makes the ellipse enclose
157
- # 99.7% of the points when the data is normally distributed.
158
- # This demo shows a two plots of the same dataset with different
159
- # values for "n_std".
160
- dependency_nstd_1 = np .array ([
194
+
195
+ #############################################################################
196
+ #
197
+ # Different number of standard deviations
198
+ # """""""""""""""""""""""""""""""""""""""
199
+ #
200
+ # A plot with n_std = 3 (gray), 2 (blue) and 1 (red)
201
+
202
+ fig , ax_nstd = plt .subplots (figsize = (6 , 6 ))
203
+
204
+ dependency_nstd = np .array ([
161
205
[0.8 , 0.75 ],
162
206
[- 0.2 , 0.35 ]
163
207
])
164
208
mu = np .array ([0 , 0 ]).T
165
209
scale = np .array ([8 , 5 ]).T
166
210
167
- ax_kwargs .axvline (c = 'grey' , lw = 1 )
168
- ax_kwargs .axhline (c = 'grey' , lw = 1 )
169
-
170
- x , y = get_correlated_dataset (500 , dependency_nstd_1 , mu , scale )
171
- # Onde standard deviation
172
- # Now plot the dataset first ("under" the ellipse) in order to
173
- # demonstrate the transparency of the ellipse (alpha).
174
- ax_nstd1 .scatter (x , y , s = 0.5 )
175
- confidence_ellipse (x , y , ax_nstd1 , n_std = 1 ,
176
- facecolor = 'none' , edgecolor = 'red' )
177
- confidence_ellipse (x , y , ax_nstd1 , n_std = 3 ,
178
- facecolor = 'none' , edgecolor = 'gray' , linestyle = '--' )
211
+ ax_nstd .axvline (c = 'grey' , lw = 1 )
212
+ ax_nstd .axhline (c = 'grey' , lw = 1 )
179
213
180
- ax_nstd1 . scatter ([ mu [ 0 ]], [ mu [ 1 ]], c = 'red' , s = 3 )
181
- ax_nstd1 . set_title ( f'One standard deviation' )
214
+ x , y = get_correlated_dataset ( 500 , dependency_nstd , mu , scale )
215
+ ax_nstd . scatter ( x , y , s = 0.5 )
182
216
183
- # Two standard deviations
184
- ax_nstd2 .scatter (x , y , s = 0.5 )
185
- confidence_ellipse (x , y , ax_nstd2 , n_std = 2 ,
217
+ confidence_ellipse (x , y , ax_nstd , n_std = 1 ,
186
218
facecolor = 'none' , edgecolor = 'red' )
187
- confidence_ellipse (x , y , ax_nstd2 , n_std = 3 ,
219
+ confidence_ellipse (x , y , ax_nstd , n_std = 2 ,
220
+ facecolor = 'none' , edgecolor = 'blue' )
221
+ confidence_ellipse (x , y , ax_nstd , n_std = 3 ,
188
222
facecolor = 'none' , edgecolor = 'gray' , linestyle = '--' )
189
223
190
- ax_nstd2 .scatter ([mu [0 ]], [mu [1 ]], c = 'red' , s = 3 )
191
- ax_nstd2 .set_title (f'Two standard deviations' )
224
+ ax_nstd .scatter ([mu [0 ]], [mu [1 ]], c = 'red' , s = 3 )
225
+ ax_nstd .set_title (f'Different standard deviations' )
226
+ plt .show ()
227
+
192
228
229
+ #############################################################################
230
+ #
231
+ # Using the keyword arguments
232
+ # """""""""""""""""""""""""""
233
+ #
234
+ # Use the kwargs specified for matplotlib.patches.Patch in order
235
+ # to have the ellipse rendered in different ways.
193
236
194
- # Demo bottom right: Using kwargs
237
+ fig , ax_kwargs = plt . subplots ( figsize = ( 6 , 6 ))
195
238
dependency_kwargs = np .array ([
196
239
[- 0.8 , 0.5 ],
197
240
[- 0.2 , 0.5 ]
0 commit comments