├── README.md ├── mcmm ├── analysis.py ├── estimation.py ├── clustering.py ├── __init__.py └── example.py ├── supporting_material ├── lectures │ ├── 03_pcca_tpt.pdf │ ├── 04_Estimation.pdf │ ├── 01_markov_chains.pdf │ ├── 02_spectral_properties.pdf │ ├── 05_06_transfer_operator.pdf │ ├── 07_variational_principle.pdf │ └── background │ │ └── stationary_distribution.pdf ├── lab_slides │ └── mcmm-20160428.pdf └── notebooks │ ├── README.md │ ├── introduction.ipynb │ └── oop.ipynb ├── setup.py ├── .gitignore └── test └── test_example.py /README.md: -------------------------------------------------------------------------------- 1 | # mcmm-project 2 | 3 | Template for the software lab project to the lecture Markov chains and Markov models. 4 | -------------------------------------------------------------------------------- /mcmm/analysis.py: -------------------------------------------------------------------------------- 1 | r""" 2 | This module should handle the analysis of an estimated Markov state model. 3 | """ 4 | 5 | 6 | -------------------------------------------------------------------------------- /mcmm/estimation.py: -------------------------------------------------------------------------------- 1 | r""" 2 | This module should handle the transition counting and transition matrix estimation. 3 | """ 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /mcmm/clustering.py: -------------------------------------------------------------------------------- 1 | r""" 2 | This module should handle the discretization by means of a kmeans or regspace clustering. 3 | """ 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /supporting_material/lectures/03_pcca_tpt.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markovmodel/mcmm-project/master/supporting_material/lectures/03_pcca_tpt.pdf -------------------------------------------------------------------------------- /supporting_material/lab_slides/mcmm-20160428.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markovmodel/mcmm-project/master/supporting_material/lab_slides/mcmm-20160428.pdf -------------------------------------------------------------------------------- /supporting_material/lectures/04_Estimation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markovmodel/mcmm-project/master/supporting_material/lectures/04_Estimation.pdf -------------------------------------------------------------------------------- /supporting_material/lectures/01_markov_chains.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markovmodel/mcmm-project/master/supporting_material/lectures/01_markov_chains.pdf -------------------------------------------------------------------------------- /supporting_material/lectures/02_spectral_properties.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markovmodel/mcmm-project/master/supporting_material/lectures/02_spectral_properties.pdf -------------------------------------------------------------------------------- /supporting_material/lectures/05_06_transfer_operator.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markovmodel/mcmm-project/master/supporting_material/lectures/05_06_transfer_operator.pdf -------------------------------------------------------------------------------- /supporting_material/lectures/07_variational_principle.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markovmodel/mcmm-project/master/supporting_material/lectures/07_variational_principle.pdf -------------------------------------------------------------------------------- /supporting_material/lectures/background/stationary_distribution.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markovmodel/mcmm-project/master/supporting_material/lectures/background/stationary_distribution.pdf -------------------------------------------------------------------------------- /mcmm/__init__.py: -------------------------------------------------------------------------------- 1 | r""" 2 | The mcmm package should allow to build Markov state models from trajectory data. Three stages are 3 | necessary: discretization (clustering), estimation, and analysis of the resulting model. 4 | """ 5 | 6 | from . import example 7 | -------------------------------------------------------------------------------- /supporting_material/notebooks/README.md: -------------------------------------------------------------------------------- 1 | # mcmm-project - juptyer notebooks 2 | 3 | Make sure that `ipython`, `jupyter`, and `notebook` are installed. 4 | 5 | Open a shell, go to this folder and type 6 | 7 | ```bash 8 | jupyter notebook 9 | ``` 10 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | def readme(): 4 | with open('README.md') as f: 5 | return f.read() 6 | 7 | setup( 8 | name='mcmm', 9 | version='0.0', 10 | description='', 11 | long_description=readme(), 12 | classifiers=[ 13 | 'Development Status :: 1 - Planning', 14 | 'Programming Language :: Python :: 2.7', 15 | 'Programming Language :: Python :: 3'], 16 | url='', 17 | author='', 18 | author_email='', 19 | packages=['mcmm'], 20 | install_requires=['numpy'], 21 | tests_require=['nose'], 22 | test_suite='nose.collector') 23 | -------------------------------------------------------------------------------- /.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 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | 55 | # Sphinx documentation 56 | docs/_build/ 57 | 58 | # PyBuilder 59 | target/ 60 | 61 | #Ipython Notebook 62 | .ipynb_checkpoints 63 | 64 | .DS_Store 65 | -------------------------------------------------------------------------------- /mcmm/example.py: -------------------------------------------------------------------------------- 1 | r""" 2 | This module generates trajectories of a simple two dimensional toy model for testing purposes. 3 | """ 4 | 5 | import numpy as np 6 | 7 | __all__ = ['generate_test_data'] 8 | 9 | def _gradient(x, y): 10 | return (x * x - 1.0) * 4.0 * x + 0.5, (4.0 * y * y - 7.0) * y 11 | 12 | def _bd(x0, y0, length, dt=0.005): 13 | coeff_A = dt 14 | coeff_B = np.sqrt(2.0 * dt) 15 | x = [x0] 16 | y = [y0] 17 | for _i in range(1, length): 18 | dx, dy = _gradient(x[-1], y[-1]) 19 | x.append(x[-1] - coeff_A * dx + coeff_B * np.random.normal()) 20 | y.append(y[-1] - coeff_A * dy + coeff_B * np.random.normal()) 21 | return np.array([[_x, _y] for _x, _y in zip(x, y)], dtype=np.float64) 22 | 23 | def generate_test_data(traj_length=20000, num_trajs=5): 24 | r""" 25 | This functions handles the test data generation via Brownian dynamics simulations with 26 | randomized starting configurations. 27 | 28 | Parameters 29 | ---------- 30 | traj_length : int, optional, default=20000 31 | Length of a single trajectory. 32 | num_trajs : int, optional, default=5 33 | Number of independent trajectories. 34 | 35 | Returns 36 | ------- 37 | trajs : list of numpy.ndarray(shape=(traj_length, 2), dtype=numpy.float64) objects 38 | Time series of configurations of the toy model. 39 | """ 40 | trajs = [] 41 | for _i in range(num_trajs): 42 | trajs.append(_bd(3.0 * np.random.rand() - 1.5, 3.0 * np.random.rand() - 1.5, traj_length)) 43 | return trajs 44 | -------------------------------------------------------------------------------- /test/test_example.py: -------------------------------------------------------------------------------- 1 | r""" 2 | This test script should illustrate how unit tests should be written. Here, we basically just check 3 | whether mcmm.example.generate_test_data produces the correct number of independent trajectories and 4 | that all trajectories have the correct length, dimension, and floating point type. 5 | """ 6 | 7 | import mcmm 8 | import numpy as np 9 | from nose.tools import assert_true 10 | 11 | def check_trajs(trajs, traj_length, num_trajs): 12 | r""" 13 | This function handles the checks that we need in all other tests. 14 | """ 15 | assert_true(isinstance(trajs, list)) 16 | assert_true(len(trajs) == num_trajs) 17 | for traj in trajs: 18 | assert_true(isinstance(traj, np.ndarray)) 19 | assert_true(traj.dtype == np.float64) 20 | assert_true(traj.ndim == 2) 21 | assert_true(traj.shape[0] == traj_length) 22 | assert_true(traj.shape[1] == 2) 23 | 24 | def test_interface_default(): 25 | r""" 26 | Does the default setting produce the expected data? 27 | """ 28 | trajs = mcmm.example.generate_test_data() 29 | check_trajs(trajs, 20000, 5) 30 | 31 | def test_interface_custom(): 32 | r""" 33 | Does a custom setting produce the requested data? 34 | """ 35 | traj_length = 10000 36 | num_trajs = 7 37 | trajs = mcmm.example.generate_test_data(traj_length, num_trajs) 38 | check_trajs(trajs, traj_length, num_trajs) 39 | 40 | def test_interface_random(): 41 | r""" 42 | Does a randomly chosen setting produce the requested data? 43 | """ 44 | traj_length = np.random.randint(500, 25000) 45 | num_trajs = np.random.randint(3, 9) 46 | trajs = mcmm.example.generate_test_data(traj_length, num_trajs) 47 | check_trajs(trajs, traj_length, num_trajs) 48 | -------------------------------------------------------------------------------- /supporting_material/notebooks/introduction.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Introduction to jupyter notebooks and test-driven development\n", 8 | "\n", 9 | "> The Jupyter Notebook is a web application that allows you to create and share documents that contain live code, equations, visualizations and explanatory text.\n", 10 | ">\n", 11 | "> --http://jupyter.org\n", 12 | "\n", 13 | "We often use jupyter notebooks for the ongoing analysis of new data, because it is interactive (no need to rerun all scripts when you want to change something along the line) and allows to have code snippets, figures, data, and text in one document. The notebooks are also useful for prototyping.\n", 14 | "\n", 15 | "You can learn more about jupyter notebooks on\n", 16 | "* https://youtu.be/-F4WS8o-G2A\n", 17 | "* https://youtu.be/o8fmjaW9a0A\n", 18 | "* https://youtu.be/kHPEz1wZZWc" 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": null, 24 | "metadata": { 25 | "collapsed": true 26 | }, 27 | "outputs": [], 28 | "source": [ 29 | "# We start by importing the most commonly needed packages, i.e., numpy and matplotlib.pyplot\n", 30 | "%matplotlib inline\n", 31 | "import matplotlib.pyplot as plt\n", 32 | "import numpy as np" 33 | ] 34 | }, 35 | { 36 | "cell_type": "markdown", 37 | "metadata": {}, 38 | "source": [ 39 | "## Plotting example\n", 40 | "\n", 41 | "`numpy` and `matplotlib.pyplot` are very useful tools for generation, manipulation, and visualisation of data.\n", 42 | "\n", 43 | "Let's make a plot of the function\n", 44 | "$$f(x)=\\exp\\left(-x^2\\right), \\quad x \\in [-3, 3].$$" 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": null, 50 | "metadata": { 51 | "collapsed": false 52 | }, 53 | "outputs": [], 54 | "source": [ 55 | "x = np.linspace(-3, 3, 100) # generate 100 x values in the range [-3, 3]\n", 56 | "f = np.exp(-x**2) # compute f(x) for all generated x values\n", 57 | "plt.plot(x, f) # plot f(x)" 58 | ] 59 | }, 60 | { 61 | "cell_type": "markdown", 62 | "metadata": {}, 63 | "source": [ 64 | "## Fancy plotting example" 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": null, 70 | "metadata": { 71 | "collapsed": false 72 | }, 73 | "outputs": [], 74 | "source": [ 75 | "fig, ax = plt.subplots(figsize=(8, 4.5))\n", 76 | "ax.plot(x, f, linewidth=2, label=r\"$f(x)=\\exp(-x^2)$\")\n", 77 | "ax.plot([0, 0], [0, 1.1], '--', color='grey')\n", 78 | "ax.fill_between(x, 0.0, f, alpha=0.2)\n", 79 | "ax.set_ylim([0, 1.1])\n", 80 | "ax.set_xlabel(r\"$x$\", fontsize=20)\n", 81 | "ax.set_ylabel(r\"$f(x)$\", fontsize=20)\n", 82 | "ax.tick_params(labelsize=15)\n", 83 | "ax.legend(fontsize=17, fancybox=True, framealpha=0.2)" 84 | ] 85 | }, 86 | { 87 | "cell_type": "markdown", 88 | "metadata": {}, 89 | "source": [ 90 | "## Test-driven development (TDD)\n", 91 | "\n", 92 | "TDD is a programming style where you\n", 93 | "1. define the interface of a function,\n", 94 | "2. write some tests before you write code,\n", 95 | "3. write the function until all tests are passed, and\n", 96 | "4. modify your function to improve efficiency without breaking its functionality and repeat from 2. if you introduce new functionality.\n", 97 | "\n", 98 | "TDD is a lot of work during the development stage, but bug fixing is very easy compared to large projects without unit tests.\n", 99 | "\n", 100 | "**Example:** write a function that computes the sum of all elements in a given list:\n", 101 | "$$\\texttt{summation}\\left([x_0, \\dots, x_{n-1}]\\right) \\rightarrow \\sum\\limits_{i=0}^{n-1} x_i$$\n", 102 | "\n", 103 | "### First stage: interface\n", 104 | "\n", 105 | "```python\n", 106 | "def summation(x):\n", 107 | " pass\n", 108 | "```\n", 109 | "\n", 110 | "### Second stage: tests\n", 111 | "\n", 112 | "Ideas for simple tests:\n", 113 | "* sum of zeros equals zero\n", 114 | "* sum of ones equals number of elements\n", 115 | "* sum of $1, \\dots, n$ equals $n(n+1)/2$\n", 116 | "\n", 117 | "```python\n", 118 | "from nose.tools import assert_true\n", 119 | "\n", 120 | "def test_zeros():\n", 121 | " n = 100\n", 122 | " x = [0] * n\n", 123 | " assert_true(summation(x) == 0)\n", 124 | "\n", 125 | "def test_ones():\n", 126 | " n = 100\n", 127 | " x = [1] * n\n", 128 | " assert_true(summation(x) == n)\n", 129 | "\n", 130 | "def test_range():\n", 131 | " n = 100\n", 132 | " x = [i + 1 for i in range(n)]\n", 133 | " assert_true(summation(x) == (n * (n + 1)) / 2)\n", 134 | "```\n", 135 | "\n", 136 | "### Third stage: code\n", 137 | "\n", 138 | "```python\n", 139 | "def summation(x):\n", 140 | " result = 0\n", 141 | " for y in x:\n", 142 | " result += y\n", 143 | " return result\n", 144 | "```\n", 145 | "\n", 146 | "### Fourth stage: modify\n", 147 | "\n", 148 | "`summation` will throw a `TypeError` if `x` is not a `list` (or any other iterable object). Let's add a feature that, if `x` is a single figure, `summation` returns `x`:\n", 149 | "\n", 150 | "```python\n", 151 | "def test_single_value():\n", 152 | " x = np.random.rand()\n", 153 | " assert_true(summation(x) == x)\n", 154 | "\n", 155 | "def summation(x):\n", 156 | " result = 0\n", 157 | " try:\n", 158 | " for y in x:\n", 159 | " result += y\n", 160 | " except TypeError:\n", 161 | " result = x\n", 162 | " return result\n", 163 | "```\n", 164 | "\n", 165 | "## Hands-on TDD (optional)\n", 166 | "\n", 167 | "Implement a `logsumexp` summation:\n", 168 | "$$\\texttt{logsumexp}([x_0, \\dots, x_{n-1}]) \\rightarrow -\\ln\\left(\\sum_{i=0}^{n-1} \\exp\\left(-x_i\\right)\\right)$$" 169 | ] 170 | }, 171 | { 172 | "cell_type": "code", 173 | "execution_count": null, 174 | "metadata": { 175 | "collapsed": true 176 | }, 177 | "outputs": [], 178 | "source": [] 179 | } 180 | ], 181 | "metadata": { 182 | "kernelspec": { 183 | "display_name": "Python 2", 184 | "language": "python", 185 | "name": "python2" 186 | }, 187 | "language_info": { 188 | "codemirror_mode": { 189 | "name": "ipython", 190 | "version": 2 191 | }, 192 | "file_extension": ".py", 193 | "mimetype": "text/x-python", 194 | "name": "python", 195 | "nbconvert_exporter": "python", 196 | "pygments_lexer": "ipython2", 197 | "version": "2.7.11" 198 | } 199 | }, 200 | "nbformat": 4, 201 | "nbformat_minor": 0 202 | } 203 | -------------------------------------------------------------------------------- /supporting_material/notebooks/oop.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Introduction to objected-oriented programming\n", 8 | "\n", 9 | "In this notebook, we will address the concept of Python classes." 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": null, 15 | "metadata": { 16 | "collapsed": true 17 | }, 18 | "outputs": [], 19 | "source": [ 20 | "%matplotlib inline\n", 21 | "import matplotlib.pyplot as plt\n", 22 | "import numpy as np\n", 23 | "from mcmm.example import generate_test_data" 24 | ] 25 | }, 26 | { 27 | "cell_type": "markdown", 28 | "metadata": {}, 29 | "source": [ 30 | "## The simple approach (cells + attentiveness)\n", 31 | "\n", 32 | "First step: we run `generate_test_data()` from `mcmm.example` to generate a time series." 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": null, 38 | "metadata": { 39 | "collapsed": true 40 | }, 41 | "outputs": [], 42 | "source": [ 43 | "traj = generate_test_data(traj_length=100000, num_trajs=1)[0]" 44 | ] 45 | }, 46 | { 47 | "cell_type": "markdown", 48 | "metadata": {}, 49 | "source": [ 50 | "Second step: we build a 2D histogram to visualise how often a bin has been visited in the trajectory." 51 | ] 52 | }, 53 | { 54 | "cell_type": "code", 55 | "execution_count": null, 56 | "metadata": { 57 | "collapsed": true 58 | }, 59 | "outputs": [], 60 | "source": [ 61 | "h, xedges, yedges = np.histogram2d(traj[:, 0], traj[:, 1], bins=(50, 50))\n", 62 | "xcenters = xedges[:-1] + 0.5 * (xedges[1:] - xedges[:-1])\n", 63 | "ycenters = yedges[:-1] + 0.5 * (yedges[1:] - yedges[:-1])\n", 64 | "x, y = np.meshgrid(xcenters, ycenters, indexing='ij')" 65 | ] 66 | }, 67 | { 68 | "cell_type": "markdown", 69 | "metadata": {}, 70 | "source": [ 71 | "Third step: we make a nice plot of the histogram." 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": null, 77 | "metadata": { 78 | "collapsed": false 79 | }, 80 | "outputs": [], 81 | "source": [ 82 | "fig, ax = plt.subplots()\n", 83 | "ax.contourf(x, y, h, np.linspace(h.min(), h.max(), 60))\n", 84 | "ax.set_xlabel(r\"$x$ / a.u.\", fontsize=12)\n", 85 | "ax.set_ylabel(r\"$y$ / a.u.\", fontsize=12)\n", 86 | "ax.set(aspect='equal', adjustable='box-forced')" 87 | ] 88 | }, 89 | { 90 | "cell_type": "markdown", 91 | "metadata": {}, 92 | "source": [ 93 | "Fourth step: we play around with the settings and rerun cells, until we understand what's going on.\n", 94 | "\n", 95 | "## The object-oriented approach\n", 96 | "\n", 97 | "First step: we write a class to encapsulate data and analysis." 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": null, 103 | "metadata": { 104 | "collapsed": true 105 | }, 106 | "outputs": [], 107 | "source": [ 108 | "class Example(object):\n", 109 | " def __init__(self, traj_length=10000):\n", 110 | " self.traj_length = traj_length\n", 111 | " self._traj = None\n", 112 | " @property\n", 113 | " def traj(self):\n", 114 | " if self._traj is None:\n", 115 | " self._traj = generate_test_data(traj_length=self.traj_length, num_trajs=1)[0]\n", 116 | " return self._traj\n", 117 | " def plot_histogram(self, bins, ax=None):\n", 118 | " h, xedges, yedges = np.histogram2d(self.traj[:, 0], self.traj[:, 1], bins=bins)\n", 119 | " xcenters = xedges[:-1] + 0.5 * (xedges[1:] - xedges[:-1])\n", 120 | " ycenters = yedges[:-1] + 0.5 * (yedges[1:] - yedges[:-1])\n", 121 | " x, y = np.meshgrid(xcenters, ycenters, indexing='ij')\n", 122 | " if ax is None:\n", 123 | " fig, ax = plt.subplots()\n", 124 | " ax.contourf(x, y, h, np.linspace(h.min(), h.max(), 60))\n", 125 | " ax.set_xlabel(r\"$x$ / a.u.\", fontsize=12)\n", 126 | " ax.set_ylabel(r\"$y$ / a.u.\", fontsize=12)\n", 127 | " ax.set(aspect='equal', adjustable='box-forced')\n", 128 | " return ax" 129 | ] 130 | }, 131 | { 132 | "cell_type": "markdown", 133 | "metadata": {}, 134 | "source": [ 135 | "Second step: we instanciate an object." 136 | ] 137 | }, 138 | { 139 | "cell_type": "code", 140 | "execution_count": null, 141 | "metadata": { 142 | "collapsed": false 143 | }, 144 | "outputs": [], 145 | "source": [ 146 | "example = Example(traj_length=1000000)" 147 | ] 148 | }, 149 | { 150 | "cell_type": "markdown", 151 | "metadata": {}, 152 | "source": [ 153 | "Third step: we run the `plot_histogram()` method of our `example` object." 154 | ] 155 | }, 156 | { 157 | "cell_type": "code", 158 | "execution_count": null, 159 | "metadata": { 160 | "collapsed": false 161 | }, 162 | "outputs": [], 163 | "source": [ 164 | "ax = example.plot_histogram((100, 100))" 165 | ] 166 | }, 167 | { 168 | "cell_type": "markdown", 169 | "metadata": {}, 170 | "source": [ 171 | "Fourth step: we play around with the settings and rerun cells, until we understand what's going on." 172 | ] 173 | }, 174 | { 175 | "cell_type": "markdown", 176 | "metadata": {}, 177 | "source": [ 178 | "## A documented class\n", 179 | "\n", 180 | "We still have to add some documentation to our class:" 181 | ] 182 | }, 183 | { 184 | "cell_type": "code", 185 | "execution_count": null, 186 | "metadata": { 187 | "collapsed": true 188 | }, 189 | "outputs": [], 190 | "source": [ 191 | "class Example(object):\n", 192 | " r\"\"\"An example class to encapsulate trajectory data and histogram visualisation.\"\"\"\n", 193 | " def __init__(self, traj_length=10000):\n", 194 | " r\"\"\"\n", 195 | " Parameters\n", 196 | " ----------\n", 197 | " traj_length : in, optional, default=10000\n", 198 | " Number of samples in the trajectory.\n", 199 | " \"\"\"\n", 200 | " self.traj_length = traj_length\n", 201 | " self._traj = None\n", 202 | " @property\n", 203 | " def traj(self):\n", 204 | " r\"\"\"Compute the trajectory on demand.\n", 205 | " \n", 206 | " Returns\n", 207 | " -------\n", 208 | " traj : numpy.ndarray(shape=(traj_length, 2))\n", 209 | " Generated trajectory with traj_length time steps.\n", 210 | " \"\"\"\n", 211 | " if self._traj is None:\n", 212 | " self._traj = generate_test_data(traj_length=self.traj_length, num_trajs=1)[0]\n", 213 | " return self._traj\n", 214 | " def plot_histogram(self, bins, ax=None):\n", 215 | " r\"\"\"Make a 2D histogram plot.\n", 216 | " \n", 217 | " Parameters\n", 218 | " ----------\n", 219 | " bins : (int, int)\n", 220 | " Number of bins along x and y.\n", 221 | " ax : matplotlib Axes object, optional, default=None\n", 222 | " Target axis for plotting; will be created if ax=None.\n", 223 | " \n", 224 | " Returns\n", 225 | " -------\n", 226 | " ax : matplotlib Axes object\n", 227 | " Axis object with the 2D histogram plot.\n", 228 | " \"\"\"\n", 229 | " h, xedges, yedges = np.histogram2d(self.traj[:, 0], self.traj[:, 1], bins=bins)\n", 230 | " xcenters = xedges[:-1] + 0.5 * (xedges[1:] - xedges[:-1])\n", 231 | " ycenters = yedges[:-1] + 0.5 * (yedges[1:] - yedges[:-1])\n", 232 | " x, y = np.meshgrid(xcenters, ycenters, indexing='ij')\n", 233 | " if ax is None:\n", 234 | " fig, ax = plt.subplots()\n", 235 | " ax.contourf(x, y, h, np.linspace(h.min(), h.max(), 60))\n", 236 | " ax.set_xlabel(r\"$x$ / a.u.\", fontsize=12)\n", 237 | " ax.set_ylabel(r\"$y$ / a.u.\", fontsize=12)\n", 238 | " ax.set(aspect='equal', adjustable='box-forced')\n", 239 | " return ax" 240 | ] 241 | } 242 | ], 243 | "metadata": { 244 | "kernelspec": { 245 | "display_name": "Python 2", 246 | "language": "python", 247 | "name": "python2" 248 | }, 249 | "language_info": { 250 | "codemirror_mode": { 251 | "name": "ipython", 252 | "version": 2 253 | }, 254 | "file_extension": ".py", 255 | "mimetype": "text/x-python", 256 | "name": "python", 257 | "nbconvert_exporter": "python", 258 | "pygments_lexer": "ipython2", 259 | "version": "2.7.11" 260 | } 261 | }, 262 | "nbformat": 4, 263 | "nbformat_minor": 0 264 | } 265 | --------------------------------------------------------------------------------