initial upload

This commit is contained in:
2025-10-21 11:20:44 +08:00
parent ad1b18ba06
commit 4333398dbe
131 changed files with 124404 additions and 0 deletions

View File

@@ -0,0 +1,97 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n# Optimization of a two-parameter function\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import numpy as np\n\n\n# Define the function that we are interested in\ndef sixhump(x):\n return (\n (4 - 2.1 * x[0] ** 2 + x[0] ** 4 / 3) * x[0] ** 2\n + x[0] * x[1]\n + (-4 + 4 * x[1] ** 2) * x[1] ** 2\n )\n\n\n# Make a grid to evaluate the function (for plotting)\nxlim = [-2, 2]\nylim = [-1, 1]\nx = np.linspace(*xlim) # type: ignore[call-overload]\ny = np.linspace(*ylim) # type: ignore[call-overload]\nxg, yg = np.meshgrid(x, y)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## A 2D image plot of the function\n Simple visualization in 2D\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\n\nplt.figure()\nplt.imshow(sixhump([xg, yg]), extent=xlim + ylim, origin=\"lower\") # type: ignore[arg-type]\nplt.colorbar()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## A 3D surface plot of the function\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"from mpl_toolkits.mplot3d import Axes3D\n\nfig = plt.figure()\nax: Axes3D = fig.add_subplot(111, projection=\"3d\")\nsurf = ax.plot_surface(\n xg,\n yg,\n sixhump([xg, yg]),\n rstride=1,\n cstride=1,\n cmap=\"viridis\",\n linewidth=0,\n antialiased=False,\n)\n\nax.set_xlabel(\"x\")\nax.set_ylabel(\"y\")\nax.set_zlabel(\"f(x, y)\")\nax.set_title(\"Six-hump Camelback function\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Find minima\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import scipy as sp\n\n# local minimization\nres_local = sp.optimize.minimize(sixhump, x0=[0, 0])\n\n# global minimization\nres_global = sp.optimize.differential_evolution(sixhump, bounds=[xlim, ylim])\n\nplt.figure()\n# Show the function in 2D\nplt.imshow(sixhump([xg, yg]), extent=xlim + ylim, origin=\"lower\") # type: ignore[arg-type]\nplt.colorbar()\n# Mark the minima\nplt.scatter(res_local.x[0], res_local.x[1], label=\"local minimizer\")\nplt.scatter(res_global.x[0], res_global.x[1], label=\"global minimizer\")\nplt.legend()\nplt.show()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.11"
}
},
"nbformat": 4,
"nbformat_minor": 0
}

View File

@@ -0,0 +1,97 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n# Demo connected components\n\nExtracting and labeling connected components in a 2D array\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import numpy as np\nimport matplotlib.pyplot as plt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Generate some binary data\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"x, y = np.indices((100, 100))\nsig = (\n np.sin(2 * np.pi * x / 50.0)\n * np.sin(2 * np.pi * y / 50.0)\n * (1 + x * y / 50.0**2) ** 2\n)\nmask = sig > 1\n\nplt.figure(figsize=(7, 3.5))\nplt.subplot(1, 2, 1)\nplt.imshow(sig)\nplt.axis(\"off\")\nplt.title(\"sig\")\n\nplt.subplot(1, 2, 2)\nplt.imshow(mask, cmap=\"gray\")\nplt.axis(\"off\")\nplt.title(\"mask\")\nplt.subplots_adjust(wspace=0.05, left=0.01, bottom=0.01, right=0.99, top=0.9)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Label connected components\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import scipy as sp\n\nlabels, nb = sp.ndimage.label(mask)\n\nplt.figure(figsize=(3.5, 3.5))\nplt.imshow(labels)\nplt.title(\"label\")\nplt.axis(\"off\")\n\nplt.subplots_adjust(wspace=0.05, left=0.01, bottom=0.01, right=0.99, top=0.9)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Extract the 4th connected component, and crop the array around it\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"sl = sp.ndimage.find_objects(labels == 4)\nplt.figure(figsize=(3.5, 3.5))\nplt.imshow(sig[sl[0]])\nplt.title(\"Cropped connected component\")\nplt.axis(\"off\")\n\nplt.subplots_adjust(wspace=0.05, left=0.01, bottom=0.01, right=0.99, top=0.9)\n\nplt.show()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.11"
}
},
"nbformat": 4,
"nbformat_minor": 0
}

View File

@@ -0,0 +1,86 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n# Curve fitting\n\nDemos a simple curve fitting\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First generate some data\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import numpy as np\n\n# Seed the random number generator for reproducibility\nrng = np.random.default_rng(27446968)\n\nx_data = np.linspace(-5, 5, num=50)\nnoise = 0.01 * np.cos(100 * x_data)\na, b = 2.9, 1.5\ny_data = a * np.cos(b * x_data) + noise\n\n# And plot it\nimport matplotlib.pyplot as plt\n\nplt.figure(figsize=(6, 4))\nplt.scatter(x_data, y_data)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now fit a simple sine function to the data\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import scipy as sp\n\n\ndef test_func(x, a, b, c):\n return a * np.sin(b * x + c)\n\n\nparams, params_covariance = sp.optimize.curve_fit(\n test_func, x_data, y_data, p0=[2, 1, 3]\n)\n\nprint(params)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"And plot the resulting curve on the data\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"plt.figure(figsize=(6, 4))\nplt.scatter(x_data, y_data, label=\"Data\")\nplt.plot(x_data, test_func(x_data, *params), label=\"Fitted function\")\n\nplt.legend(loc=\"best\")\n\nplt.show()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.11"
}
},
"nbformat": 4,
"nbformat_minor": 0
}

View File

@@ -0,0 +1,86 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n# Detrending a signal\n\n:func:`scipy.signal.detrend` removes a linear trend.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Generate a random signal with a trend\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import numpy as np\n\nt = np.linspace(0, 5, 100)\nrng = np.random.default_rng()\nx = t + rng.normal(size=100)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Detrend\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import scipy as sp\n\nx_detrended = sp.signal.detrend(x)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Plot\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\n\nplt.figure(figsize=(5, 4))\nplt.plot(t, x, label=\"x\")\nplt.plot(t, x_detrended, label=\"x_detrended\")\nplt.legend(loc=\"best\")\nplt.show()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.11"
}
},
"nbformat": 4,
"nbformat_minor": 0
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,43 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n# Normal distribution: histogram and PDF\n\nExplore the normal distribution: a histogram built from samples and the\nPDF (probability density function).\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import numpy as np\nimport scipy as sp\nimport matplotlib.pyplot as plt\n\ndist = sp.stats.norm(loc=0, scale=1) # standard normal distribution\nsample = dist.rvs(size=100000) # \"random variate sample\"\nplt.hist(\n sample,\n bins=51, # group the observations into 50 bins\n density=True, # normalize the frequencies\n label=\"normalized histogram\",\n)\n\nx = np.linspace(-5, 5) # possible values of the random variable\nplt.plot(x, dist.pdf(x), label=\"PDF\")\nplt.legend()\nplt.show()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.11"
}
},
"nbformat": 4,
"nbformat_minor": 0
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,86 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n# Resample a signal with scipy.signal.resample\n\n:func:`scipy.signal.resample` uses FFT to resample a 1D signal.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Generate a signal with 100 data point\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import numpy as np\n\nt = np.linspace(0, 5, 100)\nx = np.sin(t)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Downsample it by a factor of 4\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import scipy as sp\n\nx_resampled = sp.signal.resample(x, 25)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Plot\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\n\nplt.figure(figsize=(5, 4))\nplt.plot(t, x, label=\"Original signal\")\nplt.plot(t[::4], x_resampled, \"ko\", label=\"Resampled signal\")\n\nplt.legend(loc=\"best\")\nplt.show()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.11"
}
},
"nbformat": 4,
"nbformat_minor": 0
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,86 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n# Curve fitting: temperature as a function of month of the year\n\nWe have the min and max temperatures in Alaska for each months of the\nyear. We would like to find a function to describe this yearly evolution.\n\nFor this, we will fit a periodic function.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## The data\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import numpy as np\n\ntemp_max = np.array([17, 19, 21, 28, 33, 38, 37, 37, 31, 23, 19, 18])\ntemp_min = np.array([-62, -59, -56, -46, -32, -18, -9, -13, -25, -46, -52, -58])\n\nimport matplotlib.pyplot as plt\n\nmonths = np.arange(12)\nplt.plot(months, temp_max, \"ro\")\nplt.plot(months, temp_min, \"bo\")\nplt.xlabel(\"Month\")\nplt.ylabel(\"Min and max temperature\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Fitting it to a periodic function\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import scipy as sp\n\n\ndef yearly_temps(times, avg, ampl, time_offset):\n return avg + ampl * np.cos((times + time_offset) * 2 * np.pi / times.max())\n\n\nres_max, cov_max = sp.optimize.curve_fit(yearly_temps, months, temp_max, [20, 10, 0])\nres_min, cov_min = sp.optimize.curve_fit(yearly_temps, months, temp_min, [-40, 20, 0])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Plotting the fit\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"days = np.linspace(0, 12, num=365)\n\nplt.figure()\nplt.plot(months, temp_max, \"ro\")\nplt.plot(days, yearly_temps(days, *res_max), \"r-\")\nplt.plot(months, temp_min, \"bo\")\nplt.plot(days, yearly_temps(days, *res_min), \"b-\")\nplt.xlabel(\"Month\")\nplt.ylabel(r\"Temperature ($^\\circ$C)\")\n\nplt.show()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.11"
}
},
"nbformat": 4,
"nbformat_minor": 0
}

View File

@@ -0,0 +1,122 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n# Image denoising by FFT\n\nDenoise an image (:download:`../../../../data/moonlanding.png`) by\nimplementing a blur with an FFT.\n\nImplements, via FFT, the following convolution:\n\n\\begin{align}f_1(t) = \\int dt'\\, K(t-t') f_0(t')\\end{align}\n\n\\begin{align}\\tilde{f}_1(\\omega) = \\tilde{K}(\\omega) \\tilde{f}_0(\\omega)\\end{align}\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Read and plot the image\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import numpy as np\nimport matplotlib.pyplot as plt\n\nim = plt.imread(\"../../../../data/moonlanding.png\").astype(float)\n\nplt.figure()\nplt.imshow(im, \"gray\")\nplt.title(\"Original image\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Compute the 2d FFT of the input image\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import scipy as sp\n\nim_fft = sp.fft.fft2(im)\n\n# Show the results\n\n\ndef plot_spectrum(im_fft):\n from matplotlib.colors import LogNorm\n\n # A logarithmic colormap\n plt.imshow(np.abs(im_fft), norm=LogNorm(vmin=5))\n plt.colorbar()\n\n\nplt.figure()\nplot_spectrum(im_fft)\nplt.title(\"Fourier transform\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Filter in FFT\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# In the lines following, we'll make a copy of the original spectrum and\n# truncate coefficients.\n\n# Define the fraction of coefficients (in each direction) we keep\nkeep_fraction = 0.1\n\n# Call ff a copy of the original transform. NumPy arrays have a copy\n# method for this purpose.\nim_fft2 = im_fft.copy()\n\n# Set r and c to be the number of rows and columns of the array.\nr, c = im_fft2.shape\n\n# Set to zero all rows with indices between r*keep_fraction and\n# r*(1-keep_fraction):\nim_fft2[int(r * keep_fraction) : int(r * (1 - keep_fraction))] = 0\n\n# Similarly with the columns:\nim_fft2[:, int(c * keep_fraction) : int(c * (1 - keep_fraction))] = 0\n\nplt.figure()\nplot_spectrum(im_fft2)\nplt.title(\"Filtered Spectrum\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Reconstruct the final image\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# Reconstruct the denoised image from the filtered spectrum, keep only the\n# real part for display.\nim_new = sp.fft.ifft2(im_fft2).real\n\nplt.figure()\nplt.imshow(im_new, \"gray\")\nplt.title(\"Reconstructed Image\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Easier and better: :func:`scipy.ndimage.gaussian_filter`\n\n Implementing filtering directly with FFTs is tricky and time consuming.\n We can use the Gaussian filter from :mod:`scipy.ndimage`\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"im_blur = sp.ndimage.gaussian_filter(im, 4)\n\nplt.figure()\nplt.imshow(im_blur, \"gray\")\nplt.title(\"Blurred image\")\n\nplt.show()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.11"
}
},
"nbformat": 4,
"nbformat_minor": 0
}

View File

@@ -0,0 +1,140 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n# Simple image blur by convolution with a Gaussian kernel\n\nBlur an an image (:download:`../../../../data/elephant.png`) using a\nGaussian kernel.\n\nConvolution is easy to perform with FFT: convolving two signals boils\ndown to multiplying their FFTs (and performing an inverse FFT).\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import numpy as np\nimport scipy as sp\nimport matplotlib.pyplot as plt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## The original image\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# read image\nimg = plt.imread(\"../../../../data/elephant.png\")\nplt.figure()\nplt.imshow(img)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Prepare an Gaussian convolution kernel\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# First a 1-D Gaussian\nt = np.linspace(-10, 10, 30)\nbump = np.exp(-0.1 * t**2)\nbump /= np.trapezoid(bump) # normalize the integral to 1\n\n# make a 2-D kernel out of it\nkernel = bump[:, np.newaxis] * bump[np.newaxis, :]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Implement convolution via FFT\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# Padded fourier transform, with the same shape as the image\n# We use :func:`scipy.fft.fft2` to have a 2D FFT\nkernel_ft = sp.fft.fft2(kernel, s=img.shape[:2], axes=(0, 1))\n\n# convolve\nimg_ft = sp.fft.fft2(img, axes=(0, 1))\n# the 'newaxis' is to match to color direction\nimg2_ft = kernel_ft[:, :, np.newaxis] * img_ft\nimg2 = sp.fft.ifft2(img2_ft, axes=(0, 1)).real\n\n# clip values to range\nimg2 = np.clip(img2, 0, 1)\n\n# plot output\nplt.figure()\nplt.imshow(img2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Further exercise (only if you are familiar with this stuff):\n\nA \"wrapped border\" appears in the upper left and top edges of the\nimage. This is because the padding is not done correctly, and does\nnot take the kernel size into account (so the convolution \"flows out\nof bounds of the image\"). Try to remove this artifact.\n\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## A function to do it: :func:`scipy.signal.fftconvolve`\n\n The above exercise was only for didactic reasons: there exists a\n function in scipy that will do this for us, and probably do a better\n job: :func:`scipy.signal.fftconvolve`\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# mode='same' is there to enforce the same output shape as input arrays\n# (ie avoid border effects)\nimg3 = sp.signal.fftconvolve(img, kernel[:, :, np.newaxis], mode=\"same\")\nplt.figure()\nplt.imshow(img3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note that we still have a decay to zero at the border of the image.\nUsing :func:`scipy.ndimage.gaussian_filter` would get rid of this\nartifact\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"plt.show()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.11"
}
},
"nbformat": 4,
"nbformat_minor": 0
}

View File

@@ -0,0 +1,93 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n# Crude periodicity finding\n\nDiscover the periods in evolution of animal populations\n(:download:`../../../../data/populations.txt`)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Load the data\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import numpy as np\n\ndata = np.loadtxt(\"../../../../data/populations.txt\")\nyears = data[:, 0]\npopulations = data[:, 1:]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Plot the data\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\n\nplt.figure()\nplt.plot(years, populations * 1e-3)\nplt.xlabel(\"Year\")\nplt.ylabel(r\"Population number ($\\cdot10^3$)\")\nplt.legend([\"hare\", \"lynx\", \"carrot\"], loc=1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Plot its periods\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import scipy as sp\n\nft_populations = sp.fft.fft(populations, axis=0)\nfrequencies = sp.fft.fftfreq(populations.shape[0], years[1] - years[0])\nperiods = 1 / frequencies\n\nplt.figure()\nplt.plot(periods, abs(ft_populations) * 1e-3, \"o\")\nplt.xlim(0, 22)\nplt.xlabel(\"Period\")\nplt.ylabel(r\"Power ($\\cdot10^3$)\")\n\nplt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There's probably a period of around 10 years (obvious from the\nplot), but for this crude a method, there's not enough data to say\nmuch more.\n\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.11"
}
},
"nbformat": 4,
"nbformat_minor": 0
}