Skip to content
Snippets Groups Projects
Commit 779cd772 authored by Mayr, Hannes's avatar Mayr, Hannes
Browse files

Restructure functions and methods to use **kwargs and improve docstrings.

parent 03fb017f
No related branches found
No related tags found
7 merge requests!41Include latest changes in main branch,!37Merge dev upstream changes into improve/metadata,!34Include architecture diagram in docs,!32SAST implementation,!27Update documentation and version number,!26Merge !23, !24, !25 into main,!22Restructure and introduce additional object to transfer figures and IDs from...
Pipeline #791742 waiting for manual action
......@@ -3,7 +3,7 @@
Create an identifier to print it on a plot.
Functions:
create_id(str) -> string
create_id(str) -> str
"""
import time
import uuid
......@@ -13,12 +13,17 @@ def create_id(id_method):
"""
Create an Identifier (str).
Creates an (sometimes unique) identifier based on the selected method
if no method is selected method 1 will be the default method
Creates an (sometimes unique) identifier based on the selected method.
Parameters
----------
id_method : str
id_method for creating the ID. Create an ID by Unix time is referenced
as 'time', create a random ID with id_method='random'.
Returns
-------
figure_id
figure_id : str
"""
match id_method:
case 'time':
......
......@@ -14,7 +14,7 @@ from plotid.tagplot import tagplot
from plotid.publish import publish
# %% Set Project ID
PROJECT_ID = "MR04_"
PROJECT_ID = "MR05_"
# %% Create sample data
x = np.linspace(0, 10, 100)
......@@ -44,8 +44,8 @@ FIGS_AS_LIST = [FIG1, FIG2]
IMGS_AS_LIST = [IMG1, IMG2]
# Example for how to use tagplot with matplotlib figures
[TAGGED_FIGS, ID] = tagplot(FIGS_AS_LIST, 'matplotlib', prefix=PROJECT_ID,
id_method='time', location='west')
[TAGGED_FIGS, ID] = tagplot(FIGS_AS_LIST, 'matplotlib', location='west',
id_method='random', prefix=PROJECT_ID)
# Example for how to use tagplot with image files
# [TAGGED_FIGS, ID] = tagplot(IMGS_AS_LIST, 'image', prefix=PROJECT_ID,
......
......@@ -16,23 +16,30 @@ class PlotOptions:
----------
figs : figure object
Figure that will be tagged.
prefix : str
Prefix that is placed before the ID.
id_method : str
Method that decides which method is used to generate the ID.
rotation : int
Rotation angle for the ID.
position : tuple
Relative position of the ID on the plot (x,y).
**kwargs : dict, optional
Extra arguments for additional plot options.
Other Parameters
----------------
prefix : str, optional
Will be added as prefix to the ID.
id_method : str, optional
id_method for creating the ID. Create an ID by Unix time is referenced
as 'time', create a random ID with id_method='random'.
The default is 'time'.
"""
def __init__(self, figs, prefix, id_method, rotation, position):
def __init__(self, figs, rotation, position, **kwargs):
self.figs = figs
self.prefix = prefix
self.id_method = id_method
self.rotation = rotation
self.position = position
self.prefix = kwargs.get('prefix', '')
self.id_method = kwargs.get('id_method', 'time')
def validate_input(self):
"""
......
......@@ -8,7 +8,7 @@ the plot is based on. Additionally, the script that produced the plot will be
copied to the destination directory.
Functions:
publish(str, str, figure, str, str) -> None
publish(str, str, figure, str) -> None
"""
import os
......@@ -25,34 +25,19 @@ class PublishOptions:
Methods
-------
__init__
validate_input: Check if input is correct type.
Attributes
----------
src_datapaths : str or list of str
Path(s) to data that should be published.
dst_path : str
Path to the destination directory.
figure : figure object
Figure that was tagged and now should be saved as picture.
plot_name : str
Name for the exported plot.
data_storage : str
Method how the data should be stored. Available options:
centralized : The data files will copied only once. All other plots
will reference this data via sym link.
individual [default]: The complete data files will be copied to a
separate folder for every plot.
validate_input
Check if input is correct type.
export
Export the plot and copy specified files to the destiantion folder.
"""
def __init__(self, src_datapaths, dst_path, figure, plot_names,
data_storage='individual'):
def __init__(self, src_datapaths, dst_path, figure, plot_names, **kwargs):
self.src_datapaths = src_datapaths
self.dst_path = dst_path
self.figure = figure
self.plot_names = plot_names
self.data_storage = data_storage
self.data_storage = kwargs.get('data_storage', 'individual')
self.dst_path_head, self.dst_dirname = os.path.split(self.dst_path)
# If the second string after os.path.split is empty,
......@@ -202,7 +187,7 @@ class PublishOptions:
Parameters
----------
destination : string
destination : str
Directory where the data should be stored.
pic_paths : list
Paths to the picture file that will be stored in destination.
......@@ -232,22 +217,26 @@ class PublishOptions:
os.remove(path)
def publish(src_datapath, dst_path, figure, plot_name,
data_storage='individual'):
def publish(src_datapath, dst_path, figure, plot_name, **kwargs):
"""
Save plot, data and measuring script.
Parameters
----------
src_datapath : str
src_datapath : str or list of str
Path to data that should be published.
dst_path : str
Path to the destination directory.
figure : figure object
Figure that was tagged and now should be saved as picture.
plot_name : str
plot_name : str or list of str
Name for the exported plot.
data_storage : str
**kwargs : dict, optional
Extra arguments for additional publish options.
Other Parameters
----------------
data_storage : str, optional
Method how the data should be stored. Available options:
centralized : The raw data will copied only once. All other plots
will reference this data via sym link.
......@@ -260,6 +249,6 @@ def publish(src_datapath, dst_path, figure, plot_name,
"""
publish_container = PublishOptions(src_datapath, dst_path, figure,
plot_name, data_storage)
plot_name, **kwargs)
publish_container.validate_input()
publish_container.export()
......@@ -4,7 +4,7 @@
Export a plot figure to a picture file.
Functions:
save_plot(figure, string) -> path-like
save_plot(figure, str) -> path-like
"""
import warnings
......@@ -20,16 +20,15 @@ def save_plot(figures, plot_names, extension='png'):
----------
figure : list of/single figure object
Figure that was tagged and now should be saved as picture.
plot_name : list of strings
plot_name : str or list of str
Names of the files where the plots will be saved to.
extension : str
File extension for the plot export.
Returns
-------
plot_path : list
plot_path : str or list of str
Names of the created pictures.
"""
# Check if figs is a valid figure or a list of valid figures
if isinstance(figures, matplotlib.figure.Figure):
......
......@@ -16,27 +16,32 @@ from plotid.tagplot_matplotlib import tagplot_matplotlib
from plotid.tagplot_image import tagplot_image
def tagplot(figs, engine, prefix='', id_method='time', location='east'):
def tagplot(figs, engine, location='east', **kwargs):
"""
Tag your figure/plot with an ID.
After determining the plot engine, TagPlot calls the corresponding
After determining the plot engine, tagplot calls the corresponding
function which tags the plot.
Parameters
----------
figs : list
Figures that should be tagged.
engine : string
engine : str
Plot engine which should be used to tag the plot.
prefix : string
location : str, optional
Location for ID to be displayed on the plot. Default is 'east'.
**kwargs : dict, optional
Extra arguments for additional plot options.
Other Parameters
----------------
prefix : str, optional
Will be added as prefix to the ID.
id_method : string, optional
id_method : str, optional
id_method for creating the ID. Create an ID by Unix time is referenced
as 'time', create a random ID with id_method='random'.
The default is 'time'.
location : string, optional
Location for ID to be displayed on the plot. Default is 'east'.
Raises
------
......@@ -84,8 +89,7 @@ def tagplot(figs, engine, prefix='', id_method='time', location='east'):
rotation = 90
position = (0.975, 0.35)
option_container = PlotOptions(figs, prefix, id_method,
rotation, position)
option_container = PlotOptions(figs, rotation, position, **kwargs)
option_container.validate_input()
match engine:
......
......@@ -17,7 +17,14 @@ def tagplot_image(plotid_object):
The ID is placed visual on the figure window and returned as string in a
list together with the figures.
TagPlot can tag multiple figures at once.
Parameters
----------
plotid_object : instance of PlotOptions
Returns
-------
list with figures and IDs
"""
# Check if plotid_object is a valid instance of PlotOptions
if not isinstance(plotid_object, PlotOptions):
......
......@@ -18,7 +18,14 @@ def tagplot_matplotlib(plotid_object):
The ID is placed visual on the figure window and returned as string in a
list together with the figures.
TagPlot can tag multiple figures at once.
Parameters
----------
plotid_object : instance of PlotOptions
Returns
-------
list with figures and IDs
"""
# Check if plotid_object is a valid instance of PlotOptions
if not isinstance(plotid_object, PlotOptions):
......
......@@ -46,7 +46,8 @@ class TestPublish(unittest.TestCase):
'copied.')
def test_publish(self):
""" Test publish and check if an exported picture file exists. """
publish(SRC_DIR, DST_PATH + '/', FIG, PIC_NAME, 'individual')
publish(SRC_DIR, DST_PATH + '/', FIG, PIC_NAME,
data_storage='individual')
assert os.path.isfile(os.path.join(DST_PATH, PIC_NAME + '.png'))
# Skip test if tests are run from command line.
......@@ -58,7 +59,7 @@ class TestPublish(unittest.TestCase):
Test publish with multiple figures and check if all exported picture
files exist.
"""
publish(SRC_DIR, DST_PATH, FIGS_AS_LIST, PIC_NAME_LIST, 'individual')
publish(SRC_DIR, DST_PATH, FIGS_AS_LIST, PIC_NAME_LIST)
for name in PIC_NAME_LIST:
assert os.path.isfile(os.path.join(DST_PATH, name + '.png'))
......@@ -70,7 +71,7 @@ class TestPublish(unittest.TestCase):
files_and_dir = list(SRC_FILES)
files_and_dir.append(SRC_DIR)
publish(files_and_dir, DST_PATH, FIGS_AS_LIST, PIC_NAME_LIST,
'individual')
data_storage='individual')
assert os.path.isdir(DST_PATH)
for file in SRC_FILES:
assert os.path.isfile(os.path.join(DST_PATH, file))
......@@ -78,21 +79,19 @@ class TestPublish(unittest.TestCase):
def test_src_directory(self):
""" Test if Error is raised when source directory does not exist."""
with self.assertRaises(FileNotFoundError):
publish('not_existing_folder', DST_PATH, FIG,
PIC_NAME, 'individual')
publish('not_existing_folder', DST_PATH, FIG, PIC_NAME)
def test_src_directory_type(self):
""" Test if Error is raised when source directory is not a string."""
with self.assertRaises(TypeError):
publish([SRC_DIR, 4], DST_PATH, FIG, PIC_NAME, 'individual')
publish([SRC_DIR, 4], DST_PATH, FIG, PIC_NAME)
with self.assertRaises(TypeError):
publish(4, DST_PATH, FIG, PIC_NAME, 'individual')
publish(4, DST_PATH, FIG, PIC_NAME)
def test_dst_directory(self):
""" Test if Error is raised when destination dir does not exist."""
with self.assertRaises(FileNotFoundError):
publish(SRC_DIR, 'not_existing_folder',
FIG, PIC_NAME, 'individual')
publish(SRC_DIR, 'not_existing_folder', FIG, PIC_NAME)
def test_script_exists(self):
"""
......@@ -139,7 +138,8 @@ class TestPublish(unittest.TestCase):
os.mkdir(DST_PATH)
# Mock user input as 'yes'
with patch('builtins.input', return_value='yes'):
publish(SRC_DIR, DST_PATH, FIG, PIC_NAME, 'individual')
publish(SRC_DIR, DST_PATH, FIG, PIC_NAME,
data_storage='individual')
# Skip test if tests are run from command line.
@unittest.skipIf(not os.path.isfile(sys.argv[0]), 'Publish is not called '
......@@ -154,7 +154,7 @@ class TestPublish(unittest.TestCase):
# Mock user input as 'no'
with patch('builtins.input', return_value='no'):
with self.assertRaises(RuntimeError):
publish(SRC_DIR, DST_PATH, FIG, PIC_NAME, 'individual')
publish(SRC_DIR, DST_PATH, FIG, PIC_NAME)
# Skip test if tests are run from command line.
@unittest.skipIf(not os.path.isfile(sys.argv[0]), 'Publish is not called '
......@@ -169,7 +169,8 @@ class TestPublish(unittest.TestCase):
# Mock user input as empty (no should be default).
with patch('builtins.input', return_value=''):
with self.assertRaises(RuntimeError):
publish(SRC_DIR, DST_PATH, FIG, PIC_NAME, 'individual')
publish(SRC_DIR, DST_PATH, FIG, PIC_NAME,
data_storage='individual')
# Skip test if tests are run from command line.
@unittest.skipIf(not os.path.isfile(sys.argv[0]), 'Publish is not called '
......@@ -185,28 +186,29 @@ class TestPublish(unittest.TestCase):
# Mock user input as 'yes'
with patch('builtins.input', return_value='yes'):
with self.assertRaises(RuntimeError):
publish(SRC_DIR, DST_PATH, FIG, PIC_NAME, 'individual')
publish(SRC_DIR, DST_PATH, FIG, PIC_NAME)
assert not os.path.isdir(INVISIBLE_PATH)
def test_plot_names(self):
""" Test if Error is raised if plot_name is not a string. """
with self.assertRaises(TypeError):
publish(SRC_DIR, DST_PATH, FIG, 7.6, 'individual')
publish(SRC_DIR, DST_PATH, FIG, 7.6, data_storage='individual')
with self.assertRaises(TypeError):
publish(SRC_DIR, DST_PATH, FIG, (), 'individual')
publish(SRC_DIR, DST_PATH, FIG, (), data_storage='individual')
with self.assertRaises(TypeError):
publish(SRC_DIR, DST_PATH, FIG, ['test', 3], 'individual')
publish(SRC_DIR, DST_PATH, FIG, ['test', 3])
def test_data_storage(self):
"""
Test if Error is raised when unsupported storage method was chosen.
"""
with self.assertRaises(ValueError):
publish(SRC_DIR, DST_PATH, FIG, PIC_NAME, 'none_existing_method')
publish(SRC_DIR, DST_PATH, FIG, PIC_NAME,
data_storage='none_existing_method')
with self.assertRaises(TypeError):
publish(SRC_DIR, DST_PATH, FIG, PIC_NAME, 3)
publish(SRC_DIR, DST_PATH, FIG, PIC_NAME, data_storage=3)
with self.assertRaises(TypeError):
publish(SRC_DIR, DST_PATH, FIG, PIC_NAME, [])
publish(SRC_DIR, DST_PATH, FIG, PIC_NAME, data_storage=[])
def tearDown(self):
""" Delete all files created in setUp. """
......
......@@ -35,44 +35,44 @@ class TestTagplot(unittest.TestCase):
"""
Test if tagplot runs successful.
"""
tagplot(FIGS_AS_LIST, PLOT_ENGINE, PROJECT_ID, METHOD)
tagplot(IMGS_AS_LIST, 'image', PROJECT_ID, METHOD, location='north')
tagplot(FIGS_AS_LIST, PLOT_ENGINE, prefix=PROJECT_ID, id_method=METHOD)
tagplot(IMGS_AS_LIST, 'image', location='north')
def test_prefix(self):
""" Test if Error is raised if prefix is not a string. """
with self.assertRaises(TypeError):
tagplot(FIGS_AS_LIST, PLOT_ENGINE, 3, METHOD, location='southeast')
tagplot(FIGS_AS_LIST, PLOT_ENGINE, location='southeast',
prefix=3, id_method=METHOD)
def test_plotengine(self):
"""
Test if Errors are raised if the provided plot engine is not supported.
"""
with self.assertRaises(ValueError):
tagplot(FIGS_AS_LIST, 1, PROJECT_ID, METHOD, location='north')
tagplot(FIGS_AS_LIST, 1, location='north')
with self.assertRaises(ValueError):
tagplot(FIGS_AS_LIST, 'xyz', PROJECT_ID, METHOD, location='south')
tagplot(FIGS_AS_LIST, 'xyz', location='south')
def test_idmethod(self):
"""
Test if Errors are raised if the id_method is not an string.
"""
with self.assertRaises(TypeError):
tagplot(FIGS_AS_LIST, PLOT_ENGINE, PROJECT_ID, id_method=(0, 1),
tagplot(FIGS_AS_LIST, PLOT_ENGINE, id_method=(0, 1),
location='west')
with self.assertRaises(TypeError):
tagplot(FIGS_AS_LIST, PLOT_ENGINE, PROJECT_ID, id_method=1)
tagplot(FIGS_AS_LIST, PLOT_ENGINE, id_method=1)
with self.assertRaises(TypeError):
tagplot(FIGS_AS_LIST, PLOT_ENGINE, PROJECT_ID, id_method=[0, 1])
tagplot(FIGS_AS_LIST, PLOT_ENGINE, id_method=[0, 1])
def test_location(self):
"""
Test if Errors are raised if the provided location is not supported.
"""
with self.assertRaises(TypeError):
tagplot(FIGS_AS_LIST, PLOT_ENGINE, PROJECT_ID, METHOD, location=1)
tagplot(FIGS_AS_LIST, PLOT_ENGINE, location=1)
with self.assertWarns(Warning):
tagplot(FIGS_AS_LIST, PLOT_ENGINE, PROJECT_ID, METHOD,
location='up')
tagplot(FIGS_AS_LIST, PLOT_ENGINE, location='up')
def tearDown(self):
os.remove(IMG1)
......
......@@ -39,8 +39,8 @@ class TestTagplotImage(unittest.TestCase):
Test of returned objects. Check if they are png and jpg files,
respectively.
"""
options = PlotOptions(IMGS_AS_LIST, PROJECT_ID, METHOD,
ROTATION, POSITION)
options = PlotOptions(IMGS_AS_LIST, ROTATION, POSITION,
prefix=PROJECT_ID, id_method=METHOD)
options.validate_input()
[figs, _] = tagplot_image(options)
self.assertIsInstance(figs[0], PngImagePlugin.PngImageFile)
......@@ -51,24 +51,22 @@ class TestTagplotImage(unittest.TestCase):
Test of returned objects. Check if png files are returned,
if a single matplot figure is given (not as a list).
"""
options = PlotOptions(IMG1, PROJECT_ID, METHOD, ROTATION,
POSITION)
options = PlotOptions(IMG1, ROTATION, POSITION)
options.validate_input()
[figs, _] = tagplot_image(options)
self.assertIsInstance(figs[0], PngImagePlugin.PngImageFile)
def test_image_not_str(self):
""" Test if Error is raised if wrong type of image is given. """
options = PlotOptions(3, PROJECT_ID, METHOD, ROTATION,
POSITION)
options = PlotOptions(3, ROTATION, POSITION,
prefix=PROJECT_ID, id_method=METHOD)
options.validate_input()
with self.assertRaises(TypeError):
tagplot_image(options)
def test_image_not_file(self):
""" Test if Error is raised if the image file does not exist. """
options = PlotOptions('xyz', PROJECT_ID, METHOD, ROTATION,
POSITION)
options = PlotOptions('xyz', ROTATION, POSITION)
options.validate_input()
with self.assertRaises(TypeError):
tagplot_image(options)
......
......@@ -29,8 +29,8 @@ class TestTagplotMatplotlib(unittest.TestCase):
def test_mplfigures(self):
""" Test of returned objects. Check if they are matplotlib figures. """
options = PlotOptions(FIGS_AS_LIST, PROJECT_ID, METHOD,
ROTATION, POSITION)
options = PlotOptions(FIGS_AS_LIST, ROTATION, POSITION,
prefix=PROJECT_ID, id_method=METHOD)
options.validate_input()
[figs, _] = tagplot_matplotlib(options)
self.assertIsInstance(figs[0], Figure)
......@@ -41,16 +41,14 @@ class TestTagplotMatplotlib(unittest.TestCase):
Test of returned objects. Check if matplotlib figures are returned,
if a single matplot figure is given (not as a list).
"""
options = PlotOptions(FIG1, PROJECT_ID, METHOD, ROTATION,
POSITION)
options = PlotOptions(FIG1, ROTATION, POSITION)
options.validate_input()
[figs, _] = tagplot_matplotlib(options)
self.assertIsInstance(figs[0], Figure)
def test_mplerror(self):
""" Test if Error is raised if wrong type of figures is given. """
options = PlotOptions(3, PROJECT_ID, METHOD, ROTATION,
POSITION)
options = PlotOptions(3, ROTATION, POSITION)
options.validate_input()
with self.assertRaises(TypeError):
tagplot_matplotlib(options)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment