diff --git a/.github/workflows/conventional-prs.yml b/.github/workflows/conventional-prs.yml index 1be14be9..d1bc280a 100644 --- a/.github/workflows/conventional-prs.yml +++ b/.github/workflows/conventional-prs.yml @@ -17,6 +17,6 @@ jobs: statuses: write # for amannn/action-semantic-pull-request to mark status of analyzed PR runs-on: ubuntu-latest steps: - - uses: amannn/action-semantic-pull-request@v4.6.0 + - uses: amannn/action-semantic-pull-request@v5.0.2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 08210fb0..4f29be9d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -66,6 +66,8 @@ jobs: name: File sizes runs-on: ubuntu-latest steps: + - name: Check out the repository + uses: actions/checkout@v3 - name: Check for large files uses: actionsdesk/lfs-warning@v3.2 with: diff --git a/docs/project_info/contributing.rst b/docs/project_info/contributing.rst index 0aebc229..1a0ed642 100644 --- a/docs/project_info/contributing.rst +++ b/docs/project_info/contributing.rst @@ -45,14 +45,14 @@ To create a pull request you need to do these steps: - Or, if you had already forked the repository a while ago, `sync your fork `_ to make sure you're working with the latest version of haptools 3. `Clone your fork locally `_ 4. :code:`cd haptools` into the new directory - 5. Create a new branch off of the ``main`` branch with :code:`git checkout -b `. Please follow best practices when naming your branch + 5. Create a new branch off of the :code:`main` branch with :code:`git checkout -b `. Please follow `best practices `_ when naming your branch 6. Setup our development environment by following the instructions in :ref:`dev-setup-instructions` below 7. Make your changes to the code 8. Add additional tests to the :code:`tests/` directory and add comments to the documentation to explain how to use your new code. We use pytest for testing and sphinx/numpydoc for documentation 9. Run the automated code-checking steps detailed in :ref:`code-check-instructions` below 10. Commit your changes. Please use informative commit messages and do your best to ensure the commit history is clean and easy to interpret 11. Now you can push your changes to your Github copy of haptools by running :code:`git push origin ` - 12. Go to your Github copy of haptools in your browser and create a pull request. Be sure to change the pull request target branch to :code:`main` on this original repository! + 12. Go to your Github copy of haptools in your browser and create a pull request titled according to the `conventional commits spec `_. Be sure to change the pull request target branch to :code:`main` on this original repository. 13. Please write an informative pull request detailing the changes you have made and why you made them. Tag any related issues by referring to them by a hashtag followed by their ID @@ -78,7 +78,9 @@ Follow these steps to set up a development environment. .. code-block:: bash - poetry install -E docs -E test -E files + poetry install -E docs -E tests -E files + +Now, try importing ``haptools`` or running it on the command line. --------------------- Managing Dependencies @@ -91,6 +93,12 @@ For example, to add a pypi dependency to our list and install it, just run poetry add +You should specify a `version constraint `_ when adding a dependency. Use the oldest version compatible with your code. Don't worry if you're not sure at first -- you can (and should!) always update it later. For example, to specify a version of ``click`` >= 8.0.4: + + .. code-block:: bash + + poetry add 'click>=8.0.4' + .. _code-check-instructions: ----------- @@ -132,7 +140,8 @@ Code 1. Please type-hint all function parameters 2. Please adhere to PEP8 whenever possible. :code:`black` will help you with this. - 3. For readability, please separate imports into three paragraph blocks: + 3. Please use relative imports whenever importing modules from the code base + 4. For readability, please separate imports into three paragraph blocks: i. from the python standard library ii. from external, third party packages iii. from our own internal code diff --git a/docs/project_info/installation.rst b/docs/project_info/installation.rst index f6da301a..4a2e5f46 100644 --- a/docs/project_info/installation.rst +++ b/docs/project_info/installation.rst @@ -7,7 +7,7 @@ Installation Using pip --------- -You can install ``haptools`` from PyPI using ``pip``. We recommend using ``pip >= 22.2.2`` because of `an issue in pysam `_. +You can install ``haptools`` from PyPI using ``pip``. .. code-block:: bash @@ -45,3 +45,11 @@ We also support installing ``haptools`` from bioconda using ``conda``. .. note:: Installing ``haptools`` from bioconda with PGEN support is not yet possible. See `issue 228 `_ for current progress on this challenge. + +Installing the latest, unreleased version +----------------------------------------- +Can't wait for us to tag and release our most recent updates? You can install ``haptools`` directly from the ``main`` branch of our Github repository using ``pip``. + +.. code-block:: bash + + pip install --upgrade --force-reinstall git+https://github.com/cast-genomics/haptools.git diff --git a/haptools/sim_phenotype.py b/haptools/sim_phenotype.py index 4b90a5e0..327cf2a1 100644 --- a/haptools/sim_phenotype.py +++ b/haptools/sim_phenotype.py @@ -158,7 +158,14 @@ def run( noise = 1 - heritability else: # compute the environmental effect - noise = np.var(pt) * (np.reciprocal(heritability) - 1) + noise = np.var(pt) + if noise == 0: + self.log.warning( + "Your genotypes have a variance of 0. Creating artificial noise..." + ) + noise = 1 + # TODO: handle a heritability of 0 somehow + noise *= np.reciprocal(heritability) - 1 self.log.info(f"Adding environmental component {noise} for h^2 {heritability}") # finally, add everything together to get the simulated phenotypes pt_noise = self.rng.normal(0, np.sqrt(noise), size=pt.shape) diff --git a/tests/test_simphenotype.py b/tests/test_simphenotype.py index 5bf50fce..fc4807e8 100644 --- a/tests/test_simphenotype.py +++ b/tests/test_simphenotype.py @@ -111,6 +111,35 @@ def test_one_hap_zero_noise_all_same(self): assert phens.samples == expected.samples assert phens.names[0] == expected.names[0] + def test_one_hap_zero_noise_all_same_nonzero_heritability(self): + gts = self._get_fake_gens() + hps = self._get_fake_haps() + expected = self._get_expected_phens() + + gts_shape = list(gts.data.shape) + gts_shape[1] = 1 + # set the genotypes + gts.variants = gts.variants[:1] + gts.data = np.zeros(tuple(gts_shape), dtype=gts.data.dtype) + 1 + # set the expected phenotypes + expected.names = expected.names[:1] + expected.data = np.zeros((gts_shape[0], 1), dtype=expected.data.dtype) + + previous_std = np.inf + for h2 in (0, 0.5, 1): + pt_sim = PhenoSimulator(gts, seed=42) + data = pt_sim.run([hps[0]], heritability=h2) + data = data[:, np.newaxis] + phens = pt_sim.phens + + # check the data and the generated phenotype object + assert phens.data.shape == (5, 1) + current_std = np.std(phens.data) + assert current_std < previous_std + previous_std = current_std + assert phens.samples == expected.samples + assert phens.names[0] == expected.names[0] + def test_one_hap_zero_noise_neg_beta(self): """ the same test as test_one_phen_zero_noise but with a negative beta this time