From c33d931ccdf3c6048c33c6389c6fbedec862dc8b Mon Sep 17 00:00:00 2001 From: Saeed Date: Fri, 15 Nov 2024 19:00:34 +0330 Subject: [PATCH] Refactor the structure of code --- LICENSE | 2 +- README.md | 39 +++++++++++-- example.py | 30 ++++++++++ main.py | 92 ------------------------------- recurrence/__init__.py | 0 {utils => recurrence}/convolve.py | 0 recurrence/plotting.py | 61 ++++++++++++++++++++ 7 files changed, 127 insertions(+), 97 deletions(-) create mode 100644 example.py delete mode 100644 main.py create mode 100644 recurrence/__init__.py rename {utils => recurrence}/convolve.py (100%) create mode 100644 recurrence/plotting.py diff --git a/LICENSE b/LICENSE index 886853c..ff07f96 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The Academic License -Copyright (c) [2020] [Saeed Hasani Borzadaran] +Copyright (c) [2020] [Saeed Hasani] This project includes academic-research code and documents under development. You would be a fool to run any of the code. diff --git a/README.md b/README.md index 3dc199e..ca4285a 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,45 @@ # Recurrence Plot [Recurrence Plot](https://en.wikipedia.org/wiki/Recurrence_plot) – A recurrence plot (RP) is an advanced technique of **nonlinear** data analysis. It is a visualisation (or a graph) of a square matrix, in which the matrix elements correspond to those times at which a state of a dynamical system recurs (columns and rows correspond then to a certain pair of times). -# Result +## Result ![](results/1D_to_2D.jpg) -# Usage +## Usage **1. Install requirements:** +Ensure you have Python 3 installed. Install the required dependencies using: + + pip install -r requirements.txt -**2. Run `main.py` script:** +**2. Run `example.py` script:** + + python3 example.py # or python example.py + +This will: + +- Generate a random signal. +- Smooth the signal using a moving average filter. +- Compute and visualize the recurrence plot. +- Save the resulting plot as results/1D_to_2D.jpg. + +---- +## How to Use the recurrence Package + +If you want to use the recurrence package in your own projects: + +1) **Import the Required Modules:** + + For recurrence plot functions, import from recurrence.plotting. + For signal processing utilities, import from recurrence.convolve. + + Example: + + ```python + from recurrence.plotting import setup_plot, save_plot + from recurrence.convolve import calculate_convolve + ``` - python3 main.py +2) **Process Your Signal:** + + Use `calculate_convolve` to smooth your input signal, then use the `setup_plot` and `save_plot` functions to generate and save recurrence plots. \ No newline at end of file diff --git a/example.py b/example.py new file mode 100644 index 0000000..242f5b5 --- /dev/null +++ b/example.py @@ -0,0 +1,30 @@ +import matplotlib.pyplot as plt +import numpy as np +from recurrence.plotting import setup_plot, save_plot +from recurrence.convolve import calculate_convolve + +if __name__ == "__main__": + # Example usage + fig = plt.figure(figsize=(8, 2)) + + # Configuration + row, col = 1, 2 + size = f"{row}{col}" + + # Generate raw signal + raw_signal = np.random.uniform(-1, 1, 50) + + # Process the signal + convolved_signal = calculate_convolve(raw_signal) + + # Plot signals and recurrence plot + setup_plot( + signal=convolved_signal, + size=size, + cell=1, + signal_name='Input Signal', + image_name='2D Image of Signal' + ) + + # Save the plot + save_plot(filepath='results/1D_to_2D.jpg') diff --git a/main.py b/main.py deleted file mode 100644 index 17d18b5..0000000 --- a/main.py +++ /dev/null @@ -1,92 +0,0 @@ -from __future__ import division, print_function -import numpy as np -import pylab as plt -from scipy.spatial.distance import pdist, squareform - -from utils.convolve import calculate_convolve - -# ----------------- Plot config --------------------------------------- # -SMALL = 8 -MEDIUM = 10 -BIGGER = 11 - -plt.rc('font', size=SMALL) # controls default text sizes -plt.rc('axes', titlesize=SMALL) # font size of the axes title -plt.rc('axes', labelsize=MEDIUM) # font size of the x and y labels -plt.rc('xtick', labelsize=SMALL) # font size of the tick labels -plt.rc('ytick', labelsize=SMALL) # font size of the tick labels -plt.rc('legend', fontsize=SMALL) # legend font size -plt.rc('figure', titlesize=BIGGER) # font size of the figure title - -plt.rcParams["font.family"] = "Times", "Times New Roman", "serif" - - -# --------------------------------------------------------------------- # - -def save_plot(): - left = 0.2 - right = 0.9 - bottom = 0.1 - top = 0.9 - wspace = 0.2 - hspace = 0.1 - - plt.subplots_adjust(left, bottom, right, top, wspace, hspace) - plt.savefig('results/1D_to_2D.jpg', bbox_inches='tight') - - -class RecurrencePlot(object): - def __init__(self, row=2, col=2): - self.signal = [] - - # config pylab config for plot - self.size = '%d%d' % (row, col) - - def set_signal(self, signal): - self.signal = signal - - def recurrence_plot(self, eps=0.10, steps=3): - # Convert 1-D signal to 2-D signal - _2d_array = self.signal[:, None] - - # Pairwise distances - distance = pdist(_2d_array) - distance = np.floor(distance / eps) - distance[distance > steps] = steps - return squareform(distance) - - def subplot(self, x, is_signal=True, cell=1, title=None, grid=True): - ax = plt.subplot(int('%s%d' % (self.size, cell))) - ax.grid(color='gray', linestyle='dotted', linewidth=0.5) - ax.spines['top'].set_visible(False) - ax.spines['right'].set_visible(False) - - plt.plot(x, 'm', linewidth=1, ) if is_signal else plt.imshow(x) - plt.title(title) - plt.grid(grid) - - def setup_plot(self, cell=1, signal_name='Raw Signal', image_name='2D Image'): - # plot with various axes scales - self.subplot(self.signal, cell=cell, title=signal_name) - self.subplot(self.recurrence_plot(), is_signal=False, cell=cell + 1, title=image_name) - - -if __name__ == "__main__": - # This is an example of how to give a signal to class `RecurrencePlot`. - # The input signal can be like [-1, 0.5, 1, ... ,1.5]. - - fig = plt.figure(figsize=(8, 2)) - rp = RecurrencePlot(row=1, col=2) - - # This is how I generated a signal with a length of 50. - raw_signal = np.random.uniform(-1, 1, 50) - - # Then I got the convolve signal. I finally drew it. - convolved_signal = calculate_convolve(raw_signal) - rp.set_signal(convolved_signal) - - # cell value must be odd number. You can create your own `setup_plot` - # subplot 11(1 | 2) - rp.setup_plot(cell=1, signal_name='Input Signal', image_name='2D image of Input Signal') - - save_plot() diff --git a/recurrence/__init__.py b/recurrence/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/utils/convolve.py b/recurrence/convolve.py similarity index 100% rename from utils/convolve.py rename to recurrence/convolve.py diff --git a/recurrence/plotting.py b/recurrence/plotting.py new file mode 100644 index 0000000..10cd015 --- /dev/null +++ b/recurrence/plotting.py @@ -0,0 +1,61 @@ +import matplotlib.pyplot as plt +import numpy as np +from scipy.spatial.distance import pdist, squareform + +# ----------------- Plot config --------------------------------------- # +SMALL = 8 +MEDIUM = 10 +BIGGER = 11 + +plt.rc('font', size=SMALL) # controls default text sizes +plt.rc('axes', titlesize=SMALL) # font size of the axes title +plt.rc('axes', labelsize=MEDIUM) # font size of the x and y labels +plt.rc('xtick', labelsize=SMALL) # font size of the tick labels +plt.rc('ytick', labelsize=SMALL) # font size of the tick labels +plt.rc('legend', fontsize=SMALL) # legend font size +plt.rc('figure', titlesize=BIGGER) # font size of the figure title + +plt.rcParams["font.family"] = "Times", "Times New Roman", "serif" + +# --------------------------------------------------------------------- # + +def save_plot(filepath='results/1D_to_2D.jpg'): + """Adjust and save the plot.""" + left = 0.2 + right = 0.9 + bottom = 0.1 + top = 0.9 + wspace = 0.2 + hspace = 0.1 + + plt.subplots_adjust(left, bottom, right, top, wspace, hspace) + plt.savefig(filepath, bbox_inches='tight') + +def recurrence_plot(signal, eps=0.10, steps=3): + """Generate a recurrence plot from a 1D signal.""" + _2d_array = signal[:, None] + distance = pdist(_2d_array) + distance = np.floor(distance / eps) + distance[distance > steps] = steps + return squareform(distance) + +def subplot(x, size, cell, is_signal=True, title=None, grid=True): + """Create a subplot for the signal or image.""" + ax = plt.subplot(int(f"{size}{cell}")) + ax.grid(color='gray', linestyle='dotted', linewidth=0.5) + ax.spines['top'].set_visible(False) + ax.spines['right'].set_visible(False) + + if is_signal: + plt.plot(x, 'm', linewidth=1) + else: + plt.imshow(x) + + plt.title(title) + plt.grid(grid) + +def setup_plot(signal, size, cell, signal_name='Raw Signal', image_name='2D Image'): + """Set up and display the plot for the signal and its recurrence plot.""" + subplot(signal, size=size, cell=cell, is_signal=True, title=signal_name) + rp = recurrence_plot(signal) + subplot(rp, size=size, cell=cell + 1, is_signal=False, title=image_name)