diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml deleted file mode 100644 index ac1d511a0..000000000 --- a/.github/workflows/build-docs.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: Build docs and upload to gh-pages - -on: - push: - branches: - - master - -jobs: - docs: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: conda-incubator/setup-miniconda@v2 - with: - auto-update-conda: true - python-version: 3.7 - - uses: actions/cache@v2 - with: - path: ~/.cache/pip - key: ${{ hashFiles('setup.py') }}-${{ hashFiles('requirements.txt') }}-${{ hashFiles('docs/requirements.txt') }} - - name: Install Python dependencies - run: | - python -m pip install --upgrade pip wheel - python -m pip install --upgrade --ignore-installed setuptools - python -m pip install -r requirements.txt --upgrade --upgrade-strategy eager - pip install -e . - - name: Run Sphinx - run: | - cd docs - pip install -r requirements.txt - /home/runner/.local/bin/sphinx-build -b html . _build - pwd - - name: Commit documentation changes - run: | - git clone https://github.com/PsychoinformaticsLab/pliers.git --branch gh-pages --single-branch gh-pages - pwd - ls - cp -r docs/_build/* gh-pages/ - cd gh-pages - git config --local user.email "action@github.com" - git config --local user.name "GitHub Action" - git add . - git commit -m "Update documentation" -a || true - # The above command will fail if no changes were present, so we ignore - # the return code. - - name: Push changes - uses: ad-m/github-push-action@master - with: - branch: gh-pages - directory: gh-pages - github_token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml deleted file mode 100644 index 895d42ff9..000000000 --- a/.github/workflows/pull_request.yml +++ /dev/null @@ -1,36 +0,0 @@ - -name: Pull Request Docs Check - -on: [pull_request] - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - uses: conda-incubator/setup-miniconda@v2 - with: - auto-update-conda: true - python-version: 3.7 - - uses: actions/cache@v2 - with: - path: ~/.cache/pip - key: ${{ hashFiles('setup.py') }}--${{ hashFiles('requirements.txt') }}--${{ hashFiles('docs/requirements.txt') }} - - name: Install Python dependencies - run: | - python -m pip install --upgrade pip wheel - python -m pip install --upgrade --ignore-installed setuptools - python -m pip install -r requirements.txt --upgrade --upgrade-strategy eager - python -m pip install -e . - - name: Run Sphinx - run: | - cd docs - python -m pip install -r requirements.txt - /home/runner/.local/bin/sphinx-build -b html . _build - - name: Create artifact of the html output - uses: actions/upload-artifact@v2 - with: - name: DocumentationHTML - path: docs/_build/ \ No newline at end of file diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 000000000..d1ae27be5 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,11 @@ +version: 2 + +build: + os: "ubuntu-20.04" + tools: + python: "3.8" + +python: + install: + - requirements: requirements.txt + - path: . \ No newline at end of file diff --git a/README.rst b/README.rst index 12620f359..06405c547 100644 --- a/README.rst +++ b/README.rst @@ -1,7 +1,7 @@ *pliers*: a python package for automated feature extraction =========================================================== -|PyPI version fury.io| |pytest| |Coverage Status| +|PyPI version fury.io| |pytest| |Coverage Status| [docs] |DOI:10.1145/3097983.3098075| @@ -52,62 +52,6 @@ Pliers is a general purpose tool, this is just one domain where it's useful. The above video is from a `tutorial `__ as a part of a `course about naturalistic data `__. -Installation ------------- - -Simply use pip to install the latest release: - - pip install pliers - -Dependencies -~~~~~~~~~~~~ - -Installing pliers with pip will only install third-party -libraries that are essential for pliers to function properly. However, -because pliers provides interfaces to a large number of feature -extraction tools, there are dozens of optional dependencies that may be -required depending on what kinds of features you plan to extract. You -may install dependencies piece meal (pliers will alert you if -you're missing a depedency) or you may install all the required -dependencies: - - pip install -r optional-dependencies.txt - -Note, that some of these Python dependencies may have their own requirements. -For example, python-magic -requires libmagic and without this, you’ll be relegated to loading all -your stims explicitly rather than passing in filenames (i.e., -``stim = VideoStim('my_video.mp4')`` will work fine, but passing -'my_video.mp4' directly to an ``Extractor`` may not). - -Docker image -^^^^^^^^^^^^ - -You may also use the provided Docker image which fulfills all the optional dependencies. - -:: - - docker run -p 8888:8888 ghcr.io/psychoinformaticslab/pliers:unstable - -Follow `these instructions `__. - -API Keys -^^^^^^^^ - -While installing pliers itself is straightforward, configuring web-based -feature extraction APIs can take a more -effort. For example, pliers includes support for face and object -recognition via Google’s Cloud Vision API, and enables conversion of -audio files to text transcripts via several different speech-to-text -services. While some of these APIs are free to use (and usually provide -a limited number of free monthly calls), they require users to -register to received API credentials. More details on API key setup -are available -`here `__. - -Another option is to exclusively use local models and algorithms, such as -the wide range covered by TensforFlow Hub using the ``TFHubExtractor``. - How to cite ----------- @@ -126,3 +70,6 @@ If you use pliers in your work, please cite both the pliers and the following pa :target: https://coveralls.io/github/psychoinformaticslab/pliers?branch=master .. |DOI:10.1145/3097983.3098075| image:: https://zenodo.org/badge/DOI/10.1145/3097983.3098075.svg :target: https://doi.org/10.1145/3097983.3098075 +.. |docs| image:: https://readthedocs.org/projects/pliers/badge/?version=latest + :target: https://pliers.readthedocs.io/en/latest/?badge=latest + :alt: Documentation Status \ No newline at end of file diff --git a/docs/_includes/_replacements.rst b/docs/_includes/_replacements.rst index 4e22d060e..8fed239d3 100644 --- a/docs/_includes/_replacements.rst +++ b/docs/_includes/_replacements.rst @@ -66,6 +66,7 @@ .. |TFHubExtractor| replace:: :py:class:`TFHubExtractor` .. |TFHubImageExtractor| replace:: :py:class:`TFHubImageExtractor` .. |TFHubTextExtractor| replace:: :py:class:`TFHubTextExtractor` +.. |MetricExtractor| replace:: :py:class:`MetricExtractor` .. currentmodule:: pliers.converters @@ -91,10 +92,10 @@ .. |FrameSamplingFilter| replace:: :py:class:`FrameSamplingFilter` .. |ImageCroppingFilter| replace:: :py:class:`ImageCroppingFilter` .. |PillowImageFilter| replace:: :py:class:`PillowImageFilter` -.. |PunctuationRemovalFilter| replace :py:class:`PunctuationRemovalFilter` -.. |TokenizingFilter| replace :py:class:`TokenizingFilter` -.. |TokenRemovalFilter| replace :py:class:`TokenRemovalFilter` -.. |WordStemmingFilter| replace :py:class:`WordStemmingFilter` +.. |PunctuationRemovalFilter| replace:: :py:class:`PunctuationRemovalFilter` +.. |TokenizingFilter| replace:: :py:class:`TokenizingFilter` +.. |TokenRemovalFilter| replace:: :py:class:`TokenRemovalFilter` +.. |WordStemmingFilter| replace:: :py:class:`WordStemmingFilter` .. |AudioResamplingFilter| replace:: :py:class:`AudioResamplingFilter` .. currentmodule:: pliers.graph diff --git a/docs/conf.py b/docs/conf.py index 896cd6bb7..53fcd797d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -17,7 +17,12 @@ # documentation root, use os.path.abspath to make it absolute, like shown here. # import sphinx_rtd_theme +import sys +import os +sys.path.insert(0, os.path.abspath('../')) + import pliers +from pliers import * # -- General configuration ------------------------------------------------ @@ -30,7 +35,6 @@ # ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.autosummary', - 'sphinx.ext.autosectionlabel', 'sphinx.ext.intersphinx', 'sphinx.ext.coverage', 'sphinx.ext.mathjax', @@ -67,17 +71,10 @@ # The full version, including alpha/beta/rc tags. release = '0.4.1' -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = None - # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', 'generated'] +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' @@ -105,22 +102,6 @@ # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] -# Custom sidebar templates, must be a dictionary that maps document names -# to template names. -# -# This is required for the alabaster theme -# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars -html_sidebars = { - '**': [ - 'about.html', - 'navigation.html', - 'relations.html', # needs 'show_related': True theme option to display - 'searchbox.html', - 'donate.html', - ] -} - - # -- Options for HTMLHelp output ------------------------------------------ # Output file base name for HTML help builder. @@ -179,6 +160,4 @@ # Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'https://docs.python.org/': None} - -autoclass_content = 'class' +intersphinx_mapping = {'https://docs.python.org/': None} \ No newline at end of file diff --git a/docs/development.rst b/docs/development.rst deleted file mode 100644 index bff84e2d8..000000000 --- a/docs/development.rst +++ /dev/null @@ -1,11 +0,0 @@ -Developer guide -=============== - -Pliers is, at its core, a standardized interface to other feature extraction tools and services. This means that, to a greater extent than most other open-source projects, the utility of pliers is closely tied to the number (and quality) of community-contributed extensions. - -The easiest way to contribute new functionality to pliers is to create new |Stim| or |Transformer| classes. - -Creating new |Stim| classes ---------------------------- - -Every |Stim| in pliers must inherit from the base |Stim| class or one of its subclasses. \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst index 48b4617fd..f8f61fb7d 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,7 +3,7 @@ .. toctree:: - :maxdepth: 2 + :maxdepth: 1 :caption: Contents: installation diff --git a/docs/installation.rst b/docs/installation.rst index 71c90bac9..fbe929f3d 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -35,7 +35,7 @@ Or, if you installed via GitHub clone: pip install -r optional-dependencies.txt -Note, however, that some of these Python dependencies have their own (possibly platform-dependent) requirements. Most notably, python-magic requires libmagic (see `here `_ for installation instructions), and without this, you'll be relegated to loading all your stims explicitly rather than passing in filenames (i.e., :py:`stim = VideoStim('my_video.mp4'`) will work fine, but passing 'my_video.mp4' directly to an |Extractor| will not). Additionally, the Python OpenCV bindings require `OpenCV3 `_ (which can be a bit more challenging to install)--but relatively few of the feature extractors in pliers currently depend on OpenCV, so you may not need to bother with this. Similarly, the |TesseractConverter| requires the tesseract OCR library, but no other |Transformer| does, so unless you're planning to capture text from images, you're probably safe. +Note, however, that some of these Python dependencies have their own (possibly platform-dependent) requirements. Most notably, python-magic requires libmagic (see `python-magic `_ for installation instructions), and without this, you'll be relegated to loading all your stims explicitly rather than passing in filenames (i.e., :py:`stim = VideoStim('my_video.mp4'`) will work fine, but passing 'my_video.mp4' directly to an |Extractor| will not). Additionally, the Python OpenCV bindings require `OpenCV3 `_ (which can be a bit more challenging to install)--but relatively few of the feature extractors in pliers currently depend on OpenCV, so you may not need to bother with this. Similarly, the |TesseractConverter| requires the tesseract OCR library, but no other |Transformer| does, so unless you're planning to capture text from images, you're probably safe. Docker ------ @@ -93,17 +93,17 @@ While installing pliers itself is usually straightforward, setting up some of th | IBMSpeechAPIConverter | `IBM Watson speech-to-text API `__ | IBM\_USERNAME | API username and password | 98452-bvc42-fd-42221-cv21 (username*) | | | | IBM\_PASSWORD | | FJ14fns21N1f (password) | +---------------------------------------+-----------------------------------------------------------------------------------------------------+--------------------------------------+--------------------------------+---------------------------------------+ -| GoogleSpeechAPIConverter | `Google Cloud Speech API `__ | GOOGLE\_APPLICATION\_CREDENTIALS | path to .json service account key | path/to/credentials.json | +| GoogleSpeechAPIConverter | `Google Cloud Speech API `__ | GOOGLE\_APPLICATION\_CREDENTIALS | path to service account key | path/to/credentials.json | +---------------------------------------+-----------------------------------------------------------------------------------------------------+--------------------------------------+--------------------------------+---------------------------------------+ -| GoogleVisionAPITextConverter | `Google Cloud Vision API `__ | GOOGLE\_APPLICATION\_CREDENTIALS | path to .json service account key | path/to/credentials.json | +| GoogleVisionAPITextConverter | `Google Cloud Vision API `__ | GOOGLE\_APPLICATION\_CREDENTIALS | path to service account key | path/to/credentials.json | +---------------------------------------+-----------------------------------------------------------------------------------------------------+--------------------------------------+--------------------------------+---------------------------------------+ -| GoogleVisionAPIFaceExtractor | `Google Cloud Vision API `__ | GOOGLE\_APPLICATION\_CREDENTIALS | path to .json service account key | path/to/credentials.json | +| GoogleVisionAPIFaceExtractor | `Google Cloud Vision API `__ | GOOGLE\_APPLICATION\_CREDENTIALS | path to service account key | path/to/credentials.json | +---------------------------------------+-----------------------------------------------------------------------------------------------------+--------------------------------------+--------------------------------+---------------------------------------+ -| GoogleVisionAPILabelExtractor | `Google Cloud Vision API `__ | GOOGLE\_APPLICATION\_CREDENTIALS | path to .json service account key | path/to/credentials.json | +| GoogleVisionAPILabelExtractor | `Google Cloud Vision API `__ | GOOGLE\_APPLICATION\_CREDENTIALS | path to service account key | path/to/credentials.json | +---------------------------------------+-----------------------------------------------------------------------------------------------------+--------------------------------------+--------------------------------+---------------------------------------+ -| GoogleVisionAPIPropertyExtractor | `Google Cloud Vision API `__ | GOOGLE\_APPLICATION\_CREDENTIALS | path to .json service account key | path/to/credentials.json | +| GoogleVisionAPIPropertyExtractor | `Google Cloud Vision API `__ | GOOGLE\_APPLICATION\_CREDENTIALS | path to service account key | path/to/credentials.json | +---------------------------------------+-----------------------------------------------------------------------------------------------------+--------------------------------------+--------------------------------+---------------------------------------+ -| GoogleVisionAPIWebEntitiesExtractor | `Google Cloud Vision API `__ | GOOGLE\_APPLICATION\_CREDENTIALS | path to .json service account key | path/to/credentials.json | +| GoogleVisionAPIWebEntitiesExtractor | `Google Cloud Vision API `__ | GOOGLE\_APPLICATION\_CREDENTIALS | path to service account key | path/to/credentials.json | +---------------------------------------+-----------------------------------------------------------------------------------------------------+--------------------------------------+--------------------------------+---------------------------------------+ | MicrosoftAPITextConverter | `Microsoft Computer Vision API `__ | MICROSOFT\_VISION\_SUBSCRIPTION\_KEY | API key and | 152b067184e2ae03711e6439de124c27 | | | | MICROSOFT\_SUBSCRIPTION\_LOCATION | registered region | westus | @@ -116,7 +116,7 @@ While installing pliers itself is usually straightforward, setting up some of th +---------------------------------------+-----------------------------------------------------------------------------------------------------+--------------------------------------+--------------------------------+---------------------------------------+ | ClarifaiAPIExtractor | `Clarifai recognition API `__ | CLARIFAI\_ACCESS_TOKEN | Personal access token | 168ed02e137459ead66c3a661be7b784 | | (and subclasses | | CLARIFAI\_USER\_ID | User name | user_name | -| e.g ClarifaiAPIImageExtractor) | | CLARIFAI\_APP\_ID | Application name | my_application | +| e.g ClarifaiAPIImageExtractor) | | CLARIFAI\_APP\_ID | Application name | my_application | +---------------------------------------+-----------------------------------------------------------------------------------------------------+--------------------------------------+--------------------------------+---------------------------------------+ | RevAISpeechAPIConverter | `Rev.ai speech-to-text API `__ | REVAI\_ACCESS\_TOKEN | API key | 686n83674ab3989d2f5e4aa0aec9f273 | +---------------------------------------+-----------------------------------------------------------------------------------------------------+--------------------------------------+--------------------------------+---------------------------------------+ diff --git a/docs/results.rst b/docs/results.rst index 92fa400b4..fbd3a162b 100644 --- a/docs/results.rst +++ b/docs/results.rst @@ -188,7 +188,7 @@ The only notable exception in terms of argument behavior is that the ``extractor In all other respects, the outputs of ``merge_results`` should look just like those generated by ``to_df`` calls--except of course that the results for different Extractors and Stims are now concatenated together along either the row or the column axes (depending on the ``format`` argument). As a general rule of thumb, we recommend using the default format ('wide') in cases where one is working with a small number of different Extractors and/or features, and switching to ``format='long'`` when the number of Extractors and/or features gets large. (The main reason for this recommendation is that the merged DataFrames are typically sparse, so in 'wide' format, one can end up with a very large number of ``NaN`` values when working with many Extractors at once. In 'long' format, there are virtually no missing values.) Converting results to SeriesStim -------------------------- +-------------------------------- |ExtractorResult| can be converted into instances of |SeriesStim| using |ExtractorResultToSeriesConverter|. This way, results from an Extractor can be fed to |MetricExtractor|, which enables extraction of summary metrics (computed with any arbitrary function) across features. Graph results diff --git a/pliers/__init__.py b/pliers/__init__.py index abd1fb022..51fc4922b 100644 --- a/pliers/__init__.py +++ b/pliers/__init__.py @@ -1,26 +1,23 @@ from .config import set_option, get_option, set_options -from .graph import Graph from .version import __version__ from .support.due import due, Url, BibTeX - __all__ = [ - 'config' + 'config', 'set_option', 'set_options', 'get_option', 'graph', 'transformers', 'utils', + 'diagnostics', 'converters', 'datasets', - 'diagnostics', 'external', 'extractors', 'filters', 'stimuli', 'support', - 'Graph' ] # TODO: replace with Doi whenever available (Zenodo?) diff --git a/pliers/diagnostics/__init__.py b/pliers/diagnostics/__init__.py index d1aeb0705..763d61394 100644 --- a/pliers/diagnostics/__init__.py +++ b/pliers/diagnostics/__init__.py @@ -1,13 +1,13 @@ ''' The `diagnostics` module contains functions for computing basic metrics that may be of use in determining the quality of `Extractor` results. ''' -from .diagnostics import Diagnostics -from .diagnostics import correlation_matrix -from .diagnostics import eigenvalues -from .diagnostics import condition_indices -from .diagnostics import variance_inflation_factors -from .diagnostics import mahalanobis_distances -from .diagnostics import variances +from .base import Diagnostics +from .base import correlation_matrix +from .base import eigenvalues +from .base import condition_indices +from .base import variance_inflation_factors +from .base import mahalanobis_distances +from .base import variances __all__ = [ diff --git a/pliers/diagnostics/diagnostics.py b/pliers/diagnostics/base.py similarity index 98% rename from pliers/diagnostics/diagnostics.py rename to pliers/diagnostics/base.py index cb6f741fa..57e4d8c7b 100644 --- a/pliers/diagnostics/diagnostics.py +++ b/pliers/diagnostics/base.py @@ -1,10 +1,10 @@ import pandas as pd import numpy as np from pliers.utils import attempt_to_import, verify_dependencies -import matplotlib.pyplot as plt from scipy.spatial.distance import mahalanobis from numpy.linalg import LinAlgError +mpl = attempt_to_import('matplotlib') sns = attempt_to_import('seaborn') @@ -152,10 +152,10 @@ def summary(self, stdout=True, plot=False): verify_dependencies('seaborn') for key, result in self.results.items(): if key == 'CorrelationMatrix': - ax = plt.axes() + ax = mpl.pyplot.axes() sns.heatmap(result, cmap='Blues', ax=ax) ax.set_title(key) - sns.plt.show() + sns.mpl.pyplot.show() else: result.plot(kind='bar', title=key) plt.show()