├── .gitignore ├── LICENSE ├── README.md ├── apt.txt ├── environment.yml ├── images └── jupyter_logo.png ├── index.ipynb ├── postBuild └── sample.tex /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ 102 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2019, Binder Project 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Using latex with Binder 2 | 3 | [![Binder](http://mybinder.org/badge.svg)](http://mybinder.org/v2/gh/binder-examples/latex/master?filepath=index.ipynb) 4 | 5 | This repository demonstrates how to install latex alongside matplotlib 6 | for Binder. This repository also makes use of [JupyterLab Latex](https://github.com/jupyterlab/jupyterlab-latex) to render latex files in Jupyter lab. This requires a few different build components: 7 | 8 | * `apt.txt` for apt-installing the latex components 9 | * `environment.yml` for installing the python dependencies 10 | * `postBuild` for forcing matplotlib to build the font cache and for installing JupyterLab Latex. 11 | 12 | Thanks to [m-weigand](https://github.com/m-weigand) for giving 13 | [inspiration for this repo](https://github.com/m-weigand/binder-example-latex-mpl/blob/master/index.ipynb)! 14 | -------------------------------------------------------------------------------- /apt.txt: -------------------------------------------------------------------------------- 1 | dvipng 2 | ghostscript 3 | texlive-fonts-recommended 4 | texlive-generic-recommended 5 | texlive-latex-base 6 | texlive-latex-extra 7 | texlive-latex-recommended 8 | texlive-publishers 9 | texlive-science 10 | texlive-xetex 11 | cm-super 12 | -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | channels: 2 | - conda-forge 3 | dependencies: 4 | - python 5 | - pip 6 | - setuptools 7 | - matplotlib 8 | - jupyterlab 9 | - pip: 10 | - jupyterlab_latex 11 | -------------------------------------------------------------------------------- /images/jupyter_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binder-examples/latex/c5fb3dcf9f70e25f286b857e2d2f1b80d61d50ab/images/jupyter_logo.png -------------------------------------------------------------------------------- /index.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Run the cells below to plot with LaTeX in Matplotlib.\n", 8 | "\n", 9 | "Note that you may need to run the bottom cell twice (it'll error the first time due to a caching bug with matplotlib)" 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 1, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "import matplotlib.pyplot as plt\n", 19 | "plt.rcParams['text.usetex'] = True\n", 20 | "plt.ion()" 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": 2, 26 | "metadata": {}, 27 | "outputs": [ 28 | { 29 | "data": { 30 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXcAAAD8CAYAAACMwORRAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4wLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvFvnyVgAACU5JREFUeJzt3dFxFFcahuH/bG0AskMQGci+3LuVMgATgSEDqI2AggzERoDlDOBybyEDlIFtMjh70adRM4ykEUie0TfPU9Ulq9WjaVTlt3tOn+lpvfcCIMs/tr0DANw+cQcIJO4AgcQdIJC4AwQSd4BA4g4QSNwBAok7QCBxBwgk7gCBxB0gkLgDBBJ3gEDiDhBI3AECiTtAIHEHCCTuAIHEHSCQuAMEEneAQOIOEEjcAQKJO0AgcQcIJO4AgcQdIJC4AwQSd4BA4g4QSNwBAok7QCBxBwgk7gCBxB0gkLgDBBJ3gEDiDhBI3AECiTtAIHEHCCTuAIHEHSCQuAMEEneAQOIOEEjcAQKJO0AgcQcIJO4AgcQdIJC4AwQSd4BA4g4QSNwBAok7QCBxBwgk7gCBxB0gkLgDBBJ3gEDiDhBI3AECiTtAIHEHCCTuAIHEHSCQuAMEEneAQOIOEEjcAQKJO0AgcQcIJO4AgcQdIJC4AwQSd4BA4g4QSNwBAok7QCBxBwgk7gCBxB0gkLgDBBJ3gEDiDhBI3OEbtNaetNY+ttZ6a+142/sDq1rvfdv7APdSa+1hVZ1V1Q+990/b3h9YcuYO3+6kqj4IO7tI3OHbHVfVu23vBKwj7uHG2HAfy+Gan5+On71crOu3sBzcYB8/XrWPa7Y/aK39NbZ/u/lf4/aMf99hVV36/K21t2Mfz5K24X4Qd34ZX58s1p1X1adLlqXLtrnpMMXJ4r83icpZVR2M53l0w+f6yjhYPBkHuocrPztqrX1c87Bfqqp6787c2UnivsfGLI+DqnpeVQfzrI/e+4Pe+w/rlroYhji/bJuxbBz43vt5XUT6aPkqYs0+P6lpOKSq6tEtjXe/7L2/rqr3VbX63I9r/cHqpK4fktlk3+7jNtwD4r7fntYUqNeL77ei9/77Yj+erZteOIZsTse3r2/jrLm1dlQXrxZOqurDyiaXjasf1xVDMiv+DN2GHSbue2qMGT+sqrNx9vthfL81vfendRHXszXj9nOEz8e2t/GcHxYHiYdV9Wb+2Xj+o1qJ+DjIHJSLqewwcd9f81j7b+Prm6rPc7e3aR6eOaiq/84rx1DN0fj2ZPVB32v+d49XELOfx7rViB9X1afe++pZPuwMcd9fT+vLOdpbH5qp+mr8/eG40HlUVc/Guudjm9v2uL4+E183TDOv3+SsfdeGUQzH7BFx30OL4YbPQxCLoZnjm0xjXPO7l1MvN12+mP64Mv5+WhfDMe9676823Iez1tr7cQF2Xv9yrJ+X5fMe1hXj7a21Zyvr387Pdf1fZecuiLqwugfEfT/NQfp9Zf3pys+/11VTJa+cNrky/n5YG057HGf5D3rvj6rqRVWdttaOx7ztN2P9m5oCvZwZc77yex6O5103DfKgqs6/5yAId+2f294BtmIeevnYWlv388dVde0Z8gZ++s4hlOd1cTHz9YbTHh/XFPWqqh/H17Oq+vdijPxxTYFeXij9taaLuPMZ+rux7mSse73Y9mlNB5qjTV5JwDaI+54ZZ7aHNcX7dM0mpzUNzRze0dj2TSz371lr7XSDfTpcHAR+Gl9frFz8/LVWxu7HY1Yv1H6or1/d1JgTDzvNsMz+eTy+vui9n68udRHUrV5Yba2d1nQQOq+Li5dXzisfwyTLA8LP4+sXMe69f/qbDlzzQeaPsG24B8R9/zyp6cLkZWPdv9f0P/htjbvf2HgD0/z8j8byqaoOR/TXGtFezmI5qmlOvIuD7B1x3y//qmms+dJADr/VdDuCo2u2u3Xj7HueHfNqvMloeTH1ySZz8RfvcPVGI/aSuO+X//Xe28obdb7Se386ttvGm3Tmm4Kd996fL/ZpeZuE1WmM68wHg63cNRK2zQVV7tLb1tp1QyIv5oPN6k3BVjfsvT8dZ+TzrXYfXPF7d+HM/U1NY9dX7cN93IZ7QNy5S9fem73GdMWVm4K9uuJVw6Oa7t54OGbPfHXhd3Gv9a1+StL4N1z56uc+bsP9IO7cpQc3mJWyvCnY88s26r1/aK09r+kNSE9aa2/XDDPtwln78pbK55cdrO7jNtwTvXdL8FLTrJM+lr+uWzb4fW/H7/q4wfMdbriPL7/hMe8ve0xNrwB6VR1v+W8//63Okrax3I/Fmft+2bm3y48zxW+5Kdijurg1wLrx9+WtfDfdl4OaDk6favpbPRj79GmxzXFNB48fa/qwkHfzG8P6NReq4e/UxtEabsW4KDqPnd9kWGarRrSf1+LTneaLt328I3UxTXOO+3xAOezTPWtgZzhzZ++Ni7lnNd0LZw77QU2vDr4Y/++9n6w87qWws4vEHaYx/z9ruqfO55V9ZSbOyvCMsLPTxB2mj9d71Te8IdgYY38q7OwycYfJuvu2f2WMwz9aPauHXeP2A9yljxt+EtN197q5a5e+0Wl5H5sR9pPVsI/Pd4WdIu4wfbjHF/dyb60djmjPH7N3VNMsmT/Gx/XNn+/6vhYfVwi7wlRIqM9n33/UxRz38+W89dbayz7eOTs+mek/Nd1r/tfunZzsIHEHCGRYBiCQuAMEEneAQOIOEEjcAQKJO0AgcQcIJO4AgcQdIJC4AwQSd4BA4g4QSNwBAok7QCBxBwgk7gCBxB0gkLgDBBJ3gEDiDhBI3AECiTtAIHEHCCTuAIHEHSCQuAMEEneAQOIOEEjcAQKJO0AgcQcIJO4AgcQdIJC4AwQSd4BA4g4QSNwBAok7QCBxBwgk7gCBxB0gkLgDBBJ3gEDiDhBI3AECiTtAIHEHCCTuAIHEHSCQuAMEEneAQOIOEEjcAQKJO0AgcQcIJO4AgcQdIJC4AwQSd4BA4g4QSNwBAok7QCBxBwgk7gCBxB0gkLgDBBJ3gEDiDhBI3AECiTtAIHEHCCTuAIHEHSCQuAMEEneAQOIOEEjcAQKJO0AgcQcIJO4AgcQdIJC4AwQSd4BA4g4QSNwBAok7QCBxBwgk7gCBxB0gkLgDBBJ3gEDiDhBI3AECiTtAIHEHCCTuAIHEHSCQuAMEEneAQOIOEEjcAQKJO0AgcQcIJO4AgcQdIJC4AwQSd4BA4g4QSNwBAok7QCBxBwgk7gCBxB0gkLgDBBJ3gEDiDhBI3AECiTtAIHEHCCTuAIHEHSCQuAMEEneAQOIOEEjcAQKJO0AgcQcIJO4AgcQdIJC4AwQSd4BA/wdXKudGvI1VKgAAAABJRU5ErkJggg==\n", 31 | "text/plain": [ 32 | "
" 33 | ] 34 | }, 35 | "metadata": {}, 36 | "output_type": "display_data" 37 | } 38 | ], 39 | "source": [ 40 | "fig, ax = plt.subplots()\n", 41 | "ax.text(.5, .5, \"\\LaTeX $r_{ez}^{ul}$!!!!!!\", fontsize=30, horizontalalignment='center')\n", 42 | "ax.set_axis_off()" 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": null, 48 | "metadata": {}, 49 | "outputs": [], 50 | "source": [] 51 | } 52 | ], 53 | "metadata": { 54 | "kernelspec": { 55 | "display_name": "Python 3", 56 | "language": "python", 57 | "name": "python3" 58 | }, 59 | "language_info": { 60 | "codemirror_mode": { 61 | "name": "ipython", 62 | "version": 3 63 | }, 64 | "file_extension": ".py", 65 | "mimetype": "text/x-python", 66 | "name": "python", 67 | "nbconvert_exporter": "python", 68 | "pygments_lexer": "ipython3", 69 | "version": "3.6.2" 70 | } 71 | }, 72 | "nbformat": 4, 73 | "nbformat_minor": 2 74 | } 75 | -------------------------------------------------------------------------------- /postBuild: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # run matplotlib once to generate the font cache 4 | python -c "import matplotlib as mpl; mpl.use('Agg'); import pylab as plt; fig, ax = plt.subplots(); fig.savefig('test.png')" 5 | 6 | test -e test.png && rm test.png 7 | 8 | # install JupyterLab extension 9 | jupyter labextension install @jupyterlab/latex 10 | -------------------------------------------------------------------------------- /sample.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \usepackage{graphicx} 3 | 4 | \begin{document} 5 | 6 | \title{JupyterLab \LaTeX} 7 | \date{} 8 | \maketitle 9 | 10 | \section{Introduction} 11 | This is a sample document demonstrating the ability live-edit 12 | \LaTeX documents in JupyterLab. 13 | \\ 14 | \\ 15 | Right-click on this document, and select "Show LaTeX Preview". 16 | A new panel should open up on the right with the PDF that is generated 17 | by this document. If there are any errors in the document, an 18 | error panel should open below. 19 | \\ 20 | \\ 21 | We can write equations: 22 | \begin{equation} 23 | \rho \left( \frac{\partial \mathbf{u}}{\partial t} + \mathbf{u} \cdot \nabla \mathbf{u} \right) = 24 | -\nabla P + \eta \nabla^2 \mathbf{u} + \rho \mathbf{g}. 25 | \end{equation} 26 | \\ 27 | \\ 28 | And we can write tables: 29 | \begin{center} 30 | \begin{tabular}{ | l | c | r| } 31 | \hline 32 | 1 & 2 & 3 \\ 33 | 4 & 5 & 6 \\ 34 | 7 & 8 & 9 \\ 35 | \hline 36 | \end{tabular} 37 | \end{center} 38 | 39 | \subsection{We can add new subsections} 40 | And we can include images, such as the Jupyter logo: 41 | \begin{center} 42 | \includegraphics[width=0.65\textwidth]{images/jupyter_logo.png} 43 | \end{center} 44 | 45 | 46 | 47 | \pagebreak 48 | 49 | 50 | 51 | 52 | You can also use SyncTeX by typing ⌘(CMD)/CTRL+⇧(SHIFT)+X. 53 | 54 | \end{document} 55 | --------------------------------------------------------------------------------