From 541894e8b50ac9ec1b8d746d71397ced961bc1e0 Mon Sep 17 00:00:00 2001 From: Taylor Salo Date: Sat, 28 May 2022 15:02:23 -0400 Subject: [PATCH] Add a code of conduct and update documentation theme (#96) * Add some documentation. * More improvements. --- .zenodo.json | 5 + CODE_OF_CONDUCT.md | 73 ++++++ CONTRIBUTING.md | 3 +- docs/_static/nimare.css | 243 ++++++++++++++++++ docs/about.rst | 9 + docs/conf.py | 21 +- docs/links.rst | 6 +- examples/01_basic_io/plot_create_dataset.py | 21 +- .../plot_meta-analysis_walkthrough.py | 8 +- pymare/estimators/estimators.py | 7 +- setup.cfg | 4 +- 11 files changed, 373 insertions(+), 27 deletions(-) create mode 100644 CODE_OF_CONDUCT.md create mode 100644 docs/_static/nimare.css diff --git a/.zenodo.json b/.zenodo.json index 519c233..f524e90 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -9,6 +9,11 @@ "name": "Salo, Taylor", "affiliation": "Florida International University", "orcid": "0000-0001-9813-3167" + }, + { + "name": "Nichols, Thomas E.", + "affiliation": "Big Data Institute, University of Oxford", + "orcid": "0000-0002-4516-5103" } ], "keywords": [ diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..c2719ae --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,73 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +education, socio-economic status, nationality, personal appearance, race, +religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting our code of conduct enforcer, James Kent, at **james.kent@austin.utexas.edu**. +All complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. +The project team is obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a71348a..4c033ee 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,8 +18,7 @@ By starting the governance structure early in our development, we hope to welcom We are committed to continuing to update the governance structures as necessary. Every member of the ``PyMARE`` community is encouraged to comment on these processes and suggest improvements. -As the first interim [Benevolent Dictator for Life (BDFL)](https://en.wikipedia.org/wiki/Benevolent_dictator_for_life), Tal Yarkoni is ultimately responsible for any major decisions pertaining to ``PyMARE`` development. -However, all potential changes are explicitly and openly discussed in the described channels of communication, and we strive for consensus amongst all community members. +All potential changes to ``PyMARE`` are explicitly and openly discussed in the described channels of communication, and we strive for consensus amongst all community members. ## Code of conduct diff --git a/docs/_static/nimare.css b/docs/_static/nimare.css new file mode 100644 index 0000000..cd0a73c --- /dev/null +++ b/docs/_static/nimare.css @@ -0,0 +1,243 @@ +/*Alterations to the theme defaults*/ + +/* Sidebar header (and topbar for mobile) */ +.wy-side-nav-search, .wy-nav-top { + background: #899fdf; + } + + /* Sphinx gallery example titles */ + /* Taken from scikit-learn */ + #examples { + font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; + } + + .sphx-glr-thumbcontainer span.caption-text { + font-style: normal; + font-size: 0.9rem; + text-align: center; + } + + #examples h1 { + border-radius: 0.3rem; + background-color: #b8a6db; + text-align: center; + font-size: 2rem; + font-weight: 500; + margin-bottom: 1rem; + padding: 0.5rem; + font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; + } + + #examples h2 { + border-radius: 0.3rem; + background-color: #d589d8; + text-align: center; + font-size: 1.5rem; + font-weight: 500; + margin-bottom: 1rem; + padding: 0.5rem; + font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; + } + + .rst-content img { + max-width: 800px; + } + + /* Enforce nice versionmodified titles */ + :root { + + /***************************************************************************** + * Color + * + * Colors are defined in rgb string way, "red, green, blue" + **/ + --pst-color-primary: 19, 6, 84; + --pst-color-success: 40, 167, 69; + --pst-color-info: 0, 123, 255; /*23, 162, 184;*/ + --pst-color-warning: 255, 193, 7; + --pst-color-danger: 220, 53, 69; + --pst-color-text-base: 51, 51, 51; + + --pst-color-h1: var(--pst-color-primary); + --pst-color-h2: var(--pst-color-primary); + --pst-color-h3: var(--pst-color-text-base); + --pst-color-h4: var(--pst-color-text-base); + --pst-color-h5: var(--pst-color-text-base); + --pst-color-h6: var(--pst-color-text-base); + --pst-color-paragraph: var(--pst-color-text-base); + --pst-color-link: 0, 91, 129; + --pst-color-link-hover: 227, 46, 0; + --pst-color-headerlink: 198, 15, 15; + --pst-color-headerlink-hover: 255, 255, 255; + --pst-color-preformatted-text: 34, 34, 34; + --pst-color-preformatted-background: 250, 250, 250; + --pst-color-inline-code: 232, 62, 140; + + --pst-color-active-navigation: 19, 6, 84; + --pst-color-navbar-link: 77, 77, 77; + --pst-color-navbar-link-hover: var(--pst-color-active-navigation); + --pst-color-navbar-link-active: var(--pst-color-active-navigation); + --pst-color-sidebar-link: 77, 77, 77; + --pst-color-sidebar-link-hover: var(--pst-color-active-navigation); + --pst-color-sidebar-link-active: var(--pst-color-active-navigation); + --pst-color-sidebar-expander-background-hover: 244, 244, 244; + --pst-color-sidebar-caption: 77, 77, 77; + --pst-color-toc-link: 119, 117, 122; + --pst-color-toc-link-hover: var(--pst-color-active-navigation); + --pst-color-toc-link-active: var(--pst-color-active-navigation); + + /***************************************************************************** + * Icon + **/ + + /* font awesome icons*/ + --pst-icon-check-circle: "\f058"; + --pst-icon-info-circle: "\f05a"; + --pst-icon-exclamation-triangle: "\f071"; + --pst-icon-exclamation-circle: "\f06a"; + --pst-icon-times-circle: "\f057"; + --pst-icon-lightbulb: "\f0eb"; + + /***************************************************************************** + * Admonitions + **/ + + --pst-color-admonition-default: var(--pst-color-info); + --pst-color-admonition-note: var(--pst-color-info); + --pst-color-admonition-attention: var(--pst-color-warning); + --pst-color-admonition-caution: var(--pst-color-warning); + --pst-color-admonition-warning: var(--pst-color-warning); + --pst-color-admonition-danger: var(--pst-color-danger); + --pst-color-admonition-error: var(--pst-color-danger); + --pst-color-admonition-hint: var(--pst-color-success); + --pst-color-admonition-tip: var(--pst-color-success); + --pst-color-admonition-important: var(--pst-color-success); + + --pst-icon-admonition-default: var(--pst-icon-info-circle); + --pst-icon-admonition-note: var(--pst-icon-info-circle); + --pst-icon-admonition-attention: var(--pst-icon-exclamation-circle); + --pst-icon-admonition-caution: var(--pst-icon-exclamation-triangle); + --pst-icon-admonition-warning: var(--pst-icon-exclamation-triangle); + --pst-icon-admonition-danger: var(--pst-icon-exclamation-triangle); + --pst-icon-admonition-error: var(--pst-icon-times-circle); + --pst-icon-admonition-hint: var(--pst-icon-lightbulb); + --pst-icon-admonition-tip: var(--pst-icon-lightbulb); + --pst-icon-admonition-important: var(--pst-icon-exclamation-circle); + + /** versionmodified **/ + --pst-color-versionmodified-default: var(--pst-color-info); + --pst-color-versionmodified-added: var(--pst-color-success); + --pst-color-versionmodified-changed: var(--pst-color-warning); + --pst-color-versionmodified-deprecated: var(--pst-color-danger); + + --pst-icon-versionmodified-default: var(--pst-icon-exclamation-circle); + --pst-icon-versionmodified-added: var(--pst-icon-exclamation-circle); + --pst-icon-versionmodified-changed: var(--pst-icon-exclamation-circle); + --pst-icon-versionmodified-deprecated: var(--pst-icon-exclamation-circle); + } + + .versionadded, + .versionchanged, + .deprecated { + margin: 0.5em auto; + padding: 0 0.6rem 0 0.6rem; + overflow: hidden; + page-break-inside: avoid; + border-left: 0.2rem solid; + border-color: rgba(var(--pst-color-versionmodified-default), 1); + border-radius: 0.2rem; + box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), + 0 0 0.0625rem rgba(0, 0, 0, 0.1); + transition: color 250ms, background-color 250ms, border-color 250ms; + background-color: rgba(var(--pst-color-versionmodified-default), 0.1); + } + + div.admonition-references.admonition .label { + border-left: 0px !important; + background: inherit !important; + } + + div.versionchanged > p { + margin-bottom: 5px; + margin-top: 5px; + } + + div.versionchanged > ul.simple { + margin-bottom: 5px; + margin-top: 5px; + } + + div.versionadded > p { + margin-bottom: 5px; + margin-top: 5px; + } + + div.versionadded > ul.simple { + margin-bottom: 5px; + margin-top: 5px; + } + + div.deprecated > p { + margin-bottom: 5px; + margin-top: 5px; + } + + div.deprecated > ul.simple { + margin-bottom: 5px; + margin-top: 5px; + } + + .versionadded { + background-color: rgba(var(--pst-color-versionmodified-added), 0.1); + border-color: rgba(var(--pst-color-versionmodified-added), 1); + } + + .versionmodified.added { + font-style: normal; + font-weight: 700; + } + + .versionmodified.added::before { + font-family: "FontAwesome"; + margin-right: 0.6rem; + content: var(--pst-icon-versionmodified-added); + color: rgba(var(--pst-color-versionmodified-added), 1); + } + + .versionchanged { + background-color: rgba(var(--pst-color-versionmodified-changed), 0.1); + border-color: rgba(var(--pst-color-versionmodified-changed), 1); + } + + .versionmodified.changed { + font-style: normal; + font-weight: 700; + } + + .versionmodified.changed::before { + font-family: "FontAwesome"; + margin-right: 0.6rem; + content: var(--pst-icon-versionmodified-changed); + color: rgba(var(--pst-color-versionmodified-changed), 1); + } + + .deprecated { + background-color: rgba(var(--pst-color-versionmodified-deprecated), 0.1); + border-color: rgba(var(--pst-color-versionmodified-deprecated), 1); + } + + .versionmodified.deprecated { + font-style: normal; + font-weight: 700; + border-radius: 0rem; + border-left: 0rem; + background-color: inherit; + box-shadow: None; + } + + .versionmodified.deprecated::before { + font-family: "FontAwesome"; + margin-right: 0.6rem; + content: var(--pst-icon-versionmodified-deprecated); + color: rgba(var(--pst-color-versionmodified-deprecated), 1); + } diff --git a/docs/about.rst b/docs/about.rst index a81e795..90ba68a 100644 --- a/docs/about.rst +++ b/docs/about.rst @@ -4,3 +4,12 @@ About PyMARE ============ PyMARE does meta-analyses and meta-regressions in Python. + +PyMARE has largely been conceived and developed as support for `NiMARE`_, a library for performing neuroimaging meta-analyses. +As such, PyMARE provides only a small subset of the functionality of other meta-analysis libraries, such as `metafor`_. +If you need to perform a meta-analysis that is not supported by PyMARE, we suggest using `metafor`_ instead. + +.. tip:: + + If you want to see where PyMARE fits within the NeuroStore 2.0 ecosystem, check out + `neurostuff.github.io `_. diff --git a/docs/conf.py b/docs/conf.py index f1382e9..8ca683e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -101,7 +101,7 @@ default_role = "autolink" # The name of the Pygments (syntax highlighting) style to use. -pygments_style = "sphinx" +pygments_style = "default" # ----------------------------------------------------------------------------- # Napoleon settings @@ -111,13 +111,16 @@ napoleon_include_init_with_doc = True napoleon_include_private_with_doc = False napoleon_include_special_with_doc = False -napoleon_use_admonition_for_examples = False -napoleon_use_admonition_for_notes = False -napoleon_use_admonition_for_references = False +napoleon_use_admonition_for_examples = True +napoleon_use_admonition_for_notes = True +napoleon_use_admonition_for_references = True napoleon_use_ivar = True -napoleon_use_param = False +napoleon_use_param = True napoleon_use_keyword = True -napoleon_use_rtype = False +napoleon_use_rtype = True +napoleon_preprocess_types = False +napoleon_type_aliases = None +napoleon_attr_annotations = True # ----------------------------------------------------------------------------- # HTML output @@ -138,8 +141,8 @@ # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ["_static"] -html_favicon = "_static/nimare_favicon.png" -html_logo = "_static/nimare_banner.png" +# html_favicon = "_static/nimare_favicon.png" +# html_logo = "_static/nimare_banner.png" # ----------------------------------------------------------------------------- # HTMLHelp output @@ -202,7 +205,7 @@ def setup(app): """From https://github.com/rtfd/sphinx_rtd_theme/issues/117.""" app.add_css_file("theme_overrides.css") - app.add_css_file("pymare.css") + app.add_css_file("nimare.css") app.connect("autodoc-process-docstring", generate_example_rst) # Fix to https://github.com/sphinx-doc/sphinx/issues/7420 # from https://github.com/life4/deal/commit/7f33cbc595ed31519cefdfaaf6f415dada5acd94 diff --git a/docs/links.rst b/docs/links.rst index 5b94392..a81420d 100644 --- a/docs/links.rst +++ b/docs/links.rst @@ -1,3 +1,5 @@ -.. _NiMARE: https://nimare.readthedocs.io - .. _Anaconda: https://www.anaconda.com/download/#macos + +.. _metafor: https://www.metafor-project.org/doku.php + +.. _NiMARE: https://nimare.readthedocs.io diff --git a/examples/01_basic_io/plot_create_dataset.py b/examples/01_basic_io/plot_create_dataset.py index fc4fd59..3413c36 100644 --- a/examples/01_basic_io/plot_create_dataset.py +++ b/examples/01_basic_io/plot_create_dataset.py @@ -1,22 +1,20 @@ -# emacs: -*- mode: python-mode; py-indent-offset: 4; tab-width: 4; indent-tabs-mode: nil -*- -# ex: set sts=4 ts=4 sw=4 et: """ .. _io1: -=================== - Creating a dataset -=================== +================== +Creating a dataset +================== In PyMARE, operations are performed on :class:`~pymare.core.Dataset` objects. Datasets are very lightweight objects that store the data used for meta-analyses, including study-level estimates (y), variances (v), predictors (X), and sample sizes (n). """ -from pprint import pprint - ############################################################################### # Start with the necessary imports # -------------------------------- +from pprint import pprint + import pandas as pd from pymare import core @@ -32,7 +30,14 @@ ############################################################################### # Datasets can also be created from pandas DataFrames # --------------------------------------------------- -df = pd.DataFrame({"y": [2, 4, 6], "v_alt": [100, 100, 100], "X1": [5, 2, 1], "X7": [9, 8, 7]}) +df = pd.DataFrame( + { + "y": [2, 4, 6], + "v_alt": [100, 100, 100], + "X1": [5, 2, 1], + "X7": [9, 8, 7], + } +) dataset = core.Dataset(v="v_alt", X=["X1", "X7"], data=df, add_intercept=False) pprint(vars(dataset)) diff --git a/examples/02_meta-analysis/plot_meta-analysis_walkthrough.py b/examples/02_meta-analysis/plot_meta-analysis_walkthrough.py index 6373cc0..2bce6de 100644 --- a/examples/02_meta-analysis/plot_meta-analysis_walkthrough.py +++ b/examples/02_meta-analysis/plot_meta-analysis_walkthrough.py @@ -27,6 +27,8 @@ from pymare import core, estimators from pymare.stats import var_to_ci +sns.set_style("whitegrid") + ############################################################################### # Here we simulate a dataset # ----------------------------------------------------------------------------- @@ -56,7 +58,7 @@ ############################################################################### # Plot variable distributions # ----------------------------------------------------------------------------- -fig, axes = plt.subplots(nrows=5, figsize=(16, 10)) +fig, axes = plt.subplots(nrows=5, figsize=(6, 5)) sns.distplot(y, ax=axes[0], bins=20) axes[0].set_title("y") sns.distplot(v, ax=axes[1], bins=20) @@ -76,7 +78,7 @@ # ----------------------------------- # Here we can show study-wise mean effect and CIs, along with the true effect # and CI corresponding to the between-study variance. -fig, ax = plt.subplots(figsize=(8, 16)) +fig, ax = plt.subplots(figsize=(6, 14)) study_ticks = np.arange(N_STUDIES) # Get 95% CI for individual studies @@ -236,7 +238,7 @@ ############################################################################### # Let's check out our results! # ````````````````````````````````````````````````````````````````````````````` -fig, ax = plt.subplots(figsize=(8, 8)) +fig, ax = plt.subplots(figsize=(6, 6)) for i, (estimator_name, summary_df) in enumerate(results.items()): ax.scatter((summary_df.loc[0, "estimate"],), (i + 1,), label=estimator_name) diff --git a/pymare/estimators/estimators.py b/pymare/estimators/estimators.py index 460994e..7149c3f 100644 --- a/pymare/estimators/estimators.py +++ b/pymare/estimators/estimators.py @@ -141,7 +141,12 @@ def get_v(self, dataset): return self.params_["sigma2"] / dataset.n def summary(self): - """Generate a MetaRegressionResults object for the fitted estimator.""" + """Generate a MetaRegressionResults object for the fitted estimator. + + Returns + ------- + :obj:`~pymare.results.MetaRegressionResults` + """ if not hasattr(self, "params_"): name = self.__class__.__name__ raise ValueError( diff --git a/setup.cfg b/setup.cfg index e5e9287..a71d2e7 100644 --- a/setup.cfg +++ b/setup.cfg @@ -2,8 +2,8 @@ url = https://github.com/neurostuff/PyMARE license = MIT author = PyMARE developers -author_email = tyarkoni@gmail.com -maintainer = Tal Yarkoni +author_email = tsalo006@fiu.edu +maintainer = Taylor Salo maintainer_email = tsalo006@fiu.edu description = PyMARE: Python Meta-Analysis & Regression Engine description-file = README.md