Skip to content

Commit

Permalink
add functionality to constrain parameters to a range (#56)
Browse files Browse the repository at this point in the history
- The curve fitting parameters (top, bottom, slope) can now be constrained to a range in addition to being completely free or fixed. This can help with fitting some curves more sensibly (see [this issue](#53)). Specifically:
  - ``fixtop`` and ``fixbottom`` parameters to ``HillCurve`` can be 2-tuples of bounds
  - added ``fixslope`` parameter to ``HillCurve`` and ``CurveFits``
  - New ``constrain_params_range`` notebook tests and documents this functionality.

- Add ``no_curve_fit_first`` argument to ``HillCurve`` to aid debugging/development.
  • Loading branch information
jbloom authored Mar 24, 2024
1 parent 606b532 commit 60b54ad
Show file tree
Hide file tree
Showing 13 changed files with 1,101 additions and 131 deletions.
3 changes: 0 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ jobs:
- name: lint code with ruff
run: ruff check .

- name: lint Jupyter notebooks with ruff
run: nbqa ruff .

- name: check code format with black
run: black --check .

Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ All notable changes to this project will be documented in this file.

The format is based on `Keep a Changelog <https://keepachangelog.com>`_.

2.0.0
-----
- The curve fitting parameters (top, bottom, slope) can now be constrained to a range in addition to being completely free or fixed. This can help with fitting some curves more sensibly (see [this issue](https://github.com/jbloomlab/neutcurve/issues/53)). Specifically:
- ``fixtop`` and ``fixbottom`` parameters to ``HillCurve`` can be 2-tuples of bounds
- added ``fixslope`` parameter to ``HillCurve`` and ``CurveFits``
- New ``constrain_params_range`` notebook tests and documents this functionality.

- Add ``no_curve_fit_first`` argument to ``HillCurve`` to aid debugging/development.

1.1.2
-----

Expand Down
3 changes: 0 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,10 @@ neutcurve

.. image:: https://img.shields.io/pypi/v/neutcurve.svg
:target: https://pypi.python.org/pypi/neutcurve

.. image:: https://github.com/jbloomlab/neutcurve/actions/workflows/test.yml/badge.svg
:target: https://github.com/jbloomlab/neutcurve/actions/workflows/test.yml

.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
:target: https://github.com/psf/black

.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json
:target: https://github.com/astral-sh/ruff

Expand Down
3 changes: 3 additions & 0 deletions docs/constrain_params_range.nblink
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"path": "../notebooks/constrain_params_range.ipynb"
}
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Contents
installation
hillcurve_example
curvefits_example
constrain_params_range
combine_curvefits
test_curves
neutcurve
Expand Down
2 changes: 1 addition & 1 deletion neutcurve/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

__author__ = "Jesse Bloom"
__email__ = "[email protected]"
__version__ = "1.1.2"
__version__ = "2.0.0"
__url__ = "https://github.com/jbloomlab/neutcurve"

from neutcurve.curvefits import CurveFits # noqa: F401
Expand Down
14 changes: 10 additions & 4 deletions neutcurve/curvefits.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@ class CurveFits:
`replicate_col` (str`)
Column in data with name of replicate of this measurement. Replicates can
**not** be named 'average' as we compute the average from the replicates.
`fixbottom` (`False` or float)
`fixbottom` (`False` or float or 2-tuple)
Same meaning as for :class:`neutcurve.hillcurve.HillCurve`.
`fixtop` (`False` or float)
`fixtop` (`False` or float or 2-tuple)
Same meaning as for :class:`neutcurve.hillcurve.HillCurve`.
`fixslope` (`False` or float or 2-tuple)
Same meaning as for :class:`neutcurve.hillcurve.HillCurve`.
`infectivity_or_neutralized` ({'infectivity', 'neutralized'})
Same meaning as for :class:`neutcurve.hillcurve.HillCurve`.
Expand Down Expand Up @@ -121,6 +123,7 @@ def combineCurveFits(
attrs_can_differ = [ # attributes that can differ among objects
"fixbottom",
"fixtop",
"fixslope",
"df",
"sera",
"allviruses",
Expand All @@ -142,8 +145,8 @@ def combineCurveFits(
for attr in attrs_can_differ:
delattr(combined_fits, attr)

# fixtop and fixbottom are kept at shared value or None
for attr in ["fixtop", "fixbottom"]:
# fixtop, fixbottom, fixslope are kept at shared value or None
for attr in ["fixtop", "fixbottom", "fixslope"]:
if any(
getattr(curvefits_list[0], attr) != getattr(c, attr)
for c in curvefits_list
Expand Down Expand Up @@ -293,6 +296,7 @@ def __init__(
init_slope=1.5,
fixbottom=0,
fixtop=1,
fixslope=False,
allow_reps_unequal_conc=False,
):
"""See main class docstring."""
Expand All @@ -304,6 +308,7 @@ def __init__(
self.replicate_col = replicate_col
self.fixbottom = fixbottom
self.fixtop = fixtop
self.fixslope = fixslope
self._infectivity_or_neutralized = infectivity_or_neutralized
self._fix_slope_first = fix_slope_first
self._init_slope = init_slope
Expand Down Expand Up @@ -462,6 +467,7 @@ def getCurve(self, *, serum, virus, replicate):
fs_stderr=fs_stderr,
fixbottom=self.fixbottom,
fixtop=self.fixtop,
fixslope=self.fixslope,
infectivity_or_neutralized=self._infectivity_or_neutralized,
fix_slope_first=self._fix_slope_first,
init_slope=self._init_slope,
Expand Down
Loading

0 comments on commit 60b54ad

Please sign in to comment.