diff --git a/.gitignore b/.gitignore index 0e0aa744..e6996bb4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # IDEs .vscode/ .idea/ +.venv/ # Intermediate Coverage file .coverage diff --git a/README.md b/README.md index c9506464..0afb4a03 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,34 @@ -# Introduction +# Inflam +![Continuous Integration build in GitHub Actions](https://github.com/JBello1610/python-intermediate-inflammation/workflows/CI/badge.svg?branch=main) -This is a template software project repository used by the [Intermediate Research Software Development Skills In Python](https://github.com/carpentries-incubator/python-intermediate-development). +Inflam is a data management system written in Python that manages trial data used in clinical inflammation studies. -## Purpose +## Main Features +Here are some key features of Inflam: -This repository is intended to be used as a code template which is copied by learners at [Intermediate Research Software Development Skills In Python](https://github.com/carpentries-incubator/python-intermediate-development) course. -This can be done using the `Use this template` button towards the top right of this repo's GitHub page. +- Provide basic statistical analyses over clinical trial data +- Ability ti woek on trial data in Comma0-Seperated Value (CSV) format. +- Generate plots of trial data. +- Analytical functions and views can be easily extended based on its Model-View-Controller architecture -This software project is not finished, is currently failing to run and contains some code style issues. It is used as a starting point for the course - issues will be fixed and code will be added in a number of places during the course by learners in their own copies of the repository, as course topics are introduced. +## Prerequisites +Inflam requires the following Python packages: -## Tests +- [NumPy](https://www.numpy.org/) - makes use of NumPy's statistical functions. +- [Matplotlib](https://matplotlib.org/stable/index.html) - uses Matplotlib to generate statistical plots -Several tests have been implemented already, some of which are currently failing. -These failing tests set out the requirements for the additional code to be implemented during the workshop. +The following optional packages are required to run Inflam's unit tests: -The tests should be run using `pytest`, which will be introduced during the workshop. +- [pytest](https://docs.pytest.org/stable/) - Inflam's unit tests are written using pytest +- [pytest-cov](https://pypi.org/project/pytest-cov/) - Adds test coverage stats to unit testing + +## Installation +Can be installed and run by cloning this git repository and running the below commands: + +```bash +git clone git@github.com:JBello1610/python-intermediate-inflammation.git + +cd python-intermediate-inflammation/ + +python inflammation-analysis.py +``` diff --git a/inflammation-analysis.py b/inflammation-analysis.py index e1564317..4c612feb 100644 --- a/inflammation-analysis.py +++ b/inflammation-analysis.py @@ -27,7 +27,8 @@ def main(args): for filename in InFiles: inflammation_data = models.load_csv(filename) - view_data = {'average': models.daily_mean(inflammation_data), 'max': models.daily_max(inflammation_data), 'min': models.daily_min(inflammation_data)} + view_data = {'average': models.daily_mean(inflammation_data), 'max': models.daily_max(inflammation_data), 'min': models.daily_min(inflammation_data), **(models.s_dev(inflammation_data))} + views.visualize(view_data) diff --git a/inflammation/models.py b/inflammation/models.py index 94387ee3..6ab046dc 100644 --- a/inflammation/models.py +++ b/inflammation/models.py @@ -2,8 +2,8 @@ The Model layer is responsible for the 'business logic' part of the software. -Patients' data is held in an inflammation table (2D array) where each row contains -inflammation data for a single patient taken over a number of days +Patients' data is held in an inflammation table (2D array) where each row contains +inflammation data for a single patient taken over a number of days and each column represents a single day across all patients. """ @@ -16,7 +16,8 @@ def load_csv(filename): :param filename: Filename of CSV to load """ - return np.loadtxt(fname=filename, delimiter=',') + return np.loadtxt(fname=filename, delimiter=",") + def load_json(filename): """Load a numpy array from a JSON document. @@ -34,10 +35,9 @@ def load_json(filename): :param filename: Filename of CSV to load """ - with open(filename, 'r', encoding='utf-8') as file: + with open(filename, "r", encoding="utf-8") as file: data_as_json = json.load(file) - return [np.array(entry['observations']) for entry in data_as_json] - + return [np.array(entry["observations"]) for entry in data_as_json] def daily_mean(data): @@ -54,3 +54,13 @@ def daily_min(data): """Calculate the daily min of a 2d inflammation data array.""" return np.min(data, axis=0) + +def s_dev(data): + """Computes and returns standard deviation for data.""" + mean_of_data = np.mean(data, axis=0) + devs = [] + for entry in data: + devs.append((entry - mean_of_data) * (entry - mean_of_data)) + + standard_dev = sum(devs) / len(data) + return {"standard deviation": np.sqrt(standard_dev)} diff --git a/tests/test_models.py b/tests/test_models.py index 292d00c4..c825b1a3 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -3,15 +3,14 @@ import numpy as np import numpy.testing as npt import os +import pytest def test_daily_mean_zeros(): """Test that mean function works for an array of zeros.""" from inflammation.models import daily_mean - test_input = np.array([[0, 0], - [0, 0], - [0, 0]]) + test_input = np.array([[0, 0], [0, 0], [0, 0]]) test_result = np.array([0, 0]) # Need to use Numpy testing functions to compare arrays @@ -22,18 +21,33 @@ def test_daily_mean_integers(): """Test that mean function works for an array of positive integers.""" from inflammation.models import daily_mean - test_input = np.array([[1, 2], - [3, 4], - [5, 6]]) + test_input = np.array([[1, 2], [3, 4], [5, 6]]) test_result = np.array([3, 4]) # Need to use Numpy testing functions to compare arrays npt.assert_array_equal(daily_mean(test_input), test_result) + def test_load_from_json(tmpdir): from inflammation.models import load_json - example_path = os.path.join(tmpdir, 'example.json') - with open(example_path, 'w') as temp_json_file: + + example_path = os.path.join(tmpdir, "example.json") + with open(example_path, "w") as temp_json_file: temp_json_file.write('[{"observations":[1, 2, 3]},{"observations":[4, 5, 6]}]') result = load_json(example_path) npt.assert_array_equal(result, [[1, 2, 3], [4, 5, 6]]) + + +@pytest.mark.parametrize( + "data, expected_standard_deviation", + [ + ([0, 0, 0], 0.0), + ([1.0, 1.0, 1.0], 0), + ([1.0, 2.0, 3.0, 4.0, 5.0, 5.0, 5.0, 5.0, 10.0], 2.4088314876309775), + ], +) +def test_daily_standard_deviation(data, expected_standard_deviation): + from inflammation.models import s_dev + + result_data = s_dev(data)["standard deviation"] + npt.assert_approx_equal(result_data, expected_standard_deviation)