From 1d7fe7c06d48750fa8faf61f68116ce6c9d2da18 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 14:05:09 -0600 Subject: [PATCH] Auto-format code using pep8 (#289) Co-authored-by: GitHub Actions --- src/acom_music_box/data_output.py | 4 +- src/acom_music_box/plot_output.py | 254 +++++++++--------- .../test_executable_data_output.py | 2 +- tests/unit/test_plot_output.py | 5 +- 4 files changed, 133 insertions(+), 132 deletions(-) diff --git a/src/acom_music_box/data_output.py b/src/acom_music_box/data_output.py index 46f2050..3165554 100644 --- a/src/acom_music_box/data_output.py +++ b/src/acom_music_box/data_output.py @@ -143,6 +143,6 @@ def output(self): # Even if we are printing to the terminal, we still allow output to be written to csv if an output path is provided if (self.args.output_format == 'csv') or (self.args.output is not None and self.args.output_format == 'terminal'): self._output_csv() - + if self.args.output_format == 'netcdf': - self._output_netcdf() \ No newline at end of file + self._output_netcdf() diff --git a/src/acom_music_box/plot_output.py b/src/acom_music_box/plot_output.py index cef9ac6..e84093f 100644 --- a/src/acom_music_box/plot_output.py +++ b/src/acom_music_box/plot_output.py @@ -7,105 +7,105 @@ logger = logging.getLogger(__name__) + class PlotOutput: - """ - A class to handle plotting operations for a DataFrame, including plotting species - concentrations over time using gnuplot or matplotlib. - - This class manages the plotting tool, species list, and data output formats based on - the provided arguments, ensuring valid paths and creating necessary directories. - - Attributes - ---------- - df : pandas.DataFrame - The DataFrame to be plotted. - args : argparse.Namespace - Command-line arguments or configurations specifying plot options. - species_list : list - A list of species to plot. - - Examples - -------- - >>> import pandas as pd - >>> from argparse import Namespace - >>> df = pd.DataFrame({ - ... 'time': [0, 1, 2], - ... 'CONC.A.mol m-3': [1, 2, 3], - ... 'CONC.B.mol m-3': [4, 5, 6], - ... 'CONC.C.mol m-3': [7, 8, 9] - ... }) - >>> args = Namespace(plot='CONC.A,CONC.B', plot_tool='matplotlib') - >>> plot_output = PlotOutput(df, args) - >>> plot_output.plot() - """ - - def __init__(self, df, args): """ - Initialize the PlotOutput class with a DataFrame and configuration arguments. + A class to handle plotting operations for a DataFrame, including plotting species + concentrations over time using gnuplot or matplotlib. + + This class manages the plotting tool, species list, and data output formats based on + the provided arguments, ensuring valid paths and creating necessary directories. - Parameters + Attributes ---------- df : pandas.DataFrame - The DataFrame containing the data to be output. + The DataFrame to be plotted. args : argparse.Namespace - Arguments specifying the plot configuration, such as plot tool and species list. - """ - - self.df = df.copy(deep=True) - self.args = args - self.species_list = self._format_species_list(self.args.plot.split(',') if self.args.plot else None) - - - def _format_species_list(self, species_list): - """ - Format the species list for plotting. - - This method formats the species list for plotting by adding the 'CONC.' prefix - to each species name if it is not already present. - - Parameters - ---------- + Command-line arguments or configurations specifying plot options. species_list : list A list of species to plot. - Returns - ------- - list - A formatted list of species for plotting. + Examples + -------- + >>> import pandas as pd + >>> from argparse import Namespace + >>> df = pd.DataFrame({ + ... 'time': [0, 1, 2], + ... 'CONC.A.mol m-3': [1, 2, 3], + ... 'CONC.B.mol m-3': [4, 5, 6], + ... 'CONC.C.mol m-3': [7, 8, 9] + ... }) + >>> args = Namespace(plot='CONC.A,CONC.B', plot_tool='matplotlib') + >>> plot_output = PlotOutput(df, args) + >>> plot_output.plot() """ - plot_list = None - if species_list is not None: - plot_list = [] - for species in species_list: - species = species.strip() - if 'CONC.' not in species: - species = f'CONC.{species}' - plot_list.append(species) - - return plot_list - - def _plot_with_gnuplot(self): - """ - Plot the specified species using gnuplot. - """ - # Prepare columns and data for plotting - columns = ['time'] + self.species_list - data_to_plot = self.df[columns] - - data_csv = data_to_plot.to_csv(index=False) - - try: - with tempfile.NamedTemporaryFile(suffix='.csv', mode='w+', delete=True) as data_file: - data_file.write(data_csv) - data_file.flush() - data_file_path = data_file.name - - plot_commands = ',\n\t'.join( - f"'{data_file_path}' using 1:{i+2} with lines title '{species}'" for i, - species in enumerate(self.species_list)) - - gnuplot_command = f""" + def __init__(self, df, args): + """ + Initialize the PlotOutput class with a DataFrame and configuration arguments. + + Parameters + ---------- + df : pandas.DataFrame + The DataFrame containing the data to be output. + args : argparse.Namespace + Arguments specifying the plot configuration, such as plot tool and species list. + """ + + self.df = df.copy(deep=True) + self.args = args + self.species_list = self._format_species_list(self.args.plot.split(',') if self.args.plot else None) + + def _format_species_list(self, species_list): + """ + Format the species list for plotting. + + This method formats the species list for plotting by adding the 'CONC.' prefix + to each species name if it is not already present. + + Parameters + ---------- + species_list : list + A list of species to plot. + + Returns + ------- + list + A formatted list of species for plotting. + """ + + plot_list = None + if species_list is not None: + plot_list = [] + for species in species_list: + species = species.strip() + if 'CONC.' not in species: + species = f'CONC.{species}' + plot_list.append(species) + + return plot_list + + def _plot_with_gnuplot(self): + """ + Plot the specified species using gnuplot. + """ + # Prepare columns and data for plotting + columns = ['time'] + self.species_list + data_to_plot = self.df[columns] + + data_csv = data_to_plot.to_csv(index=False) + + try: + with tempfile.NamedTemporaryFile(suffix='.csv', mode='w+', delete=True) as data_file: + data_file.write(data_csv) + data_file.flush() + data_file_path = data_file.name + + plot_commands = ',\n\t'.join( + f"'{data_file_path}' using 1:{i+2} with lines title '{species}'" for i, + species in enumerate(self.species_list)) + + gnuplot_command = f""" set datafile separator ","; set terminal dumb size 120,25; set xlabel 'Time'; @@ -114,53 +114,53 @@ def _plot_with_gnuplot(self): plot {plot_commands} """ - subprocess.run(['gnuplot', '-e', gnuplot_command], check=True) - except FileNotFoundError as e: - logging.critical("gnuplot is not installed. Skipping plotting.") - raise e - except subprocess.CalledProcessError as e: - logging.error(f"Error occurred while plotting: {e}") - raise e + subprocess.run(['gnuplot', '-e', gnuplot_command], check=True) + except FileNotFoundError as e: + logging.critical("gnuplot is not installed. Skipping plotting.") + raise e + except subprocess.CalledProcessError as e: + logging.error(f"Error occurred while plotting: {e}") + raise e + + def _plot_with_matplotlib(self): + """ + Plot the specified species using matplotlib. + """ - def _plot_with_matplotlib(self): - """ - Plot the specified species using matplotlib. - """ + indexed = self.df.set_index('time') - indexed = self.df.set_index('time') + fig, ax = plt.subplots() + indexed[self.species_list].plot(ax=ax) - fig, ax = plt.subplots() - indexed[self.species_list].plot(ax=ax) + ax.set(xlabel='Time [s]', ylabel='Concentration [mol m-3]', title='Time vs Species') - ax.set(xlabel='Time [s]', ylabel='Concentration [mol m-3]', title='Time vs Species') + ax.spines[:].set_visible(False) + ax.spines['left'].set_visible(True) + ax.spines['bottom'].set_visible(True) - ax.spines[:].set_visible(False) - ax.spines['left'].set_visible(True) - ax.spines['bottom'].set_visible(True) + ax.grid(alpha=0.5) + ax.legend() - ax.grid(alpha=0.5) - ax.legend() + # Enable interactive data cursors with hover functionality + cursor = mplcursors.cursor(hover=True) - # Enable interactive data cursors with hover functionality - cursor = mplcursors.cursor(hover=True) + # Customize the annotation format + @cursor.connect("add") + def on_add(sel): + sel.annotation.set_text(f'Time: {sel.target[0]:.2f}\nConcentration: {sel.target[1]:1.2e}') - # Customize the annotation format - @cursor.connect("add") - def on_add(sel): - sel.annotation.set_text(f'Time: {sel.target[0]:.2f}\nConcentration: {sel.target[1]:1.2e}') + plt.show() - plt.show() - - def plot(self): - """ - Plot the specified species using the selected plotting tool. - """ + def plot(self): + """ + Plot the specified species using the selected plotting tool. + """ - if self.species_list is None: - logger.debug("No species provided for plotting.") - return + if self.species_list is None: + logger.debug("No species provided for plotting.") + return - if self.args.plot_tool == 'gnuplot': - self._plot_with_gnuplot() - else: - self._plot_with_matplotlib() \ No newline at end of file + if self.args.plot_tool == 'gnuplot': + self._plot_with_gnuplot() + else: + self._plot_with_matplotlib() diff --git a/tests/integration/test_executable_data_output.py b/tests/integration/test_executable_data_output.py index 4282882..ecc43a6 100644 --- a/tests/integration/test_executable_data_output.py +++ b/tests/integration/test_executable_data_output.py @@ -85,4 +85,4 @@ def test_create_directory_and_timestamped_netcdf(temp_dir): def test_run_configuration_file(temp_dir): result = subprocess.run(['music_box', '-c', Examples.Analytical.path], capture_output=True, text=True, cwd=temp_dir) - assert result.returncode == 0 \ No newline at end of file + assert result.returncode == 0 diff --git a/tests/unit/test_plot_output.py b/tests/unit/test_plot_output.py index 8b25051..8893dab 100644 --- a/tests/unit/test_plot_output.py +++ b/tests/unit/test_plot_output.py @@ -1,3 +1,4 @@ +from acom_music_box.plot_output import PlotOutput import unittest import pandas as pd import shutil @@ -7,7 +8,6 @@ matplotlib.use('Agg') # Use a non-interactive backend -from acom_music_box.plot_output import PlotOutput class TestPlotOutput(unittest.TestCase): @@ -44,5 +44,6 @@ def test_plot_with_matplotlib(self): plot_output = PlotOutput(self.df, args) plot_output.plot() + if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main()