This repository has been archived by the owner on Jul 21, 2022. It is now read-only.
generated from grahamfindlay/minimal-shablona
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit e365085
Showing
9 changed files
with
333 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
*.py[co] | ||
*~ | ||
*.DS_Store | ||
_build/ | ||
auto_examples/ | ||
gen_api/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
## shablona | ||
A bare-bones template for Python packages, ready for use with setuptools (PyPI), pip, and py.test. | ||
|
||
### Using this as a template | ||
Let's assume that you want to create a small scientific Python project called `smallish`. | ||
|
||
To use this repository as a template, click the green "use this template" button on the front page of the "shablona" repository. | ||
|
||
In "Repository name" enter the name of your project. For example, enter `smallish` here. After that, you can hit the "Create repository from template" button. | ||
|
||
You should then be able to clone the new repo into your machine. You will want to change the names of the files. For example, you will want to move `shablona/shablona.py` to be called `smallish/smallish.py` | ||
``` | ||
git mv shablona smallish | ||
git mv smallish/shablona.py smallish/smallish.py | ||
git mv smallish/tests/test_shablona.py smallish/tests/test_smallish.py | ||
``` | ||
|
||
Make a commit recording these changes. Something like: | ||
``` | ||
git commit -a -m "Moved names from `shablona` to `smallish`" | ||
``` | ||
|
||
You will want to edit a few more places that still have `shablona` in them. Type the following to see where all these files are: | ||
``` | ||
git grep shablona | ||
``` | ||
|
||
You can replace `shablona` for `smallish` quickly with: | ||
``` | ||
git grep -l 'shablona' | xargs sed -i 's/shablona/smallish/g' | ||
``` | ||
|
||
Edit `shablona/__init__.py`, and `shablona/version.py` with the information specific to your project. | ||
|
||
This very file (`README.md`) should be edited to reflect what your project is about. | ||
|
||
At this point, make another commit, and continue to develop your own code based on this template. | ||
|
||
|
||
### Contributing | ||
If you wish to make any changes (e.g. add documentation, tests, continuous integration, etc.), please follow the [Shablona](https://github.com/uwescience/shablona) template. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# Per https://stackoverflow.com/questions/43658870/requirements-txt-vs-setup-py | ||
|
||
# requirements.txt | ||
# | ||
# installs dependencies from ./setup.py, and the package itself, | ||
# in editable mode | ||
-e . | ||
|
||
# (the -e above is optional). you could also just install the package | ||
# normally with just the line below (after uncommenting) | ||
# . |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import sys | ||
import os | ||
from setuptools import setup, find_packages | ||
PACKAGES = find_packages() | ||
|
||
# Get version and release info, which is all stored in shablona/version.py | ||
ver_file = os.path.join('shablona', 'version.py') | ||
with open(ver_file) as f: | ||
exec(f.read()) | ||
|
||
# Give setuptools a hint to complain if it's too old a version | ||
# 24.2.0 added the python_requires option | ||
# Should match pyproject.toml | ||
SETUP_REQUIRES = ['setuptools >= 24.2.0'] | ||
# This enables setuptools to install wheel on-the-fly | ||
SETUP_REQUIRES += ['wheel'] if 'bdist_wheel' in sys.argv else [] | ||
|
||
opts = dict(name=NAME, | ||
maintainer=MAINTAINER, | ||
maintainer_email=MAINTAINER_EMAIL, | ||
description=DESCRIPTION, | ||
long_description=LONG_DESCRIPTION, | ||
url=URL, | ||
download_url=DOWNLOAD_URL, | ||
license=LICENSE, | ||
classifiers=CLASSIFIERS, | ||
author=AUTHOR, | ||
author_email=AUTHOR_EMAIL, | ||
platforms=PLATFORMS, | ||
version=VERSION, | ||
packages=PACKAGES, | ||
package_data=PACKAGE_DATA, | ||
install_requires=REQUIRES, | ||
python_requires=PYTHON_REQUIRES, | ||
setup_requires=SETUP_REQUIRES, | ||
requires=REQUIRES) | ||
|
||
|
||
if __name__ == '__main__': | ||
setup(**opts) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from .shablona import * # noqa |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
|
||
from __future__ import absolute_import, division, print_function | ||
import numpy as np | ||
import pandas as pd | ||
import scipy.optimize as opt | ||
from scipy.special import erf | ||
|
||
|
||
def transform_data(data): | ||
""" | ||
Function that takes experimental data and gives us the | ||
dependent/independent variables for analysis. | ||
Parameters | ||
---------- | ||
data : Pandas DataFrame or string. | ||
If this is a DataFrame, it should have the columns `contrast1` and | ||
`answer` from which the dependent and independent variables will be | ||
extracted. If this is a string, it should be the full path to a csv | ||
file that contains data that can be read into a DataFrame with this | ||
specification. | ||
Returns | ||
------- | ||
x : array | ||
The unique contrast differences. | ||
y : array | ||
The proportion of '2' answers in each contrast difference | ||
n : array | ||
The number of trials in each x,y condition | ||
""" | ||
if isinstance(data, str): | ||
data = pd.read_csv(data) | ||
|
||
contrast1 = data['contrast1'] | ||
answers = data['answer'] | ||
|
||
x = np.unique(contrast1) | ||
y = [] | ||
n = [] | ||
|
||
for c in x: | ||
idx = np.where(contrast1 == c) | ||
n.append(float(len(idx[0]))) | ||
answer1 = len(np.where(answers[idx[0]] == 1)[0]) | ||
y.append(answer1 / n[-1]) | ||
return x, y, n | ||
|
||
|
||
def cumgauss(x, mu, sigma): | ||
""" | ||
The cumulative Gaussian at x, for the distribution with mean mu and | ||
standard deviation sigma. | ||
Parameters | ||
---------- | ||
x : float or array | ||
The values of x over which to evaluate the cumulative Gaussian function | ||
mu : float | ||
The mean parameter. Determines the x value at which the y value is 0.5 | ||
sigma : float | ||
The variance parameter. Determines the slope of the curve at the point | ||
of Deflection | ||
Returns | ||
------- | ||
g : float or array | ||
The cumulative gaussian with mean $\\mu$ and variance $\\sigma$ | ||
evaluated at all points in `x`. | ||
Notes | ||
----- | ||
Based on: | ||
http://en.wikipedia.org/wiki/Normal_distribution#Cumulative_distribution_function | ||
The cumulative Gaussian function is defined as: | ||
.. math:: | ||
\\Phi(x) = \\frac{1}{2} [1 + erf(\\frac{x}{\\sqrt{2}})] | ||
Where, $erf$, the error function is defined as: | ||
.. math:: | ||
erf(x) = \\frac{1}{\\sqrt{\\pi}} \\int_{-x}^{x} e^{t^2} dt | ||
""" | ||
return 0.5 * (1 + erf((x - mu) / (np.sqrt(2) * sigma))) | ||
|
||
|
||
def opt_err_func(params, x, y, func): | ||
""" | ||
Error function for fitting a function using non-linear optimization. | ||
Parameters | ||
---------- | ||
params : tuple | ||
A tuple with the parameters of `func` according to their order of | ||
input | ||
x : float array | ||
An independent variable. | ||
y : float array | ||
The dependent variable. | ||
func : function | ||
A function with inputs: `(x, *params)` | ||
Returns | ||
------- | ||
float array | ||
The marginals of the fit to x/y given the params | ||
""" | ||
return y - func(x, *params) | ||
|
||
|
||
class Model(object): | ||
"""Class for fitting cumulative Gaussian functions to data""" | ||
def __init__(self, func=cumgauss): | ||
""" Initialize a model object. | ||
Parameters | ||
---------- | ||
data : Pandas DataFrame | ||
Data from a subjective contrast judgement experiment | ||
func : callable, optional | ||
A function that relates x and y through a set of parameters. | ||
Default: :func:`cumgauss` | ||
""" | ||
self.func = func | ||
|
||
def fit(self, x, y, initial=[0.5, 1]): | ||
""" | ||
Fit a Model to data. | ||
Parameters | ||
---------- | ||
x : float or array | ||
The independent variable: contrast values presented in the | ||
experiment | ||
y : float or array | ||
The dependent variable | ||
Returns | ||
------- | ||
fit : :class:`Fit` instance | ||
A :class:`Fit` object that contains the parameters of the model. | ||
""" | ||
params, _ = opt.leastsq(opt_err_func, initial, | ||
args=(x, y, self.func)) | ||
return Fit(self, params) | ||
|
||
|
||
class Fit(object): | ||
""" | ||
Class for representing a fit of a model to data | ||
""" | ||
def __init__(self, model, params): | ||
""" | ||
Initialize a :class:`Fit` object. | ||
Parameters | ||
---------- | ||
model : a :class:`Model` instance | ||
An object representing the model used | ||
params : array or list | ||
The parameters of the model evaluated for the data | ||
""" | ||
self.model = model | ||
self.params = params | ||
|
||
def predict(self, x): | ||
""" | ||
Predict values of the dependent variable based on values of the | ||
indpendent variable. | ||
Parameters | ||
---------- | ||
x : float or array | ||
Values of the independent variable. Can be values presented in | ||
the experiment. For out-of-sample prediction (e.g. in | ||
cross-validation), these can be values | ||
that were not presented in the experiment. | ||
Returns | ||
------- | ||
y : float or array | ||
Predicted values of the dependent variable, corresponding to | ||
values of the independent variable. | ||
""" | ||
return self.model.func(x, *self.params) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import os.path as op | ||
import numpy.testing as npt | ||
import shablona as ece | ||
|
||
data_path = op.join(ece.__path__[0], 'data') | ||
#Load data like: op.join(data_path, 'mydatafile.dat') | ||
|
||
|
||
def test_trivial(): | ||
""" | ||
Should always pass. Just used to ensure that py.test is setup correctly. | ||
""" | ||
npt.assert_equal(np.array([1, 1, 1]), np.array([1, 1, 1])) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
from os.path import join as pjoin | ||
|
||
# Format expected by setup.py and doc/source/conf.py: string of form "X.Y.Z" | ||
_version_major = 0 | ||
_version_minor = 1 | ||
_version_micro = '' # use '' for first of series, number for 1 and above | ||
_version_extra = 'dev' | ||
# _version_extra = '' # Uncomment this for full releases | ||
|
||
# Construct full version string from these. | ||
_ver = [_version_major, _version_minor] | ||
if _version_micro: | ||
_ver.append(_version_micro) | ||
if _version_extra: | ||
_ver.append(_version_extra) | ||
|
||
__version__ = '.'.join(map(str, _ver)) | ||
|
||
CLASSIFIERS = ["Development Status :: 3 - Alpha", | ||
"Environment :: Console", | ||
"Intended Audience :: Science/Research", | ||
"License :: OSI Approved :: MIT License", | ||
"Operating System :: OS Independent", | ||
"Programming Language :: Python", | ||
"Topic :: Scientific/Engineering"] | ||
|
||
# Description should be a one-liner: | ||
description = "shablona: Put a one-liner description of your code here" | ||
# Long description will go up on the pypi page | ||
long_description = """ | ||
shablona: Put a longer description of your code here. | ||
""" | ||
|
||
NAME = "shablona" | ||
MAINTAINER = "Graham Findlay" | ||
MAINTAINER_EMAIL = "[email protected]" | ||
DESCRIPTION = description | ||
LONG_DESCRIPTION = long_description | ||
URL = "http://github.com/CSC-UW/shablona" | ||
DOWNLOAD_URL = "" | ||
LICENSE = "MIT" | ||
AUTHOR = "Graham Findlay" | ||
AUTHOR_EMAIL = "[email protected]" | ||
PLATFORMS = "OS Independent" | ||
MAJOR = _version_major | ||
MINOR = _version_minor | ||
MICRO = _version_micro | ||
VERSION = __version__ | ||
PACKAGE_DATA = {'shablona': [pjoin('data', '*')]} | ||
REQUIRES = ["numpy"] | ||
PYTHON_REQUIRES = ">= 3.7" |