compiling notebooks into a report

For a master's project in computational neuroscience, we adopted a quite novel workflow to go all the steps from the learning of the small steps to the wrtiting of the final thesis. Though we were flexible in our method during the 6 months of this work, a simple workflow emerged that I describe here.

Compiling a set of notebook to a LaTeX document.

The project involved the modelling of a rather complex system involving the modelling of spiking neurons, studying the emerging states when they interact in populations. Of particular interest was the possibility to obtain what is called a "balanced state" which is relevant to model the brain. Finally, we modeled some realistic representation of the coding of orientation in what is called a "ring model".

  • As such, we had a hierarchy of problems to solve from the single neuron to the full network. The only solution was thus to take small steps and we were careful to create on a daily basis new notebooks reporting for these advances (pre-pended with the iso8601, for instance 2016-03-02_FeedForward_comparing_ExpVSAlpha).
  • To avoid the usual rush at the moment of handing over the thesis, another constraint that we adopted was that for every notebook, the first cell would describe what was done with possibly a visual figure. One huge advantage is that the student did not have to learn LaTeX, but only markdown.
  • In the end we had a bunch of notebooks that could just be "compiled" to produce a nice looking PDF file.

Let's focus on how to do that. For those in a hurry, let's just say that it involves:

  • globing a set of relevant notebooks,
  • striping out what is not important and keep the important stuff,
  • concatenate all of these in one notebook,
  • convert that to a PDF using a latex template

This is summarized in this script:

In [1]:
%%writefile thesis.py
name = 'thesis'

import nbconvert
import nbformat

nb_list = []
import glob
for fname in glob.glob('*.ipynb'):
    if fname[0] in ['1', '2',  '3', '4']:
        print ("'{}', ".format(fname) )
        nb_list.append(fname)
        
def strip(nb):
    """
    Keeps only the cells :
    - starting with the first to begin with a section (that is with a ``#``)
    - stoping with the next cell to begin with a section (that is with a ``#``)
    
    """
    start, stop = -1, len(nb.cells)
    nb_out = nb.copy()
    for i_cell, cell in enumerate(nb_out.cells):
        if len(cell['source'])>0:
            if cell['source'][0] == '#':
                if start == -1: start = i_cell
                else:
                    if stop == len(nb.cells): stop = i_cell
    if start == -1: start = 0
    nb_out.cells = nb.cells[start:stop]
    return nb_out
    
def merge_notebooks(outfile, filenames):
    merged = None
    for fname in filenames:
        with open(fname, 'r', encoding='utf-8') as f:
            nb = nbformat.read(f, nbformat.NO_CONVERT)
        
        nb = strip(nb)
        if merged is None:
            merged = nb
        else:
            merged.cells.extend(nb.cells)
    with open(outfile, 'w', encoding='utf-8') as f:
        f.write(nbformat.writes(merged, nbformat.NO_CONVERT))
merge_notebooks(name + '.ipynb', nb_list)  

with open(name + '.ipynb', 'r') as f:
    nb = nbformat.read(f, as_version=nbformat.NO_CONVERT)

latex_exporter = nbconvert.PDFExporter()
latex_exporter.template_file = name # assumes it has the same name as the output
latex_exporter.verbose = True
(body, resources) = latex_exporter.from_notebook_node(nb)
with open(name + '.pdf', 'w', encoding="iso-8859-1") as f:
    f.write(body.decode(encoding="iso-8859-1"))
Overwriting thesis.py
In [2]:
%run thesis.py
'1.0-Introduction.ipynb', 
'1.1-Plan.ipynb', 
'2.0.0_SpikingNeuronModels.ipynb', 
'2.1.1_NeuralNetworks_SpikingNeuronModel.ipynb', 
'2.1.2_NeuralNetworks_Brian_OneNeuron.ipynb', 
'2.1.3_NeuralNetworks_Brian.ipynb', 
'2.1.4_NeuralNetworks_Nest.ipynb', 
'2.1.5_NeuralNetworks_pyNN_CODAvsCUBA.ipynb', 
'2.1.6_FeedForward_Exploration_I-Fcurve.ipynb', 
'2.2.1_RRNN_Presentation.ipynb', 
'2.2.2_RRNN_Exploration_control cell parameters.ipynb', 
'2.2.3_RRNN_Exploration_ModelExpVSAlpha.ipynb', 
'2.2.4_RRNN_Rasterplot_InputVariation.ipynb', 
'2.2.5_RRNN_Rasterplot_CheckingInvariants.ipynb', 
'2.2.6_RRNN_Rasterplot_GlobalWeight_Variation.ipynb', 
'2.2.7_RRNN_Exploration_Curve_Weights.ipynb', 
'2.2.8_RRNN_Exploration_Curve_Sparseness.ipynb', 
'2.2.9_RRNN_Exploration_Curve_G.ipynb', 
'2.3.1_RRNN_BalancedStates_MultiOptimisation_Intro.ipynb', 
'2.3.3_RRNN_BalancedStates_MultiOptimisation_DifferentG.ipynb', 
'3.1.1_Ring Intro.ipynb', 
'3.2.1_Ring UnTuned = input + feed-forward.ipynb', 
'3.2.2_Ring UnTuned input Homogeneous weight.ipynb', 
'3.2.3_Ring UnTuned_Bandwidths.ipynb', 
'3.2.4_Ring Untuned_FittingResponse.ipynb', 
'3.3.1_Ring_FeedForwardvsRecurrent-Rasterplots.ipynb', 
'3.3.2_Ring recurrent_Bandwidths.ipynb', 
'3.3.3_Ring recurrent_FittingResponse.ipynb', 
'4.1_Discussion et perspectives.ipynb', 
'4.2_These.ipynb', 

Voilà!

details of the method

Below I will detail the method in more detail.

templating

While essential to typeset documents, $\LaTeX$ takes a while to learn and we decided to have everything written down in MarkDown, as it is native to ipython notebooks and allows to cover most of most needs, from structuring a document to writing equations. In ipython's nbconvert scheme, this involves doing the conversion machinery in a template that we simply adapted to our needs (mainly by tweeking the report.tplx file and using information around the web). Still some cosmetics could be done to pass some parameters such as author's name etc... programmatically, but that is pratictally what came out:

In [3]:
%%writefile thesis.tplx
((*- extends 'report.tplx' -*))

% Default to the notebook output style
((* set cell_style = 'style_ipython.tplx' *))
%((* set cell_style = 'style_bw_python.tplx' *))

((* block docclass *))
\documentclass[french, 12pt]{report}
((* endblock docclass *))

((* block packages *))
((( super() )))
\usepackage[french]{babel}%
%\usepackage{graphics}%
\usepackage{setspace}%

\newcommand{\BookTitle}{
{\bf Aix-Marseille Université}\\
        {\bf Mémoire de Recherche} \\
        présenté en vue de l'obtention du \\
         {\bf MASTER de NEUROSCIENCES} \\
         (Spécialité: NIC)
        }
\newcommand{\Title}{OB-V1 : un modèle de détection de l'orientation dans l'aire visuelle primaire}% 
\newcommand{\Author}{Fernand David Arbib}%
\newcommand{\AuthorB}{Laurent U.~Perrinet}%
\newcommand{\Team}{\'Equipe Inference in Visual Behaviour (InViBe)}%
\newcommand{\Institute}{Institut de Neurosciences de la Timone}%
\newcommand{\InstituteUMR}{UMR 7289, CNRS / Aix-Marseille Université}%
\newcommand{\Address}{27, Bd. Jean Moulin, 13385 Marseille Cedex 5, France} 
\newcommand{\Website}{https://URL/LaurentPerrinet}
\newcommand{\Email}{Laurent.Perrinet@univ-amu.fr} 
                   
((* endblock packages *))

((* block h1 -*))\chapter((* endblock h1 -*))
((* block h2 -*))\section((* endblock h2 -*))
((* block h3 -*))\subsection((* endblock h3 -*))
((* block h4 -*))\subsubsection((* endblock h4 -*))
((* block h5 -*))\paragraph((* endblock h5 -*))

((* block abstract *))
%\tableofcontents
~\par
\newpage
((* endblock abstract *))

((* block margins *))
\parindent=0pt
\parskip=6pt
((* endblock margins *))

((* block predoc *))
((* block title *))
                            \title{\Title}
((* endblock title *))
((* block author *))
                            \author{\Author}
((* endblock author *))
((* block maketitle *))     
%\maketitle
\begin{titlepage}

\begin{center}
%\vskip 2cm
                   \begin{spacing}{1.2}
{\Large \BookTitle }%
                   \end{spacing}
\vskip 1cm
                   \begin{spacing}{1.5}
{\Huge \Title }
                   \end{spacing}
%\vskip 1cm
%\emph{\Large \SubTitle }%
\begin{center}
\includegraphics{/tmp/troislogos.png} 
\end{center}
%\vskip 1cm
                   {\renewcommand{\arraystretch}{1.5} %<- modify value to suit your needs
\begin{tabular}[t]{|c|c|}
\hline
Par: & {\large \Author}  \\\hline
Responsable de Stage: & {\large \AuthorB}  \\%\hline
&\url{\Website}\\%\hline
&\url{\Email}\\\hline
Laboratoire: & \Team \\%\hline
             &          \Institute \\ 
             &           \InstituteUMR \\%\hline
             &\Address \\\hline
\end{tabular}
                    }
\vskip .5cm

\vfill
{\large Juin 2016}
%\pageskip
\end{center}
\end{titlepage}
\tableofcontents
%\doublespacing
                   
((* endblock maketitle *))
((* endblock predoc *))

((* block commands *))
    % Prevent overflowing lines due to hard-to-break entities
    \sloppy
    % Setup hyperref package
    \hypersetup{
      breaklinks=true, % so long urls are correctly broken across lines
	pdftitle={\Title},
	pdfauthor={\Author},
	colorlinks=true, %colorise les liens
	breaklinks=true, %permet le retour à la ligne dans les liens trop longs
	urlcolor= blue, %couleur des hyperliens
	linkcolor= blue, %couleur des liens internes
	citecolor=blue,    %couleur des liens de citations
	bookmarksopen=false,
	pdftoolbar=false,
	pdfmenubar=false,
%      hidelinks
      }
    % Slightly bigger margins than the latex defaults
    \geometry{verbose,tmargin=1in,bmargin=1in,lmargin=1in,rmargin=1in}

    ((* endblock commands *))

((* block bibliography *))
\bibliographystyle{plain}
\bibliography{/tmp/thesis}
((* endblock bibliography *))
Overwriting thesis.tplx

For some reason, the latex file is compiled on a temporary folder and loses track of the current working directory. One solution is to copy files in an absolute path that will be cleaned-up at the next reboot:

In [4]:
!cp ../figs/troislogos.png /tmp/troislogos.png
!cp ../figs/ring_model.png /tmp/ring_model.png
!cp ../figs/future_model.png /tmp/future_model.png

Optionnally, it is possible to disable selectively some cells by introduciong the following in the template:

% Disable input cells %((* block input_group *)) %((* endblock input_group *)) % Disable output cells %((* block output_group *)) %((* endblock output_group *))

including references

Moreover, it is possible to include references and have that included using BibTeX. In MarkDown, it has to be fomatted like

<cite data-cite="Brunel2000">(Brunel, 2000)</cite>

To get somthing like (Brunel, 2000). This involves of course creating a bibliography file:

In [5]:
%%writefile /tmp/thesis.bib

@article{Brunel_2007,
	Author = {Brunel, Nicolas and van Rossum, Mark C. W.},
	Doi = {10.1007/s00422-007-0190-0},
	Issn = {1432-0770},
	Journal = {Biol Cybern},
	Month = {Oct},
	Number = {5-6},
	Pages = {337--339},
	Publisher = {Springer Science + Business Media},
	Title = {Lapicque's 1907 paper: from frogs to integrate-and-fire},
	Url = {http://dx.doi.org/10.1007/s00422-007-0190-0},
	Volume = {97},
	Year = {2007},
	Bdsk-Url-1 = {http://dx.doi.org/10.1007/s00422-007-0190-0}}

@article{Burkitt_2006,
	Author = {Burkitt, A. N.},
	Doi = {10.1007/s00422-006-0068-6},
	Issn = {1432-0770},
	Journal = {Biol Cybern},
	Month = {Apr},
	Number = {1},
	Pages = {1--19},
	Publisher = {Springer Science + Business Media},
	Title = {A Review of the Integrate-and-fire Neuron Model: I. Homogeneous Synaptic Input},
	Url = {http://dx.doi.org/10.1007/s00422-006-0068-6},
	Volume = {95},
	Year = {2006},
	Bdsk-Url-1 = {http://dx.doi.org/10.1007/s00422-006-0068-6}}

@article{Burkitt_2006a,
	Author = {Burkitt, A. N.},
	Date-Modified = {2016-06-02 09:06:54 +0000},
	Doi = {10.1007/s00422-006-0082-8},
	Issn = {1432-0770},
	Journal = {Biol Cybern},
	Month = {Jul},
	Number = {2},
	Pages = {97--112},
	Publisher = {Springer Science + Business Media},
	Title = {A review of the integrate-and-fire neuron model: II. Inhomogeneous synaptic input and network properties},
	Url = {http://dx.doi.org/10.1007/s00422-006-0082-8},
	Volume = {95},
	Year = {2006},
	Bdsk-Url-1 = {http://dx.doi.org/10.1007/s00422-006-0082-8}}

@article{Goris_2015,
	Author = {Goris, Robbe L.T. and Simoncelli, Eero P. and Movshon, J. Anthony},
	Doi = {10.1016/j.neuron.2015.10.009},
	Issn = {0896-6273},
	Journal = {Neuron},
	Month = {Nov},
	Number = {4},
	Pages = {819--831},
	Publisher = {Elsevier BV},
	Title = {Origin and Function of Tuning Diversity in Macaque Visual Cortex},
	Url = {http://dx.doi.org/10.1016/j.neuron.2015.10.009},
	Volume = {88},
	Year = {2015},
	Bdsk-Url-1 = {http://dx.doi.org/10.1016/j.neuron.2015.10.009}}

@article{hansel1995synchrony,
	Author = {Hansel, David and Mato, Germ{\'a}n and Meunier, Claude},
	Date-Added = {2016-06-02 09:07:52 +0000},
	Date-Modified = {2016-06-02 09:07:52 +0000},
	Journal = {Neural computation},
	Number = {2},
	Pages = {307--337},
	Publisher = {MIT Press},
	Title = {Synchrony in excitatory neural networks},
	Volume = {7},
	Year = {1995}}

@article{Hunter07,
	Abstract = {Matplotlib is a {2D} graphics package for Python for application development, interactive scripting, and publication-quality image generation across user interfaces and operating systems.},
	Address = {Los Alamitos, CA, USA},
	Author = {Hunter, John D.},
	Booktitle = {Computing in Science \& Engineering},
	Citeulike-Article-Id = {2878517},
	Citeulike-Linkout-0 = {http://dx.doi.org/10.1109/MCSE.2007.55},
	Citeulike-Linkout-1 = {http://doi.ieeecomputersociety.org/10.1109/MCSE.2007.55},
	Citeulike-Linkout-2 = {http://dx.doi.org/10.1109/mcse.2007.55},
	Citeulike-Linkout-3 = {http://ieeexplore.ieee.org/xpls/abs\_all.jsp?arnumber=4160265},
	Date-Added = {2016-06-02 09:06:18 +0000},
	Date-Modified = {2016-06-02 09:06:18 +0000},
	Day = {01},
	Doi = {10.1109/MCSE.2007.55},
	Issn = {1521-9615},
	Journal = {Computing in Science and Engineering},
	Keywords = {assofield, bicv-motion, bicv-sparse, kaplan13, khoei13jpp, perrinet12pred, python, reproducible-science, thesis},
	Month = may,
	Number = {3},
	Pages = {90--95},
	Priority = {0},
	Publisher = {IEEE Computer Society},
	Title = {Matplotlib: A {2D} Graphics Environment},
	Url = {http://dx.doi.org/10.1109/MCSE.2007.55},
	Volume = {9},
	Year = {2007},
	Bdsk-Url-1 = {http://dx.doi.org/10.1109/MCSE.2007.55}}

@article{Leon12,
	Abstract = {Choosing an appropriate set of stimuli is essential to characterize the response of a sensory system to a particular functional dimension, such as the eye movement following the motion of a visual scene. Here, we describe a framework to generate random texture movies with controlled information content, i.e., Motion Clouds. These stimuli are defined using a generative model that is based on controlled experimental parametrization. We show that Motion Clouds correspond to dense mixing of localized moving gratings with random positions. Their global envelope is similar to natural-like stimulation with an approximate full-field translation corresponding to a retinal slip. We describe the construction of these stimuli mathematically and propose an open-source Python-based implementation. Examples of the use of this framework are shown. We also propose extensions to other modalities such as color vision, touch, and audition.},
	Author = {Sanz-Leon, Paula and Vanzetta, I. and Masson, G. S. and Perrinet, L. U.},
	Citeulike-Article-Id = {10461699},
	Citeulike-Linkout-0 = {http://dx.doi.org/10.1152/jn.00737.2011},
	Citeulike-Linkout-1 = {http://jn.physiology.org/content/early/2012/03/10/jn.00737.2011.abstract},
	Citeulike-Linkout-2 = {http://jn.physiology.org/content/early/2012/03/10/jn.00737.2011.full.pdf},
	Citeulike-Linkout-3 = {http://view.ncbi.nlm.nih.gov/pubmed/22423003},
	Citeulike-Linkout-4 = {http://www.hubmed.org/display.cgi?uids=22423003},
	Date-Added = {2016-06-02 09:07:31 +0000},
	Date-Modified = {2016-06-02 09:07:31 +0000},
	Day = {14},
	Doi = {10.1152/jn.00737.2011},
	Issn = {1522-1598},
	Journal = {Journal of Neurophysiology},
	Keywords = {bicv-sparse, freemove, kaplan13, motion-clouds, sanz12jnp, vacher14},
	Month = mar,
	Number = {11},
	Pages = {3217--3226},
	Pmid = {22423003},
	Priority = {0},
	Publisher = {American Physiological Society},
	Title = {Motion clouds: model-based stimulus synthesis of natural-like random textures for the study of motion perception},
	Url = {http://dx.doi.org/10.1152/jn.00737.2011},
	Volume = {107},
	Year = {2012},
	Bdsk-Url-1 = {http://dx.doi.org/10.1152/jn.00737.2011}}

@article{Oliphant07,
	Abstract = {By itself, Python is an excellent "steering" language for scientific codes written in other languages. However, with additional basic tools, Python transforms into a high-level language suited for scientific and engineering code that's often fast enough to be immediately useful but also flexible enough to be sped up with additional extensions.},
	Address = {Los Alamitos, CA, USA},
	Author = {Oliphant, T. E.},
	Citeulike-Article-Id = {5662279},
	Citeulike-Linkout-0 = {http://dx.doi.org/10.1109/MCSE.2007.58},
	Citeulike-Linkout-1 = {http://doi.ieeecomputersociety.org/10.1109/MCSE.2007.58},
	Citeulike-Linkout-2 = {http://dx.doi.org/10.1109/mcse.2007.58},
	Citeulike-Linkout-3 = {http://ieeexplore.ieee.org/xpls/abs\_all.jsp?arnumber=4160250},
	Date-Added = {2016-06-02 09:06:18 +0000},
	Date-Modified = {2016-06-02 09:06:18 +0000},
	Day = {01},
	Doi = {10.1109/MCSE.2007.58},
	Institution = {Brigham Young Univ., Provo},
	Issn = {1521-9615},
	Journal = {Computing in Science and Engineering},
	Keywords = {assofield, bicv-motion, bicv-sparse, kaplan13, khoei13jpp, perrinet12pred, python, reproducible-science, thesis},
	Month = may,
	Number = {3},
	Pages = {10--20},
	Priority = {0},
	Publisher = {IEEE Computer Society},
	Title = {Python for Scientific Computing},
	Url = {http://dx.doi.org/10.1109/MCSE.2007.58},
	Volume = {9},
	Year = {2007},
	Bdsk-Url-1 = {http://dx.doi.org/10.1109/MCSE.2007.58}}
Overwriting /tmp/thesis.bib

merging all notebooks

From all dated notebooks, we slected the one to be included in the report and ordered theme according to a hierarchical naming schemes that allowed to easily glob them:

In [6]:
if False: # manual mode
    nb_list =['1-Introduction.ipynb', 
'2.1.1_NeuralNetworks_SpikingNeuronModel.ipynb', 
'2.1.2_NeuralNetworks_Brian_OneNeuron.ipynb', 
'2.1.3_NeuralNetworks_Brian.ipynb', 
'2.1.4_NeuralNetworks_Nest.ipynb', 
'2.1.5_NeuralNetworks_pyNN_CODAvsCUBA.ipynb', 
'2.1.6_FeedForward_Exploration_I-Fcurve.ipynb', 
'2.2.10_RRNN_Exploration_Curve_Sparseness.ipynb', 
'2.2.11_RRNN_Exploration_Curve_G.ipynb', 
'2.2.12_RRNN_Rasterplot_G.ipynb', 
'2.2.1_RRNN_Presentation.ipynb', 
'2.2.2_RRNN_Exploration_control cell parameters.ipynb', 
'2.2.3_RRNN_Exploration_ModelExpVSAlpha.ipynb', 
'2.2.4_RRNN_Rasterplot_InputVariation.ipynb', 
'2.2.5_RRNN_Rasterplot_InputWeight.ipynb', 
'2.2.6_RRNN_Exploration_I-Fcurve.ipynb', 
'2.2.7_RRNN_Rasterplot_CheckingInvariants.ipynb', 
'2.2.8_RRNN_Rasterplot_GlobalWeight_Variation.ipynb', 
'2.2.9_RRNN_Exploration_Curve_Weights.ipynb', 
'2.3.1_RRNN_BalancedStates_MultiOptimisation_Intro.ipynb', 
'2.3.2_RRNN_BalancedStates_MultiOptimisation_DifferentWeight.ipynb', 
'2.3.3_RRNN_BalancedStates_MultiOptimisation_DifferentG.ipynb', 
'3.1.1_Ring Intro.ipynb', 
'3.2.1_Ring Tuned input.ipynb', 
'3.2.2_Ring Tuned input Homogeneous weight.ipynb', 
'3.2.3_Ring Tuned_Bandwidths.ipynb', 
             ]    
else:
    nb_list = []
    import glob
    for fname in glob.glob('*.ipynb'):
        if fname[0] in ['1', '2',  '3', '4']:
            print ("'{}', ".format(fname) )
            nb_list.append(fname)
'1.0-Introduction.ipynb', 
'1.1-Plan.ipynb', 
'2.0.0_SpikingNeuronModels.ipynb', 
'2.1.1_NeuralNetworks_SpikingNeuronModel.ipynb', 
'2.1.2_NeuralNetworks_Brian_OneNeuron.ipynb', 
'2.1.3_NeuralNetworks_Brian.ipynb', 
'2.1.4_NeuralNetworks_Nest.ipynb', 
'2.1.5_NeuralNetworks_pyNN_CODAvsCUBA.ipynb', 
'2.1.6_FeedForward_Exploration_I-Fcurve.ipynb', 
'2.2.1_RRNN_Presentation.ipynb', 
'2.2.2_RRNN_Exploration_control cell parameters.ipynb', 
'2.2.3_RRNN_Exploration_ModelExpVSAlpha.ipynb', 
'2.2.4_RRNN_Rasterplot_InputVariation.ipynb', 
'2.2.5_RRNN_Rasterplot_CheckingInvariants.ipynb', 
'2.2.6_RRNN_Rasterplot_GlobalWeight_Variation.ipynb', 
'2.2.7_RRNN_Exploration_Curve_Weights.ipynb', 
'2.2.8_RRNN_Exploration_Curve_Sparseness.ipynb', 
'2.2.9_RRNN_Exploration_Curve_G.ipynb', 
'2.3.1_RRNN_BalancedStates_MultiOptimisation_Intro.ipynb', 
'2.3.3_RRNN_BalancedStates_MultiOptimisation_DifferentG.ipynb', 
'3.1.1_Ring Intro.ipynb', 
'3.2.1_Ring UnTuned = input + feed-forward.ipynb', 
'3.2.2_Ring UnTuned input Homogeneous weight.ipynb', 
'3.2.3_Ring UnTuned_Bandwidths.ipynb', 
'3.2.4_Ring Untuned_FittingResponse.ipynb', 
'3.3.1_Ring_FeedForwardvsRecurrent-Rasterplots.ipynb', 
'3.3.2_Ring recurrent_Bandwidths.ipynb', 
'3.3.3_Ring recurrent_FittingResponse.ipynb', 
'4.1_Discussion et perspectives.ipynb', 
'4.2_These.ipynb', 

This also gives the outline of the thesis.

stripping the first block

When working on a notebook, you want to be free to experiment new things or to be able to test code bits. By convention, we chose to define a "serious block" the rest being stripped of the the final report. by convention, we chose to keep only the cells :

  • starting with the first to begin with a section (that is with a #)
  • stoping with the next cell to begin with a section (that is with a #)

We can experiment how to read for instance one notebook:

In [7]:
with open('1.0-Introduction.ipynb', 'r') as f:
    nb = nbformat.read(f, as_version=nbformat.NO_CONVERT)
nb.cells = nb.cells[0:len(nb.cells)]
print ('Number of cells: ', len(nb.cells))
Number of cells:  13

And define different blocks:

In [8]:
with open('1.0-Introduction.ipynb', 'r') as f:
    nb = nbformat.read(f, as_version=nbformat.NO_CONVERT)

print (nb.cells[2])    
blocks = 0    
for cell in nb.cells:
    if len(cell['source'])>0:
        if cell['source'][0] == '#': 
            blocks += 1
    print('-----')
    print(blocks)    
    print('-----')
    print(cell['source'])
{'metadata': {}, 'source': '## figures / autre notes\n\n(Les caractéristiques de la réponse de la plupart des neurones sélectifs à l\'orientation, ont également été étudiées. Il existe une certaine diversité dans la courbe d\'accord de ces neurones. En effet, la largeur de bande ou "bandwidth" de cette courbe varie d\'un neurone à l\'autre. Ainsi, la discriminabilité de l\'orientation par les neurones du cortex visuel primaire n\'est pas uniforme. Cette caractéristique a un effet direct sur le codage des orientations présentes dans un stimulus visuel . Les stimuli ne contenant qu\'une seule orientation sont mieux codés par les neurones les plus sélectifs. A contrario, les stimuli riches en orientations sont mieux représentés par l\'activité des neurones les moins sélectifs <cite data-cite="Goris_2015">(Goris, 2015)</cite>.)\n\n![](figs/orientation_tuning.png) \nAinsi, la perception des orientations contenues dans les différents stimuli visuels doit dépendre également de propriétés quantitatives que nous nous proposons d\'étudier dans ce travail.\n\n\n\n\n\nParamètres pour balanced states :\n\n* g = 4\n* w_in = 0.015\n* w = 0.04\n* s = 1\n* c = 0.015\n* p = 0.8\n* n = 1080', 'cell_type': 'markdown'}
-----
0
-----
%load_ext autoreload
%autoreload 2

%matplotlib inline
import numpy as np
-----
1
-----
# Introduction

## Motivation

Une entité ne peut être vivante si elle n'interagit pas avec son environnement. La vie, réduit à son plus simple appareil, comporte du code génétique. Pour se perpétuer, ce code génétique doit permettre de produire des molécules qui vont former le matériel nécessaire à sa protection, à son alimentation et enfin à sa reproduction. La cellule remplit ces rôles, aussi, sa membrane et les protéines qui la constituent lui permettent de jouer un rôle d'interface entre le code génétique et l'environnement. Il apparait que la notion d'interface soit importante dans le vivant. Ainsi, l'interface se conserve et se sophistique, au fil de nombreuses mutations du code génétique et de la sélection naturelle. Cette dernière va permettre l'émergence d'interfaces de plus en plus élaborées, qui vont offrir de multiples manières de filtrer l'environnement et des moyens d'explorer celui-ci.

Avec l'apparition des organismes pluricellulaires et des moyens de communications entre les cellules, les cellules se spécialisent, s'assemblent et constituent des tissus cellulaires, des organes et des systèmes qui vont permettre à l'ensemble de l'organisme d'interagir, d'une manière spécifique au système considéré, avec l'environnement. Le système nerveux en est un exemple. En effet, celui-ci permet de traiter des informations externes ou internes, et une partie de ce traitement comprend diverses fonctions que l'on regroupe dans le concept de perception.

Selon l'approche neurophysiologique de la vision, la perception visuelle est construite sur la photosensibilité de certaines cellules, les cônes et les bâtonnets. Ces cellules et d'autres comme, par exemple, les cellules ganglionnaires, forment la rétine tapissant le fond de l'oeil où, à tout instant, une image de l'environnement se projette. Les cellules photosensibles vont permettre d'encoder les variations locales de luminosité composant l'image en variations de potentiel membranaire. Ces variations de potentiel vont ensuite être codées en influx nerveux qui vont être transmis dans le réseau rétinien pour y être transformés. Les informations visuelles arrivent alors au niveau du cortex visuel primaire via les entrées thalamiques. L'organisation de ce cortex est rétinotopique. Ainsi, l'activité du cortex visuel primaire représente l'espace visuel, composé d'éléments locaux comme, par exemple, les bords orientés et les couleurs. Une question se pose alors lorsqu'on cherche à associer ce substrat biologique à la perception visuelle : comment le système nerveux central réalise l'intégration de ces éléments locaux afin de constuire un percept global ?

Afin de répondre à cette large problématique, il convient de s'intéresser aux divers constituants de l'image composante par composante. Ainsi, le travail qui vous est présenté est dédié à l'étude de la détection d'orientations. Il s'incrit dans un projet interdisciplinaire porté par l'équipe InViBe au sein de l'Institut de Neurosciences de la Timone. Ce projet prévoit, outre diverses expérimentations chez l'animal, une approche computationnelle des mécanismes impliqués dans cette détection d'orientations, qui constitue l'objet de ce travail.

## Contexte scientifique

### Organisation des orientations
Des électrophysiologistes tels que Hubel et Wiesel ont mis en évidence, chez le chat, que des colonnes corticales du cortex visuel primaire ont une sensibilité préférentielle à une orientation possible de barres de contraste<cite data-cite="Hubel">(Hubel, Wiesel, 1962)</cite>. L'avancée des études sur la sélectivité à l'orientation des neurones corticaux, montrent que le cortex visuel primaire des mammifères carnivores et des primates est comme une carte, où les neurones de même sélectivité à l'orientation sont regroupés en domaines d'iso-orientation. L'organisation particulière de ces domaines ou îlots donne lieu à des propriétés remarquables. En effet, il existe différents voisinages d'un neurone se trouvant dans le cortex visuel primaire. Si celui-ci se trouve à l'intérieur des îlots, il est à proximité de neurones de même, ou proche, sélectivité à l'orientation. Si, en revanche, toutes les orientations sont codées par son voisinage, alors il est à l'intérieur des fractures (ou pinwheels), où la sélectivité à l'orientation varie rapidement <cite data-cite="ohki">(Ohki et al., 2006)</cite> <cite data-cite="grinvald">(Bonhoeffer, Grinvald 1991)</cite>. Dans le cortex visuel primaire du rongeur, il n'existe pas de domaines d'iso-orientation, le voisinage d'un neurone quelconque est alors de la deuxième espèce citée.

### Réponse à une orientation

De telles organisations suscitent des hypothèses quant à l'intégration des informations sur l'orientation au sein des colonnes corticales du cortex visuel primaire.
Une d'entre elles postule que la probablité de connexion entre les neurones du cortex visuel primaire est exclusivement dépendante de leur distance anatomique <cite data-cite="das">(Das, Gilbert 1999)</cite>. Ce qui signifie que, dans le cas admis où il existe des connexions récurrentes et latérales au niveau cortical, les neurones à l'intérieur des domaines d'iso-orientation intègrent des informations provenant de neurones de même préférence à l'orientation. Ainsi, la réponse de ces neurones est fortement sélective et est robuste à la richesse en orientations d'un stimulus. Cela veut dire également qu'à proximité des fractures, et dans le cortex visuel primaire du rat, les neurones devraient avoir une faible sélectivité à l'orientation car ils intègrent les informations provenant de neurones sélectifs à différentes orientations. Ce n'est pourtant pas ce qui est montré expérimentalement. Une étude explique alors ce paradoxe. En effet, il a été théoriquement démontré que la réponse de ces neurones, supposés peu sélectifs, peut être plus sélective à l'orientation si le réseau du cortex visuel primaire est dans un état balancé entre l'excitation et l'inhibition <cite data-cite="HanselVan">(Hansel, Van Vreeswijk 2012)</cite>.

Nous nous proposons donc d'étudier la réponse d'un réseau de neurones artificiel, un ring, à différents stimuli visuels, des motion clouds <cite data-cite="Leon12">(Leon)</cite>, dont nous ferons alors varier la richesse en orientations. En effet, le contenu en orientations de chaque stimulus peut être défini de façon quantitative en modulant une certaine valeur de bandwidth $B_\theta$ caractérisant l'entrée visuelle. Le but est d'implémenter le réseau, de façon à ce qu'il possède des propriétés similaires à celles évoquées plus haut concernant le cortex visuel primaire. Nous comparerons alors la réponse de ce réseau à des données physiologiques.


![Réseau de neurones organisé en "ring".](/tmp/ring_model.png)
-----
2
-----
## figures / autre notes

(Les caractéristiques de la réponse de la plupart des neurones sélectifs à l'orientation, ont également été étudiées. Il existe une certaine diversité dans la courbe d'accord de ces neurones. En effet, la largeur de bande ou "bandwidth" de cette courbe varie d'un neurone à l'autre. Ainsi, la discriminabilité de l'orientation par les neurones du cortex visuel primaire n'est pas uniforme. Cette caractéristique a un effet direct sur le codage des orientations présentes dans un stimulus visuel . Les stimuli ne contenant qu'une seule orientation sont mieux codés par les neurones les plus sélectifs. A contrario, les stimuli riches en orientations sont mieux représentés par l'activité des neurones les moins sélectifs <cite data-cite="Goris_2015">(Goris, 2015)</cite>.)

![](figs/orientation_tuning.png) 
Ainsi, la perception des orientations contenues dans les différents stimuli visuels doit dépendre également de propriétés quantitatives que nous nous proposons d'étudier dans ce travail.





Paramètres pour balanced states :

* g = 4
* w_in = 0.015
* w = 0.04
* s = 1
* c = 0.015
* p = 0.8
* n = 1080
-----
3
-----
## brouillon

- chez primates et carnivores : 2 zones anatomo-fonctionnelles différentes : pinwheel et intérieur d'un patch
- chez rat : pas d'iso-orientation

gradient de sélectivité :
couche 4 : peu de sélectivité
couche 2-3 : bcp de sélectivité

problématique dans l'intégration de la réponse :

on pense que neurones à certaines PO intègrent des réponses d'autres neurones de même PO
mais ça c'est valide qu'à l'intérieur d'un patch
qu'en est il pour le pinwheel???

- si probabilité de connexion dépend uniquement de proximité anatomique : les neurones dans pinwheel sont peu sélectifs à l'orientation

- du coup V1 balancé pourrait avoir SO

- plusieurs stimuli gratings, mc dont la réponse a V1 à ceux ci permet d'infirmer une des deux hypothèses.







-----
3
-----
import matplotlib.pyplot as plt

def envelope(th, theta, B_theta):
    if B_theta==np.inf:
        env = np.ones_like(th) 
    elif B_theta==0:
        env = np.zeros_like(th)
        env[np.argmin(th < theta)] = 1.
    else:
        env = np.exp((np.cos(2*(th-theta))-1)/4/B_theta**2)
    return env/env.max()        

N_theta = 12
bins = 180
th = np.linspace(0, np.pi, bins, endpoint=False)
fig, axs = plt.subplots(1, 2, figsize=(8, 5))
for i, B_theta_ in enumerate([np.pi/12, np.pi/4]):#[0, np.pi/64, np.pi/32, np.pi/16, np.pi/8, np.pi/4, np.pi/2, np.inf]:
    for theta, color in zip(np.linspace(0, np.pi, N_theta, endpoint=False), 
                            [plt.cm.hsv(h) for h in np.linspace(0, 1, N_theta)]):
        axs[i].plot(th*180/np.pi, envelope(th, theta, B_theta_), alpha=.6, color=color, lw=3)
        axs[i].fill_between(th*180/np.pi, 0, envelope(th, theta, B_theta_), alpha=.1, color=color)
    axs[i].set_xlim([0, 180])
    axs[i].set_ylim([0, 1.1])
    axs[i].set_xticks(np.linspace(0, 180, 5, endpoint=True) )#to specify number of tick…
fig.savefig('../figs/tuning_functions.png', dpi = 600)

-----
3
-----
from IPython.display import FileLink, FileLinks
FileLinks('.')
-----
3
-----
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle, Arrow
from matplotlib.colors import hsv_to_rgb

def model(future=False):
    fig = plt.figure(figsize=(8, 8))

    ax2 = fig.add_subplot(111, alpha=0., axis_bgcolor=(1,1,1,0))
    ax = fig.add_subplot(111, projection='polar', alpha=0., axis_bgcolor=(1,1,1,0))

    opts= dict(ha='center', fontsize=14)
    N = 24
    s = 42
    theta = np.linspace(0, 2*np.pi, N+1, endpoint=True)

    ## connexions
    N_arrow = 3
    dthetas = alphas = np.linspace(-N_arrow, N_arrow, 2*N_arrow+1, endpoint=True)
    dthetas *= 1.75*np.pi/N
    alphas = np.exp( - alphas**2/ .4**2 / 2)
    #print(alphas)
    for dtheta, alpha in zip(dthetas, alphas):
        plt.arrow(np.pi/2, 1.4, dtheta, -.2, color='k', alpha=alpha)

        plt.arrow(0, 1.1, dtheta, -.1, color='r', alpha=alpha)
        plt.arrow(0, 1.1, dtheta, 0., color='r', alpha=alpha)

        plt.arrow(np.pi, .9, dtheta, .1, color='b', alpha=alpha)
        plt.arrow(np.pi, .9, dtheta, 0., color='b', alpha=alpha)
        #set_connectionstyle("arc,angleA=0,armA=30,rad=10")
        #set_arrowstyle("Fancy,head_length=0.2")

    ## neurones
    colors = theta
    for r, c in zip([.9, 1.1, 1.4], ['b', 'r', 'k']):
        ax.plot(theta, r*np.ones_like(theta), c=c, alpha=.4)
        c = ax.scatter(theta[:-1], r*np.ones_like(theta[:-1]), c=c, s=s)
        #c.set_alpha(0.15)

    ## entrée
    N = 1080
    theta = np.linspace(0, 2*np.pi, N)
    ax.fill_between(theta, 1.45, 1.45 + envelope(theta/2, np.pi/4, np.pi/24)/2.5, lw=0, color='g', alpha=.3)

    ax.set_ylim((0, 1.85))

    ax.text(-np.pi/2, 1.25, 'Excitateurs', **opts)
    ax.text(-np.pi/2, .8, 'Inhibiteurs', **opts)
    if future:

        ax.text(np.pi/2, 1.6, 'Entrée\ndirectionnelle', **opts)
        ax.text(-np.pi/2, 1.55, 'convergence corticale', **opts)
    else:
        
        ax.text(np.pi/2, 1.6, 'Entrée\norientationnelle', **opts)
        ax.text(-np.pi/2, 1.55, 'convergence thalamo-corticale', **opts)

    N = 12
    for theta in np.linspace(0, 2*np.pi, N, endpoint=False):
        r, angle, l = .15, theta, .1
        if future:
            ax2.add_patch(Arrow((r-l/2)*np.sin(angle)+.5, (r-l/2)*np.cos(angle)+.5, l*np.sin(angle), l*np.cos(angle), width=.06, color='k'))
        else:
            ax2.add_patch(Rectangle([r*np.sin(angle)+.5, r*np.cos(angle)+.5], .01, .04, angle=theta/2*180/np.pi, color=hsv_to_rgb([theta/2/np.pi, 1, 1])))            

    for ax_ in [ax, ax2]:
        ax_.grid(False, axis='both')

        ax_.set_xticks([])
        ax_.set_yticks([])
        ax_.set_axis_off()
    
    fig.subplots_adjust(hspace = .0, wspace = .0, left=0.01, bottom=0.01, right=.99, top=.99)
    return fig, ax
-----
3
-----
fig, ax = model()
fig.savefig('../figs/ring_model.png', dpi=600)
-----
3
-----
fig, ax = model(future=True)
fig.savefig('../figs/future_model.png', dpi=600)
-----
4
-----
### more code
-----
4
-----
fig = plt.figure(figsize=(8, 8))
ax = plt.subplot(111)

N = 12
s = 42
for theta in np.linspace(0, 2*np.pi, N, endpoint=False):
    r, angle = .35, theta#
    ax.add_patch(Rectangle([r*np.sin(angle-0.*np.pi/N/2)+.5, r*np.cos(angle-0.*np.pi/N/2)+.5], .01, .04, angle=theta/2*180/np.pi, color=hsv_to_rgb([theta/2/np.pi, 1, 1])))

ax.grid(True, axis='both')

#ax.set_xticks([])
#ax.set_yticks([])
#ax.set_axis_off()
#fig.tight_layout()
-----
4
-----
from matplotlib.patches import Rectangle
from matplotlib.colors import hsv_to_rgb
fig = plt.figure(figsize=(8, 8))
ax = plt.subplot(111)

N = 12
s = 42
for theta in np.linspace(0, 2*np.pi, N, endpoint=False):
    r, angle, l = .35, theta, .1
    ax.add_patch(Arrow(r*np.sin(angle)+.5, r*np.cos(angle)+.5, l*np.sin(angle), l*np.cos(angle), width=.06, color='k'))

ax.grid(True, axis='both')

#ax.set_xticks([])
#ax.set_yticks([])
#ax.set_axis_off()
#fig.tight_layout()
-----
4
-----

fig = plt.figure(figsize=(8, 8))

ax2 = fig.add_subplot(111, alpha=0., axis_bgcolor=(1,1,1,0))
ax = fig.add_subplot(111, projection='polar', alpha=0., axis_bgcolor=(1,1,1,0))

ax2.grid(False, axis='both')

## entrée
N = 1080
theta = np.linspace(0, 2*np.pi, N)
ax.fill_between(theta, 1.45, 1.45 + envelope(theta/2, np.pi/4, np.pi/24)/2.5, lw=0, color='g', alpha=.3)


N = 12
s = 42
for theta in np.linspace(0, 2*np.pi, N, endpoint=False):
    r, angle = .15, theta#
    ax2.add_patch(Rectangle([r*np.sin(angle-np.pi/N)+.5, r*np.cos(angle-np.pi/N)+.5], .01, .04, angle=theta/2*180/np.pi, color=hsv_to_rgb([theta/2/np.pi, 1, 1])))

for ax_ in [ax, ax2]:
    ax_.grid(False, axis='both')

    ax_.set_xticks([])
    ax_.set_yticks([])
    ax_.set_axis_off()
fig.tight_layout()    

we can wrap up this in one function:

In [9]:
with open('1.0-Introduction.ipynb', 'r') as f:
    nb = nbformat.read(f, as_version=nbformat.NO_CONVERT)

def strip(nb):
    """
    Keeps only the cells :
    - starting with the first to begin with a section (that is with a ``#``)
    - stoping with the next cell to begin with a section (that is with a ``#``)
    
    """
    start, stop = -1, len(nb.cells)
    nb_out = nb.copy()
    for i_cell, cell in enumerate(nb_out.cells):
        if len(cell['source'])>0:
            if cell['source'][0] == '#':
                if start == -1: start = i_cell
                else:
                    if stop == len(nb.cells): stop = i_cell
        #print(start, stop, cell['source'])
    if start == -1: start = 0
    nb_out.cells = nb.cells[start:stop]
    #print(start, stop, nb_out.cells)
    return nb_out
    
nb_out = strip(nb)
print(nb_out)
{'metadata': {'language_info': {'codemirror_mode': {'version': 3, 'name': 'ipython'}, 'pygments_lexer': 'ipython3', 'name': 'python', 'mimetype': 'text/x-python', 'nbconvert_exporter': 'python', 'version': '3.5.1', 'file_extension': '.py'}, 'kernelspec': {'language': 'python', 'name': 'python3', 'display_name': 'Python 3'}, 'widgets': {'state': {}, 'version': '1.1.2'}}, 'nbformat': 4, 'cells': [{'metadata': {}, 'source': '# Introduction\n\n## Motivation\n\nUne entité ne peut être vivante si elle n\'interagit pas avec son environnement. La vie, réduit à son plus simple appareil, comporte du code génétique. Pour se perpétuer, ce code génétique doit permettre de produire des molécules qui vont former le matériel nécessaire à sa protection, à son alimentation et enfin à sa reproduction. La cellule remplit ces rôles, aussi, sa membrane et les protéines qui la constituent lui permettent de jouer un rôle d\'interface entre le code génétique et l\'environnement. Il apparait que la notion d\'interface soit importante dans le vivant. Ainsi, l\'interface se conserve et se sophistique, au fil de nombreuses mutations du code génétique et de la sélection naturelle. Cette dernière va permettre l\'émergence d\'interfaces de plus en plus élaborées, qui vont offrir de multiples manières de filtrer l\'environnement et des moyens d\'explorer celui-ci.\n\nAvec l\'apparition des organismes pluricellulaires et des moyens de communications entre les cellules, les cellules se spécialisent, s\'assemblent et constituent des tissus cellulaires, des organes et des systèmes qui vont permettre à l\'ensemble de l\'organisme d\'interagir, d\'une manière spécifique au système considéré, avec l\'environnement. Le système nerveux en est un exemple. En effet, celui-ci permet de traiter des informations externes ou internes, et une partie de ce traitement comprend diverses fonctions que l\'on regroupe dans le concept de perception.\n\nSelon l\'approche neurophysiologique de la vision, la perception visuelle est construite sur la photosensibilité de certaines cellules, les cônes et les bâtonnets. Ces cellules et d\'autres comme, par exemple, les cellules ganglionnaires, forment la rétine tapissant le fond de l\'oeil où, à tout instant, une image de l\'environnement se projette. Les cellules photosensibles vont permettre d\'encoder les variations locales de luminosité composant l\'image en variations de potentiel membranaire. Ces variations de potentiel vont ensuite être codées en influx nerveux qui vont être transmis dans le réseau rétinien pour y être transformés. Les informations visuelles arrivent alors au niveau du cortex visuel primaire via les entrées thalamiques. L\'organisation de ce cortex est rétinotopique. Ainsi, l\'activité du cortex visuel primaire représente l\'espace visuel, composé d\'éléments locaux comme, par exemple, les bords orientés et les couleurs. Une question se pose alors lorsqu\'on cherche à associer ce substrat biologique à la perception visuelle : comment le système nerveux central réalise l\'intégration de ces éléments locaux afin de constuire un percept global ?\n\nAfin de répondre à cette large problématique, il convient de s\'intéresser aux divers constituants de l\'image composante par composante. Ainsi, le travail qui vous est présenté est dédié à l\'étude de la détection d\'orientations. Il s\'incrit dans un projet interdisciplinaire porté par l\'équipe InViBe au sein de l\'Institut de Neurosciences de la Timone. Ce projet prévoit, outre diverses expérimentations chez l\'animal, une approche computationnelle des mécanismes impliqués dans cette détection d\'orientations, qui constitue l\'objet de ce travail.\n\n## Contexte scientifique\n\n### Organisation des orientations\nDes électrophysiologistes tels que Hubel et Wiesel ont mis en évidence, chez le chat, que des colonnes corticales du cortex visuel primaire ont une sensibilité préférentielle à une orientation possible de barres de contraste<cite data-cite="Hubel">(Hubel, Wiesel, 1962)</cite>. L\'avancée des études sur la sélectivité à l\'orientation des neurones corticaux, montrent que le cortex visuel primaire des mammifères carnivores et des primates est comme une carte, où les neurones de même sélectivité à l\'orientation sont regroupés en domaines d\'iso-orientation. L\'organisation particulière de ces domaines ou îlots donne lieu à des propriétés remarquables. En effet, il existe différents voisinages d\'un neurone se trouvant dans le cortex visuel primaire. Si celui-ci se trouve à l\'intérieur des îlots, il est à proximité de neurones de même, ou proche, sélectivité à l\'orientation. Si, en revanche, toutes les orientations sont codées par son voisinage, alors il est à l\'intérieur des fractures (ou pinwheels), où la sélectivité à l\'orientation varie rapidement <cite data-cite="ohki">(Ohki et al., 2006)</cite> <cite data-cite="grinvald">(Bonhoeffer, Grinvald 1991)</cite>. Dans le cortex visuel primaire du rongeur, il n\'existe pas de domaines d\'iso-orientation, le voisinage d\'un neurone quelconque est alors de la deuxième espèce citée.\n\n### Réponse à une orientation\n\nDe telles organisations suscitent des hypothèses quant à l\'intégration des informations sur l\'orientation au sein des colonnes corticales du cortex visuel primaire.\nUne d\'entre elles postule que la probablité de connexion entre les neurones du cortex visuel primaire est exclusivement dépendante de leur distance anatomique <cite data-cite="das">(Das, Gilbert 1999)</cite>. Ce qui signifie que, dans le cas admis où il existe des connexions récurrentes et latérales au niveau cortical, les neurones à l\'intérieur des domaines d\'iso-orientation intègrent des informations provenant de neurones de même préférence à l\'orientation. Ainsi, la réponse de ces neurones est fortement sélective et est robuste à la richesse en orientations d\'un stimulus. Cela veut dire également qu\'à proximité des fractures, et dans le cortex visuel primaire du rat, les neurones devraient avoir une faible sélectivité à l\'orientation car ils intègrent les informations provenant de neurones sélectifs à différentes orientations. Ce n\'est pourtant pas ce qui est montré expérimentalement. Une étude explique alors ce paradoxe. En effet, il a été théoriquement démontré que la réponse de ces neurones, supposés peu sélectifs, peut être plus sélective à l\'orientation si le réseau du cortex visuel primaire est dans un état balancé entre l\'excitation et l\'inhibition <cite data-cite="HanselVan">(Hansel, Van Vreeswijk 2012)</cite>.\n\nNous nous proposons donc d\'étudier la réponse d\'un réseau de neurones artificiel, un ring, à différents stimuli visuels, des motion clouds <cite data-cite="Leon12">(Leon)</cite>, dont nous ferons alors varier la richesse en orientations. En effet, le contenu en orientations de chaque stimulus peut être défini de façon quantitative en modulant une certaine valeur de bandwidth $B_\\theta$ caractérisant l\'entrée visuelle. Le but est d\'implémenter le réseau, de façon à ce qu\'il possède des propriétés similaires à celles évoquées plus haut concernant le cortex visuel primaire. Nous comparerons alors la réponse de ce réseau à des données physiologiques.\n\n\n![Réseau de neurones organisé en "ring".](/tmp/ring_model.png)', 'cell_type': 'markdown'}], 'nbformat_minor': 0}

merging notebooks

We can now merge these blocks together in one master notebook:

In [10]:
def merge_notebooks(outfile, filenames):
    merged = None
    for fname in filenames:
        with open(fname, 'r', encoding='utf-8') as f:
            nb = nbformat.read(f, nbformat.NO_CONVERT)
        nb = strip(nb)
        if merged is None:
            merged = nb
        else:
            merged.cells.extend(nb.cells)
    with open(outfile, 'w', encoding='utf-8') as f:
        f.write(nbformat.writes(merged, nbformat.NO_CONVERT))
merge_notebooks(name + '.ipynb', nb_list)

converting to LaTeX and PDF

Finally, we convert this notebook using nconvert and the template that we defined above.

In [11]:
with open(name + '.ipynb', 'r') as f:
    nb = nbformat.read(f, as_version=nbformat.NO_CONVERT)
#nb.cells[0]
In [12]:
import nbconvert
#help(nbconvert.LatexExporter)
#nbconvert.exporters.export_latex(nb)
from traitlets.config import Config
# 1. Import the exporter
from nbconvert import PDFExporter
# 2. Instantiate the exporter. We use the `basic` template for now; we'll get into
# later about how to customize the exporter further.
latex_exporter = PDFExporter()
latex_exporter.template_file = 'thesis'
latex_exporter.verbose = True
# 3. Process the notebook we loaded earlier
(body, resources) = latex_exporter.from_notebook_node(nb)
# 4. write to file
with open(name + '.pdf', 'w', encoding="iso-8859-1") as f:
    f.write(body.decode(encoding="iso-8859-1"))

We can now enjoy reading the thesis file:

In [13]:
!open thesis.pdf