Full Code of pydata/pydata-cookbook for AI

master 6db99b03c544 cached
119 files
2.5 MB
655.6k tokens
195 symbols
1 requests
Download .txt
Showing preview only (2,621K chars total). Download the full file or copy to clipboard to get everything.
Repository: pydata/pydata-cookbook
Branch: master
Commit: 6db99b03c544
Files: 119
Total size: 2.5 MB

Directory structure:
gitextract_dc6ud5d9/

├── .gitignore
├── LICENSE.txt
├── README.md
├── abstracts/
│   ├── 00_pymc/
│   │   └── pymc3.rst
│   ├── 00_rudiger/
│   │   └── 00_rudiger.rst
│   ├── aaron_meurer/
│   │   └── sympy.rst
│   ├── dask/
│   │   └── dask.rst
│   ├── mpi4py/
│   │   └── mpi4py.rst
│   └── ryan_abernathey/
│       └── xarray.rst
├── environment.yml
├── examples/
│   ├── 00_bibderwalt/
│   │   ├── 00_bibderwalt.rst
│   │   └── mybib.bib
│   └── 00_vanderwalt/
│       └── 00_vanderwalt.rst
├── make_paper.sh
├── papers/
│   ├── joshua_warner/
│   │   ├── 00_scikitimage.rst
│   │   ├── reproduction_corner.ipynb
│   │   ├── reproduction_denoise.ipynb
│   │   └── reproduction_pano.ipynb
│   ├── maxwell_margenot/
│   │   ├── bayesian_linear_regression.ipynb
│   │   ├── maxwell_margenot.rst
│   │   └── mybib.bib
│   ├── numba/
│   │   ├── 00_numba.rst
│   │   ├── array_vs_list/
│   │   │   ├── array_vs_list.ipynb
│   │   │   └── array_vs_list.rst
│   │   ├── gufunc/
│   │   │   ├── gufunc.ipynb
│   │   │   └── gufunc.rst
│   │   ├── intro/
│   │   │   └── intro.rst
│   │   ├── looplifting/
│   │   │   ├── LoopLiftingCode.ipynb
│   │   │   ├── inspect_types_ex.py
│   │   │   └── looplifting.rst
│   │   ├── nogilthreads/
│   │   │   ├── BadThreadsExample.ipynb
│   │   │   ├── Mandel.ipynb
│   │   │   └── nogilthreads.rst
│   │   └── piecewise/
│   │       ├── piecewise.ipynb
│   │       └── piecewise.rst
│   ├── prabhu_ramachandran/
│   │   ├── code/
│   │   │   ├── viewer0.py
│   │   │   ├── viewer1.py
│   │   │   └── viewer2.py
│   │   └── mayavi_chapter.rst
│   ├── scipy/
│   │   ├── code/
│   │   │   └── signal/
│   │   │       ├── LICENSE.txt
│   │   │       ├── bandpass_batch_example.py
│   │   │       ├── bandpass_example.py
│   │   │       ├── butter.py
│   │   │       ├── firlp_lowpass_example.py
│   │   │       ├── firls_example.py
│   │   │       ├── firwin2_examples.py
│   │   │       ├── initial_conditions.py
│   │   │       ├── kaiser_lowpass_filter_design.py
│   │   │       ├── lowpass_design_specs.py
│   │   │       ├── make_data.py
│   │   │       ├── moving_avg_freq_response.py
│   │   │       ├── opt_lowpass.py
│   │   │       ├── pressure_example.py
│   │   │       ├── remez_example.py
│   │   │       ├── sos_bandpass_response.py
│   │   │       └── unstable_butterworth.py
│   │   └── scipy.rst
│   └── yuan_tang_hongliang_liu/
│       ├── convert.sh
│       ├── distributed_and_gpus.md
│       ├── distributed_and_gpus.txt
│       ├── intro.txt
│       ├── main_functionalities.txt
│       ├── model_tune.md
│       ├── model_tune.txt
│       ├── parameter_explained.md
│       ├── parameter_explained.txt
│       ├── references.txt
│       ├── vs_gbdt.md
│       ├── vs_gbdt.txt
│       └── xgboost_chapter.rst
├── publisher/
│   ├── Makefile
│   ├── _static/
│   │   ├── common.css
│   │   ├── google_analytics.js
│   │   ├── proc_links.js
│   │   ├── pydata-cookbook.css
│   │   ├── pydata.sty
│   │   ├── screen.css
│   │   └── status.sty
│   ├── _templates/
│   │   ├── article.bib.tmpl
│   │   ├── article.html.tmpl
│   │   ├── copyright.tex.tmpl
│   │   ├── header.html.tmpl
│   │   ├── index.html.tmpl
│   │   ├── organization.html.tmpl
│   │   ├── organization.tex.tmpl
│   │   ├── proceedings.bib.tmpl
│   │   ├── proceedings.tex.tmpl
│   │   ├── students.html.tmpl
│   │   ├── students.tex.tmpl
│   │   ├── title.tex.tmpl
│   │   └── toc.tex.tmpl
│   ├── build_html.py
│   ├── build_paper.py
│   ├── build_papers.py
│   ├── build_template.py
│   ├── conf.py
│   ├── mail/
│   │   ├── _mailer.py
│   │   ├── email.json
│   │   ├── mail_authors.py
│   │   ├── mail_authors_example.txt
│   │   ├── mail_reviewers.py
│   │   └── templates/
│   │       ├── author-revision.txt.tmpl
│   │       └── reviewer-invite.txt.tmpl
│   ├── options.py
│   ├── tempita/
│   │   ├── __init__.py
│   │   ├── _looper.py
│   │   └── compat3.py
│   └── writer/
│       ├── __init__.py
│       ├── code_block.py
│       ├── rstmath.py
│       └── sphinx_highlight.py
├── pydata-cookbook.json
├── review_criteria.md
└── reviews/
    ├── README
    ├── invite-abstract-reviews.rst
    ├── invite-paper-reviews.rst
    ├── invite-reviewer.txt.in
    ├── review-template.rst
    └── submission-template.rst

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
output
_build
*.pyc
*~
papers/maxwell_margenot/.ipynb_checkpoints


================================================
FILE: LICENSE.txt
================================================
Copyright (c) 2016 PyData Cookbook Authors.
All rights reserved.

The majority of files are adapted from the scipy-proceedings project and are

Copyright (c) 2010-2011 SciPy Developers.
All rights reserved.

The files code_block.py, rstmath.py and sphinx_highlight.py are
adapted from the Sphinx project and are

Copyright (c) 2007-2010 by the Sphinx team (see http://sphinx.pocoo.org).

Modifications to rstmath.py are

Copyright (c) 2010 Marcin Cieslik <mpc4p at virginia.edu>


The following BSD license holds for all the above code:

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

  * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
  * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the
    distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.


================================================
FILE: README.md
================================================
# PyData Cookbook

 We are starting a project to build a cookbook of advanced material for the PyData community. The cookbook will be published by Addison-Wesley. We have invited a number of contributors to see if such a project would have some interest and received overwhelmingly positive feedback. 

The book will cover several major topics, organized as such, with some sample packages:

- IDE: IPython/Jupyter
- Data Structures / Numerics: NumPy, Pandas, Xray, PyTables
- Viz: Matplotlib, PyViz (HoloViews, Bokeh, Datashader), Seaborn, yt
- Algorithms / Science: SciPy, Scikit-learn, Scikit-image, statsmodels, sympy, gensim, XGBoost
- Performance / Scale: Cython, Numexpr, Numba, Dask, pyspark


We expect each submission to be about 15 - 20 pages describing an example of the power of each library. While we have reached out to the projects about putting each submission together we are happy to accept chapters for libraries we did not initially identify.

## FAQ

Q: There are normally royalties for book authors. What happens to those?

A: All royalties go to NumFOCUS and will be used to support the further development of projects in the PyData stack.

Q: Is all content we contribute reusable for documentation of projects?

A: We can use chapters for documentation of projects but not a collection of all chapters in one volume. Essentially, there needs to be some value to buying the book to be published.


## Instructions for Reviewers

- Click on the Pull Requests Tab and browse to find the chapters assigned to you
- After reading the paper, you can start the review conversation by simply commenting
  on the chapter, taking into consideration [the suggested review criteria](review_criteria.md).
- Authors will then respond to the comments and/or modify the paper to address the comments. 
- This will begin an iterative review process where authors and reviewers can discuss the
  evolving submission.
- Reviewers may also apply one of the labels 'needs-more-review', 'pending-comment', or 
  'unready' to flag the current state of the review process.
- Only once a reviewer is satisfied that the review process is complete and the submission should
  be accepted to the proceedings, should they affix the 'ready' label. 
- Reviewers should come to a final 'ready', 'unready' decision before **July 10th** at 18:00 PST.

## Instructions for Authors

Submissions must be received by **March 31st, 2018** at 23:59 PST, but modifications are
allowed during the open review period which ends Dec 15th at 18:00 PST.  Submissions are
considered received once a Pull Request has been opened following the procedure
outlined below.

Papers are formatted using reStructuredText and the compiled version should be
no longer than 25 pages, including figures.  Here are the steps to produce a
paper:

- Fork the
  [pydata-cookbook](https://github.com/pydata/pydata-cookbook)
  repository on GitHub.

- An example paper is provided in ``examples/00_vanderwalt``.  Create a new
  directory ``papers/firstname_surname``, copy the example paper into it, and
  modify to your liking.

- Run ``./make_paper.sh papers/firstname_surname`` to compile your paper to
  PDF (requires LaTeX, docutils, Python--see below).  The output appears in
  ``output/firstname_surname/paper.pdf``.

- Once you are ready to submit your paper, file a pull request on GitHub.

- Please do not modify any files outside of your paper directory.

## Schedule Summary

Authors may make changes to their submissions throughout the review process.

There are many different styles of review (some do paragraph comments, others
do 'code review' style line edits) and the process is open.

We encourage authors and reviewers to work together iteratively to make each 
others papers the best they can be.
Combine the best principles of open source development and academic publication.

These dates are the 

- Sept 1st - Initial PR with title, abstract, and authors
- Nov 15th - Initial submissions
- Nov 22th - Reviewers assigned
- Dec 30th - Reviews due
- Dec 30th- Jan 31st: Authors revised papers based on reviews
- Feb 1th - Submission for publication

## General Guidelines

- All figures and tables should have captions.
- License conditions on images and figures must be respected (Creative Commons,
  etc.).
- Code snippets should be formatted to fit inside a single column without
  overflow.
- Avoid custom LaTeX markup where possible.

## Review Criteria

Please follow the included [review criteria](review_criteria.md).
Suggestions and amendments to these review criteria are enthusiastically
welcomed via discussion or pull request. 

## Other markup

Please refer to the example paper in ``papers/00_vanderwalt`` for
examples of how to:

 - Label figures, equations and tables
 - Use math markup
 - Include code snippets

## Requirements

 - IEEETran (often packaged as ``texlive-publishers``, or download from
   [CTAN](http://www.ctan.org/tex-archive/macros/latex/contrib/IEEEtran/)) LaTeX
   class
 - AMSmath LaTeX classes (included in most LaTeX distributions)
 - alphaurl (often packaged as ``texlive-bibtex-extra``, or download from
   [CTAN](https://www.ctan.org/pkg/urlbst)) urlbst BibTeX style
 - `docutils` 0.8 or later (``easy_install docutils``)
 - `pygments` for code highlighting (``easy_install pygments``)
 - Due to a bug in the Debian packaging of ``pdfannotextractor``, you may have
   to execute ``pdfannotextractor --install`` to fetch the PDFBox library.

On Debian-like distributions:

```
sudo apt-get install python-docutils texlive-latex-base texlive-publishers \
                     texlive-latex-extra texlive-fonts-recommended \
                     texlive-bibtex-extra
```

Note you will still need to install `docutils` with `easy-install` or `pip` even on a Debian system.

On Fedora, the package names are slightly different:

```
su -c `dnf install python-docutils texlive-collection-basic texlive-collection-fontsrecommended texlive-collection-latex texlive-collection-latexrecommended texlive-collection-latexextra texlive-collection-publishers texlive-collection-bibtexextra`
```

## Build Server

**To be added**

## For organizers

To build the whole proceedings, see the Makefile in the publisher directory.


## Credit

This repo was lovingly copied from the excellent [scipy-proceedings](https://github.com/scipy-conference/scipy_proceedings).
It retains the BSD license from that project and uses the same license for all contributions.


================================================
FILE: abstracts/00_pymc/pymc3.rst
================================================
:author: Christopher Fonnesbeck
:email: chris.fonnesbeck@vanderbilt.edu
:institution: Vanderbilt University Medical Center

:author: Peadar Coyle
:email: peadarcoyle@googlemail.com

:author: Thomas Wiecki
:email: thomas.wiecki@gmail.com

---------------------------------------
Bayesian Regression Analysis with PyMC3
---------------------------------------

.. class:: abstract

Regression analysis is a fundamental statistical method for relating two sets of variables to one another in order to provide inference or make predictions. It provides estimates of how outcomes of interest vary as the value of specific predictor variables change, along with estimates of uncertainty about this relationship. Adopting the Bayesian approach recasts the regression problem in probabilistic terms, with all model inputs and outputs expressed as probability distributions. This confers a great deal of flexibility to the modeling task, and makes model outputs easier to interpret. However, there has historically been a great deal of computational complexity associated with building and fitting Bayesian models. PyMC3 is a Python package for Bayesian statistical analysis that makes regression analysis easy by providing a high-level language for specifying models and a suite of powerful fitting algorithms for generating output. We present an example-driven guide to Bayesian regression modeling in PyMC3, starting with simple one-line models for linear regression, then expand the simple case to address realistic problems encountered by scientists, including the estimation of non-linear relationships, discrete and binary outcomes, and hierarchical variable relationships. We'll also introduce some of the methods for checking models, since we believe in the old saying that 'all models are wrong, some are useful' it is important to evaluate models before putting them to use.


================================================
FILE: abstracts/00_rudiger/00_rudiger.rst
================================================
:author: Philipp J. F. Rudiger
:email: philippjfr@continuum.io
:institution: Continuum Analytics, Inc.
:equal-contributor:

:author: Jean-Luc R. Stevens
:email: jstevens@continuum.io 
:institution: Continuum Analytics, Inc.
:institution: University of Edinburgh
:equal-contributor:

:author: James A. Bednar
:email: jbednar@continuum.io
:institution: Continuum Analytics, Inc.
:institution: University of Edinburgh
:corresponding:

:video: https://www.youtube.com/watch?v=0jhUivliNSo

-------------------------------------------------
HoloViews: Visualization
-------------------------------------------------

.. class:: abstract

   HoloViews_ provides a high-level declarative Python API to
   encapsulate multidimensional datasets in a form that can be
   instantly visualized and analyzed.  HoloViews allows you to specify
   even complex animated, multi-figure layouts using just a couple of
   lines of Python code, producing publication-quality plots rendered
   using Matplotlib.  You can just as easily build highly interactive
   web applications with sliders, selections, and streaming data,
   rendered using Bokeh_. You can now fill your Jupyter notebooks with
   informative, interactive visualizations specified clearly and
   succinctly, rather clogging it with pages and pages of
   domain-specific plotting code that is impossible to read or
   maintain.  HoloViews_ (and its companion geographic library
   GeoViews_) makes it simple to designate how your data should
   appear, and then let you index, select, sample, slice, reduce, and
   aggregate it to show just the data you are interested in.  Every
   HoloViews object preserves the original data from which it was
   constructed, allowing you to work as naturally and flexibly with a
   visualization in Python as you can with the original dataset,
   always being able to continue visualizing and analyzing at any
   point without having to replay your steps.  These features all
   derive from the way that HoloViews cleanly separates the plotting
   details from the semantic aspects of your data (*how* your plot
   should appear vs. *what* it shows), making it much simpler to work
   with both your data and your visualizations over time.  In this
   chapter we show how to create HoloViews objects from source data in
   NumPy, Pandas, and Xarray objects, how to manipulate them
   to show different aspects of the data, how to flexibly customize
   how the plots appear, and how to build dynamic, interactive
   visualizations using minimal code for maximal effect.
   
.. _HoloViews: http://holoviews.org
.. _GeoViews: http://geo.holoviews.org
.. _Matplotlib: http://matplotlib.org
.. _Bokeh: http://bokeh.pydata.org

.. class:: keywords

   Visualization, Plotting, Python, Declarative APIs, Bokeh, Matplotlib


================================================
FILE: abstracts/aaron_meurer/sympy.rst
================================================
:author: Aaron Meurer
:email: asmeurer@gmail.com
:institution: University of South Carolina
:corresponding:

-----
SymPy
-----

.. class:: abstract

   SymPy is a symbolic mathematics library written in pure Python. It is a
   full-featured computer algebra system, including functionality for symbolic
   calculus, equation solving, symbolic matrices, code generation, and much
   more, as well as several domain-specific modules including statistics,
   quantum mechanics, and classical mechanics. In this chapter, we give an
   introduction to symbolic computing and the SymPy library, and show through
   an example how it can be used as part of a larger scientific workflow.

.. class:: keywords

   symbolic mathematics, sympy


================================================
FILE: abstracts/dask/dask.rst
================================================
:author: James Crist
:email: jcrist@continuum.io
:institution: Continuum Analytics

:author: Matthew Rocklin
:email: mrocklin@gmail.com
:institution: Continuum Analytics

----
Dask
----

.. class:: abstract

Dask is a general purpose library for parallel computing that is designed to
complement other PyData libraries.  At its core, Dask is a task scheduling
system, similar to libraries like Luigi or Airflow, but designed for the
computational and interactive workloads found in data science and analytic
problems.

On top of this core, Dask provides parallel and larger-than-memory versions of
NumPy, Pandas, and lists by coordinating operations on many of these objects
with the task schedulers.  For example one logical dask.array is comprised of a
grid of NumPy arrays and one logical dask.dataframe is a sequence of Pandas
dataframes.  Dask includes the parallel algorithms necessary to faithfully
implement a broad and commonly used subset of the functionality of those
libraries.

This chapter will cover both the use of the Dask collections like Dask.array
and Dask.dataframe, and also the use of the core task scheduler, for parallel
problems that do not fit into either of these molds.  This chapter discusses
both scaling up on a single machine, expanding workable data sizes from "fits
in memory" to "fits on disk" as well as the use of Dask on a cluster.


================================================
FILE: abstracts/mpi4py/mpi4py.rst
================================================
:author: Lisandro Dalcin
:email: dalcinl@gmail.com
:institution: KAUST
:institution: CONICET


:author: Thomas Spura
:email: thomas.spura@gmail.com


:author: Andy R. Terrel
:email: andy.terrel@gmail.com


------
mpi4py
------

.. class:: abstract

MPI for Python (mpi4py) is a package that provides Python bindings for the
Message Passing Standard (MPI) and can be used to employ parallel and high
performance computing with core packages of the PyData stack. It includes
convenient communication methods for any pickable Python object as well as
efficient communication methods for buffer-like Python objects via the the
standard Python buffer interface (such as NumPy arrays, PyCUDA GPU arrays, or
selected built-in types). In this paper, we show easy to follow examples and
applications that use mpi4py to speed up the calculations of core packages of
the PyData stack.

.. _mpi4py: https://bitbucket.org/mpi4py/mpi4py/
.. _MPI: http://www.mpi-forum.org/

.. class:: keywords

parallel computing, parallel processing, high performance computing, message
passing interface, dynamic process management, performance



================================================
FILE: abstracts/ryan_abernathey/xarray.rst
================================================
:author: Ryan Abernathey
:email: rpa@ldeo.columbia.edu
:institution: Columbia University, New York, NY, USA
:institution: Lamont Doherty Earth Observatory, Palisades, NY, USA
:corresponding:

:author: Joe Hamman
:email: jhamman1@uw.edu
:institution: Department of Civil & Environmental Engineering,
  University of Washington, Seattle, WA

:author: Stephan Hoyer
:email: shoyer@gmail.com
:institution: Google Research, Mountain View, CA, USA

-------------------------------------------------
xarray: N-D labeled arrays and datasets in Python
-------------------------------------------------

.. class:: abstract

   xarray is an open source project and Python package that provides a toolkit
   and data structures for N-dimensional labeled arrays. The Common Data Model,
   an abstract data model for scientific datasets, is the foundation for
   xarray data stuctures. By combining the array-manipuation capabilites of
   NumPy, the out-of-core computations of dask, and the indexing and grouping
   functionality of Pandas, xarray streamlines and accelerates a wide range of
   data-science workflows, particularly when dealing with gridded datasets
   common in geosciences. Serialization to and from common storage formats
   (e.g. netCDF, HDF, etc.) is also supported. This paper reviews the basic
   xarray api and then dives into some examples from climate science.

.. class:: keywords

   Data Analysis, Python, Pandas, dask, netCDF

Introduction
------------

Many categories of data can be represented as multidimensional (i.e.
N-dimensional) numeric arrays. One-dimensional data are produced by continuous
point measurements, such as timeseries of temperature from a weather station.
Two dimensional data is associated with images and is commonly produced via
remote sensing (aircraft and satellites). Such data can be actual visible
imagery or other fields such as surface temperature, soil moisture, elevation,
etc. When two-dimensional image data is gathered over time, the resulting
dataset becomes three-dimensional. Four dimensions are realized by earth system
models, which simulate how a three-dimensional system evolves in time. Finally,
arbitrary numbers of dimensions result when ensembles of data products are
concatenated, compared, and synthesized in one analysis. (Our examples
are mostly drawn from environmental sciences, where xarray was adopted early on,
but many other fields will recognize parallels, including physics, astronomy,
finance, and biomedical imaging.)

The day-to-day work of scientists and researchers in many fields consists of
organizing, analyzing, and visualizing N-dimensional array data. Within the
python ecosystem, ``numpy`` and ``matplotlib`` have been the backbone of these
workflows for more than a decade. ``xarray`` provides a layer on top of these
tools which greatly simplifies and accelerates workflows, resulting in cleaner,
more-readable code; more intuitive, data-aware syntax; and intelligent
visualization. Furthermore, by integrating with ``dask`` (link to dask
chapter?), ``xarray`` facilitates the analysis of very large datasets without
forcing the user to learn specialized "big data" tools.

A central concept behind ``xarray`` is the notion that *most data is labelled*.
For example, a weather station might gather the variables ``temperature`` and
``humidity`` over the dimension ``time``. These labels are part of the data's
"metadata." It is unfortunately common practice in scientific data analysis to
discard metadata during the data-processing phase. This can lead to bugs and
misinterpretations and creates a barrier to reproducibility. ``xarray`` keeps
the data's labels (and possibly other metadata) together with the raw data
itself for the duration of the workflow, from ingestion through processing to
visualization.

This chapter first introduces basic ``xarray`` usage, including the data model
indexing operators, computation, and grouping operators.We then discuss how to
load common data formats, with a focus on common problems and pitfalls. Finally,
we have an in-depth example which demonstrates advanced usage.

Basic Usage
-----------

The Data Model
^^^^^^^^^^^^^^

Do we just copy the xarray docs here? Is that even allowed by copyright?

Indexing
^^^^^^^^

GroupBy: split-apply-combine
^^^^^^^^^^^^^^^^^^^^^^^^^^^^


Reading and Writing Data
------------------------

Backends and Engines
^^^^^^^^^^^^^^^^^^^^

netCDF, HDF, RasterIO, OpenDAP
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Writing
^^^^^^^

We need to address compression, chunking, out-of-core!


Advanced Example
----------------

Load a global surface temperature dataset. Remove seasonal cycle. Detrend.
Apply EOF analysis. (Can we use ``apply``?)


================================================
FILE: environment.yml
================================================
name: pydata-cookbook
channels:
    - defaults
    - conda-forge
dependencies:
    - pip:
        - docutils==0.13.1
        - pygments==2.2.0


================================================
FILE: examples/00_bibderwalt/00_bibderwalt.rst
================================================
:author: Gaius Caesar
:email: jj@rome.it
:institution: Senate House, S.P.Q.R.
:institution: Egyptian Embassy, S.P.Q.R.

:author: Mark Anthony
:email: mark37@rome.it
:institution: Egyptian Embassy, S.P.Q.R.

:author: Jarrod Millman
:email: millman@rome.it
:institution: Egyptian Embassy, S.P.Q.R.
:institution: Yet another place, S.P.Q.R.

:author: Brutus
:email: brutus@rome.it
:institution: Unaffiliated
:bibliography: mybib


:video: http://www.youtube.com/watch?v=dhRUe-gz690

------------------------------------------------
A Numerical Perspective to Terraforming a Desert
------------------------------------------------

.. class:: abstract

   A short version of the long version that is way too long to be written as a
   short version anyway.  Still, when considering the facts from first
   principles, we find that the outcomes of this introspective approach is
   compatible with the guidelines previously established.

   In such an experiment it is then clear that the potential for further
   development not only depends on previous relationships found but also on
   connections made during exploitation of this novel new experimental
   protocol.

.. class:: keywords

   terraforming, desert, numerical perspective

Introduction
------------

Twelve hundred years ago  |---| in a galaxy just across the hill...

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum sapien
tortor, bibendum et pretium molestie, dapibus ac ante. Nam odio orci, interdum
sit amet placerat non, molestie sed dui. Pellentesque eu quam ac mauris
tristique sodales. Fusce sodales laoreet nulla, id pellentesque risus convallis
eget. Nam id ante gravida justo eleifend semper vel ut nisi. Phasellus
adipiscing risus quis dui facilisis fermentum. Duis quis sodales neque. Aliquam
ut tellus dolor. Etiam ac elit nec risus lobortis tempus id nec erat. Morbi eu
purus enim. Integer et velit vitae arcu interdum aliquet at eget purus. Integer
quis nisi neque. Morbi ac odio et leo dignissim sodales. Pellentesque nec nibh
nulla. Donec faucibus purus leo. Nullam vel lorem eget enim blandit ultrices.
Ut urna lacus, scelerisque nec pellentesque quis, laoreet eu magna. Quisque ac
justo vitae odio tincidunt tempus at vitae tortor.


Bibliographies, citations and block quotes
------------------------------------------

If you want to include a ``.bib`` file, do so above by placing  :code:`:bibliography: yourFilenameWithoutExtension` as above (replacing ``mybib``) for a file named :code:`yourFilenameWithoutExtension.bib` after removing the ``.bib`` extension. 

**Do not include any special characters that need to be escaped or any spaces in the bib-file's name**. Doing so makes bibTeX cranky, & the rst to LaTeX+bibTeX transform won't work. 

To reference citations contained in that bibliography use the :code:`:cite:`citation-key`` role, as in :cite:`hume48` (which literally is :code:`:cite:`hume48`` in accordance with the ``hume48`` cite-key in the associated ``mybib.bib`` file).

However, if you use a bibtex file, this will overwrite any manually written references. 

So what would previously have registered as a in text reference ``[Atr03]_`` for 

:: 

     [Atr03] P. Atreides. *How to catch a sandworm*,
           Transactions on Terraforming, 21(3):261-300, August 2003.

what you actually see will be an empty reference rendered as **[?]**.

E.g., [Atr03]_.


If you wish to have a block quote, you can just indent the text, as in 

    When it is asked, What is the nature of all our reasonings concerning matter of fact? the proper answer seems to be, that they are founded on the relation of cause and effect. When again it is asked, What is the foundation of all our reasonings and conclusions concerning that relation? it may be replied in one word, experience. But if we still carry on our sifting humor, and ask, What is the foundation of all conclusions from experience? this implies a new question, which may be of more difficult solution and explication. :cite:`hume48`


Source code examples
--------------------

Of course, no paper would be complete without some source code.  Without
highlighting, it would look like this::

   def sum(a, b):
       """Sum two numbers."""

       return a + b

With code-highlighting:

.. code-block:: python

   def sum(a, b):
       """Sum two numbers."""

       return a + b

Maybe also in another language, and with line numbers:

.. code-block:: c
   :linenos:

   int main() {
       for (int i = 0; i < 10; i++) {
           /* do something */
       }
       return 0;
   }

Or a snippet from the above code, starting at the correct line number:

.. code-block:: c
   :linenos:
   :linenostart: 2

   for (int i = 0; i < 10; i++) {
       /* do something */
   }
 
Important Part
--------------

It is well known [Atr03]_ that Spice grows on the planet Dune.  Test
some maths, for example :math:`e^{\pi i} + 3 \delta`.  Or maybe an
equation on a separate line:

.. math::

   g(x) = \int_0^\infty f(x) dx

or on multiple, aligned lines:

.. math::
   :type: eqnarray

   g(x) &=& \int_0^\infty f(x) dx \\
        &=& \ldots

The area of a circle and volume of a sphere are given as

.. math::
   :label: circarea

   A(r) = \pi r^2.

.. math::
   :label: spherevol

   V(r) = \frac{4}{3} \pi r^3

We can then refer back to Equation (:ref:`circarea`) or
(:ref:`spherevol`) later.

Mauris purus enim, volutpat non dapibus et, gravida sit amet sapien. In at
consectetur lacus. Praesent orci nulla, blandit eu egestas nec, facilisis vel
lacus. Fusce non ante vitae justo faucibus facilisis. Nam venenatis lacinia
turpis. Donec eu ultrices mauris. Ut pulvinar viverra rhoncus. Vivamus
adipiscing faucibus ligula, in porta orci vehicula in. Suspendisse quis augue
arcu, sit amet accumsan diam. Vestibulum lacinia luctus dui. Aliquam odio arcu,
faucibus non laoreet ac, condimentum eu quam. Quisque et nunc non diam
consequat iaculis ut quis leo. Integer suscipit accumsan ligula. Sed nec eros a
orci aliquam dictum sed ac felis. Suspendisse sit amet dui ut ligula iaculis
sollicitudin vel id velit. Pellentesque hendrerit sapien ac ante facilisis
lacinia. Nunc sit amet sem sem. In tellus metus, elementum vitae tincidunt ac,
volutpat sit amet mauris. Maecenas [#]_ diam turpis, placerat [#]_ at adipiscing ac,
pulvinar id metus.

.. [#] On the one hand, a footnote.
.. [#] On the other hand, another footnote.

.. figure:: figure1.png

   This is the caption. :label:`egfig`

.. figure:: figure1.png
   :align: center
   :figclass: w

   This is a wide figure, specified by adding "w" to the figclass.  It is also
   center aligned, by setting the align keyword (can be left, right or center).

.. figure:: figure1.png
   :scale: 20%
   :figclass: bht

   This is the caption on a smaller figure that will be placed by default at the
   bottom of the page, and failing that it will be placed inline or at the top.
   Note that for now, scale is relative to a completely arbitrary original
   reference size which might be the original size of your image - you probably
   have to play with it. :label:`egfig2`

As you can see in Figures :ref:`egfig` and :ref:`egfig2`, this is how you reference auto-numbered
figures.

.. table:: This is the caption for the materials table. :label:`mtable`

   +------------+----------------+
   | Material   | Units          |
   +============+================+
   | Stone      | 3              |
   +------------+----------------+
   | Water      | 12             |
   +------------+----------------+
   | Cement     | :math:`\alpha` |
   +------------+----------------+


We show the different quantities of materials required in Table
:ref:`mtable`.


.. The statement below shows how to adjust the width of a table.

.. raw:: latex

   \setlength{\tablewidth}{0.8\linewidth}


.. table:: This is the caption for the wide table.
   :class: w

   +--------+----+------+------+------+------+--------+
   | This   | is |  a   | very | very | wide | table  |
   +--------+----+------+------+------+------+--------+

Unfortunately, restructuredtext can be picky about tables, so if it simply
won't work try raw LaTeX:


.. raw:: latex

   \begin{table*}

     \begin{longtable*}{|l|r|r|r|}
     \hline
     \multirow{2}{*}{Projection} & \multicolumn{3}{c|}{Area in square miles}\tabularnewline
     \cline{2-4}
      & Large Horizontal Area & Large Vertical Area & Smaller Square Area\tabularnewline
     \hline
     Albers Equal Area  & 7,498.7 & 10,847.3 & 35.8\tabularnewline
     \hline
     Web Mercator & 13,410.0 & 18,271.4 & 63.0\tabularnewline
     \hline
     Difference & 5,911.3 & 7,424.1 & 27.2\tabularnewline
     \hline
     Percent Difference & 44\% & 41\% & 43\%\tabularnewline
     \hline
     \end{longtable*}

     \caption{Area Comparisons \DUrole{label}{quanitities-table}}

   \end{table*}

Perhaps we want to end off with a quote by Lao Tse [#]_:

  *Muddy water, let stand, becomes clear.*

.. [#] :math:`\mathrm{e^{-i\pi}}`

.. Customised LaTeX packages
.. -------------------------

.. Please avoid using this feature, unless agreed upon with the
.. proceedings editors.

.. ::

..   .. latex::
..      :usepackage: somepackage

..      Some custom LaTeX source here.

References
----------
.. [Atr03] P. Atreides. *How to catch a sandworm*,
           Transactions on Terraforming, 21(3):261-300, August 2003.




================================================
FILE: examples/00_bibderwalt/mybib.bib
================================================
@Book{hume48,
  author =  "David Hume",
  year =    "1748",
  title =   "An enquiry concerning human understanding",
  address =     "Indianapolis, IN",
  publisher =   "Hackett",
}


================================================
FILE: examples/00_vanderwalt/00_vanderwalt.rst
================================================
:author: Gaius Caesar
:email: jj@rome.it
:institution: Senate House, S.P.Q.R.
:institution: Egyptian Embassy, S.P.Q.R.
:corresponding:

:author: Mark Anthony
:email: mark37@rome.it
:institution: Egyptian Embassy, S.P.Q.R.

:author: Jarrod Millman
:email: millman@rome.it
:institution: Egyptian Embassy, S.P.Q.R.
:institution: Yet another place, S.P.Q.R.
:equal-contributor:

:author: Brutus
:email: brutus@rome.it
:institution: Unaffiliated
:equal-contributor:

:video: http://www.youtube.com/watch?v=dhRUe-gz690

------------------------------------------------
A Numerical Perspective to Terraforming a Desert
------------------------------------------------

.. class:: abstract

   A short version of the long version that is way too long to be written as a
   short version anyway.  Still, when considering the facts from first
   principles, we find that the outcomes of this introspective approach is
   compatible with the guidelines previously established.

   In such an experiment it is then clear that the potential for further
   development not only depends on previous relationships found but also on
   connections made during exploitation of this novel new experimental
   protocol.

.. class:: keywords

   terraforming, desert, numerical perspective

Introduction
------------

Twelve hundred years ago  |---| in a galaxy just across the hill...

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum sapien
tortor, bibendum et pretium molestie, dapibus ac ante. Nam odio orci, interdum
sit amet placerat non, molestie sed dui. Pellentesque eu quam ac mauris
tristique sodales. Fusce sodales laoreet nulla, id pellentesque risus convallis
eget. Nam id ante gravida justo eleifend semper vel ut nisi. Phasellus
adipiscing risus quis dui facilisis fermentum. Duis quis sodales neque. Aliquam
ut tellus dolor. Etiam ac elit nec risus lobortis tempus id nec erat. Morbi eu
purus enim. Integer et velit vitae arcu interdum aliquet at eget purus. Integer
quis nisi neque. Morbi ac odio et leo dignissim sodales. Pellentesque nec nibh
nulla. Donec faucibus purus leo. Nullam vel lorem eget enim blandit ultrices.
Ut urna lacus, scelerisque nec pellentesque quis, laoreet eu magna. Quisque ac
justo vitae odio tincidunt tempus at vitae tortor.

Of course, no paper would be complete without some source code.  Without
highlighting, it would look like this::

   def sum(a, b):
       """Sum two numbers."""

       return a + b

With code-highlighting:

.. code-block:: python

   def sum(a, b):
       """Sum two numbers."""

       return a + b

Maybe also in another language, and with line numbers:

.. code-block:: c
   :linenos:

   int main() {
       for (int i = 0; i < 10; i++) {
           /* do something */
       }
       return 0;
   }

Or a snippet from the above code, starting at the correct line number:

.. code-block:: c
   :linenos:
   :linenostart: 2

   for (int i = 0; i < 10; i++) {
       /* do something */
   }

Important Part
--------------

It is well known [Atr03]_ that Spice grows on the planet Dune.  Test
some maths, for example :math:`e^{\pi i} + 3 \delta`.  Or maybe an
equation on a separate line:

.. math::

   g(x) = \int_0^\infty f(x) dx

or on multiple, aligned lines:

.. math::
   :type: eqnarray

   g(x) &=& \int_0^\infty f(x) dx \\
        &=& \ldots

The area of a circle and volume of a sphere are given as

.. math::
   :label: circarea

   A(r) = \pi r^2.

.. math::
   :label: spherevol

   V(r) = \frac{4}{3} \pi r^3

We can then refer back to Equation (:ref:`circarea`) or
(:ref:`spherevol`) later.

Mauris purus enim, volutpat non dapibus et, gravida sit amet sapien. In at
consectetur lacus. Praesent orci nulla, blandit eu egestas nec, facilisis vel
lacus. Fusce non ante vitae justo faucibus facilisis. Nam venenatis lacinia
turpis. Donec eu ultrices mauris. Ut pulvinar viverra rhoncus. Vivamus
adipiscing faucibus ligula, in porta orci vehicula in. Suspendisse quis augue
arcu, sit amet accumsan diam. Vestibulum lacinia luctus dui. Aliquam odio arcu,
faucibus non laoreet ac, condimentum eu quam. Quisque et nunc non diam
consequat iaculis ut quis leo. Integer suscipit accumsan ligula. Sed nec eros a
orci aliquam dictum sed ac felis. Suspendisse sit amet dui ut ligula iaculis
sollicitudin vel id velit. Pellentesque hendrerit sapien ac ante facilisis
lacinia. Nunc sit amet sem sem. In tellus metus, elementum vitae tincidunt ac,
volutpat sit amet mauris. Maecenas [#]_ diam turpis, placerat [#]_ at adipiscing ac,
pulvinar id metus.

.. [#] On the one hand, a footnote.
.. [#] On the other hand, another footnote.

.. figure:: figure1.png

   This is the caption. :label:`egfig`

.. figure:: figure1.png
   :align: center
   :figclass: w

   This is a wide figure, specified by adding "w" to the figclass.  It is also
   center aligned, by setting the align keyword (can be left, right or center).

.. figure:: figure1.png
   :scale: 20%
   :figclass: bht

   This is the caption on a smaller figure that will be placed by default at the
   bottom of the page, and failing that it will be placed inline or at the top.
   Note that for now, scale is relative to a completely arbitrary original
   reference size which might be the original size of your image - you probably
   have to play with it. :label:`egfig2`

As you can see in Figures :ref:`egfig` and :ref:`egfig2`, this is how you reference auto-numbered
figures.

.. table:: This is the caption for the materials table. :label:`mtable`

   +------------+----------------+
   | Material   | Units          |
   +============+================+
   | Stone      | 3              |
   +------------+----------------+
   | Water      | 12             |
   +------------+----------------+
   | Cement     | :math:`\alpha` |
   +------------+----------------+


We show the different quantities of materials required in Table
:ref:`mtable`.


.. The statement below shows how to adjust the width of a table.

.. raw:: latex

   \setlength{\tablewidth}{0.8\linewidth}


.. table:: This is the caption for the wide table.
   :class: w

   +--------+----+------+------+------+------+--------+
   | This   | is |  a   | very | very | wide | table  |
   +--------+----+------+------+------+------+--------+

Unfortunately, restructuredtext can be picky about tables, so if it simply
won't work try raw LaTeX:


.. raw:: latex

   \begin{table*}

     \begin{longtable*}{|l|r|r|r|}
     \hline
     \multirow{2}{*}{Projection} & \multicolumn{3}{c|}{Area in square miles}\tabularnewline
     \cline{2-4}
      & Large Horizontal Area & Large Vertical Area & Smaller Square Area\tabularnewline
     \hline
     Albers Equal Area  & 7,498.7 & 10,847.3 & 35.8\tabularnewline
     \hline
     Web Mercator & 13,410.0 & 18,271.4 & 63.0\tabularnewline
     \hline
     Difference & 5,911.3 & 7,424.1 & 27.2\tabularnewline
     \hline
     Percent Difference & 44\% & 41\% & 43\%\tabularnewline
     \hline
     \end{longtable*}

     \caption{Area Comparisons \DUrole{label}{quanitities-table}}

   \end{table*}

Perhaps we want to end off with a quote by Lao Tse [#]_:

  *Muddy water, let stand, becomes clear.*

.. [#] :math:`\mathrm{e^{-i\pi}}`

.. Customised LaTeX packages
.. -------------------------

.. Please avoid using this feature, unless agreed upon with the
.. proceedings editors.

.. ::

..   .. latex::
..      :usepackage: somepackage

..      Some custom LaTeX source here.

References
----------
.. [Atr03] P. Atreides. *How to catch a sandworm*,
           Transactions on Terraforming, 21(3):261-300, August 2003.




================================================
FILE: make_paper.sh
================================================
#!/bin/bash

DIR=$1

if [[ ! -d $DIR ]]; then
  echo "Usage: make_paper.sh source_dir"
  exit -1
fi

python publisher/build_paper.py $DIR
if [ "$?" -ne "0" ]; then
    echo "Error building paper $DIR. Aborting."
    exit 1
fi

#cd $OUTDIR
#$TEX2PDF > /dev/null && $TEX2PDF | (python $WD/publisher/page_count.py)


================================================
FILE: papers/joshua_warner/00_scikitimage.rst
================================================
:author: Joshua D. Warner
:email: joshua.dale.warner@gmail.com
:institution: Mayo Clinic, Rochester, USA
:first-author:

:author: Alexandre F. de Siqueira
:email: afdesiqueira@protonmail.com
:institution: University of Campinas, Campinas, Brazil
:institution: TU Bergakademie Freiberg, Freiberg, Germany
:equal-contributor:

:author: Emmanuelle Gouillart
:email: emmanuelle.gouillart@nsup.org
:institution: Joint Unit CNRS/Saint-Gobain Surface of Glass and Interfaces, Aubervilliers, France
:equal-contributor:

:author: Stéfan van der Walt
:email: stefanv@berkeley.edu
:institution: Berkeley Institute for Data Science, University of California at Berkeley, USA
:corresponding:


------------
scikit-image
------------

3.. class:: abstract

   ``scikit-image`` is an image processing library that implements
   algorithms and utilities for use in research, education and
   industry applications. It is released under the liberal Modified
   BSD open source license, provides a well-documented API in the
   Python programming language, and is developed by an active,
   international team of collaborators. In this chapter we highlight
   the advantages of open source to achieve the goals of the
   ``scikit-image library``, and we showcase a few real-world image
   processing applications that uses ``scikit-image`` extensively. More
   information can be found on the project homepage,
   http://scikit-image.org.

.. class:: keywords

   image processing, computer vision, python

Introduction
------------

``scikit-image`` is an image processing library designed to complement and extend the capabilities of the core scientific Python libraries NumPy and SciPy for image processing applications [Van14]_.  Like other ``scikits``, it is domain-specific in scope and moves faster than the core libraries to meet users' evolving needs.

Images are NumPy arrays
***********************

Images are simply a collection of data on a regular grid, represented by a NumPy array (see Figure :ref:`penguin`).  Thus, ``scikit-image`` shares the foundational data representation of the scientific Python ecosystem, allowing maximum compatibliity [Van11]_.

Essentially all operations in ``scikit-image`` are defined for at
least two-dimensional images and, where possible, are generalized to
work with images of arbitrary dimensionality.  Some images, like color
images, may have more than one channel, e.g., red, green, and blue
(RGB).  Such an image is represented as an `(M, N, c)` array, with
color information carried in the third dimension.  To disambiguate
color images from, e.g., 3-D volume data (a 3-D array with shape `(plane,
rows, cols)`), certain operations support a `multichannel` flag.

.. figure:: penguin.png
   :align: center

   This enlarged public domain image of Tux, the Linux kernel mascot, shows individual pixels.  The inset illustrates the luminance gray value at each underlying point. :label:`penguin`

A note on image coordinates
***************************

It bears repeating that ``scikit-image`` shares NumPy conventions for
array indexing.  When specifying points, one must use ``(row,
column)`` indexing, not ``(x, y)`` coordinates.  For a two-dimensional
image, the origin is in the upper left corner.  Figure :ref:`row-col`
illustrates how indexing works in NumPy and ``scikit-image``.  Please refer to the `scikit-image user guide
<http://scikit-image.org/docs/stable/user_guide/numpy_images.html#coordinate-conventions>`_
for more detail.


.. figure:: row-col.png
   :align: center

   Illustration of NumPy ``(row, column)`` indexing for a two-dimensional array or image.  Note the origin is in the upper left. :label:`row-col`


Parallel & distributed processing via dask
******************************************

``scikit-image`` has very basic parallel processing support through
`skimage.util.apply_parallel(function, image)`.  The aim of
`apply_parallel` is to make use of all processors on a single machine,
by dividing the image into blocks and applying the specified function
to each.  To handle edge effects, the blocks can have some overlap,
with the central part of each processed block being used to construct
the output.

This approach addresses the most basic use-case, but for anything more
challenging we recommend the `dask` and `distributed` libraries.  We
now follow along with a parallel processing image processing example
by the author of the above-mentioned libraries, Matthew Rocklin.

.. From: https://gist.github.com/mrocklin/611c64e4fb62486269b507a872984cc5

.. Matthew writes:

.. Email from last night from colleague at the NIH:

.. Electron microscopy is probably generating the biggest ndarray
.. datasets in the field - terabytes regularly. Neuroscience need EM to
.. see connections between neurons because the critical features of
.. neural synapses (connections) are below the diffraction limit of light
.. microscopes. The hard part is machine vision on the data to follow
.. small neuron parts from one slice to the next. This type of research
.. has been called "connectomics".

.. This data is from drosophila: http://emdata.janelia.org/

.. Here is an example 2d slice of the data. If you take the below URL and change the last number you can get about 5000 different images. http://emdata.janelia.org/api/node/bf1/grayscale/raw/xy/2000_2000/1800_2300_5000

.. The data is a bit sparse (many black pixels) but it's around a 25GB dataset if you pull down all the slices. And it's a 3d ndarray.*

.. note:: TODO: Reduce the notebook at the above mentioned URL into a concise example.

Package roadmap
---------------

Most of the functionality in ``scikit-image`` is located in *subpackages*, which group similar tools.  This is similar to how SciPy is designed [Oli07]_ [Jar11]_.  There is far more functionality in ``scikit-image`` than can be conveyed in a single chapter, so a brief overview of the subpackages included as of version 0.12 is included below.

``color``
    Color conversion routines, including grayscale to RGB (``rgb2gray``) and vice versa (``gray2rgb``) as well as many additional color spaces.
``data``
    Test images shipped with the package, including ``astronaut`` (see crop in Figure :ref:`noise-types`).
``draw``
    Routines to draw primitives including lines, shapes, and text.
``exposure``
    Intensity and contrast adjustments.
``feature``
    Feature detection, extraction, and matching. This subpackage includes ``ORB``, which is used in the panorama example to follow, as well as blob-finding and feature matching algorithms.
``filters``
    Whole-image changes like sharpening.  See also the rank filters exposed in ``skimage.filters.rank``.
``future``
    Similar to Python's ability to import from the ``__future__``, this is a glimpse into the future of ``scikit-image``.  Contains stable functions which are ready for use, but with API that may not be finalized.
``graph``
    Graph theory, including path finding which is used in the panorama example to follow.
``io``
    Reading and writing images; multiple plugins supported.
``measure``
    Tools to quantify image properties such as length or shape.  Also includes ``marching_cubes``, ``marching_squares``, and Hough transforms to find lines, circles, or ellipses.
``morphology``
    Morphological operations, e.g., dilation and erosion. Binary and grayscale morphology supported.
``novice``
    Simplified teaching interface.
``restoration``
    Reduce noise or deconvolve images.
``segmentation``
    Partition an image into two or more regions.  Includes both unsupervised (``felzenszwalb``, ``slic``, ``quickshift``) and supervised (``random_walker``) methods.
``transform``
    Warp or rotate images.
``util``
    Common utility functions.
``viewer``
    QT-based interactive GUI.


Reducing noise
--------------

There are many types of noise which can affect images, and the first step to reducing unwanted noise is to understand what kind of noise is present.  In scikit-image, there is a noise generation utility named ``random_noise`` located in ``skimage.util`` which can generate most commonly encountered types of noise.  In Figure :ref:`noise-types` we show a comparison of several common noise types applied to a crop of the ``astronaut`` image available in ``skimage.data`` [#]_. This crop has both fine detail in the NASA patch and flat fields, so it is a good example to evaluate denoising algorithms.

.. [#] Press photograph of NASA astronaut Eileen Collins, in the public domain.

.. figure:: noise_types.png
   :align: center
   :scale: 90%

   Original, clean image and four different types of noise applied to it with ``skimage.util.random_noise``.  Poisson noise is subtle, but difficult to remove, whereas gaussian as well as salt & pepper are not subtle but also challenging. :label:`noise-types`

It should come as no surprise that a particular denoising algorithm may be stronger or weaker at removing a particular kind of noise.  In this example the noise type is speckle noise, which is a kind of multiplicative noise often encountered in ultrasound medical imaging. Three different denoising algorithms implemented in scikit-image will be applied: total variation, bilateral, and wavelet denoising.

The act of denoising is always a balance.  It is almost never possible to entirely remove noise; doing so would eliminate the fine features and texture one desires to keep.  When used to excess, or with parameters set too high, denoising algorithms typically produce “posterized” images with flat domains separated by sharp edges.  Denoising is thus typically an iterative approach to control the tradeoff between smoothing and faithfulness to the original image by tuning function parameters.

.. code-block:: python

   from skimage import data, img_as_float
   from skimage.util import random_noise

   astronaut = img_as_float(data.astronaut())
   astro = astronaut[300:450, 100:320]

   sigma = 0.3
   noisy = random_noise(img_astro, var=sigma**2)

The ``noisy`` image generated here and seen in Figure :ref:`denoise` is what our approaches below will attempt to fix.  Denoising algorithms are located in ``skimage.restoration``, prefixed with ``denoise_``.

.. figure:: denoise.png
   :align: center

   Top row: original image and with speckle noise applied. Subsequent rows show total variation, bilateral, and wavelet denoising respectively with pertinent settings in the titles. :label:`denoise`

Total variation minimization
****************************

Denoising by minimizing the total variation attempts to change the image in such a way as to reduce the total variation present.  Thus, if applied too strongly it will eliminate fine features of the original image along with noise.  The total variation norm being minimized is the L1 norm of the image gradient.  This is an excellent method to reduce salt-and-pepper noise.  As the norm being minimized is that of the gradient, when applied too strongly this algorithm results in very smooth results with no hard edges.

There are two approaches to total variation denoising implemented in scikit-image: split-Bregman [Get12]_ and Chambolle [Cha04]_. In this example the latter is used.

.. code-block:: python

   from skimage.restoration import denoise_tv_chambolle

   tv_cham_low = denoise_tv_chambolle(
       img_noisy, weight=0.05, multichannel=True)
   tv_cham_high = denoise_tv_chambolle(
       img_noisy, weight=0.1, multichannel=True)

The function ``denoise_tv_chambolle`` accepts several parameters, of which the most pertinent are ``weight`` and ``multichannel``

* ``weight`` represents the denoising strength: the greater the weight, the more noise is removed (at the expense of fidelity to the input image).
* ``multichannel`` enables the option to apply total-variation denoising separately for each color channel. This parameter defaults to ``False`` but should be set ``True`` for color images; if not, the result will have color fringing artifacts.

The results of total variation denoising via the Chambolle method are shown in the second row of Figure :ref:`denoise`.


Bilateral filter
****************

A bilateral filter [Tom98]_ reduces noise while preserving edges. It assigns new values based on a local, weighted mean with two main features: proximity and similar value.  The bilateral filter is implemented by the function `denoise_bilateral`, contained in the module `restoration`.  This filter tends to produce piecewise-constant or cartoon-like images if applied to excess.

.. code-block:: python

   from skimage.restoration import denoise_bilateral

   bilat_low = denoise_bilateral(
       img_noisy, sigma_color=0.05, sigma_spatial=25)
   bilat_high = denoise_bilateral(
       img_noisy, sigma_color=0.1, sigma_spatial=20)

``denoise_bilateral`` allows the user to control the weight given to closeness in color and spatial proximity separately with the keyword arguments ``sigma_color`` and ``sigma_spatial``:

* ``sigma_color`` represents the radiometric similarity, i.e., the standard deviation for color/value distance. The expected value is on the range [0, 1].  In the default case, `None`, the standard deviation of the input image is used.
* ``sigma_spatial`` is the standard deviation for range distance. A larger value allows more distant pixels to more strongly influence the result.

The results of bilateral filter denoising are shown in the third row of Figure :ref:`denoise`.

Wavelet denoising
*****************

Wavelets [#]_ are a fascinating mathematical construct that can be thought of as a way to combine the best of frequency and time domain analysis.  They are applied at multiple scales.  For brevity, the most important feature of wavelets for denoising purposes is that of *sparsity*.

.. [#] At time of writing, wavelet algorithms are only available in the devevelopment version of scikit-image.  They will be available in stable version of scikit-image 0.13 and above.

Wavelets, when applied to 2-dimensional images, decompose the image into a representation made up of many individual wavelets.  This representation is sparse, i.e., there are relatively few wavelet coefficients with high values and many that are quite low.  Denoising simply sets a threshold below which small coefficients are discarded, then inverts the result yielding an image with less noise.  Sparse representations are similarly useful for image compression.

.. code-block:: python

   from skimage.restoration import (denoise_wavelet,
                                    estimate_sigma)
   # Need to estimate noise present
   sigma_est = estimate_sigma(
       noisy, multichannel=True, average_sigmas=True)

   wave_low = denoise_wavelet(noisy, sigma=sigma_est,
                              multichannel=True)
   wave_high = denoise_wavelet(noisy,
                               sigma=1.4*sigma_est,
                               multichannel=True)

The primary control over denoising strength is ``sigma=``, and there is also an algorithm to estimate the noise present ``estimage_sigma``.  Generally this is an underestimate due to clipping, as true Gaussian noise has no limit to its range but the image data does.

The results of wavelet denoising are shown in the fourth row of Figure :ref:`denoise`.

Corner detection
----------------

Corner detection is used to extract sharp features from an image. There are several corner detectors implemented on scikit-image. This example shows the Harris corner detector [Har88]_, which finds corner points and determine their position with sub-pixel precision.

The input image will be based on an image of a checkerboard, given by the function ``data.checkerboard()``, but a rectangular checkerboard is too easy.  Using the functions ``warp`` and ``AffineTransform`` contained in in ``skimage.transform``, the checkerboard can be stretched and warped out of shape (see Figure :ref:`corners`)

.. code-block:: python

   from skimage import data
   from skimage.transform import warp, AffineTransform

   affine = AffineTransform(
       scale=(0.8, 1.1), rotation=1, shear=0.7,
       translation=(220, 50))
   image = warp(data.checkerboard(), affine.inverse,
                output_shape=(200, 310))

Then we use three functions from ``skimage.feature``:

* ``corner_harris`` computes the Harris corner measure response image.
* ``corner_peaks`` identifies corners in a corner measure response image, like the one returned by ``corner_harris``.
* ``corner_subpix`` determines the sub-pixel position of corners.

.. code-block:: python

   from skimage.feature import (corner_harris,
                                corner_subpix,
                                corner_peaks)

   harris_coords = corner_peaks(corner_harris(image))
   harris_subpix = corner_subpix(image, harris_coords)

The detected corners are shown in Figure :ref:`corners`.

.. figure:: harris_corners.png
   :align: center

   On left, the warped checkerboard.  On right, corners detected with the Harris corner detector are marked in red.  These corners are defined with sub-pixel precision, but the markers are larger for legibility. :label:`corners`

Panorama stitching
------------------

This example stitches three images into a seamless panorama using several tools in scikit-image, including feature detection [Rub11]_, RANdom SAmple Consensus (RANSAC) [Fis81]_, graph theory, and affine transformations.  The images used in this example are available at https://github.com/scikit-image/skimage-tutorials/tree/master/images/pano named ``JDW_9*.jpg``, released under the CC-BY 4.0 by the author.

Load images
***********

The ``io`` module in scikit-image allows images to be loaded and saved. In this case the color panorama images will be loaded into an iterable `ImageCollection`, though one could also load them individually.

.. code-block:: python

   from skimage import io
   pano_images = io.ImageCollection(
       '/path/to/images/JDW_9*')

.. figure:: pano0_originals.png
   :align: center
   :figclass: w
   :scale: 60%

   Panorama source images, taken on the trail to Delicate Arch in Arches National Park, USA.  Released under CC-BY 4.0 by Joshua D. Warner. :label:`fig-pano0`

Feature detection and matching
******************************

To correctly align the images, a *projective* transformation relating them is required.

1. Define one image as a *target* or *destination* image, which will remain anchored while the others are warped.
2. Detect features in all three images.
3. Match features from left and right images against the features in the center, anchored image.

In this series, the middle image is the logical anchor point.  Numerous feature detection algorithms are available; this example will use Oriented FAST and rotated BRIEF (ORB) features available as ``skimage.feature.ORB`` [Rub11]_.

.. code-block:: python

   import matplotlib.pyplot as plt
   from skimage.color import rgb2gray
   from skimage.feature import (ORB, match_descriptors,
                                plot_matches)

   # Initialize ORB
   orb = ORB(n_keypoints=800, fast_threshold=0.05)
   keypoints = []
   descriptors = []

   # Detect features
   for image in pano_images:
       orb.detect_and_extract(rgb2gray(image))
       keypoints.append(orb.keypoints)
       descriptors.append(orb.descriptors)

   # Match features from images 0 -> 1 and 2 -> 1
   matches01 = match_descriptors(descriptors[0],
                                 descriptors[1],
                                 cross_check=True)
   matches12 = match_descriptors(descriptors[1],
                                 descriptors[2],
                                 cross_check=True)

   # Show raw matched features from left to center
   fig, ax = plt.subplots()
   plot_matches(ax, pano_images[0], pano_images[1],
                keypoints[0], keypoints[1], matches01)
   ax.axis('off');

.. figure:: pano1_ORB-raw.png
   :align: center

   Matched ORB keypoints from left and center images from :ref:`fig-pano0`. Most features line up similarly, but there are a number of obvious outliers or false matches. :label:`fig-pano1`

Transform estimation
********************

To filter out the false matches observed in Figure :ref:`fig-pano1`, RANdom SAmple Consensus (RANSAC) is used [Fis81]_. RANSAC is a powerful method of rejecting outliers available in ``skimage.transform.ransac``. The transformation is estimated using an iterative process based on randomly chosen subsets, finally selecting the model which corresponds best with the majority of matches.

It is important to note the randomness inherent to RANSAC. The results are robust, but will vary slightly every time.  Thus, it is expected that readers' results will deviate slightly from the published figures after this point.

.. code-block:: python

   from skimage.measure import ransac
   from skimage.transform import ProjectiveTransform

   # Keypoints from left (src) to middle (dst) images
   src = keypoints[0][matches01[:, 0]][:, ::-1]
   dst = keypoints[1][matches01[:, 1]][:, ::-1]

   model_ransac01, inliers01 = ransac(
       (src, dst), ProjectiveTransform, min_samples=4,
       residual_threshold=1, max_trials=300)

   # Keypoints from right (src) to middle (dst) images
   src = keypoints[2][matches12[:, 1]][:, ::-1]
   dst = keypoints[1][matches12[:, 0]][:, ::-1]

   model_ransac12, inliers12 = ransac(
       (src, dst), ProjectiveTransform, min_samples=4,
       residual_threshold=1, max_trials=300)

   # Show robust, RANSAC-matched features
   fig, ax = plt.subplots()
   plot_matches(ax, pano_images[0], pano_images[1],
                keypoints[0], keypoints[1],
                matches01[inliers01])
   ax.axis('off');

The results of robust transform estimation with RANSAC are shown in Figure :ref:`fig-pano2`.

.. figure:: pano2_ORB-RANSAC.png
   :align: center

   The best RANSAC transform estimation uses only these keypoints. The outliers are now excluded (compare with Figure :ref:`fig-pano1`). :label:`fig-pano2`

Warp images into place
**********************

Before producing the panorama, the correct size for a new canvas to hold all three warped images is needed.  The entire size, or extent, of this image is carefully found.

.. code-block:: python

   # All three images have the same size
   r, c = pano_images[1].shape[:2]

   # Note that transformations take coordinates in
   # (x, y) format, not (row, column), for literature
   # consistency
   corners = np.array([[0, 0],
                       [0, r],
                       [c, 0],
                       [c, r]])

   # Warp image corners to their new positions
   warped_corners01 = model_ransac01(corners)
   warped_corners12 = model_ransac12(corners)

   # Extents of both target and warped images
   all_corners = np.vstack((warped_corners01,
                            warped_corners12,
                            corners))

   # Overall output shape is max - min
   corner_min = np.min(all_corners, axis=0)
   corner_max = np.max(all_corners, axis=0)
   output_shape = (corner_max - corner_min)

   # Ensure integer shape
   output_shape = np.ceil(
       output_shape[::-1]).astype(int)


Next, each image is warped and placed into a new canvas of shape ``output_shape``.

Translate middle target image
*****************************

The middle image is stationary, but still needs to be shifted into the center of the larger canvas.  This is done with simple translation using a ``SimilarityTransform``.

.. code-block:: python

   from skimage.transform import warp
   from skimage.transform import SimilarityTransform

   offset1 = SimilarityTransform(
       translation= -corner_min)

   # Translate pano1 into place
   pano1_warped = warp(
       pano_images[1], offset1.inverse, order=3,
       output_shape=output_shape, cval=-1)

   # Acquire the image mask for later use
   # Mask == 1 inside image, then return backgroun to 0
   pano1_mask = (pano1_warped != -1)[..., 0]
   pano1_warped[~pano1_mask] = 0


Apply RANSAC-estimated transforms
*********************************

The other two images are warped by ``ProjectiveTransform`` into place.

.. code-block:: python

   # Warp left image
   transform01 = (model_ransac01 + offset1).inverse
   pano0_warped = warp(
       pano_images[0], transform01, order=3,
       output_shape=output_shape, cval=-1)

   # Mask == 1 inside image, then return backgroun to 0
   pano0_mask = (pano0_warped != -1)[..., 0]
   pano0_warped[~pano0_mask] = 0

   # Warp right image
   transform12 = (model_ransac12 + offset1).inverse
   pano2_warped = warp(
       pano_images[2], transform12, order=3,
       output_shape=output_shape, cval=-1)

   # Mask == 1 inside image, then return backgroun to 0
   pano2_mask = (pano2_warped != -1)[..., 0]
   pano1_warped[~pano1_mask] = 0

See the warped images in :ref:`fig-pano3`.

.. figure:: pano3_warped.png
   :align: center

   Each image is now correctly warped into a new frame with room for the others, ready to be composited/stitched together. :label:`fig-pano3`


Image stitching using minimum-cost path
***************************************

Because of optical non-linearities, simply averaging these images together will not work. The overlapping areas become significantly blurred.  Instead, a minimum-cost path can be found with the assistance of ``skimage.graph.route_through_array``. This function allows one to

* start at any point on an array
* find a particular path to any other point in the array
* the path found *minimizes* the sum of values on the path.

The array in this instance is a *cost array* which is carefully defined so the path found will be desired one, while the path itself is the *minimum-cost path*, or MCP. To use this technique we need starting and ending points, as well as a cost array.

Define seed points
******************

.. code-block:: python

   ymax = output_shape[1] - 1
   xmax = output_shape[0] - 1

   # Start anywhere along the top and bottom
   mask_pts01 = [[0,    ymax // 3],
                 [xmax, ymax // 3]]

   # Start anywhere along the top and bottom
   mask_pts12 = [[0,    2*ymax // 3],
                 [xmax, 2*ymax // 3]]


Construct cost array
********************
:label:`construct-costs`

For optimal results, great care goes into the creation of the cost array.  The function below is designed to construct the best possible cost array.  Its tasks are:

1. Start with a high-cost image filled with ones.
2. Use the mask - which defines where the overlapping region will be - to find the distance from the top/bottom edges to the masked area.
3. Reject mostly vertical areas.
4. Give a cost break to areas slightly further away, if the warped overlap is not parallel with the image edges, to ensure fair competition
5. Put the absolute value of the *difference* of the overlapping images in place

A convenience function ``generate_costs`` is provided in the Appendix which accomplishes the above.

.. code-block:: python

  # Use the generate_costs function
  costs01 = generate_costs(pano0_warped - pano1_warped,
                           pano0_mask & pano1_mask)
  costs12 = generate_costs(pano1_warped - pano2_warped,
                           pano1_mask & pano2_mask)


Find minimum-cost path and masks
********************************

Once the cost function is generated, the minimum cost path can be found simply and efficiently.

.. code-block:: python

   from skimage.graph import route_through_array

   # Find the MCP
   pts01, _ = route_through_array(
     costs01, mask_pts01[0], mask_pts01[1],
     fully_connected=True)

   pts01 = np.array(pts01)

   # Create final mask for the left image
   mask0 = np.zeros_like(pano0_warped[..., 0],
                         dtype=np.uint8)
   mask0[pts01[:, 0], pts01[:, 1]] = 1

   # Fill left side with flood_fill (in appendix)
   flood_fill(mask0, (0, 0), 1)

.. figure:: pano4_mcp.png
   :align: center
   :figclass: w
   :scale: 98%

   The minimum cost path in blue is the ideal stitching boundary. It stays as close to zero (mid-gray) as possible throughout its path.  The background is the cost array, with zero set to mid-gray for better visibility.  Note the subtle shading effect of cost reduction below the difference region.  Readers' paths may differ in appearance, but are optimal for their RANSAC-chosen transforms.

Because ``mask0`` is a *final* mask for the left image, it needs to constrain the solution for the right image. This step is essential if there is large overlap such that the left and right images could theoretically occupy the same space.  It ensures the MCPs will not cross.

.. code-block:: python

   # New constraint modifying cost array
   costs12[mask0 > 0] = 1

   pts12, _ = route_through_array(
     costs12, mask_pts12[0], mask_pts12[1],
     fully_connected=True)

   pts12 = np.array(pts12)

   # Final mask for right image
   mask2 = np.zeros_like(mask0, dtype=np.uint8)
   mask2[pts12[:, 0], pts12[:, 1]] = 1

   # Fill right side of image
   flood_fill(mask2, (mask2.shape[0] - 1,
                      mask2.shape[1] - 1), 1)

   # Mask for middle image is one of exclusion
   mask1 = ~(mask0 | mask2).astype(bool)


Blend images together with alpha channels
*****************************************

Most image formats can support an alpha channel as an optional fourth channel, which defines the transparency at each pixel.  We now have three warped images and three corresponding masks.  These masks can be incorporated as alpha channels to seamlessly blend them together.

.. code-block:: python

   # Convenience function for alpha blending
   def add_alpha(img, mask=None):
     """
     Adds a masked alpha channel to an image.

     Parameters
     ----------
     img : (M, N[, 3]) ndarray
         Image data, should be rank-2 or rank-3
         with RGB channels
     mask : (M, N[, 3]) ndarray, optional
         Mask to be applied. If None, the alpha channel
         is added with full opacity assumed (1) for all
         locations.
     """
     from skimage.color import gray2rgb
     if mask is None:
       mask = np.ones_like(img)

     if img.ndim == 2:
       img = gray2rgb(img)

     return np.dstack((img, mask))

   # Applying this function
   left_final = add_alpha(pano0_warped, mask0)
   middle_final = add_alpha(pano1_warped, mask1)
   right_final = add_alpha(pano2_warped, mask2)


Matplotlib's ``imshow`` supports alpha blending, but the default interpolation mode causes edge effects [Hunt07]_.  So as we create our final composite image, interpolation is disabled.

.. code-block:: python

   fig, ax = plt.subplots()

   # Turn off matplotlib's interpolation
   ax.imshow(left_final, interpolation='none')
   ax.imshow(middle_final, interpolation='none')
   ax.imshow(right_final, interpolation='none')

   ax.axis('off')
   fig.tight_layout()
   fig.show()

.. figure:: pano5_final.png
   :align: center
   :figclass: w
   :scale: 31%

   The final, seamlessly stitched panorama.


Final thoughts
--------------
Please cite the scikit-image paper [Van14]_ if you find ``scikit-image`` useful!  Citations allow developers to justify time invested in the package.

The authors would like to acknowledge and thank every contributor to ``scikit-image``.


References
----------
.. [Van14] van der Walt, S.; Schönberger, J. L.; Nunez-Iglesias, J;
           Boulogne, F; Warner, J. D.; Yager, N; Gouillart, E; Yu, T;
           the scikit-image contributors. *scikit-image: image
           processing in Python*, PeerJ, 2:e453, 2014.
           DOI:10.7717/peerj.453

.. [Oli07] Travis E. Oliphant. *Python for Scientific Computing.*
           Computing in Science & Engineering, 9:10-20, 2007. DOI:10.1109/MCSE.2007.58

.. [Jar11] Millman, K. J.; Aivazis, M. *Python for Scientists and
           Engineers.* Computing in Science & Engineering, 13:9-12,
           2011. DOI:10.1109/MCSE.2011.36

.. [Van11] van der Walt, S.; Colbert, S. C.; Varoquaux, G. *The
           NumPy Array: A Structure for Efficient Numerical
           Computation.* Computing in Science & Engineering, 13:22-30,
           2011. DOI:10.1109/MCSE.2011.37

.. [Hunt07] Hunter, J. D. *Matplotlib: A 2D graphics environment*,
            Computing In Science & Engineering, 9(3):90-95, 2007.
            DOI:10.5281/zenodo.61948

.. [Get12] Getreuer, P. *Rudin-Osher-Fatemi total variation
           denoising using split Bregman.* Image Processing On Line,
           2:74-95, 2012. DOI:10.5201/ipol.2012.g-tvd

.. [Cha04] Chambolle, A. *An algorithm for total variation
           minimization and applications.* Journal of Mathematical
           imaging and vision, 20(1-2):89-97, 2004.
           DOI: 10.1023/B:JMIV.0000011325.36760.1e

.. [Har88] Harris, C.; Stephens, M. *A combined corner and edge
           detector.* In Alvey vision conference 15:50, 1988.

.. [Tom98] Tomasi, C.; Manduchi, R. *Bilateral filtering for gray
           and color images.* IEEE Computer Vision, 1998. Sixth International Conference on, 839-846. 1998.

.. [Rub11] Rublee, E.; Rabaud, V.; Konolige, K.; Bradski, G.
           *ORB: an efficient alternative to SIFT or SURF*,
           IEEE International Conference on Computer Vision (ICCV),
           2564-2571, 2011. DOI:10.1109/ICCV.2011.6126544

.. [Fis81] Fischler, M. A.; Robert C. B. *Random sample consensus:
           a paradigm for model fitting with applications to image
           analysis and automated cartography.* Communications of
           the ACM, 24(6):381-395, 1981.


Appendix
--------

This supplemental appendix includes convenience functions which were deemed obstructive for the flow of the main chapter text.  They are referenced where appropriate above.  Including them resulted in more elegant and intuitive examples.

Minimum-cost-path cost array creation
*************************************
:label:`cost-arr-func`

This function generates an ideal cost array for panorama stitching, using the principles set forth in :ref:`construct-costs`.

.. code-block:: python

   def generate_costs(diff_image, mask,
                      vertical=True,
                      gradient_cutoff=2.,
                      zero_edges=True):
     """
     Ensure equal-cost paths from edges to
     region of interest.

     Parameters
     ----------
     diff_image : (M, N) ndarray of floats
         Difference of two overlapping images.
     mask : (M, N) ndarray of bools
         Mask representing the region of interest in
         ``diff_image``.
     vertical : bool
         Control if stitching line is vertical or
         horizontal.
     gradient_cutoff : float
         Controls how far out of parallel lines can
         be to edges before correction is terminated.
         The default (2.) is good for most cases.
     zero_edges : bool
         If True, the edges are set to zero so the
         seed is not bound to any specific horizontal
         location.

     Returns
     -------
     costs_arr : (M, N) ndarray of floats
         Adjusted costs array, ready for use.
     """
     if vertical is not True:  # run transposed
       return generate_costs(
         diff_image.T, mask.T, vertical=True,
         gradient_cutoff=gradient_cutoff).T

     # Start with a high-cost array of 1's
     diff_image = rgb2gray(diff_image)
     costs_arr = np.ones_like(diff_image)

     # Obtain extent of overlap
     row, col = mask.nonzero()
     cmin = col.min()
     cmax = col.max()

     # Label discrete regions
     cslice = slice(cmin, cmax + 1)
     labels = mask[:, cslice].astype(np.uint8).copy()

     # Fill top and bottom with unique labels
     masked_pts = np.where(labels)
     flood_fill(labels, (masked_pts[0][0],
                         masked_pts[1][0]), 2)
     flood_fill(labels, (0, labels.shape[0] // 2), 1)
     flood_fill(labels, (labels.shape[0] - 1,
                         labels.shape[1] // 2), 3)

     # Find distance from edge to region
     upper = (labels == 1).sum(axis=0)
     lower = (labels == 3).sum(axis=0)

     # Reject areas of high change
     ugood = np.abs(
       np.gradient(upper)) < gradient_cutoff
     lgood = np.abs(
       np.gradient(lower)) < gradient_cutoff

     # Cost break to areas slightly farther from edge
     costs_upper = np.ones_like(upper,
                                dtype=np.float64)
     costs_lower = np.ones_like(lower,
                                dtype=np.float64)
     costs_upper[ugood] = (
         upper.min() / np.maximum(upper[ugood], 1))
     costs_lower[lgood] = (
         lower.min() / np.maximum(lower[lgood], 1))

     # Expand from 1d back to 2d
     vdis = mask.shape[0]
     costs_upper = (
       costs_upper[np.newaxis, :].repeat(
         vdis, axis=0))
     costs_lower = (
       costs_lower[np.newaxis, :].repeat(
         vdis, axis=0))

     # Place these in output array
     costs_arr[:, cslice] = costs_upper * (labels==1)
     costs_arr[:, cslice] += costs_lower * (labels==3)

     # Finally, place the difference image
     costs_arr[mask] = np.abs(diff_image[mask])

     if zero_edges is True:  # top & bottom rows = 0
       costs_arr[0, :] = 0
       costs_arr[-1, :] = 0

     return costs_arr


Flood fill
**********
:label:`flood-fill`

This Cython function is a basic flood fill algorithm which accepts an array and modifies it in place.  The flood starts at a defined point, which is changed to a new value, then iteratively fills outward by doing the same at all connected points which carry the original value.

The conceptual analogy of this algorithm is the "bucket" tool in many photo editing programs.

.. code-block:: cython

   import cython
   import numpy as np
   cimport numpy as cnp


   # Compiler directives
   @cython.cdivision(True)
   @cython.boundscheck(False)
   @cython.nonecheck(False)
   @cython.wraparound(False)
   def flood_fill(unsigned char[:, ::1] image,
                  tuple start_coords,
                  Py_ssize_t fill_value):
     """
     Flood fill algorithm

     Parameters
     ----------
     image : (M, N) ndarray of uint8 type
         Image with flood to be filled. Modified
         inplace.
     start_coords : tuple
         Length-2 tuple of ints defining (row, col)
         start coordinates.
     fill_value : int
         Value to fill flooded area with.

     Returns
     -------
     None. ``image`` is modified inplace.
     """
     cdef:
       Py_ssize_t x, y, xsize, ysize, orig_value
       set stack

     xsize = image.shape[0]
     ysize = image.shape[1]
     orig_value = image[start_coords[0],
                        start_coords[1]]

     if fill_value == orig_value:
       raise ValueError(
         "Filling region with same value "
         "already present is unsupported. "
         "Did you already fill this region?")

     stack = set(((start_coords[0],
                   start_coords[1]), ))

     while stack:
       x, y = stack.pop()

       if image[x, y] == orig_value:
           image[x, y] = fill_value

           if x > 0:
             stack.add((x - 1, y))
           if x < (xsize - 1):
             stack.add((x + 1, y))
           if y > 0:
             stack.add((x, y - 1))
           if y < (ysize - 1):
             stack.add((x, y + 1))


================================================
FILE: papers/joshua_warner/reproduction_corner.ipynb
================================================
{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from __future__ import division, print_function\n",
    "%matplotlib inline\n",
    "%load_ext Cython"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Corner detection reproduction"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from skimage import data\n",
    "from skimage.transform import warp, AffineTransform\n",
    "\n",
    "affine = AffineTransform(\n",
    "    scale=(0.8, 1.1), rotation=1, shear=0.7, \n",
    "    translation=(220, 50))\n",
    "image = warp(data.checkerboard(), affine.inverse, \n",
    "             output_shape=(200, 310))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "fig, ax = plt.subplots()\n",
    "ax.imshow(image, cmap='gray', interpolation='none')\n",
    "ax.axis('off');"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from skimage.feature import (corner_harris,\n",
    "                             corner_subpix, \n",
    "                             corner_peaks)\n",
    "\n",
    "harris_coords = corner_peaks(corner_harris(image))\n",
    "harris_subpix = corner_subpix(image, harris_coords)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "fig, ax = plt.subplots(1, 2, figsize=(8, 4))\n",
    "ax[0].imshow(image, cmap='gray', interpolation='none')\n",
    "ax[0].set_title('Warped checkerboard', fontsize=20)\n",
    "ax[0].axis((0, 299, 199, 0))\n",
    "ax[0].axis('off')\n",
    "\n",
    "ax[1].imshow(image, cmap='gray', interpolation='none')\n",
    "ax[1].plot(harris_coords[:, 1], harris_coords[:, 0], '.b', markersize=10)\n",
    "ax[1].plot(harris_subpix[:, 1], harris_subpix[:, 0], '*r', markersize=10)\n",
    "ax[1].set_title('Sub-pixel corners', fontsize=20)\n",
    "ax[1].axis((0, 299, 199, 0))\n",
    "ax[1].axis('off')\n",
    "plt.show()\n",
    "\n",
    "fig.savefig('./harris_corners.png', dpi=300, bbox_inches=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}


================================================
FILE: papers/joshua_warner/reproduction_denoise.ipynb
================================================
{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from __future__ import division, print_function\n",
    "%matplotlib inline\n",
    "%load_ext Cython"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Denoise reproduction"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Types of image noise"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "noise_types = ['gaussian',\n",
    "               'poisson',\n",
    "               's&p',\n",
    "               'speckle']\n",
    "\n",
    "astro = img_as_float(data.astronaut())\n",
    "\n",
    "# Detail patch\n",
    "astro0 = astro[300:450, 100:320]\n",
    "\n",
    "fig, ax = plt.subplots(nrows=5, figsize=(3, 10))\n",
    "\n",
    "pretty_subplot(ax[0], astro0, 'original')\n",
    "\n",
    "gauss = random_noise(astro0, mode='gaussian', seed=42,\n",
    "                     var=0.15)\n",
    "poisson = random_noise(astro0, mode='poisson', seed=42)\n",
    "saltpepper = random_noise(astro0, mode='s&p', amount=0.2)\n",
    "speckle = random_noise(astro0, mode='speckle', var=0.15)\n",
    "\n",
    "pretty_subplot(ax[1], gauss, 'gaussian')\n",
    "pretty_subplot(ax[2], poisson, 'poisson')\n",
    "pretty_subplot(ax[3], saltpepper, 'salt & pepper')\n",
    "pretty_subplot(ax[4], speckle, 'speckle')\n",
    "\n",
    "fig.tight_layout()\n",
    "plt.show()\n",
    "fig.savefig('./noise_types.png', dpi=300, bbox_inches=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "random_noise?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "from skimage import data, img_as_float\n",
    "from skimage.restoration import (denoise_tv_chambolle, denoise_bilateral,\n",
    "                                 denoise_wavelet, estimate_sigma)\n",
    "from skimage.util import random_noise\n",
    "\n",
    "\n",
    "# astro = img_as_float(data.astronaut())\n",
    "# astro = astro[220:300, 220:320]\n",
    "astro=astro0\n",
    "\n",
    "sigma = 0.3\n",
    "noisy = random_noise(astro, 'speckle', var=sigma**2, seed=42)\n",
    "\n",
    "fig, ax = plt.subplots(nrows=4, ncols=2, figsize=(5, 7.3))\n",
    "\n",
    "def pretty_subplot(ax, image, title=None, ylabel=None):\n",
    "    ax.imshow(image)\n",
    "    ax.set_xticks([]) \n",
    "    ax.set_yticks([])\n",
    "    ax.spines['top'].set_visible(False)\n",
    "    ax.spines['right'].set_visible(False)\n",
    "    ax.spines['bottom'].set_visible(False)\n",
    "    ax.spines['left'].set_visible(False)\n",
    "    if title is not None:\n",
    "        ax.set_title(title)\n",
    "    if ylabel is not None:\n",
    "        ax.set_ylabel(ylabel)\n",
    "\n",
    "pretty_subplot(ax[0, 0], astro, 'original')\n",
    "pretty_subplot(ax[0, 1], noisy, 'noisy')\n",
    "\n",
    "pretty_subplot(ax[1, 0], \n",
    "               denoise_tv_chambolle(noisy, weight=0.05, \n",
    "                                    multichannel=True),\n",
    "               'weight: 0.05',\n",
    "               'TV-Chambolle')\n",
    "pretty_subplot(ax[1, 1], \n",
    "               denoise_tv_chambolle(noisy, weight=0.1, \n",
    "                                    multichannel=True),\n",
    "               'weight: 0.1')\n",
    "\n",
    "pretty_subplot(ax[2, 0],\n",
    "               denoise_bilateral(noisy, sigma_color=0.05, sigma_spatial=15),\n",
    "               r'$\\sigma_{color}$:0.05, $\\sigma_{spatial}$:25',\n",
    "               'Bilateral')\n",
    "pretty_subplot(ax[2, 1],\n",
    "               denoise_bilateral(noisy, sigma_color=0.1, sigma_spatial=20),\n",
    "               r'$\\sigma_{color}$:0.1, $\\sigma_{spatial}$:20')\n",
    "\n",
    "# Estimate sigma for wavelet\n",
    "sigma_est = estimate_sigma(noisy, multichannel=True, average_sigmas=True)\n",
    "pretty_subplot(ax[3, 0],\n",
    "               denoise_wavelet(noisy, sigma=sigma_est,\n",
    "                               multichannel=True),\n",
    "               r'$\\sigma$: estimated',\n",
    "               'Wavelet')\n",
    "pretty_subplot(ax[3, 1],\n",
    "               denoise_wavelet(noisy, sigma=1.4*sigma_est,\n",
    "                               multichannel=True),\n",
    "               r'$\\sigma$: 1.4*estimated')\n",
    "\n",
    "fig.tight_layout(h_pad=0.7, w_pad=0.3)\n",
    "\n",
    "plt.show()\n",
    "\n",
    "fig.savefig('./denoise.png', dpi=300, bbox_inches=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}


================================================
FILE: papers/joshua_warner/reproduction_pano.ipynb
================================================
{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from __future__ import division, print_function\n",
    "%matplotlib inline\n",
    "%load_ext Cython"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Reproduction notebook for Panorama stitching"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from skimage import io\n",
    "pano_images = io.ImageCollection(\n",
    "    './images/JDW_9*')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def compare(*images, **kwargs):\n",
    "    \"\"\"\n",
    "    Utility function to display images side by side.\n",
    "    \n",
    "    Parameters\n",
    "    ----------\n",
    "    image0, image1, image2, ... : ndarrray\n",
    "        Images to display.\n",
    "    labels : list\n",
    "        Labels for the different images.\n",
    "    \"\"\"\n",
    "    if 'vertical' in kwargs:\n",
    "        vertical = kwargs.pop('vertical')\n",
    "    else:\n",
    "        vertical = False\n",
    "        \n",
    "    if vertical is not True:\n",
    "        f, axes = plt.subplots(1, len(images), **kwargs)\n",
    "    else:\n",
    "        f, axes = plt.subplots(len(images), 1, **kwargs)\n",
    "\n",
    "    axes = np.array(axes, ndmin=1)\n",
    "    \n",
    "    labels = kwargs.pop('labels', None)\n",
    "    if labels is None:\n",
    "        labels = [''] * len(images)\n",
    "    \n",
    "    for n, (image, label) in enumerate(zip(images, labels)):\n",
    "        axes[n].imshow(image, interpolation='nearest', cmap='gray')\n",
    "        axes[n].set_title(label)\n",
    "        axes[n].axis('off')\n",
    "    \n",
    "    f.subplots_adjust(left=0, right=1, top=1, bottom=0, hspace=0.01, wspace=0.01)\n",
    "    return f, axes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "f, axes = compare(*pano_images, figsize=(12, 10));\n",
    "# f.savefig('./pano0-originals.png', dpi=300, pad_inches=0, bbox_inches='tight')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "from skimage.color import rgb2gray\n",
    "from skimage.feature import (ORB, match_descriptors,\n",
    "                             plot_matches)\n",
    "\n",
    "# Initialize ORB\n",
    "orb = ORB(n_keypoints=800, fast_threshold=0.05)\n",
    "keypoints = []\n",
    "descriptors = []\n",
    "\n",
    "# Detect features\n",
    "for image in pano_images:\n",
    "    orb.detect_and_extract(rgb2gray(image))\n",
    "    keypoints.append(orb.keypoints)\n",
    "    descriptors.append(orb.descriptors)\n",
    "\n",
    "# Match features from images 0 -> 1 and 2 -> 1\n",
    "matches01 = match_descriptors(descriptors[0],\n",
    "                              descriptors[1],\n",
    "                              cross_check=True)\n",
    "matches12 = match_descriptors(descriptors[1],\n",
    "                              descriptors[2],\n",
    "                              cross_check=True)\n",
    "\n",
    "# Show raw matched features from left to center\n",
    "fig, ax = plt.subplots()\n",
    "plot_matches(ax, pano_images[0], pano_images[1],\n",
    "             keypoints[0], keypoints[1], matches01)\n",
    "ax.axis('off');\n",
    "# fig.savefig('./pano1_ORB-raw.png', dpi=500, pad_inches=0, bbox_inches='tight')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from skimage.measure import ransac\n",
    "from skimage.transform import ProjectiveTransform\n",
    "\n",
    "# Keypoints from left (src) to middle (dst) images\n",
    "src = keypoints[0][matches01[:, 0]][:, ::-1]\n",
    "dst = keypoints[1][matches01[:, 1]][:, ::-1]\n",
    "\n",
    "model_ransac01, inliers01 = ransac(\n",
    "    (src, dst), ProjectiveTransform, min_samples=4,\n",
    "    residual_threshold=1, max_trials=300)\n",
    "\n",
    "# Keypoints from right (src) to middle (dst) images\n",
    "src = keypoints[2][matches12[:, 1]][:, ::-1]\n",
    "dst = keypoints[1][matches12[:, 0]][:, ::-1]\n",
    "\n",
    "model_ransac12, inliers12 = ransac(\n",
    "    (src, dst), ProjectiveTransform, min_samples=4,\n",
    "    residual_threshold=1, max_trials=300)\n",
    "\n",
    "# Show robust, RANSAC-matched features\n",
    "fig, ax = plt.subplots()\n",
    "plot_matches(ax, pano_images[0], pano_images[1],\n",
    "             keypoints[0], keypoints[1],\n",
    "             matches01[inliers01])\n",
    "ax.axis('off');\n",
    "# fig.savefig('./pano2_ORB-RANSAC.png', dpi=500, pad_inches=0, bbox_inches='tight')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# All three images have the same size\n",
    "r, c = pano_images[1].shape[:2]\n",
    "\n",
    "# Note that transformations take coordinates in\n",
    "# (x, y) format, not (row, column), for literature\n",
    "# consistency\n",
    "corners = np.array([[0, 0],\n",
    "                    [0, r],\n",
    "                    [c, 0],\n",
    "                    [c, r]])\n",
    "\n",
    "# Warp image corners to their new positions\n",
    "warped_corners01 = model_ransac01(corners)\n",
    "warped_corners12 = model_ransac12(corners)\n",
    "\n",
    "# Extents of both target and warped images\n",
    "all_corners = np.vstack((warped_corners01,\n",
    "                         warped_corners12,\n",
    "                         corners))\n",
    "\n",
    "# Overall output shape is max - min\n",
    "corner_min = np.min(all_corners, axis=0)\n",
    "corner_max = np.max(all_corners, axis=0)\n",
    "output_shape = (corner_max - corner_min)\n",
    "\n",
    "# Ensure integer shape\n",
    "output_shape = np.ceil(\n",
    "    output_shape[::-1]).astype(int)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from skimage.transform import warp, SimilarityTransform\n",
    "\n",
    "offset1 = SimilarityTransform(translation= -corner_min)\n",
    "\n",
    "# Translate pano1 into place\n",
    "pano1_warped = warp(\n",
    "    pano_images[1], offset1.inverse, order=3,\n",
    "    output_shape=output_shape, cval=-1)\n",
    "\n",
    "# Acquire the image mask for later use\n",
    "# Mask == 1 inside image, then return backgroun to 0\n",
    "pano1_mask = (pano1_warped != -1)[..., 0]\n",
    "pano1_warped[~pano1_mask] = 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from skimage.transform import warp, SimilarityTransform\n",
    "\n",
    "offset1 = SimilarityTransform(translation= -corner_min)\n",
    "\n",
    "# Translate pano1 into place\n",
    "pano1_warped = warp(\n",
    "    pano_images[1], offset1.inverse, order=3,\n",
    "    output_shape=output_shape, cval=-1)\n",
    "\n",
    "# Acquire the image mask for later use\n",
    "# Mask == 1 inside image, then return backgroun to 0\n",
    "pano1_mask = (pano1_warped != -1)[..., 0]\n",
    "pano1_warped[~pano1_mask] = 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# Warp left image\n",
    "transform01 = (model_ransac01 + offset1).inverse\n",
    "pano0_warped = warp(\n",
    "    pano_images[0], transform01, order=3,\n",
    "    output_shape=output_shape, cval=-1)\n",
    "\n",
    "# Mask == 1 inside image, then return backgroun to 0\n",
    "pano0_mask = (pano0_warped != -1)[..., 0]\n",
    "pano0_warped[~pano0_mask] = 0\n",
    "\n",
    "# Warp right image\n",
    "transform12 = (model_ransac12 + offset1).inverse\n",
    "pano2_warped = warp(\n",
    "    pano_images[2], transform12, order=3,\n",
    "    output_shape=output_shape, cval=-1)\n",
    "\n",
    "# Mask == 1 inside image, then return backgroun to 0\n",
    "pano2_mask = (pano2_warped != -1)[..., 0]\n",
    "pano1_warped[~pano1_mask] = 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "f, ax = compare(pano0_warped, pano1_warped, pano2_warped, vertical=True)\n",
    "# f.savefig('./pano3_warped.png', dpi=500, pad_inches=0, bbox_inches='tight')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "ymax = output_shape[1] - 1\n",
    "xmax = output_shape[0] - 1\n",
    "\n",
    "# Start anywhere along the top and bottom\n",
    "mask_pts01 = [[0,    ymax // 3],\n",
    "              [xmax, ymax // 3]]\n",
    "\n",
    "# Start anywhere along the top and bottom\n",
    "mask_pts12 = [[0,    2*ymax // 3],\n",
    "              [xmax, 2*ymax // 3]]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Cost array and flood fill functions from appendix"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "%%cython\n",
    "import cython\n",
    "import numpy as np\n",
    "cimport numpy as cnp\n",
    "\n",
    "\n",
    "# Compiler directives\n",
    "@cython.cdivision(True)\n",
    "@cython.boundscheck(False)\n",
    "@cython.nonecheck(False)\n",
    "@cython.wraparound(False)\n",
    "def flood_fill(unsigned char[:, ::1] data, tuple start_coords,\n",
    "               Py_ssize_t fill_value):\n",
    "    \"\"\"\n",
    "    Flood fill algorithm\n",
    "    \n",
    "    Parameters\n",
    "    ----------\n",
    "    data : (M, N) ndarray of uint8 type\n",
    "        Image with flood to be filled. Modified inplace.\n",
    "    start_coords : tuple\n",
    "        Length-2 tuple of ints defining (row, col) start coordinates.\n",
    "    fill_value : int\n",
    "        Value the flooded area will take after the fill.\n",
    "        \n",
    "    Returns\n",
    "    -------\n",
    "    None, ``data`` is modified inplace.\n",
    "    \"\"\"\n",
    "    cdef:\n",
    "        Py_ssize_t x, y, xsize, ysize, orig_value, ystart, xstart\n",
    "        set stack\n",
    "    \n",
    "    xsize = data.shape[0]\n",
    "    ysize = data.shape[1]\n",
    "    xstart = start_coords[0]\n",
    "    ystart = start_coords[1]\n",
    "    orig_value = data[start_coords[0], start_coords[1]]\n",
    "    \n",
    "    if fill_value == orig_value:\n",
    "        raise ValueError(\"Filling region with same value \"\n",
    "                         \"already present is unsupported. \"\n",
    "                         \"Did you already fill this region?\")\n",
    "    \n",
    "    stack = set(((start_coords[0], start_coords[1]),))\n",
    "\n",
    "    while stack:\n",
    "        x, y = stack.pop()\n",
    "\n",
    "        if data[x, y] == orig_value:\n",
    "            data[x, y] = fill_value\n",
    "            if x > 0:\n",
    "                stack.add((x - 1, y))\n",
    "            if x < (xsize - 1):\n",
    "                stack.add((x + 1, y))\n",
    "            if y > 0:\n",
    "                stack.add((x, y - 1))\n",
    "            if y < (ysize - 1):\n",
    "                stack.add((x, y + 1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def generate_costs(diff_image, mask, vertical=True,\n",
    "                   gradient_cutoff=2.,\n",
    "                   zero_edges=True):\n",
    "    \"\"\"\n",
    "    Ensure equal-cost paths from edges to\n",
    "    region of interest.\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    diff_image : (M, N) ndarray of floats\n",
    "        Difference of two overlapping images.\n",
    "    mask : (M, N) ndarray of bools\n",
    "        Mask representing the region of interest in\n",
    "        ``diff_image``.\n",
    "    vertical : bool\n",
    "        Control if stitching line is vertical or\n",
    "        horizontal.\n",
    "    gradient_cutoff : float\n",
    "        Controls how far out of parallel lines can\n",
    "        be to edges before correction is terminated.\n",
    "        The default (2.) is good for most cases.\n",
    "    zero_edges : bool\n",
    "        If True, the edges are set to zero so the\n",
    "        seed is not bound to any specific horizontal\n",
    "        location.\n",
    "\n",
    "    Returns\n",
    "    -------\n",
    "    costs_arr : (M, N) ndarray of floats\n",
    "        Adjusted costs array, ready for use.\n",
    "    \"\"\"\n",
    "    if vertical is not True:  # run transposed\n",
    "        return generate_costs(\n",
    "            diff_image.T, mask.T, vertical=True,\n",
    "            gradient_cutoff=gradient_cutoff).T\n",
    "\n",
    "    # Start with a high-cost array of 1's\n",
    "    diff_image = rgb2gray(diff_image)\n",
    "    costs_arr = np.ones_like(diff_image)\n",
    "\n",
    "    # Obtain extent of overlap\n",
    "    row, col = mask.nonzero()\n",
    "    cmin = col.min()\n",
    "    cmax = col.max()\n",
    "\n",
    "    # Label discrete regions\n",
    "    cslice = slice(cmin, cmax + 1)\n",
    "    labels = mask[:, cslice].astype(np.uint8).copy()\n",
    "\n",
    "    # Fill top and bottom with unique labels\n",
    "    masked_pts = np.where(labels)\n",
    "    flood_fill(labels, (masked_pts[0][0], \n",
    "                        masked_pts[1][0]), 2)\n",
    "    flood_fill(labels, (0, labels.shape[0] // 2), 1)\n",
    "    flood_fill(labels, (labels.shape[0] - 1, \n",
    "                        labels.shape[1] // 2), 3)\n",
    "\n",
    "    # Find distance from edge to region\n",
    "    upper = (labels == 1).sum(axis=0)\n",
    "    lower = (labels == 3).sum(axis=0)\n",
    "\n",
    "    # Reject areas of high change\n",
    "    ugood = np.abs(\n",
    "        np.gradient(upper)) < gradient_cutoff\n",
    "    lgood = np.abs(\n",
    "        np.gradient(lower)) < gradient_cutoff\n",
    "\n",
    "    # Cost break to areas slightly farther from edge\n",
    "    costs_upper = np.ones_like(upper,\n",
    "                               dtype=np.float64)\n",
    "    costs_lower = np.ones_like(lower,\n",
    "                               dtype=np.float64)\n",
    "    costs_upper[ugood] = (\n",
    "        upper.min() / np.maximum(upper[ugood], 1))\n",
    "    costs_lower[lgood] = (\n",
    "        lower.min() / np.maximum(lower[lgood], 1))\n",
    "\n",
    "    # Expand from 1d back to 2d\n",
    "    vdis = mask.shape[0]\n",
    "    costs_upper = (\n",
    "        costs_upper[np.newaxis, :].repeat(vdis, axis=0))\n",
    "    costs_lower = (\n",
    "        costs_lower[np.newaxis, :].repeat(vdis, axis=0))\n",
    "\n",
    "    # Place these in output array\n",
    "    costs_arr[:, cslice] = costs_upper * (labels==1)\n",
    "    costs_arr[:, cslice] += costs_lower * (labels==3)\n",
    "\n",
    "    # Finally, place the difference image\n",
    "    costs_arr[mask] = np.abs(diff_image[mask])\n",
    "\n",
    "    if zero_edges is True:  # top & bottom rows = zero\n",
    "        costs_arr[0, :] = 0\n",
    "        costs_arr[-1, :] = 0\n",
    "\n",
    "    return costs_arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# Use the generate_costs function\n",
    "costs01 = generate_costs(pano0_warped - pano1_warped,\n",
    "                         pano0_mask & pano1_mask)\n",
    "costs12 = generate_costs(pano1_warped - pano2_warped,\n",
    "                         pano1_mask & pano2_mask)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from skimage.graph import route_through_array\n",
    "\n",
    "# Find the MCP\n",
    "pts01, _ = route_through_array(\n",
    "    costs01, mask_pts01[0], mask_pts01[1],\n",
    "    fully_connected=True)\n",
    "\n",
    "pts01 = np.array(pts01)\n",
    "\n",
    "# Create final mask for the left image\n",
    "mask0 = np.zeros_like(pano0_warped[..., 0],\n",
    "                      dtype=np.uint8)\n",
    "mask0[pts01[:, 0], pts01[:, 1]] = 1\n",
    "flood_fill(mask0, (0, 0), 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "fig, ax = plt.subplots(figsize=(12, 12))\n",
    "import skimage.morphology as morph\n",
    "\n",
    "# Plot the difference image\n",
    "ax.imshow(costs01, cmap='gray', vmin=-1 * costs01.max(), vmax=costs01.max())\n",
    "\n",
    "# Overlay the minimum-cost path\n",
    "ax.plot(pts01[:, 1], pts01[:, 0])  \n",
    "\n",
    "plt.tight_layout()\n",
    "ax.axis('off');\n",
    "# fig.savefig('./pano4_mcp.png', dpi=600, bbox_inches='tight')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# New constraint modifying cost array\n",
    "costs12[mask0 > 0] = 1\n",
    "\n",
    "pts12, _ = route_through_array(\n",
    "    costs12, mask_pts12[0], mask_pts12[1],\n",
    "    fully_connected=True)\n",
    "\n",
    "pts12 = np.array(pts12)\n",
    "\n",
    "# Final mask for right image\n",
    "mask2 = np.zeros_like(mask0, dtype=np.uint8)\n",
    "mask2[pts12[:, 0], pts12[:, 1]] = 1\n",
    "flood_fill(mask2, (mask2.shape[0] - 1,\n",
    "                   mask2.shape[1] - 1), 1)\n",
    "\n",
    "# Mask for middle image is one of exclusion\n",
    "mask1 = ~(mask0 | mask2).astype(bool)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "fig, ax = plt.subplots(figsize=(12, 12))\n",
    "import skimage.morphology as morph\n",
    "\n",
    "# Plot the difference image\n",
    "ax.imshow(costs12, cmap='gray', vmin=-1 * costs12.max(), vmax=costs12.max())\n",
    "\n",
    "# Overlay the minimum-cost path\n",
    "ax.plot(pts12[:, 1], pts12[:, 0])  \n",
    "\n",
    "plt.tight_layout()\n",
    "ax.axis('off');\n",
    "# fig.savefig('./pano4_mcp.png', dpi=600, bbox_inches='tight')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# Convenience function for alpha blending\n",
    "def add_alpha(img, mask=None):\n",
    "    \"\"\"\n",
    "    Adds a masked alpha channel to an image.\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    img : (M, N[, 3]) ndarray\n",
    "        Image data, should be rank-2 or rank-3\n",
    "        with RGB channels\n",
    "    mask : (M, N[, 3]) ndarray, optional\n",
    "        Mask to be applied. If None, the alpha channel\n",
    "        is added with full opacity assumed (1) for all\n",
    "        locations.\n",
    "    \"\"\"\n",
    "    from skimage.color import gray2rgb\n",
    "    if mask is None:\n",
    "        mask = np.ones_like(img)\n",
    "\n",
    "    if img.ndim == 2:\n",
    "        img = gray2rgb(img)\n",
    "\n",
    "    return np.dstack((img, mask))\n",
    "\n",
    "# Applying this function\n",
    "left_final = add_alpha(pano0_warped, mask0)\n",
    "middle_final = add_alpha(pano1_warped, mask1)\n",
    "right_final = add_alpha(pano2_warped, mask2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "fig, ax = plt.subplots()\n",
    "\n",
    "# Turn off matplotlib's interpolation\n",
    "ax.imshow(left_final, interpolation='none')\n",
    "ax.imshow(middle_final, interpolation='none')\n",
    "ax.imshow(right_final, interpolation='none')\n",
    "\n",
    "ax.axis('off')\n",
    "fig.tight_layout()\n",
    "fig.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from skimage.color import gray2rgb\n",
    "\n",
    "# Start with empty image\n",
    "pano_combined = np.zeros_like(pano0_warped)\n",
    "\n",
    "# Place the masked portion of each image into the array\n",
    "# masks are 2d, they need to be (M, N, 3) to match the color images\n",
    "pano_combined += pano0_warped * gray2rgb(mask0)\n",
    "pano_combined += pano1_warped * gray2rgb(mask1)\n",
    "pano_combined += pano2_warped * gray2rgb(mask2)\n",
    "\n",
    "# Save the output - precision loss warning is expected\n",
    "# moving from floating point -> uint8\n",
    "fig, ax = plt.subplots()\n",
    "ax.imshow(pano_combined)\n",
    "ax.axis('off');\n",
    "plt.show()\n",
    "# io.imsave('./pano5_final.png', pano_combined)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}


================================================
FILE: papers/maxwell_margenot/bayesian_linear_regression.ipynb
================================================
{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Bayesian Generalized Linear Models in PyMC3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Introduction\n",
    "\n",
    "There are a number of packages in the Python ecosystem that are used heavily in statistical modeling. We will make use of several of them (`NumPy`, `pandas`) throughout the course of this chapter, but our main focus here is Bayesian modeling. Specifically we will be focusing on modifying several of our standard statistical methodologies to function within a Bayesian framework. We will discuss why a Bayesian approach is a reasonable one to take and show examples of Generalized Linear Model (GLM) implementation in PyMC3, a probabilistic programming package with intuitive syntax for defining flexible statistical models. We start with a basic Bayesian linear regression model, explaining the theory, and build up into a hierarchical linear regression model.\n",
    "\n",
    "## Generalized Linear Models (GLM)\n",
    "\n",
    "A Generalized Linear Model (GLM) is a blanket term for many of our standard linear models in statistics. This generalization allows for the assignment of arbitrary distributions to response variables, encompassing both linear and logistic regression, and allows us to create Bayesian implementations of these classical ideas. We can formulate parameters and outcomes of these models as random variables, quantifying the uncertainty in terms of probabilities.\n",
    "\n",
    "## Probabilistic Programming and Bayes' Rule\n",
    "\n",
    "In probabilistic programming, we define the components of our model as random variables. We apply Bayes' rule to adapt our initial model, incorporating observed data $\\mathbf{X}$ to infer unknown causes $\\theta$. Bayes' rule is defined as follows:\n",
    "\n",
    "$$ P(\\theta\\ |\\ \\mathbf{X}) = \\frac{P(\\mathbf{X}\\ |\\ \\theta)\\  P(\\theta)}{P(\\mathbf{X})} \\propto P(\\mathbf{X}\\ |\\ \\theta)\\  P(\\theta) $$\n",
    "\n",
    "Bayes' rule allows us to derive a posterior distribution $P(\\theta\\ |\\ \\mathbf{X})$ based on our likelihood $P(\\mathbf{X}\\ |\\ \\theta)$ and prior distribution $P(\\theta)$. \n",
    "\n",
    "Calculating the posterior distribution analytically can be complicated, especially with more complex models. Fortunately, we do not have to deal with that. With probabilistic programming, we define our priors and our likelihood and let sampling algorithms approximate the posterior! Let's modify our definition of linear regression to incorporate these principles.\n",
    "\n",
    "## Linear Regression\n",
    "\n",
    "The first GLM that we will cover is linear regression. Linear regression is a standard quantitative tool in every statistician's toolbox. It provides a simple, easy-to-understand framework for expressing a linear relationship between dependent and independent variables and can be readily applied in many situations. A standard linear regression takes the form of:\n",
    "\n",
    "$$ Y = X\\beta + \\epsilon $$\n",
    "\n",
    "Where $Y$ is the dependent variable, $X$ is our independent variable, $\\beta$ are the coefficients for each feature in $X$, and $\\epsilon$ is our error, assumed to be normally-distributed.\n",
    "\n",
    "There are several ways to fit the coefficients. We typically use either Ordinary Least Squares (OLS) to find the Maximum Likelihood Estimate (MLE).\n",
    "\n",
    "## Probabilistic Regression\n",
    "\n",
    "To reformulate this linear regression with a Bayesian methodology, we say that:\n",
    "\n",
    "$$ Y \\sim \\mathcal{N}(X\\beta, \\sigma^2) $$\n",
    "\n",
    "In other words, we assume that our response variable will follow a normal distribution with mean $X\\beta$ and variance $\\sigma^2$. With Bayesian inference, the key component is that we define the pieces of our model as probability distributions. The above is the basic formulation of the model, but *everything* is a probability distribution. All of the parameters of our model will have prior distributions associated with them so we need a way to easily define random variables. This is where we apply PyMC3 and the principles of probabilistic programming.\n",
    "\n",
    "## PyMC3\n",
    "\n",
    "All of our examples in this chapter will showcase the use of PyMC3 to formulate models in the aforementioned way. PyMC3 is an open source probabilistic programming framework that allows us to define entire Bayesian models using Python code. It uses Marokov Chain Monte Carlo and variational inference methods to approximate the posterior. For speed, PyMC3 uses `Theano` as a backend.\n",
    "\n",
    "## Advantages of the Bayesian Approach\n",
    "\n",
    "At their cores, both the frequentist and Bayesian approaches try to get at the same solution. They only differ in how they go about it. By incorporating Bayesian statistics into our methodology, we allow for the inclusion of prior distributions. Priors allow us to include our own views about our parameters into the model which act as regularizers. \n",
    "\n",
    "In addition, the $\\beta$ \"values\" that we calculate through this Bayesian approach are themselves complete posterior distributions instead of point estimates (hence the scare-quotes). A point estimate will have a confidence interval, but a posterior distribution provides us with a much more robust understanding of the uncertainty. Quantifying uncertainty as probability is the cornerstone of Bayesian inference."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Defining a Toy Example\n",
    "\n",
    "Let's generate some simple data for use with our new approach. Toy examples are always a little boring, but it is important to understand the basic approach before we get into a real world problem."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "\n",
    "import pymc3 as pm\n",
    "import theano.tensor as tt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "sns.set_style('whitegrid')\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "N = 100\n",
    "intercept = 1\n",
    "slope = 2\n",
    "noise = 0.5\n",
    "\n",
    "x = np.random.normal(0, 1, N)\n",
    "true_line = intercept + slope*x\n",
    "y = true_line + np.random.normal(0, noise, size=N)\n",
    "\n",
    "data = dict(x=x, y=y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n9uzZI0maOXOmxo0bp8mTJys1NVVnn322Pv/8c7322mvq27evTj31VM2fP7/qWN27d9dbb72lc889\nVyeddJLuvPPOqmO5+u6773TNNdfohBNO0MCBA/X6669Xe37BggU666yz1Lt3bz333HM1vr/i4mLd\nfvvtOumkk3TBBRdo7dq11Z5fvXq1rrjiCp144olKTU3V6NGj9euvv0qSzjnnHEnS2WefXTU09/nn\nn9fZZ5+t448/XmeccYZmzpxZl48ZAAAAgI8Imn6QlZ2rnLwCFe4qVU5egbKycwN2rnXr1mnatGl6\n4IEHtHTpUvXq1Utjx46VJG3dulWZmZm68sortXTpUmVlZemLL75QdnZ21f4ffPCB4uPjtXjxYvXs\n2VNjx47Vf/7zH82fP19XX321pk6dqt9///3ge8vK0n333af58+fLsixNmjTJraaysjKNHj1aaWlp\nev/99zVu3Dg9++yzWrx4sSTps88+05QpU3T77bcrOztba9eu1Y4dO7y+x/vvv1+bNm3S66+/rvvu\nu08vv/xy1XPFxcW66aabdMYZZ+iDDz7QnDlztGXLFr3wwguSpIULF0qS3nrrLQ0aNEjvvPOO5s+f\nrylTpujDDz/UrbfeqpkzZ2rdunUN+CoAAAAAqAlB0w/ytxXV+NiffvzxRzVt2lSJiYlKTEzU2LFj\nNW3aNJWXl6u8vFyTJk3S8OHDlZiYqNNOO02nnXaaNmzYULV/x44d9X//93/q0qWLhg0bpuLiYk2c\nOFFHHnmkRo0apf3792vLli1Vr7/xxht15pln6rjjjtPEiRP1j3/8Q8XFxdVqWrx4sTp16lR13P79\n++umm27S3LlzJdmhb8iQIRo8eLCSk5M1ZcoUtWzZ0uP7Ky4u1tKlSzVx4kR1795dffv21S233FL1\nfGlpqcaMGaObb75ZiYmJSk1N1XnnnVf1Hjt27ChJ6tChg1q2bKnExERNmTJFp5xyihITE5Wenq5D\nDjlE33//vV++HgAAAADcNQ91AY1BclK8CvNKqz0OlNNPP13HHHOMLrroIqWkpGjAgAEaOXKkmjZt\nqiOOOEItW7bU888/r++//17ff/+98vPzNWTIkKr9k5KSqv4eGxsrSTrssMMkSTExMZKkvXv3Vr0m\nNTW16u/HH3+89u/fr02bNlWr6YcfftD69eurvba8vFwtWrSQJOXn5+vyyy+veq59+/bq0qWLx/e3\nceNGlZeXV1tltkePHlV/P+SQQzR06FDNnTtX69at04YNG2RZlk466SSPxzv55JO1Zs0azZgxQ/n5\n+Vq3bp1+++03lZeXe3w9AAAAgIajo+kHmempSktJUMd2sUpLSVBmemrtO/koNjZWCxcu1Lx583TK\nKado0aJFuuSSS/Tzzz9r/fr1uvDCC5Wfn6+0tDRNmTJFAwcOrLZ/s2bN6nW+5s0P/i6iMpw1bVr9\nsjlw4IBOPfVULV68uOq/999/X4sWLap6TUVFRbV9KkOoN86vd35tQUGBBg8erJUrV+r444/Xvffe\nq7/85S9ej7Nw4UJlZGRo7969Ov/88/XKK68oISGhxnMDAAAAaBg6mn4QHxejSaP6BOVcX3/9tVau\nXKmbbrpJJ598sv7617+qb9++Wr16tdasWaOTTz5Z06ZNq3r95s2bddRRR/l8vnXr1skYI0lau3at\nWrZsqW7dusmyrKrXdOvWTR9//LGSkpKqVnx999139e233+ree+/V0UcfXW1Bn+LiYm3evNnj+bp1\n66bmzZtr7dq16tPH/kzz8vKqnl++fLk6dOig559/vmrbvHnzqoJpkyZNqoXUBQsW6NZbb9V1110n\nSdq1a5d+/fVXt+ALAAAAwH/oaEaY2NhYzZw5UwsXLtSPP/6oJUuWaM+ePTLGqEOHDrIsS2vWrNHG\njRv12GOPae3atdWGwtbXU089pZycHH3zzTd65JFHNGzYMLVq1araa4YMGaLS0lLdd999+uGHH/Sv\nf/1LU6ZM0SGHHCJJuvLKK/WPf/xDCxcu1A8//KBJkyaprMzzyrxxcXEaOnSoJk+erDVr1ui///1v\ntVVi27dvr+3bt2vFihXaunWrXnzxRS1btkz79u2TpKra1q9fr5KSErVv315ffPGFNm3apP/973/6\n61//qgMHDjToMwEAAABQMzqaEaZ79+569NFH9cwzz2jy5MlKTEzUtGnTdOSRR+rqq6/WunXrdN11\n1ykmJka9e/fWrbfeqiVLltT5+E2aNKl2H8phw4Zp3LhxKi4u1kUXXaTx48e77dOmTRu99NJLmjJl\nioYNG6b27dvr6quv1ujRoyVJvXv31qOPPqonn3xShYWFGj58eLU5mK7uu+8+TZ48Wdddd53atWun\na665RlOnTpUkDRw4UF9++WXVSrs9evTQPffco6efflr79u1Thw4dNGTIEI0dO1Z33nmnJk6cqPHj\nx+viiy9Wx44dNWjQILVp06ZalxQAAACAfzVp7EMIV69efZKk1V27dlWnTp1CXU5E6d69u+bPn6+0\ntLRQlxJ0JSUlWrdunY499li1bt061OUgQnDdwBdcN/AF1w18Ec7XzYHyA2rWtH5riSA4fvvtt8rF\nQHv16tXrq7ruR0cTAAAAgE+KisuUlZ2r/G1FSk6KV2Z6quLjYuq8/74D+3TlW7dJks5NPkM39L4i\nUKUiyJijCa+ch9ACAAAArrKyc5WTV6DCXaXKyStQVnZunfctKP6lKmRK0hdbvmTBxkaEjia8Wrdu\nXahLAAAAQIA0tBspSfnbimp87M1/t+Xqic9frLat9OcEPTznvz7VgfBDRxMAAACIQg3pRlZKToqv\n8bEns1a/4RYy9209WsXfd/e5DoQfOpoAAABAFPK1G+ksMz3VrSvqTUVFha575079sbek2vaWm0/X\nnoK4BtWB8EPQBAAAAKJQclK8CvNKqz2ur/i4GE0a1afW1xWX/aHr3rnTbftLQ6cq67U85RQUNKgO\nhB+GzgIAAABRKDM9VWkpCerYLlZpKQk1diMb4vvfNrqFzOZNm2vByGcUH9suaHUguOhoAgAAAFGo\nrt3IhlhifaRXvn6r2rYzu56iW0/JCGodCD46mhFo/fr1ys1lknRtunfvrpycHL8fd+bMmbr66qsl\nSYsWLdLZZ5/t93MAAABEugc/edItZN7W57pqIRONF0EzAo0ZM0abN28OdRlh7/PPP1dqamCGXlTe\nY/TCCy/UW2+9VcurAQAAose+A/s0Mvtmffvzd9W2/23g/Tr9iLQQVYVgY+hsBOJGtnXTqVOngJ+j\nZcuWatmyZcDPAwAAEAkKin/R/y2Z5Lb91Uuz1LI5PzNFEzqaEebqq6/W9u3bNX78eI0fP16rVq3S\ngAED9MADD6h3796aNWtW1XPOnIeR7t27V5MnT1afPn3Up08f3XXXXSoq8ryMtKfjS9KCBQt09tln\nKzU1Vddcc42+++7gb6zKyso0YcIE9e7dW/369dNbb72l4447Ttu3b9ePP/6o7t2769lnn9XJJ5+s\nyZMnS5KWLVumCy+8UCeeeKJGjhxZbcjr+vXrddlll+nEE09Uv3799Mwzz1Q9t2LFCl188cXq2bOn\nzj33XGVnZ3t9z9OmTVP//v2Vmpqqm2++WT/99JMkVdW0bNkynXvuuerZs6cyMzP1xx9/1Pr1ePvt\ntzVgwIBqn9Ubb7yhM888U6mpqbr77ru1b9++qtfX9D4BAAAi2X+35bqFzCM7HK43058jZEYhgmaE\nmTlzpv785z9rwoQJmjBhgiRp+/bt2rt3rxYtWqQLL7yw1mPMmDFD3377rWbNmqX58+eruLhYmZmZ\nXl/vfPyLLrpIH3/8sZ555hlNmjRJ7777rnr37q1rr71Wu3fvliQ9/PDD+uabbzRnzhw9+eSTmjVr\nlsrLy6sdMzc3V3//+991zTXXaP369brnnns0ZswYvffeexoyZIhGjx6trVu3SpLGjRun4447Th98\n8IEeeeQRzZo1S//+979VXl6usWPHatCgQfrnP/+pzMxMPfTQQ8rPz3d7D5MmTdLy5cs1bdo0ZWdn\na//+/brllluqveaFF17Qk08+qVdffVXffvutlixZUutn2aRJk6phtJL0888/68MPP9ScOXM0c+ZM\nffjhh3rnnXckqdb3CQAAEKlmrX5DT3z+YrVtl/UYosfOG+9lDzR2DJ11sWLrar259n3t2V9a+4v9\npFXzWKX3GKw+XU6q9bXx8fFq2rSp4uLiFBdn39i2SZMmGj16tLp06VLr/qWlpXrttdf09ttv6+ij\nj5YkTZ06VX369NH3339ftc2Z6/HvuOMO3XTTTerXr58k6bbbbtOnn36qxYsXa9iwYXr33Xc1e/Zs\n9ezZU5I0ceJE3XDDDdWOmZGRUXW8u+++WyNHjtSgQYMkSVdddZVWrVql119/XePGjdOPP/6oc845\nR507d1ZiYqLmzp2rpKQk7d69W0VFRerYsaM6d+6siy66SIceeqgOPfTQaufatWuXFi9erNmzZyst\nzZ4XMH36dPXv31+ff/65unbtWvU+jj/+eEnSwIEDtWbNmlo/T1cHDhzQxIkTlZycrKOOOkpnnHGG\n1q5dqxEjRmjOnDk1vk8AAIBIU15RrsveHOO2/YGzblfKoe4/VyJ6EDRdLF6/TD/u/ikk561L0PQm\nMTGxTq/bunWr9u3bp/T0dLe5nps2bfIYNF2Pn5+fr2nTpmn69OlV2/bt26eNGzfqhx9+0P79+6sC\nmySdeOKJbudyPd7SpUu1YMGCqm379+/XGWecIUm68cYbNWPGDC1YsED9+/fX0KFDq+ZfXnHFFZo4\ncaKeffZZnXXWWbr00kvVtm1bt/dVUVGhHj16VG2Lj49Xt27dlJ+fXxU0jzjiiKrn4+LidODAAY+f\nRW1cj7N///46vU8AAIBI8lPxL7rNw3zMl4ZOVXxsuxBUhHBC0HQxtPt5yl77XtA7mkO6n9ugY9S0\nII1zYKpYIhI0AAAgAElEQVT8+xtvvKHWrVtXe11Ni+c4H//AgQOaMGGC+vSpfr+jNm3a6Oeff5ZU\n84JFTZo0UUxMTLXj3XDDDbr44ourva7yNTfccIMGDRqkZcuW6ZNPPlFGRoYeeughDR8+XJMmTdKV\nV16p5cuXa/ny5crOztZzzz1XLbx5+2wOHDhQbUhvixYtqj3v66JLzZtX/7aqPE5t7xMAACBS/OO7\nT/Ry7ptu2xeMfEZNmzA7DwRNN326nNSgzmIwOM8J9KRFixbauXNn1eMtW7ZU/b1Lly5q1qyZfv/9\ndxljJEmFhYW69957NWHCBLfw6Um3bt20Y8eOakN1x48fr/POO0+nnHKKmjdvrm+//VYnn3yyJGnt\n2rU11tytWzdt27at2vEef/xxHXnkkRoyZIimTZum66+/XhkZGcrIyND999+vDz/8UP3799ezzz6r\n8ePH68Ybb9SNN96o66+/Xh9//HG1oHn44YerWbNm+uabb9S3b19J0u+//67NmzerW7dudfpM/aGm\n9zl8+PCAnx8AAMAfxrw3Qb+UFLptfzP9uRBUg3DFrxsiUOvWrfXDDz94XSm2R48e+uKLL7RixQp9\n9913evjhh6u6em3atNGIESN0//33a9WqVdqwYYPuuusubd26VUlJSXU6f0ZGhl555RW9++672rp1\nq6ZNm6alS5cqOTlZrVu31iWXXKLJkydrzZo1+vrrrzVlyhRJB8Oca6cwIyNDS5Ys0fz587V161bN\nnTtX8+bNU7du3dSyZUutXr1akydP1saNG7V27Vp9+eWXSklJUXx8vD788ENNmTJFW7duVU5Ojtav\nX6+UlBS3z2vEiBF66KGHtGrVKq1fv1533XWXEhMTddppp3msKRC8vc/KobsAAADhbmT2zW4hs1di\nD0Im3NDRjECXX365pk+frk2bNumqq65ye37o0KHKzc3VmDFj1K5dO2VmZmrz5s1Vz99zzz16/PHH\nddttt2n//v1KS0vTiy++WOeu3qBBg1RYWKinnnpKv/32m4466ii98MILOvzwwyXZq8Q+8MADysjI\nUNu2bXXllVfqySefVIsWLVRWVuZ2nhNOOEGPP/64nn76aU2bNk2HH364ZsyYoV69ekmSsrKy9OCD\n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\n/wG8b0Uh+S+IGQAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x10fc9fe10>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig = plt.figure(figsize=(11, 9))\n",
    "ax = fig.add_subplot(111, xlabel='x', ylabel='y', title='Generated data and underlying model')\n",
    "ax.plot(x, y, '.', label='sampled data')\n",
    "ax.plot(x, true_line, label='true regression line', lw=2.)\n",
    "plt.legend(loc=0);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The data points in this scatter plot are our observed information about the true relationship between $x$ and $y$. This observed information contorts our initial impressions of how our parameters are distributed into our posterior distributions."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Creating Our Model\n",
    "\n",
    "Let's define our priors for the Bayesian model. With PyMC3, it is remarkably easy to lay out which components of the model will follow which distributions, however, this may be confusing if you are unfamiliar with the Bayesian framework. The typical model definition is laid out here. In PyMC3, we define all of our variables using the `with` context."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Auto-assigning NUTS sampler...\n",
      "Initializing NUTS using advi...\n",
      "Average ELBO = -97.235: 100%|██████████| 200000/200000 [00:15<00:00, 12711.45it/s]\n",
      "Finished [100%]: Average ELBO = -97.231\n",
      "100%|██████████| 1000/1000 [00:01<00:00, 566.58it/s]\n"
     ]
    }
   ],
   "source": [
    "with pm.Model() as toy_model:\n",
    "    # Defining priors\n",
    "    sigma = pm.HalfCauchy('sigma', beta=10, testval=1.0)\n",
    "    intercept = pm.Normal('Intercept', mu=0, sd=20)\n",
    "    x_beta = pm.Normal('x', mu=0, sd=20)\n",
    "    \n",
    "    # Defining likelihood\n",
    "    likelihood = pm.Normal('y', mu=(intercept + x_beta * x), sd=sigma, observed=y)\n",
    "    \n",
    "    # Running Inference\n",
    "    toy_trace = pm.sample(1000, tune=100) # Draw posterior samples"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you are less familiar with probabilistic programming, this may look like a lot of nonsense. The syntax for defining probability distributions is intuitive, but this is a lot of extra buzz around the implementation of a basic linear regression. \n",
    "\n",
    "For this reason, the PyMC3 developers introduced a `glm` module to simplify the definition of Generalized Linear Models (GLM), including linear regressions such as ours."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Auto-assigning NUTS sampler...\n",
      "Initializing NUTS using advi...\n",
      "Average ELBO = -118.85: 100%|██████████| 200000/200000 [00:19<00:00, 10507.78it/s]\n",
      "Finished [100%]: Average ELBO = -118.85\n",
      "100%|██████████| 1000/1000 [00:01<00:00, 648.82it/s]\n"
     ]
    }
   ],
   "source": [
    "with pm.Model() as toy_model:\n",
    "    pm.glm.glm('y ~ x', data)\n",
    "    toy_trace = pm.sample(1000, tune=100)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For a more comprehensive GLM framework that allows model specification in a similar way, see [Bambi](https://github.com/bambinos/bambi) which uses PyMC3 under the hood."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Basic Diagnostics\n",
    "\n",
    "We have a few things to examine after fitting a Bayesian model. Here are the plots that show our posterior distributions as well as our traceplots: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.figure.Figure at 0x116a01780>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\nACZnEnzp3x8+pszdFYpjmVrjaCdj7MKxhUlDLVeFEr1Xg+P4WtZF/RHnAdvB3oq23VeUHaur/kiA\n3u5AU2JKWcWPqjkhzFdfPcUN1G4rn9dl67iSczwuIk1cgKimWKpn7TenUK2yv4EwTuYymzFp1agu\ny+qlXWxd25fPtmhHNq0YBHz10i56u/yEgx6WD3ZUuXZ9+eerZHZ6ljmz57plXWxa3YvbwuqpnrKr\nUaVUtU5TyBRntddOuLFaceBaSbU+6nHrdRNgaFp15a0dl2g7VLRns2NK1YmJVXjvu3SN0ZGeknhb\nrVpUqIVYGVn4i9ahVdXweeA/gTVAQfV8CfDfwD/Ot1AhxC1CiG81Lp5CoWgn/3PXDr74o4fJ5gzF\nwqffei5b1/a3WyzFMcipGwb5i3NHALj3D/v57f172iyRQtFchBA+IcQ3hRATQogxIcSVNY59gRDi\nYSHEtBDiV0KI9WX7J4UQGSFENv+XEULMK1J1+STS/NXJOnShnKKllMnayCqYeoFGJ+q1zg/43PMK\n4F3upmJ1BbPivKD0sLI2ymRzLM0Hc6+W8GPjSG9TYkqtW95t6X5jx33PjqVUNYWDWBkpCUJcSzHh\n9cxNWdxuvSmxZgpUc8WqewkbcbWa4iakGW3UaBnVZBnoCeJxu2xbHZUXs3lNH6duGLSlqKmlwGsE\nu71h175p0zVL3z0FrN4N5ce0ymV2y5o+y+uZ5apmleR265y5aYiT1y/8eFrT4NQNA5b76tWVRnUl\noNVzblehYq5Cs8I1R27BQoSUK/atXbXtydKoFWV32Ieet+7s7fLXP2GBaZVS6lzgWillsSWklGng\nE8C2+RQohHgN8KLmiKdQKNrFLXfu4Ms3PwpAT6ePf3zbeaxbvvg09opjhze8eCNL+ow00t/46WMc\nnIi2WSKFoqlcgzF2ugC4Avi4EOIV5QcJITYBP8NYFNwGPATcWlA6CSGWAB3AamAo/zcspZzXA1Oh\nMCoJHOO8nMKAO2WyZChPdmGeLDY6p6g1wDdW7lszabGaPFtZeGYzOdYs7eL0jYOsrJOFttHJiq5b\n32+tdOyFo+1Yp1ZTAA71huqe63JpnLSuv+jqAuB2Nbd9CpPmU0cHWTE0Z+1TT/FV11Kqxj6nLOkP\n0xnyzvt8rYYrYWGzXUVvNaVz1fPtuO/Ns54K/aBalrxyzG1arf00i9lx+TGNKqWszl4x1FFsY6v6\n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\nMQKWfxH4mJTyp/l9+8iPq6SUDwJvxQikfj+QA
Download .txt
gitextract_dc6ud5d9/

├── .gitignore
├── LICENSE.txt
├── README.md
├── abstracts/
│   ├── 00_pymc/
│   │   └── pymc3.rst
│   ├── 00_rudiger/
│   │   └── 00_rudiger.rst
│   ├── aaron_meurer/
│   │   └── sympy.rst
│   ├── dask/
│   │   └── dask.rst
│   ├── mpi4py/
│   │   └── mpi4py.rst
│   └── ryan_abernathey/
│       └── xarray.rst
├── environment.yml
├── examples/
│   ├── 00_bibderwalt/
│   │   ├── 00_bibderwalt.rst
│   │   └── mybib.bib
│   └── 00_vanderwalt/
│       └── 00_vanderwalt.rst
├── make_paper.sh
├── papers/
│   ├── joshua_warner/
│   │   ├── 00_scikitimage.rst
│   │   ├── reproduction_corner.ipynb
│   │   ├── reproduction_denoise.ipynb
│   │   └── reproduction_pano.ipynb
│   ├── maxwell_margenot/
│   │   ├── bayesian_linear_regression.ipynb
│   │   ├── maxwell_margenot.rst
│   │   └── mybib.bib
│   ├── numba/
│   │   ├── 00_numba.rst
│   │   ├── array_vs_list/
│   │   │   ├── array_vs_list.ipynb
│   │   │   └── array_vs_list.rst
│   │   ├── gufunc/
│   │   │   ├── gufunc.ipynb
│   │   │   └── gufunc.rst
│   │   ├── intro/
│   │   │   └── intro.rst
│   │   ├── looplifting/
│   │   │   ├── LoopLiftingCode.ipynb
│   │   │   ├── inspect_types_ex.py
│   │   │   └── looplifting.rst
│   │   ├── nogilthreads/
│   │   │   ├── BadThreadsExample.ipynb
│   │   │   ├── Mandel.ipynb
│   │   │   └── nogilthreads.rst
│   │   └── piecewise/
│   │       ├── piecewise.ipynb
│   │       └── piecewise.rst
│   ├── prabhu_ramachandran/
│   │   ├── code/
│   │   │   ├── viewer0.py
│   │   │   ├── viewer1.py
│   │   │   └── viewer2.py
│   │   └── mayavi_chapter.rst
│   ├── scipy/
│   │   ├── code/
│   │   │   └── signal/
│   │   │       ├── LICENSE.txt
│   │   │       ├── bandpass_batch_example.py
│   │   │       ├── bandpass_example.py
│   │   │       ├── butter.py
│   │   │       ├── firlp_lowpass_example.py
│   │   │       ├── firls_example.py
│   │   │       ├── firwin2_examples.py
│   │   │       ├── initial_conditions.py
│   │   │       ├── kaiser_lowpass_filter_design.py
│   │   │       ├── lowpass_design_specs.py
│   │   │       ├── make_data.py
│   │   │       ├── moving_avg_freq_response.py
│   │   │       ├── opt_lowpass.py
│   │   │       ├── pressure_example.py
│   │   │       ├── remez_example.py
│   │   │       ├── sos_bandpass_response.py
│   │   │       └── unstable_butterworth.py
│   │   └── scipy.rst
│   └── yuan_tang_hongliang_liu/
│       ├── convert.sh
│       ├── distributed_and_gpus.md
│       ├── distributed_and_gpus.txt
│       ├── intro.txt
│       ├── main_functionalities.txt
│       ├── model_tune.md
│       ├── model_tune.txt
│       ├── parameter_explained.md
│       ├── parameter_explained.txt
│       ├── references.txt
│       ├── vs_gbdt.md
│       ├── vs_gbdt.txt
│       └── xgboost_chapter.rst
├── publisher/
│   ├── Makefile
│   ├── _static/
│   │   ├── common.css
│   │   ├── google_analytics.js
│   │   ├── proc_links.js
│   │   ├── pydata-cookbook.css
│   │   ├── pydata.sty
│   │   ├── screen.css
│   │   └── status.sty
│   ├── _templates/
│   │   ├── article.bib.tmpl
│   │   ├── article.html.tmpl
│   │   ├── copyright.tex.tmpl
│   │   ├── header.html.tmpl
│   │   ├── index.html.tmpl
│   │   ├── organization.html.tmpl
│   │   ├── organization.tex.tmpl
│   │   ├── proceedings.bib.tmpl
│   │   ├── proceedings.tex.tmpl
│   │   ├── students.html.tmpl
│   │   ├── students.tex.tmpl
│   │   ├── title.tex.tmpl
│   │   └── toc.tex.tmpl
│   ├── build_html.py
│   ├── build_paper.py
│   ├── build_papers.py
│   ├── build_template.py
│   ├── conf.py
│   ├── mail/
│   │   ├── _mailer.py
│   │   ├── email.json
│   │   ├── mail_authors.py
│   │   ├── mail_authors_example.txt
│   │   ├── mail_reviewers.py
│   │   └── templates/
│   │       ├── author-revision.txt.tmpl
│   │       └── reviewer-invite.txt.tmpl
│   ├── options.py
│   ├── tempita/
│   │   ├── __init__.py
│   │   ├── _looper.py
│   │   └── compat3.py
│   └── writer/
│       ├── __init__.py
│       ├── code_block.py
│       ├── rstmath.py
│       └── sphinx_highlight.py
├── pydata-cookbook.json
├── review_criteria.md
└── reviews/
    ├── README
    ├── invite-abstract-reviews.rst
    ├── invite-paper-reviews.rst
    ├── invite-reviewer.txt.in
    ├── review-template.rst
    └── submission-template.rst
Download .txt
SYMBOL INDEX (195 symbols across 22 files)

FILE: papers/numba/looplifting/inspect_types_ex.py
  function assign_bin (line 8) | def assign_bin(val):
  function binning (line 18) | def binning(ary, debug=False):

FILE: papers/prabhu_ramachandran/code/viewer0.py
  class PySPHViewer (line 7) | class PySPHViewer(HasTraits):

FILE: papers/prabhu_ramachandran/code/viewer1.py
  class PySPHViewer (line 13) | class PySPHViewer(HasTraits):
    method update_plot (line 38) | def update_plot(self):
    method _particle_array_changed (line 54) | def _particle_array_changed(self, pa):
    method _file_name_changed (line 57) | def _file_name_changed(self, fname):

FILE: papers/prabhu_ramachandran/code/viewer2.py
  class PySPHViewer (line 13) | class PySPHViewer(HasTraits):
    method update_plot (line 41) | def update_plot(self):
    method _particle_array_changed (line 57) | def _particle_array_changed(self, pa):
    method _file_name_changed (line 61) | def _file_name_changed(self, fname):
    method _scalar_changed (line 66) | def _scalar_changed(self, scalar):

FILE: papers/scipy/code/signal/butter.py
  function butter_lowpass (line 6) | def butter_lowpass(cutoff, fs, order):
  function butter_lowpass_filtfilt (line 13) | def butter_lowpass_filtfilt(data, cutoff, fs,
  function butter_bandpass (line 20) | def butter_bandpass(lowcut, highcut, fs, order):
  function butter_bandpass_filt (line 29) | def butter_bandpass_filt(data, lowcut, highcut, fs,

FILE: papers/scipy/code/signal/firlp_lowpass_example.py
  function solve_linprog (line 10) | def solve_linprog(c, A_ub=None, b_ub=None, A_eq=None, b_eq=None, tol=None):
  function firlp_lowpass1 (line 56) | def firlp_lowpass1(numtaps, deltap, deltas, cutoff, width, fs, tol=None):

FILE: papers/scipy/code/signal/kaiser_lowpass_filter_design.py
  function kaiser_lowpass (line 9) | def kaiser_lowpass(delta_db, cutoff, width, fs):

FILE: papers/scipy/code/signal/make_data.py
  function make_data (line 6) | def make_data(T, fs):

FILE: papers/scipy/code/signal/opt_lowpass.py
  function bellanger_estimate (line 10) | def bellanger_estimate(deltap, deltas, width, fs):
  function remez_lowpass (line 19) | def remez_lowpass(deltap, deltas, cutoff, width, fs):

FILE: publisher/_static/proc_links.js
  function proc_versions (line 1) | function proc_versions() {

FILE: publisher/build_paper.py
  function rst2tex (line 42) | def rst2tex(in_path, out_path):
  function tex2pdf (line 108) | def tex2pdf(out_path):
  function tex2pdf_singlepass (line 120) | def tex2pdf_singlepass(out_path):
  function page_count (line 186) | def page_count(pdflatex_stdout, paper_dir):
  function build_paper (line 209) | def build_paper(paper_id):

FILE: publisher/build_papers.py
  function paper_stats (line 21) | def paper_stats(paper_id, start):

FILE: publisher/build_template.py
  class TeXTemplate (line 11) | class TeXTemplate(tempita.Template):
    method _repr (line 12) | def _repr(self, value, pos):
  function _from_template (line 21) | def _from_template(tmpl_basename, config, use_html=True):
  function from_template (line 29) | def from_template(tmpl_basename, config, dest_fn):
  function bib_from_tmpl (line 39) | def bib_from_tmpl(bib_type, config, target):
  function get_html_header (line 47) | def get_html_header(config):
  function get_html_content (line 50) | def get_html_content(tmpl, config):
  function html_from_tmpl (line 53) | def html_from_tmpl(src, config, target):

FILE: publisher/mail/_mailer.py
  function parse_args (line 18) | def parse_args():
  function load_config (line 33) | def load_config(conf_file):
  function get_password (line 37) | def get_password(sender):
  function email_addr_from (line 43) | def email_addr_from(name_email):
  function send_template (line 47) | def send_template(sender, recipient, template, template_data,

FILE: publisher/options.py
  function get_config (line 15) | def get_config():
  function cfg2dict (line 20) | def cfg2dict(filename):
  function dict2cfg (line 30) | def dict2cfg(d, filename):
  function mkdir_p (line 36) | def mkdir_p(dir):

FILE: publisher/tempita/__init__.py
  class TemplateError (line 49) | class TemplateError(Exception):
    method __init__ (line 53) | def __init__(self, message, position, name=None):
    method __str__ (line 58) | def __str__(self):
  class _TemplateContinue (line 68) | class _TemplateContinue(Exception):
  class _TemplateBreak (line 72) | class _TemplateBreak(Exception):
  function get_file_template (line 76) | def get_file_template(name, from_template):
  class Template (line 83) | class Template(object):
    method __init__ (line 94) | def __init__(self, content, name=None, namespace=None, stacklevel=None,
    method from_filename (line 139) | def from_filename(cls, filename, namespace=None, encoding=None,
    method __repr__ (line 151) | def __repr__(self):
    method substitute (line 156) | def substitute(self, *args, **kw):
    method _interpret (line 180) | def _interpret(self, ns):
    method _interpret_inherit (line 191) | def _interpret_inherit(self, body, defs, inherit_template, ns):
    method _interpret_codes (line 206) | def _interpret_codes(self, codes, ns, out, defs):
    method _interpret_code (line 214) | def _interpret_code(self, code, ns, out, defs):
    method _interpret_for (line 257) | def _interpret_for(self, vars, expr, content, ns, out, defs):
    method _interpret_if (line 276) | def _interpret_if(self, parts, ns, out, defs):
    method _eval (line 290) | def _eval(self, code, ns, pos):
    method _exec (line 309) | def _exec(self, code, ns, pos):
    method _repr (line 322) | def _repr(self, value, pos):
    method _add_line_info (line 366) | def _add_line_info(self, msg, pos):
  function sub (line 374) | def sub(content, delimeters=None, **kw):
  function paste_script_template_renderer (line 380) | def paste_script_template_renderer(content, vars, filename=None):
  class bunch (line 385) | class bunch(dict):
    method __init__ (line 387) | def __init__(self, **kw):
    method __setattr__ (line 391) | def __setattr__(self, name, value):
    method __getattr__ (line 394) | def __getattr__(self, name):
    method __getitem__ (line 400) | def __getitem__(self, key):
    method __repr__ (line 409) | def __repr__(self):
  class html (line 422) | class html(object):
    method __init__ (line 424) | def __init__(self, value):
    method __str__ (line 427) | def __str__(self):
    method __html__ (line 430) | def __html__(self):
    method __repr__ (line 433) | def __repr__(self):
  function html_quote (line 438) | def html_quote(value, force=True):
  function url (line 456) | def url(v):
  function attr (line 463) | def attr(**kw):
  class HTMLTemplate (line 476) | class HTMLTemplate(Template):
    method _repr (line 486) | def _repr(self, value, pos):
  function sub_html (line 499) | def sub_html(content, **kw):
  class TemplateDef (line 505) | class TemplateDef(object):
    method __init__ (line 506) | def __init__(self, template, func_name, func_signature,
    method __repr__ (line 516) | def __repr__(self):
    method __str__ (line 521) | def __str__(self):
    method __call__ (line 524) | def __call__(self, *args, **kw):
    method __get__ (line 535) | def __get__(self, obj, type=None):
    method _parse_signature (line 542) | def _parse_signature(self, args, kw):
  class TemplateObject (line 582) | class TemplateObject(object):
    method __init__ (line 584) | def __init__(self, name):
    method __repr__ (line 588) | def __repr__(self):
  class TemplateObjectGetter (line 592) | class TemplateObjectGetter(object):
    method __init__ (line 594) | def __init__(self, template_obj):
    method __getattr__ (line 597) | def __getattr__(self, attr):
    method __repr__ (line 600) | def __repr__(self):
  class _Empty (line 604) | class _Empty(object):
    method __call__ (line 605) | def __call__(self, *args, **kw):
    method __str__ (line 608) | def __str__(self):
    method __repr__ (line 611) | def __repr__(self):
    method __unicode__ (line 614) | def __unicode__(self):
    method __iter__ (line 617) | def __iter__(self):
    method __bool__ (line 620) | def __bool__(self):
  function lex (line 634) | def lex(s, name=None, trim_whitespace=True, line_offset=0, delimeters=No...
  function trim_lex (line 702) | def trim_lex(tokens):
  function find_position (line 761) | def find_position(string, index, line_offset):
  function parse (line 767) | def parse(s, name=None, line_offset=0, delimeters=None):
  function parse_expr (line 828) | def parse_expr(tokens, name, context=()):
  function parse_cond (line 881) | def parse_cond(tokens, name, context):
  function parse_one_cond (line 897) | def parse_one_cond(tokens, name, context):
  function parse_for (line 924) | def parse_for(tokens, name, context):
  function parse_default (line 959) | def parse_default(tokens, name, context):
  function parse_inherit (line 981) | def parse_inherit(tokens, name, context):
  function parse_def (line 988) | def parse_def(tokens, name, context):
  function parse_signature (line 1019) | def parse_signature(sig_text, name, pos):
  function isolate_expression (line 1095) | def isolate_expression(string, start_pos, end_pos):
  function fill_command (line 1118) | def fill_command(args=None):

FILE: publisher/tempita/_looper.py
  class looper (line 27) | class looper(object):
    method __init__ (line 38) | def __init__(self, seq):
    method __iter__ (line 41) | def __iter__(self):
    method __repr__ (line 44) | def __repr__(self):
  class looper_iter (line 49) | class looper_iter(object):
    method __init__ (line 51) | def __init__(self, seq):
    method __iter__ (line 55) | def __iter__(self):
    method __next__ (line 58) | def __next__(self):
  class loop_pos (line 69) | class loop_pos(object):
    method __init__ (line 71) | def __init__(self, seq, pos):
    method __repr__ (line 75) | def __repr__(self):
    method index (line 79) | def index(self):
    method number (line 83) | def number(self):
    method item (line 87) | def item(self):
    method __next__ (line 91) | def __next__(self):
    method previous (line 101) | def previous(self):
    method odd (line 107) | def odd(self):
    method even (line 111) | def even(self):
    method first (line 115) | def first(self):
    method last (line 119) | def last(self):
    method length (line 123) | def length(self):
    method first_group (line 127) | def first_group(self, getter=None):
    method last_group (line 138) | def last_group(self, getter=None):
    method _compare_group (line 149) | def _compare_group(self, item, other, getter):

FILE: publisher/tempita/compat3.py
  function b (line 10) | def b(s):
  function next (line 20) | def next(obj):
  function is_unicode (line 27) | def is_unicode(obj):
  function is_unicode (line 31) | def is_unicode(obj):
  function coerce_text (line 35) | def coerce_text(v):

FILE: publisher/writer/__init__.py
  class Translator (line 25) | class Translator(LaTeXTranslator):
    method __init__ (line 26) | def __init__(self, *args, **kwargs):
    method visit_docinfo (line 62) | def visit_docinfo(self, node):
    method depart_docinfo (line 65) | def depart_docinfo(self, node):
    method visit_author (line 68) | def visit_author(self, node):
    method depart_author (line 73) | def depart_author(self, node):
    method visit_author (line 76) | def visit_author(self, node):
    method depart_author (line 81) | def depart_author(self, node):
    method visit_classifier (line 84) | def visit_classifier(self, node):
    method depart_classifier (line 87) | def depart_classifier(self, node):
    method visit_field_name (line 90) | def visit_field_name(self, node):
    method visit_field_body (line 94) | def visit_field_body(self, node):
    method depart_field_body (line 123) | def depart_field_body(self, node):
    method depart_document (line 126) | def depart_document(self, node):
    method end_open_abstract (line 271) | def end_open_abstract(self, node):
    method visit_title (line 279) | def visit_title(self, node):
    method visit_paragraph (line 297) | def visit_paragraph(self, node):
    method depart_paragraph (line 318) | def depart_paragraph(self, node):
    method visit_figure (line 322) | def visit_figure(self, node):
    method depart_figure (line 339) | def depart_figure(self, node):
    method visit_image (line 342) | def visit_image(self, node):
    method visit_footnote (line 365) | def visit_footnote(self, node):
    method visit_table (line 377) | def visit_table(self, node):
    method depart_table (line 387) | def depart_table(self, node):
    method visit_thead (line 397) | def visit_thead(self, node):
    method depart_thead (line 415) | def depart_thead(self, node):
    method visit_literal_block (line 418) | def visit_literal_block(self, node):
    method depart_literal_block (line 446) | def depart_literal_block(self, node):
    method visit_block_quote (line 450) | def visit_block_quote(self, node):
    method depart_block_quote (line 454) | def depart_block_quote(self, node):
    method visit_InlineMath (line 461) | def visit_InlineMath(self, node):
    method visit_PartMath (line 466) | def visit_PartMath(self, node):
    method visit_PartLaTeX (line 472) | def visit_PartLaTeX(self, node):

FILE: publisher/writer/code_block.py
  class CodeBlock (line 6) | class CodeBlock(Directive):
    method run (line 21) | def run(self):

FILE: publisher/writer/rstmath.py
  class InlineMath (line 10) | class InlineMath(nodes.Inline, nodes.TextElement):
  class PartMath (line 13) | class PartMath(nodes.Part, nodes.Element):
  class PartLaTeX (line 16) | class PartLaTeX(nodes.Part, nodes.Element):
  function mathEnv (line 19) | def mathEnv(math, label, type):
  function mathRole (line 35) | def mathRole(role, rawtext, text, lineno, inliner, options={}, content=[]):
  class MathDirective (line 39) | class MathDirective(Directive):
    method run (line 48) | def run(self):
  class LaTeXDirective (line 59) | class LaTeXDirective(Directive):
    method run (line 67) | def run(self):

FILE: publisher/writer/sphinx_highlight.py
  class SphinxStyle (line 5) | class SphinxStyle(Style):
Condensed preview — 119 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,661K chars).
[
  {
    "path": ".gitignore",
    "chars": 66,
    "preview": "output\n_build\n*.pyc\n*~\npapers/maxwell_margenot/.ipynb_checkpoints\n"
  },
  {
    "path": "LICENSE.txt",
    "chars": 1782,
    "preview": "Copyright (c) 2016 PyData Cookbook Authors.\nAll rights reserved.\n\nThe majority of files are adapted from the scipy-proce"
  },
  {
    "path": "README.md",
    "chars": 6473,
    "preview": "# PyData Cookbook\n\n We are starting a project to build a cookbook of advanced material for the PyData community. The coo"
  },
  {
    "path": "abstracts/00_pymc/pymc3.rst",
    "chars": 1877,
    "preview": ":author: Christopher Fonnesbeck\n:email: chris.fonnesbeck@vanderbilt.edu\n:institution: Vanderbilt University Medical Cent"
  },
  {
    "path": "abstracts/00_rudiger/00_rudiger.rst",
    "chars": 2798,
    "preview": ":author: Philipp J. F. Rudiger\n:email: philippjfr@continuum.io\n:institution: Continuum Analytics, Inc.\n:equal-contributo"
  },
  {
    "path": "abstracts/aaron_meurer/sympy.rst",
    "chars": 733,
    "preview": ":author: Aaron Meurer\n:email: asmeurer@gmail.com\n:institution: University of South Carolina\n:corresponding:\n\n-----\nSymPy"
  },
  {
    "path": "abstracts/dask/dask.rst",
    "chars": 1371,
    "preview": ":author: James Crist\n:email: jcrist@continuum.io\n:institution: Continuum Analytics\n\n:author: Matthew Rocklin\n:email: mro"
  },
  {
    "path": "abstracts/mpi4py/mpi4py.rst",
    "chars": 1118,
    "preview": ":author: Lisandro Dalcin\n:email: dalcinl@gmail.com\n:institution: KAUST\n:institution: CONICET\n\n\n:author: Thomas Spura\n:em"
  },
  {
    "path": "abstracts/ryan_abernathey/xarray.rst",
    "chars": 4705,
    "preview": ":author: Ryan Abernathey\n:email: rpa@ldeo.columbia.edu\n:institution: Columbia University, New York, NY, USA\n:institution"
  },
  {
    "path": "environment.yml",
    "chars": 143,
    "preview": "name: pydata-cookbook\nchannels:\n    - defaults\n    - conda-forge\ndependencies:\n    - pip:\n        - docutils==0.13.1\n   "
  },
  {
    "path": "examples/00_bibderwalt/00_bibderwalt.rst",
    "chars": 9353,
    "preview": ":author: Gaius Caesar\n:email: jj@rome.it\n:institution: Senate House, S.P.Q.R.\n:institution: Egyptian Embassy, S.P.Q.R.\n\n"
  },
  {
    "path": "examples/00_bibderwalt/mybib.bib",
    "chars": 182,
    "preview": "@Book{hume48,\n  author =  \"David Hume\",\n  year =    \"1748\",\n  title =   \"An enquiry concerning human understanding\",\n  a"
  },
  {
    "path": "examples/00_vanderwalt/00_vanderwalt.rst",
    "chars": 7569,
    "preview": ":author: Gaius Caesar\n:email: jj@rome.it\n:institution: Senate House, S.P.Q.R.\n:institution: Egyptian Embassy, S.P.Q.R.\n:"
  },
  {
    "path": "make_paper.sh",
    "chars": 312,
    "preview": "#!/bin/bash\n\nDIR=$1\n\nif [[ ! -d $DIR ]]; then\n  echo \"Usage: make_paper.sh source_dir\"\n  exit -1\nfi\n\npython publisher/bu"
  },
  {
    "path": "papers/joshua_warner/00_scikitimage.rst",
    "chars": 39151,
    "preview": ":author: Joshua D. Warner\n:email: joshua.dale.warner@gmail.com\n:institution: Mayo Clinic, Rochester, USA\n:first-author:\n"
  },
  {
    "path": "papers/joshua_warner/reproduction_corner.ipynb",
    "chars": 3320,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {\n    \"collapsed\": true\n   },\n   \"o"
  },
  {
    "path": "papers/joshua_warner/reproduction_denoise.ipynb",
    "chars": 5681,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {\n    \"collapsed\": true\n   },\n   \"o"
  },
  {
    "path": "papers/joshua_warner/reproduction_pano.ipynb",
    "chars": 22269,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \""
  },
  {
    "path": "papers/maxwell_margenot/bayesian_linear_regression.ipynb",
    "chars": 2089625,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"# Bayesian Generalized Linear Model"
  },
  {
    "path": "papers/maxwell_margenot/maxwell_margenot.rst",
    "chars": 9347,
    "preview": ":author: Maxwell Margenot\n:email: maxwell.margenot@gmail.com\n:email: max@quantopian.com\n:institution: Quantopian\n\n:autho"
  },
  {
    "path": "papers/maxwell_margenot/mybib.bib",
    "chars": 182,
    "preview": "@Book{hume48,\n  author =  \"David Hume\",\n  year =    \"1748\",\n  title =   \"An enquiry concerning human understanding\",\n  a"
  },
  {
    "path": "papers/numba/00_numba.rst",
    "chars": 1431,
    "preview": ":author: Siu Kwan Lam\n:email: siu@continuum.io\n:institution: Continuum Analytics\n\n:author: Antoine Pitrou\n:email: antoin"
  },
  {
    "path": "papers/numba/array_vs_list/array_vs_list.ipynb",
    "chars": 7704,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 1,\n   \"metadata\": {\n    \"collapsed\": true\n   },\n   \"outp"
  },
  {
    "path": "papers/numba/array_vs_list/array_vs_list.rst",
    "chars": 6812,
    "preview": "Arrays vs. Lists\n----------------\n\nLists are a very common data structure in Python, providing a way to represent\nan ord"
  },
  {
    "path": "papers/numba/gufunc/gufunc.ipynb",
    "chars": 5917,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 2,\n   \"metadata\": {\n    \"collapsed\": true\n   },\n   \"outp"
  },
  {
    "path": "papers/numba/gufunc/gufunc.rst",
    "chars": 5470,
    "preview": "Generalized Ufuncs\n------------------\n\nIn a previous section, we saw the power of ufuncs for expressing functions on\narr"
  },
  {
    "path": "papers/numba/intro/intro.rst",
    "chars": 27,
    "preview": "Introduction\n------------\n\n"
  },
  {
    "path": "papers/numba/looplifting/LoopLiftingCode.ipynb",
    "chars": 3525,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 1,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"out"
  },
  {
    "path": "papers/numba/looplifting/inspect_types_ex.py",
    "chars": 583,
    "preview": "import numba\nimport numpy\nimport collections\nimport pprint\n\n\n@numba.jit\ndef assign_bin(val):\n    limit = 32\n    while li"
  },
  {
    "path": "papers/numba/looplifting/looplifting.rst",
    "chars": 6308,
    "preview": "Loop Lifting\n------------\n\nIn a real application, functions may depend on features that Numba has no\noptimization strate"
  },
  {
    "path": "papers/numba/nogilthreads/BadThreadsExample.ipynb",
    "chars": 3521,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 1,\n   \"metadata\": {\n    \"collapsed\": true\n   },\n   \"outp"
  },
  {
    "path": "papers/numba/nogilthreads/Mandel.ipynb",
    "chars": 6796,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 1,\n   \"metadata\": {\n    \"collapsed\": true\n   },\n   \"outp"
  },
  {
    "path": "papers/numba/nogilthreads/nogilthreads.rst",
    "chars": 7237,
    "preview": "Release the GIL for Parallel Execution\n--------------------------------------\n\nSome algorithms can be trivially parallel"
  },
  {
    "path": "papers/numba/piecewise/piecewise.ipynb",
    "chars": 4805,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 1,\n   \"metadata\": {\n    \"collapsed\": true\n   },\n   \"outp"
  },
  {
    "path": "papers/numba/piecewise/piecewise.rst",
    "chars": 4503,
    "preview": "Piecewise Functions\n-------------------\n\nLet's suppose we are creating some kind of scoring function where we need to\nco"
  },
  {
    "path": "papers/prabhu_ramachandran/code/viewer0.py",
    "chars": 621,
    "preview": "from traits.api import HasTraits, Instance\nfrom traitsui.api import View, Item, Group\nfrom mayavi.core.ui.api import Mla"
  },
  {
    "path": "papers/prabhu_ramachandran/code/viewer1.py",
    "chars": 1606,
    "preview": "import sys\nimport os\n\nfrom traits.api import (HasTraits, Instance, Str)\nfrom traitsui.api import View, Item, Group\nfrom "
  },
  {
    "path": "papers/prabhu_ramachandran/code/viewer2.py",
    "chars": 1929,
    "preview": "import sys\nimport os\n\nfrom traits.api import (HasTraits, Instance, Str, List)\nfrom traitsui.api import View, Item, Group"
  },
  {
    "path": "papers/prabhu_ramachandran/mayavi_chapter.rst",
    "chars": 35583,
    "preview": ":author: Prabhu Ramachandran\n:email: prabhu@aero.iitb.ac.in\n:institution: Department of Aerospace Engineering,\n   Indian"
  },
  {
    "path": "papers/scipy/code/signal/LICENSE.txt",
    "chars": 406,
    "preview": "The data in \"pressure.dat\" was provided by stackoverflow user Nimal Naser at:\n\n    https://stackoverflow.com/questions/2"
  },
  {
    "path": "papers/scipy/code/signal/bandpass_batch_example.py",
    "chars": 1300,
    "preview": "from __future__ import division, print_function\n\nimport numpy as np\nfrom scipy.signal import sosfilt\nimport matplotlib.p"
  },
  {
    "path": "papers/scipy/code/signal/bandpass_example.py",
    "chars": 1829,
    "preview": "from __future__ import division, print_function\n\nimport numpy as np\nfrom scipy.signal import sosfreqz\nimport matplotlib."
  },
  {
    "path": "papers/scipy/code/signal/butter.py",
    "chars": 848,
    "preview": "from __future__ import division, print_function\n\nfrom scipy.signal import butter, sosfilt, sosfiltfilt\n\n\ndef butter_lowp"
  },
  {
    "path": "papers/scipy/code/signal/firlp_lowpass_example.py",
    "chars": 5005,
    "preview": "from __future__ import division, print_function\n\nimport warnings\nimport numpy as np\nfrom scipy.optimize import linprog\nf"
  },
  {
    "path": "papers/scipy/code/signal/firls_example.py",
    "chars": 1939,
    "preview": "from __future__ import division, print_function\n\nimport numpy as np\nfrom scipy.signal import firls, freqz\nimport matplot"
  },
  {
    "path": "papers/scipy/code/signal/firwin2_examples.py",
    "chars": 1771,
    "preview": "# -*- coding: utf-8 -*-\nfrom __future__ import division, print_function\n\nimport numpy as np\nfrom scipy.signal import fir"
  },
  {
    "path": "papers/scipy/code/signal/initial_conditions.py",
    "chars": 931,
    "preview": "from __future__ import division, print_function\n\nimport numpy as np\nfrom scipy.signal import butter, sosfilt, sosfilt_zi"
  },
  {
    "path": "papers/scipy/code/signal/kaiser_lowpass_filter_design.py",
    "chars": 3115,
    "preview": "# -*- coding: utf-8 -*-\nfrom __future__ import division, print_function\n\nimport numpy as np\nfrom scipy.signal import kai"
  },
  {
    "path": "papers/scipy/code/signal/lowpass_design_specs.py",
    "chars": 2257,
    "preview": "from __future__ import division, print_function\n\nimport matplotlib.pyplot as plt\n\n\ndeltap = 0.13\ndeltas = 0.15\n\nomegac ="
  },
  {
    "path": "papers/scipy/code/signal/make_data.py",
    "chars": 409,
    "preview": "from __future__ import division, print_function\n\nimport numpy as np\n\n\ndef make_data(T, fs):\n    nsamples = int(T * fs)\n "
  },
  {
    "path": "papers/scipy/code/signal/moving_avg_freq_response.py",
    "chars": 797,
    "preview": "from __future__ import division, print_function\n\nimport numpy as np\nfrom scipy.signal import freqz\nimport matplotlib.pyp"
  },
  {
    "path": "papers/scipy/code/signal/opt_lowpass.py",
    "chars": 4247,
    "preview": "# -*- coding: utf-8 -*-\n\nfrom __future__ import division, print_function\n\nimport numpy as np\nfrom scipy.signal import re"
  },
  {
    "path": "papers/scipy/code/signal/pressure_example.py",
    "chars": 2145,
    "preview": "from __future__ import division, print_function\n\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom scipy.signal im"
  },
  {
    "path": "papers/scipy/code/signal/remez_example.py",
    "chars": 1424,
    "preview": "from __future__ import division, print_function\n\nimport numpy as np\nfrom scipy.signal import remez, freqz\nimport matplot"
  },
  {
    "path": "papers/scipy/code/signal/sos_bandpass_response.py",
    "chars": 1005,
    "preview": "from __future__ import division, print_function\n\nimport numpy as np\nfrom scipy.signal import butter, sosfreqz, sosfilt\ni"
  },
  {
    "path": "papers/scipy/code/signal/unstable_butterworth.py",
    "chars": 383,
    "preview": "from __future__ import division, print_function\n\nimport numpy as np\nfrom scipy.signal import butter, lfilter\nimport matp"
  },
  {
    "path": "papers/scipy/scipy.rst",
    "chars": 67989,
    "preview": ":author: Warren Weckesser\n:email: warren.weckesser@gmail.com\n\n..\n    Typography question: \"lowpass\", \"low-pass\" or \"low "
  },
  {
    "path": "papers/yuan_tang_hongliang_liu/convert.sh",
    "chars": 127,
    "preview": "#convert MD to rst format and save to .txt for the main .rst include\npandoc --from=markdown --to=rst --output=${1}.txt $"
  },
  {
    "path": "papers/yuan_tang_hongliang_liu/distributed_and_gpus.md",
    "chars": 7709,
    "preview": "# Title place holder (not to show in rst)\n\n## Distributed and GPU-accelerated XGBoost\n\nThough XGBoost has been proven to"
  },
  {
    "path": "papers/yuan_tang_hongliang_liu/distributed_and_gpus.txt",
    "chars": 8078,
    "preview": "Title place holder (not to show in rst)\n=======================================\n\nDistributed and GPU-accelerated XGBoost"
  },
  {
    "path": "papers/yuan_tang_hongliang_liu/intro.txt",
    "chars": 3194,
    "preview": "XGBoost\n==================================\nIntroduction\n----------------------------------\n\nMachine learning approaches "
  },
  {
    "path": "papers/yuan_tang_hongliang_liu/main_functionalities.txt",
    "chars": 13748,
    "preview": "Main Functionalities\n----------------------------------\n\n\nBasic Walk-through\n******************\n\nThe following is a basi"
  },
  {
    "path": "papers/yuan_tang_hongliang_liu/model_tune.md",
    "chars": 90,
    "preview": "# Title place holder (not to show in rst)\n\n## Model tune up and parameter selection\n\nTODO!"
  },
  {
    "path": "papers/yuan_tang_hongliang_liu/model_tune.txt",
    "chars": 164,
    "preview": "Title place holder (not to show in rst)\n=======================================\n\nModel tune up and parameter selection\n-"
  },
  {
    "path": "papers/yuan_tang_hongliang_liu/parameter_explained.md",
    "chars": 7841,
    "preview": "# Title place holder (not to show in rst)\n## Parameter explained: train `xgboost` for the best prediction\n\nThere are 3 t"
  },
  {
    "path": "papers/yuan_tang_hongliang_liu/parameter_explained.txt",
    "chars": 8665,
    "preview": "Title place holder (not to show in rst)\n=======================================\n\nParameter explained: train ``xgboost`` "
  },
  {
    "path": "papers/yuan_tang_hongliang_liu/references.txt",
    "chars": 884,
    "preview": "References\n==========\n\n-  `XGBoost: a scalable tree boosting\n   system <https://dl.acm.org/ft_gateway.cfm?id=2939785&typ"
  },
  {
    "path": "papers/yuan_tang_hongliang_liu/vs_gbdt.md",
    "chars": 1675,
    "preview": "# Title place holder (not to show in rst)\n## XGBoost vs. GBDT\n\nGradient Boosting Decision Tree (short as \"GBDT\") is a ty"
  },
  {
    "path": "papers/yuan_tang_hongliang_liu/vs_gbdt.txt",
    "chars": 1742,
    "preview": "Title place holder (not to show in rst)\n=======================================\n\nXGBoost vs. GBDT\n----------------\n\nGrad"
  },
  {
    "path": "papers/yuan_tang_hongliang_liu/xgboost_chapter.rst",
    "chars": 1878,
    "preview": ":author: Yuan Tang\n:email: terrytangyuan@gmail.com\n:institution:\n:corresponding:\n\n:author: Hongliang Liu\n:email: phunter"
  },
  {
    "path": "publisher/Makefile",
    "chars": 1041,
    "preview": "BUILDDIR = _build\nTEXDIR = _build/tex\nHTMLDIR = _build/html\nPDFDIR = _build/pdfs\nPAPERDIR = ../output\nTEMPLATES = _templ"
  },
  {
    "path": "publisher/_static/common.css",
    "chars": 4437,
    "preview": "/  common.css of MoinMoin theme \"sinorca4moin\" by David Linke.\n    $Id: common.css 102 2006-08-30 16:12:16Z linke $\n*/\n\n"
  },
  {
    "path": "publisher/_static/google_analytics.js",
    "chars": 417,
    "preview": "var _gaq = _gaq || [];\n_gaq.push(['_setAccount', 'UA-30141106-1']);\n_gaq.push(['_trackPageview']);\n\n(function() {\n  var "
  },
  {
    "path": "publisher/_static/proc_links.js",
    "chars": 442,
    "preview": "function proc_versions() {\n   var versions = ['2011', '2010', '2009', '2008'];\n   var proc_url = 'http://conference.scip"
  },
  {
    "path": "publisher/_static/pydata-cookbook.css",
    "chars": 342,
    "preview": "@import \"common.css\";\n@import \"screen.css\";\n\nbody {\n  font-family: Verdana, sans-serif;\n}\n\n#content {\n  width: 40em;\n  p"
  },
  {
    "path": "publisher/_static/pydata.sty",
    "chars": 1637,
    "preview": "% These preamble commands are from build_paper.py\n\n% DRAFT\n\\usepackage{status}\n\n% PDF Standard Fonts\n\\usepackage{mathptm"
  },
  {
    "path": "publisher/_static/screen.css",
    "chars": 10813,
    "preview": "/* screen.css of MoinMoin theme \"sinorca4moin\" by David Linke.\r\n    $Id: screen.css 104 2006-08-30 20:41:40Z linke $\r\n*/"
  },
  {
    "path": "publisher/_static/status.sty",
    "chars": 67,
    "preview": "% DRAFT ??\n\\usepackage{draftwatermark}\n\\SetWatermarkLightness{0.9}\n"
  },
  {
    "path": "publisher/_templates/article.bib.tmpl",
    "chars": 637,
    "preview": "{{py:\ndef bibtex_caps(words):\n    from string import ascii_uppercase\n    return ''.join(w if (w not in ascii_uppercase) "
  },
  {
    "path": "publisher/_templates/article.html.tmpl",
    "chars": 1800,
    "preview": "<h1>{{html_quote(article['title']) | html}}</h1>\n\n<div id=\"content\">\n\n{{for auth, inst in zip(article['author'], article"
  },
  {
    "path": "publisher/_templates/copyright.tex.tmpl",
    "chars": 901,
    "preview": "\\documentclass[letterpaper,compsoc,onecolumn,twoside]{IEEEtran}\n\\thispagestyle{empty}\n\\pagestyle{empty}\n\\usepackage[utf8"
  },
  {
    "path": "publisher/_templates/header.html.tmpl",
    "chars": 2720,
    "preview": "<html>\n<head>\n    <meta content=\"text/html; charset=utf-8\" http-equiv=\"content-type\">\n    <title>{{html_quote(proceeding"
  },
  {
    "path": "publisher/_templates/index.html.tmpl",
    "chars": 1070,
    "preview": "<h1>{{proceedings['title']['full']}} ({{proceedings['title']['acronym']}} {{proceedings['year']}})</h1>\n\n<div id=\"conten"
  },
  {
    "path": "publisher/_templates/organization.html.tmpl",
    "chars": 369,
    "preview": "<h1>Organization</h1>\n\n<div id=\"content\">\n\n{{for committee in organization}}\n\n  <h2>{{html_quote(committee['name']) | ht"
  },
  {
    "path": "publisher/_templates/organization.tex.tmpl",
    "chars": 549,
    "preview": "\\documentclass[letterpaper,compsoc,onecolumn,twoside,english]{IEEEtran}\n\\thispagestyle{empty}\n\\pagestyle{empty}\n\\usepack"
  },
  {
    "path": "publisher/_templates/proceedings.bib.tmpl",
    "chars": 297,
    "preview": "@Proceedings{ {{proceedings['citation_key']}},\n  title     = { {{proceedings['title']['full']}} },\n  booktitle = { {{pro"
  },
  {
    "path": "publisher/_templates/proceedings.tex.tmpl",
    "chars": 1347,
    "preview": "\\documentclass[letterpaper,compsoc,onecolumn,twoside,english]{IEEEtran}\n\\usepackage[utf8]{inputenc}\n\\setlength{\\parinden"
  },
  {
    "path": "publisher/_templates/students.html.tmpl",
    "chars": 365,
    "preview": "<h1>Sponsored Students</h1>\n\n<div id=\"content\">\n\n  <ul>\n\n    {{for student in sponsored_students}}\n      <li>{{html_quot"
  },
  {
    "path": "publisher/_templates/students.tex.tmpl",
    "chars": 480,
    "preview": "\\documentclass[letterpaper,compsoc,onecolumn,twoside,english]{IEEEtran}\n\\thispagestyle{empty}\n\\pagestyle{empty}\n\\usepack"
  },
  {
    "path": "publisher/_templates/title.tex.tmpl",
    "chars": 964,
    "preview": "\\documentclass[pdftex,letterpaper]{article}\n\\usepackage[pdftex]{graphicx}\n\\usepackage{palatino}\n\\usepackage[utf8]{inpute"
  },
  {
    "path": "publisher/_templates/toc.tex.tmpl",
    "chars": 570,
    "preview": "\\documentclass[letterpaper,compsoc,onecolumn,twoside,english]{IEEEtran}\n\\usepackage[utf8]{inputenc}\n\\setlength{\\parinden"
  },
  {
    "path": "publisher/build_html.py",
    "chars": 1305,
    "preview": "#!/usr/bin/env python\n\nimport os\nimport glob\nimport shutil\n\nfrom conf import bib_dir, template_dir, html_dir, static_dir"
  },
  {
    "path": "publisher/build_paper.py",
    "chars": 6199,
    "preview": "#!/usr/bin/env python\nfrom __future__ import print_function\n\nimport docutils.core as dc\nimport os.path\nimport sys\nimport"
  },
  {
    "path": "publisher/build_papers.py",
    "chars": 1706,
    "preview": "#!/usr/bin/env python\n\nimport os\nimport sys\nimport shutil\nimport subprocess\n\nimport conf\nimport options\nfrom build_paper"
  },
  {
    "path": "publisher/build_template.py",
    "chars": 2498,
    "preview": "#!/usr/bin/env python\n\nimport os\nimport sys\nimport shlex, subprocess\n\nimport tempita\nfrom conf import bib_dir, build_dir"
  },
  {
    "path": "publisher/conf.py",
    "chars": 1009,
    "preview": "import glob\nimport os\n\nexcludes = ['vanderwalt','bibderwalt']\n\nwork_dir      = os.path.dirname(__file__)\npapers_dir    ="
  },
  {
    "path": "publisher/mail/_mailer.py",
    "chars": 1712,
    "preview": "import argparse\nimport smtplib\nimport os\nimport getpass\nfrom email.mime.text import MIMEText\n\nimport sys\nsys.path.insert"
  },
  {
    "path": "publisher/mail/email.json",
    "chars": 1151,
    "preview": "{\n\n  \"conference\": \"SciPy 2011\",\n  \"year\": \"2011\",\n  \"due\": \"April 29, 2012\",\n  \"download\": \"http://jarrodmillman.com/sc"
  },
  {
    "path": "publisher/mail/mail_authors.py",
    "chars": 318,
    "preview": "#!/usr/bin/env python\n\nimport _mailer as mailer\n\nargs = mailer.parse_args()\nconfig = mailer.load_config('email.json')\n\nf"
  },
  {
    "path": "publisher/mail/mail_authors_example.txt",
    "chars": 49,
    "preview": "./mail_authors.py --template author-revision.txt\n"
  },
  {
    "path": "publisher/mail/mail_reviewers.py",
    "chars": 1204,
    "preview": "#!/usr/bin/env python\n\nimport _mailer as mailer\nimport os\nfrom conf import work_dir\n\nargs = mailer.parse_args()\nconfig ="
  },
  {
    "path": "publisher/mail/templates/author-revision.txt.tmpl",
    "chars": 973,
    "preview": "From: {{sender['name'] | html}}\nSubject: [{{conference}}] reviews submitted, revisions requested\nTo: {{email | html}}\nCc"
  },
  {
    "path": "publisher/mail/templates/reviewer-invite.txt.tmpl",
    "chars": 971,
    "preview": "From: {{sender['name'] | html}}\nSubject: [{{conference}}] invitation to review proceedings\nTo: {{email | html}}\nCc: {{cc"
  },
  {
    "path": "publisher/options.py",
    "chars": 823,
    "preview": "\"\"\"\nConfiguration utilities.\n\"\"\"\n\n__all__ = ['options']\n\nimport os.path\nimport json\nimport codecs\n\nimport conf\ntoc_conf "
  },
  {
    "path": "publisher/tempita/__init__.py",
    "chars": 39693,
    "preview": "\"\"\"\nA small templating language\n\nThis implements a small templating language.  This language implements\nif/elif/else, fo"
  },
  {
    "path": "publisher/tempita/_looper.py",
    "chars": 4161,
    "preview": "\"\"\"\nHelper for looping over sequences, particular in templates.\n\nOften in a loop in a template it's handy to know what's"
  },
  {
    "path": "publisher/tempita/compat3.py",
    "chars": 849,
    "preview": "import sys\n\n__all__ = ['b', 'basestring_', 'bytes', 'next', 'is_unicode']\n\nif sys.version < \"3\":\n    b = bytes = str\n   "
  },
  {
    "path": "publisher/writer/__init__.py",
    "chars": 17254,
    "preview": "__all__ = ['writer']\n\nimport docutils.core as dc\nimport docutils.writers\nfrom docutils import nodes\n\nfrom docutils.write"
  },
  {
    "path": "publisher/writer/code_block.py",
    "chars": 948,
    "preview": "# --- Code-block directive from Sphinx ---\n\nfrom docutils import nodes\nfrom docutils.parsers.rst import Directive, direc"
  },
  {
    "path": "publisher/writer/rstmath.py",
    "chars": 2449,
    "preview": "# This code is from: http://pypi.python.org/pypi/rstex/\n\n#!/usr/bin/python2\nfrom docutils import utils, nodes\nfrom docut"
  },
  {
    "path": "publisher/writer/sphinx_highlight.py",
    "chars": 477,
    "preview": "from pygments.style import Style\nfrom pygments.styles.friendly import FriendlyStyle\nfrom pygments.token import Generic, "
  },
  {
    "path": "pydata-cookbook.json",
    "chars": 370,
    "preview": "{\n  \"book\": {\n     \"citation_key\": \"pydata-cookbook-2018\",\n     \"title\": {\n       \"acronym\": \"PyData\",\n       \"short\": \""
  },
  {
    "path": "review_criteria.md",
    "chars": 2378,
    "preview": "# Suggested Review Criteria for PyData Cookbook\n\nThese criteria have been adapted from [the review criteria developed\nby"
  },
  {
    "path": "reviews/README",
    "chars": 525,
    "preview": "README\n======\n\nFor each SciPy review and update the substitutions in the two templates\nfor inviting reviewers to review "
  },
  {
    "path": "reviews/invite-abstract-reviews.rst",
    "chars": 1969,
    "preview": ".. note:: TODO-- improve abstract review criteria\n\n.. For each conference, update the following section,\n   which will b"
  },
  {
    "path": "reviews/invite-paper-reviews.rst",
    "chars": 2543,
    "preview": ".. For each conference, update the following section,\n   which will be inserted in the template below.\n\n.. |conference| "
  },
  {
    "path": "reviews/invite-reviewer.txt.in",
    "chars": 1126,
    "preview": "Hello {{ reviewer }}!\n\nThe 2016 Scientific Computing with Python Conference\n(http://scipy2016.scipy.org) is fast approac"
  },
  {
    "path": "reviews/review-template.rst",
    "chars": 4402,
    "preview": "Independent Review Report\n=========================\n\n.. note::  Please be aware that all reviews are made public includi"
  },
  {
    "path": "reviews/submission-template.rst",
    "chars": 1734,
    "preview": ".. Abstract submission template for SciPy 2012: The 11th\n.. Python in Science Conference, to be held in Austin, TX,\n.. J"
  }
]

About this extraction

This page contains the full source code of the pydata/pydata-cookbook GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 119 files (2.5 MB), approximately 655.6k tokens, and a symbol index with 195 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!