Skip to content

Commit 9653441

Browse files
committed
full example fit contour
1 parent 9746a7a commit 9653441

File tree

3 files changed

+132
-23
lines changed

3 files changed

+132
-23
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
"""
2+
Contour fit
3+
===========
4+
5+
Two type of fit :
6+
- Ellipse
7+
- Circle
8+
9+
In the two case we use a least square algorithm
10+
"""
11+
12+
from matplotlib import pyplot as plt
13+
from numpy import cos, linspace, radians, sin
14+
15+
from py_eddy_tracker import data
16+
from py_eddy_tracker.generic import coordinates_to_local, local_to_coordinates
17+
from py_eddy_tracker.observations.observation import EddiesObservations
18+
from py_eddy_tracker.poly import fit_circle_, fit_ellips
19+
20+
# %%
21+
# Load example identification file
22+
a = EddiesObservations.load_file(data.get_path("Anticyclonic_20190223.nc"))
23+
24+
# %%
25+
# Function to draw circle or ellips from parameter
26+
def build_circle(x0, y0, r):
27+
angle = radians(linspace(0, 360, 50))
28+
x_norm, y_norm = cos(angle), sin(angle)
29+
return local_to_coordinates(x_norm * r, y_norm * r, x0, y0)
30+
31+
32+
def build_ellips(x0, y0, a, b, theta):
33+
angle = radians(linspace(0, 360, 50))
34+
x = a * cos(theta) * cos(angle) - b * sin(theta) * sin(angle)
35+
y = a * sin(theta) * cos(angle) + b * cos(theta) * sin(angle)
36+
return local_to_coordinates(x, y, x0, y0)
37+
38+
39+
# %%
40+
# Plot fitted circle or ellips on stored contour
41+
xs, ys = a.contour_lon_s, a.contour_lat_s
42+
43+
fig = plt.figure(figsize=(15, 15))
44+
45+
j = 1
46+
for i in range(0, 800, 30):
47+
x, y = xs[i], ys[i]
48+
x0_, y0_ = x.mean(), y.mean()
49+
x_, y_ = coordinates_to_local(x, y, x0_, y0_)
50+
ax = fig.add_subplot(4, 4, j)
51+
ax.grid(), ax.set_aspect("equal")
52+
ax.plot(x, y, label="store", color="black")
53+
x0, y0, a, b, theta = fit_ellips(x_, y_)
54+
x0, y0 = local_to_coordinates(x0, y0, x0_, y0_)
55+
ax.plot(*build_ellips(x0, y0, a, b, theta), label="ellips", color="green")
56+
x0, y0, radius, shape_error = fit_circle_(x_, y_)
57+
x0, y0 = local_to_coordinates(x0, y0, x0_, y0_)
58+
ax.plot(*build_circle(x0, y0, radius), label="circle", color="red", lw=0.5)
59+
if j == 16:
60+
break
61+
j += 1
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": null,
6+
"metadata": {
7+
"collapsed": false
8+
},
9+
"outputs": [],
10+
"source": [
11+
"%matplotlib inline"
12+
]
13+
},
14+
{
15+
"cell_type": "markdown",
16+
"metadata": {},
17+
"source": [
18+
"\n# Contour fit\n\nTwo type of fit :\n - Ellipse\n - Circle\n\nIn the two case we use a least square algorithm\n"
19+
]
20+
},
21+
{
22+
"cell_type": "code",
23+
"execution_count": null,
24+
"metadata": {
25+
"collapsed": false
26+
},
27+
"outputs": [],
28+
"source": [
29+
"from py_eddy_tracker.poly import fit_circle_, fit_ellips, fit_circle\nfrom py_eddy_tracker.generic import local_to_coordinates, coordinates_to_local\nfrom matplotlib import pyplot as plt\nfrom py_eddy_tracker import data\nfrom py_eddy_tracker.observations.observation import EddiesObservations\nfrom numpy import radians, linspace, cos, sin\n\na = EddiesObservations.load_file(data.get_path(\"Anticyclonic_20190223.nc\"))\n\n\ndef build_circle(x0, y0, r):\n angle = radians(linspace(0, 360, 50))\n x_norm, y_norm = cos(angle), sin(angle)\n return local_to_coordinates(x_norm * r, y_norm * r, x0, y0)\n\ndef build_ellips(x0, y0, a, b, theta):\n angle = radians(linspace(0, 360, 50))\n x = a * cos(theta) * cos(angle) - b * sin(theta) * sin(angle)\n y = a * sin(theta) * cos(angle) + b * cos(theta) * sin(angle)\n return local_to_coordinates(x, y, x0, y0)"
30+
]
31+
},
32+
{
33+
"cell_type": "code",
34+
"execution_count": null,
35+
"metadata": {
36+
"collapsed": false
37+
},
38+
"outputs": [],
39+
"source": [
40+
"xs,ys=a.contour_lon_s,a.contour_lat_s\n\nfor i in range(20):\n x, y = xs[i], ys[i]\n x0_, y0_ = x.mean(), y.mean()\n x_, y_ = coordinates_to_local(x,y, x0_, y0_)\n fig = plt.figure()\n ax = fig.add_subplot(111)\n ax.grid(), ax.set_aspect('equal')\n ax.plot(x, y, label='store')\n x0, y0, a,b, theta = fit_ellips(x_,y_)\n x0, y0 = local_to_coordinates(x0, y0, x0_, y0_)\n ax.plot(*build_ellips(x0, y0, a,b, theta), label='ellips')\n x0, y0, radius, shape_error = fit_circle_(x_,y_)\n x0,y0 = local_to_coordinates(x0,y0, x0_, y0_)\n ax.plot(*build_circle(x0,y0, radius), label='circle')\n ax.legend()"
41+
]
42+
}
43+
],
44+
"metadata": {
45+
"kernelspec": {
46+
"display_name": "Python 3",
47+
"language": "python",
48+
"name": "python3"
49+
},
50+
"language_info": {
51+
"codemirror_mode": {
52+
"name": "ipython",
53+
"version": 3
54+
},
55+
"file_extension": ".py",
56+
"mimetype": "text/x-python",
57+
"name": "python",
58+
"nbconvert_exporter": "python",
59+
"pygments_lexer": "ipython3",
60+
"version": "3.7.7"
61+
}
62+
},
63+
"nbformat": 4,
64+
"nbformat_minor": 0
65+
}

src/py_eddy_tracker/poly.py

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -548,29 +548,12 @@ def fit_ellips(x, y):
548548
x0 = (2 * c * d - b * e) / det
549549
y0 = (2 * a * e - b * d) / det
550550

551-
A = (
552-
-(
553-
(
554-
2
555-
* (a * e ** 2 + c * d ** 2 - b * d * e - det)
556-
* (a + c + ((a - c) ** 2 + b ** 2) ** 0.5)
557-
)
558-
** 0.5
559-
)
560-
/ det
561-
)
562-
B = (
563-
-(
564-
(
565-
2
566-
* (a * e ** 2 + c * d ** 2 - b * d * e - det)
567-
* (a + c - ((a - c) ** 2 + b ** 2) ** 0.5)
568-
)
569-
** 0.5
570-
)
571-
/ det
572-
)
573-
theta = arctan((c - a - ((a - c) ** 2 + b ** 2) ** 0.5) / b)
551+
AB1 = 2 * (a * e ** 2 + c * d ** 2 - b * d * e - det)
552+
AB2 = a + c
553+
AB3 = ((a - c) ** 2 + b ** 2) ** 0.5
554+
A = -((AB1 * (AB2 + AB3)) ** 0.5) / det
555+
B = -((AB1 * (AB2 - AB3)) ** 0.5) / det
556+
theta = arctan((c - a - AB3) / b)
574557
return x0, y0, A, B, theta
575558

576559

0 commit comments

Comments
 (0)