├── MANIFEST.in
├── docs
├── .gitignore
├── _static
│ ├── logo.png
│ ├── favicon.png
│ ├── examples.json
│ ├── examples.js
│ └── d3.v2.min.js
├── _themes
│ └── daft
│ │ ├── theme.conf
│ │ ├── static
│ │ ├── code.css
│ │ ├── daft.css
│ │ └── normalize.css
│ │ ├── relations.html
│ │ ├── searchbox.html
│ │ ├── search.html
│ │ └── layout.html
├── examples
│ ├── index.rst
│ ├── nocircles.rst
│ ├── wordy.rst
│ ├── mrf.rst
│ ├── badfont.rst
│ ├── classic.rst
│ ├── nogray.rst
│ ├── weaklensing.rst
│ ├── recursive.rst
│ └── exoplanets.rst
├── api.rst
├── index.rst
├── gen_example.py
├── Makefile
└── conf.py
├── images
├── logo.png
├── wordy.pdf
├── wordy.png
├── classic.pdf
├── classic.png
├── nogray.pdf
├── nogray.png
├── nocircles.pdf
├── nocircles.png
├── weaklensing.pdf
└── weaklensing.png
├── .gitignore
├── examples
├── fixed.py
├── bca.py
├── nocircles.py
├── logo.py
├── wordy.py
├── gaia.py
├── mrf.py
├── badfont.py
├── classic.py
├── yike.py
├── nogray.py
├── thicklines.py
├── weaklensing.py
├── huey_p_newton.py
├── recursive.py
├── exoplanets.py
├── galex.py
└── astronomy.py
├── HISTORY.rst
├── README.rst
├── LICENSE.rst
├── setup.py
└── daft.py
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include README.rst LICENSE.rst
2 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | _build
2 | !*.png
3 | _static/examples/*.png
4 |
--------------------------------------------------------------------------------
/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ceshine/daft/master/images/logo.png
--------------------------------------------------------------------------------
/images/wordy.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ceshine/daft/master/images/wordy.pdf
--------------------------------------------------------------------------------
/images/wordy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ceshine/daft/master/images/wordy.png
--------------------------------------------------------------------------------
/images/classic.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ceshine/daft/master/images/classic.pdf
--------------------------------------------------------------------------------
/images/classic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ceshine/daft/master/images/classic.png
--------------------------------------------------------------------------------
/images/nogray.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ceshine/daft/master/images/nogray.pdf
--------------------------------------------------------------------------------
/images/nogray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ceshine/daft/master/images/nogray.png
--------------------------------------------------------------------------------
/docs/_static/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ceshine/daft/master/docs/_static/logo.png
--------------------------------------------------------------------------------
/images/nocircles.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ceshine/daft/master/images/nocircles.pdf
--------------------------------------------------------------------------------
/images/nocircles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ceshine/daft/master/images/nocircles.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.pyc
3 | *.pdf
4 | build
5 | dist
6 | *.egg-info
7 | *~
8 | *.png
9 |
--------------------------------------------------------------------------------
/docs/_static/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ceshine/daft/master/docs/_static/favicon.png
--------------------------------------------------------------------------------
/images/weaklensing.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ceshine/daft/master/images/weaklensing.pdf
--------------------------------------------------------------------------------
/images/weaklensing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ceshine/daft/master/images/weaklensing.png
--------------------------------------------------------------------------------
/docs/_themes/daft/theme.conf:
--------------------------------------------------------------------------------
1 | [theme]
2 | inherit = basic
3 | stylesheet = daft.css
4 | pygments_style = sphinx
5 |
6 | [options]
7 | tagline = Awesome.
8 |
--------------------------------------------------------------------------------
/examples/fixed.py:
--------------------------------------------------------------------------------
1 | import daft
2 |
3 | pgm = daft.PGM([2, 1], observed_style="outer", aspect=3.2)
4 | pgm.add_node(daft.Node("fixed", r"Fixed!", 1, 0.5, observed=True))
5 | pgm.render().figure.savefig("fixed.png", dpi=150)
6 |
--------------------------------------------------------------------------------
/docs/_themes/daft/static/code.css:
--------------------------------------------------------------------------------
1 | .highlight-python {
2 | border-left: 2px solid #ccc;
3 | padding-left: 10px;
4 | margin-left: -10px;
5 | }
6 |
7 | .highlight {
8 | background: none;
9 | }
10 |
11 | .highlight pre {
12 | font-size: 12px;
13 | }
14 |
--------------------------------------------------------------------------------
/docs/examples/index.rst:
--------------------------------------------------------------------------------
1 | .. _examples:
2 |
3 | Examples
4 | --------
5 |
6 | .. raw:: html
7 |
8 |
9 |
10 |
11 |
14 |
--------------------------------------------------------------------------------
/docs/_static/examples.json:
--------------------------------------------------------------------------------
1 | {
2 | "classic": [ 50, 10],
3 | "nogray": [ 50, 10],
4 | "nocircles": [230, 85],
5 | "wordy": [230, 105],
6 | "weaklensing": [200, 85],
7 | "mrf": [ 18, 18],
8 | "exoplanets": [117, 140],
9 | "badfont": [ 15, 10],
10 | "recursive": [247, 350]
11 | }
12 |
--------------------------------------------------------------------------------
/HISTORY.rst:
--------------------------------------------------------------------------------
1 | .. :changelog:
2 |
3 | 0.0.3 (2012-10-04)
4 | ++++++++++++++++++
5 |
6 | - Fixed rendering bug when ``aspect`` was used with angles other than 45
7 | degrees between nodes.
8 | - Added global ``aspect`` property to the rendering context.
9 | - Fixed the treatment of redundant keyword arguments that matplotlib
10 | allows.
11 |
12 |
13 | 0.0.2 (2012-09-28)
14 | ++++++++++++++++++
15 |
16 | - Initial release.
17 |
--------------------------------------------------------------------------------
/docs/_themes/daft/relations.html:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/docs/_themes/daft/searchbox.html:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | .. image:: https://raw.github.com/davidwhogg/daft/master/images/logo.png
2 |
3 | **Daft** is a Python package that uses `matplotlib `_
4 | to render pixel-perfect *probabilistic graphical models* for publication
5 | in a journal or on the internet. With a short Python script and an intuitive
6 | model-building syntax you can design directed and undirected graphs and save
7 | them in any formats that matplotlib supports.
8 |
9 | Get more information at: `daft-pgm.org `_
10 | **************************************************************
11 |
--------------------------------------------------------------------------------
/examples/bca.py:
--------------------------------------------------------------------------------
1 | from matplotlib import rc
2 | rc("font", family="serif", size=12)
3 | rc("text", usetex=True)
4 | import daft
5 |
6 | if __name__ == "__main__":
7 | pgm = daft.PGM([1.1, 3.15], origin=[0.45, 2.2])
8 | pgm.add_node(daft.Node("a", r"$a$", 1, 5))
9 | pgm.add_node(daft.Node("b", r"$b$", 1, 4))
10 | pgm.add_node(daft.Node("c", r"$c_n$", 1, 3, observed=True))
11 | pgm.add_plate(daft.Plate([0.5, 2.25, 1, 1.25], label=r"data $n$"))
12 | pgm.add_edge("a", "b")
13 | pgm.add_edge("b", "c")
14 | pgm.render()
15 | pgm.figure.savefig("bca.pdf")
16 | pgm.figure.savefig("bca.png", dpi=150)
17 |
--------------------------------------------------------------------------------
/examples/nocircles.py:
--------------------------------------------------------------------------------
1 | """
2 | Nodes can go free
3 | =================
4 |
5 | You don't need to put ellipses or circles around your node contents,
6 | if you don't want to.
7 |
8 | """
9 |
10 | from matplotlib import rc
11 | rc("font", family="serif", size=12)
12 | rc("text", usetex=True)
13 |
14 | import daft
15 |
16 | pgm = daft.PGM([3.6, 2.4], origin = [1.15, 0.8], node_ec="none")
17 | pgm.add_node(daft.Node("cloudy", r"cloudy", 3, 3))
18 | pgm.add_node(daft.Node("rain", r"rain", 2, 2))
19 | pgm.add_node(daft.Node("sprinkler", r"sprinkler", 4, 2))
20 | pgm.add_node(daft.Node("wet", r"grass wet", 3, 1))
21 | pgm.add_edge("cloudy", "rain")
22 | pgm.add_edge("cloudy", "sprinkler")
23 | pgm.add_edge("rain", "wet")
24 | pgm.add_edge("sprinkler", "wet")
25 | pgm.render()
26 | pgm.figure.savefig("nocircles.pdf")
27 | pgm.figure.savefig("nocircles.png", dpi=150)
28 |
--------------------------------------------------------------------------------
/docs/api.rst:
--------------------------------------------------------------------------------
1 | .. _api:
2 |
3 | API
4 | ===
5 |
6 | .. module:: daft
7 |
8 | The PGM Object
9 | --------------
10 |
11 | All daft scripts will start with the creation of a :class:`PGM` object. This
12 | object contains a list of :class:`Node` objects and :class:`Edge` objects
13 | connecting them. You can also specify rendering parameters and other default
14 | parameters when you initialize your :class:`PGM`.
15 |
16 | .. autoclass:: PGM
17 | :inherited-members:
18 |
19 |
20 | Nodes
21 | -----
22 |
23 | .. autoclass:: Node
24 | :inherited-members:
25 |
26 |
27 | Edges
28 | -----
29 |
30 | .. autoclass:: Edge
31 | :inherited-members:
32 |
33 |
34 | Plates
35 | ------
36 |
37 | .. autoclass:: Plate
38 | :inherited-members:
39 |
40 |
41 | The Rendering Context
42 | ---------------------
43 |
44 | .. autoclass:: _rendering_context
45 | :inherited-members:
46 |
--------------------------------------------------------------------------------
/examples/logo.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """
3 | That's an awfully DAFT logo!
4 |
5 | """
6 |
7 | from matplotlib import rc
8 | rc("font", family="serif", size=12)
9 | rc("text", usetex=True)
10 |
11 | import os
12 | import sys
13 | sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
14 |
15 | import daft
16 |
17 |
18 | if __name__ == "__main__":
19 | # Instantiate the PGM.
20 | pgm = daft.PGM((3.7, 0.7), origin=(0.15, 0.15))
21 |
22 | pgm.add_node(daft.Node("d", r"$D$", 0.5, 0.5))
23 | pgm.add_node(daft.Node("a", r"$a$", 1.5, 0.5, observed=True))
24 | pgm.add_node(daft.Node("f", r"$f$", 2.5, 0.5))
25 | pgm.add_node(daft.Node("t", r"$t$", 3.5, 0.5))
26 |
27 | pgm.add_edge("d", "a")
28 | pgm.add_edge("a", "f")
29 | pgm.add_edge("f", "t")
30 |
31 | pgm.render()
32 | pgm.figure.savefig("logo.pdf")
33 | pgm.figure.savefig("logo.png", dpi=200, transparent=True)
34 |
--------------------------------------------------------------------------------
/examples/wordy.py:
--------------------------------------------------------------------------------
1 | """
2 | Nodes can contain words
3 | =======================
4 |
5 | We here at **Daft** headquarters tend to put symbols (variable
6 | names) in our graph nodes. But you don't have to if you don't
7 | want to.
8 |
9 | """
10 |
11 | from matplotlib import rc
12 | rc("font", family="serif", size=12)
13 | rc("text", usetex=True)
14 |
15 | import daft
16 |
17 | pgm = daft.PGM([3.6, 2.7], origin=[1.15, 0.65])
18 | pgm.add_node(daft.Node("cloudy", r"cloudy", 3, 3, aspect=1.8))
19 | pgm.add_node(daft.Node("rain", r"rain", 2, 2, aspect=1.2))
20 | pgm.add_node(daft.Node("sprinkler", r"sprinkler", 4, 2, aspect=2.1))
21 | pgm.add_node(daft.Node("wet", r"grass wet", 3, 1, aspect=2.4, observed=True))
22 | pgm.add_edge("cloudy", "rain")
23 | pgm.add_edge("cloudy", "sprinkler")
24 | pgm.add_edge("rain", "wet")
25 | pgm.add_edge("sprinkler", "wet")
26 | pgm.render()
27 | pgm.figure.savefig("wordy.pdf")
28 | pgm.figure.savefig("wordy.png", dpi=150)
29 |
--------------------------------------------------------------------------------
/examples/gaia.py:
--------------------------------------------------------------------------------
1 | from matplotlib import rc
2 | rc("font", family="serif", size=12)
3 | rc("text", usetex=True)
4 | import daft
5 |
6 | if __name__ == "__main__":
7 | pgm = daft.PGM([3.7, 3.15], origin=[-0.35, 2.2])
8 | pgm.add_node(daft.Node("omega", r"$\omega$", 2, 5))
9 | pgm.add_node(daft.Node("true", r"$\tilde{X}_n$", 2, 4))
10 | pgm.add_node(daft.Node("obs", r"$X_n$", 2, 3, observed=True))
11 | pgm.add_node(daft.Node("alpha", r"$\alpha$", 3, 4))
12 | pgm.add_node(daft.Node("Sigma", r"$\Sigma$", 0, 3))
13 | pgm.add_node(daft.Node("sigma", r"$\sigma_n$", 1, 3))
14 | pgm.add_plate(daft.Plate([0.5, 2.25, 2, 2.25], label=r"stars $n$"))
15 | pgm.add_edge("omega", "true")
16 | pgm.add_edge("true", "obs")
17 | pgm.add_edge("alpha", "true")
18 | pgm.add_edge("Sigma", "sigma")
19 | pgm.add_edge("sigma", "obs")
20 | pgm.render()
21 | pgm.figure.savefig("gaia.pdf")
22 | pgm.figure.savefig("gaia.png", dpi=150)
23 |
--------------------------------------------------------------------------------
/examples/mrf.py:
--------------------------------------------------------------------------------
1 | """
2 | An undirected graph
3 | ===================
4 |
5 | This makes the simple point that you don't have to have directions on
6 | your edges; you can have *undirected* graphs. (Also, the nodes don't
7 | need to have labels!)
8 |
9 | """
10 |
11 | import itertools
12 | import numpy as np
13 |
14 | import daft
15 |
16 | # Instantiate the PGM.
17 | pgm = daft.PGM([3.6, 3.6], origin=[0.7, 0.7], node_unit=0.4, grid_unit=1,
18 | directed=False)
19 |
20 | for i, (xi, yi) in enumerate(itertools.product(range(1, 5), range(1, 5))):
21 | pgm.add_node(daft.Node(str(i), "", xi, yi))
22 |
23 |
24 | for e in [(4, 9), (6, 7), (3, 7), (10, 11), (10, 9), (10, 14),
25 | (10, 6), (10, 7), (1, 2), (1, 5), (1, 0), (1, 6), (8, 12), (12, 13),
26 | (13, 14), (15, 11)]:
27 | pgm.add_edge(str(e[0]), str(e[1]))
28 |
29 | # Render and save.
30 | pgm.render()
31 | pgm.figure.savefig("mrf.pdf")
32 | pgm.figure.savefig("mrf.png", dpi=150)
33 |
--------------------------------------------------------------------------------
/examples/badfont.py:
--------------------------------------------------------------------------------
1 | """
2 | You can use arbitrarily shitty fonts
3 | ====================================
4 |
5 | Any fonts that LaTeX or matplotlib supports can be used. Do not take
6 | this example as any kind of implied recommendation unless you plan on
7 | announcing a *huge* discovery!
8 |
9 | """
10 |
11 | from matplotlib import rc
12 |
13 | ff = "comic sans ms"
14 | # ff = "impact"
15 | # ff = "times new roman"
16 |
17 | rc("font", family=ff, size=12)
18 | rc("text", usetex=False)
19 |
20 | import daft
21 |
22 | pgm = daft.PGM([3.6, 1.8], origin=[2.2, 1.6], aspect=2.1)
23 | pgm.add_node(daft.Node("confused", r"confused", 3.0, 3.0))
24 | pgm.add_node(daft.Node("ugly", r"ugly font", 3.0, 2.0, observed=True))
25 | pgm.add_node(daft.Node("bad", r"bad talk", 5.0, 2.0, observed=True))
26 | pgm.add_edge("confused", "ugly")
27 | pgm.add_edge("ugly", "bad")
28 | pgm.add_edge("confused", "bad")
29 | pgm.render()
30 | pgm.figure.savefig("badfont.pdf")
31 | pgm.figure.savefig("badfont.png", dpi=150)
32 |
--------------------------------------------------------------------------------
/docs/examples/nocircles.rst:
--------------------------------------------------------------------------------
1 | .. _nocircles:
2 |
3 |
4 | Nodes can go free
5 | =================
6 |
7 | .. figure:: /_static/examples/nocircles.png
8 |
9 |
10 | Nodes can go free
11 | =================
12 |
13 | You don't need to put ellipses or circles around your node contents,
14 | if you don't want to.
15 |
16 |
17 |
18 | ::
19 |
20 |
21 | from matplotlib import rc
22 | rc("font", family="serif", size=12)
23 | rc("text", usetex=True)
24 |
25 | import daft
26 |
27 | pgm = daft.PGM([3.6, 2.4], origin = [1.15, 0.8], node_ec="none")
28 | pgm.add_node(daft.Node("cloudy", r"cloudy", 3, 3))
29 | pgm.add_node(daft.Node("rain", r"rain", 2, 2))
30 | pgm.add_node(daft.Node("sprinkler", r"sprinkler", 4, 2))
31 | pgm.add_node(daft.Node("wet", r"grass wet", 3, 1))
32 | pgm.add_edge("cloudy", "rain")
33 | pgm.add_edge("cloudy", "sprinkler")
34 | pgm.add_edge("rain", "wet")
35 | pgm.add_edge("sprinkler", "wet")
36 | pgm.render()
37 | pgm.figure.savefig("nocircles.pdf")
38 | pgm.figure.savefig("nocircles.png", dpi=150)
39 |
40 |
41 |
--------------------------------------------------------------------------------
/LICENSE.rst:
--------------------------------------------------------------------------------
1 | Copyright (c) 2012 Daniel Foreman-Mackey, David W. Hogg, and contributors
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | this software and associated documentation files (the "Software"), to deal in
5 | the Software without restriction, including without limitation the rights to
6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7 | the Software, and to permit persons to whom the Software is furnished to do so,
8 | subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | **THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.**
19 |
--------------------------------------------------------------------------------
/docs/_static/examples.js:
--------------------------------------------------------------------------------
1 | function shuffle(array) {
2 | // Based on: http://d3js.org
3 | var m = array.length, t, i;
4 |
5 | // While there remain elements to shuffle
6 | while (m) {
7 | // Pick a remaining element…
8 | i = Math.floor(Math.random() * m--);
9 |
10 | // And swap it with the current element.
11 | t = array[m];
12 | array[m] = array[i];
13 | array[i] = t;
14 | }
15 |
16 | return array;
17 | }
18 |
19 | function show_examples(N) {
20 | d3.json("/_static/examples.json", function (examples) {
21 | var k, names = [];
22 | for (k in examples) {
23 | names.push(k);
24 | }
25 |
26 | if (typeof(N) !== "undefined")
27 | names = shuffle(names).slice(0, N);
28 |
29 | d3.select("#examples").selectAll(".example")
30 | .data(names)
31 | .enter().append("a")
32 | .attr("class", "example")
33 | .attr("href", function (d) { return "/examples/" + d + "/"; })
34 | .append("img")
35 | .attr("src", function (d) { return "/_static/examples/" + d + "-thumb.png"; });
36 | });
37 | }
38 |
--------------------------------------------------------------------------------
/docs/examples/wordy.rst:
--------------------------------------------------------------------------------
1 | .. _wordy:
2 |
3 |
4 | Nodes can contain words
5 | =======================
6 |
7 | .. figure:: /_static/examples/wordy.png
8 |
9 |
10 | Nodes can contain words
11 | =======================
12 |
13 | We here at **Daft** headquarters tend to put symbols (variable
14 | names) in our graph nodes. But you don't have to if you don't
15 | want to.
16 |
17 |
18 |
19 | ::
20 |
21 |
22 | from matplotlib import rc
23 | rc("font", family="serif", size=12)
24 | rc("text", usetex=True)
25 |
26 | import daft
27 |
28 | pgm = daft.PGM([3.6, 2.7], origin=[1.15, 0.65])
29 | pgm.add_node(daft.Node("cloudy", r"cloudy", 3, 3, aspect=1.8))
30 | pgm.add_node(daft.Node("rain", r"rain", 2, 2, aspect=1.2))
31 | pgm.add_node(daft.Node("sprinkler", r"sprinkler", 4, 2, aspect=2.1))
32 | pgm.add_node(daft.Node("wet", r"grass wet", 3, 1, aspect=2.4, observed=True))
33 | pgm.add_edge("cloudy", "rain")
34 | pgm.add_edge("cloudy", "sprinkler")
35 | pgm.add_edge("rain", "wet")
36 | pgm.add_edge("sprinkler", "wet")
37 | pgm.render()
38 | pgm.figure.savefig("wordy.pdf")
39 | pgm.figure.savefig("wordy.png", dpi=150)
40 |
41 |
42 |
--------------------------------------------------------------------------------
/docs/examples/mrf.rst:
--------------------------------------------------------------------------------
1 | .. _mrf:
2 |
3 |
4 | An undirected graph
5 | ===================
6 |
7 | .. figure:: /_static/examples/mrf.png
8 |
9 |
10 | An undirected graph
11 | ===================
12 |
13 | This makes the simple point that you don't have to have directions on
14 | your edges; you can have *undirected* graphs. (Also, the nodes don't
15 | need to have labels!)
16 |
17 |
18 |
19 | ::
20 |
21 |
22 | import itertools
23 | import numpy as np
24 |
25 | import daft
26 |
27 | # Instantiate the PGM.
28 | pgm = daft.PGM([3.6, 3.6], origin=[0.7, 0.7], node_unit=0.4, grid_unit=1,
29 | directed=False)
30 |
31 | for i, (xi, yi) in enumerate(itertools.product(range(1, 5), range(1, 5))):
32 | pgm.add_node(daft.Node(str(i), "", xi, yi))
33 |
34 |
35 | for e in [(4, 9), (6, 7), (3, 7), (10, 11), (10, 9), (10, 14),
36 | (10, 6), (10, 7), (1, 2), (1, 5), (1, 0), (1, 6), (8, 12), (12, 13),
37 | (13, 14), (15, 11)]:
38 | pgm.add_edge(str(e[0]), str(e[1]))
39 |
40 | # Render and save.
41 | pgm.render()
42 | pgm.figure.savefig("mrf.pdf")
43 | pgm.figure.savefig("mrf.png", dpi=150)
44 |
45 |
46 |
--------------------------------------------------------------------------------
/examples/classic.py:
--------------------------------------------------------------------------------
1 | """
2 | The Quintessential PGM
3 | ======================
4 |
5 | This is a demonstration of a very common structure found in graphical models.
6 | It has been rendered using Daft's default settings for all the parameters
7 | and it shows off how much beauty is baked in by default.
8 |
9 | """
10 |
11 | from matplotlib import rc
12 | rc("font", family="serif", size=12)
13 | rc("text", usetex=True)
14 |
15 | import daft
16 |
17 | # Instantiate the PGM.
18 | pgm = daft.PGM([2.3, 2.05], origin=[0.3, 0.3])
19 |
20 | # Hierarchical parameters.
21 | pgm.add_node(daft.Node("alpha", r"$\alpha$", 0.5, 2, fixed=True))
22 | pgm.add_node(daft.Node("beta", r"$\beta$", 1.5, 2))
23 |
24 | # Latent variable.
25 | pgm.add_node(daft.Node("w", r"$w_n$", 1, 1))
26 |
27 | # Data.
28 | pgm.add_node(daft.Node("x", r"$x_n$", 2, 1, observed=True))
29 |
30 | # Add in the edges.
31 | pgm.add_edge("alpha", "beta")
32 | pgm.add_edge("beta", "w")
33 | pgm.add_edge("w", "x")
34 | pgm.add_edge("beta", "x")
35 |
36 | # And a plate.
37 | pgm.add_plate(daft.Plate([0.5, 0.5, 2, 1], label=r"$n = 1, \cdots, N$",
38 | shift=-0.1))
39 |
40 | # Render and save.
41 | pgm.render()
42 | pgm.figure.savefig("classic.pdf")
43 | pgm.figure.savefig("classic.png", dpi=150)
44 |
--------------------------------------------------------------------------------
/docs/examples/badfont.rst:
--------------------------------------------------------------------------------
1 | .. _badfont:
2 |
3 |
4 | You can use arbitrarily shitty fonts
5 | ====================================
6 |
7 | .. figure:: /_static/examples/badfont.png
8 |
9 |
10 | You can use arbitrarily shitty fonts
11 | ====================================
12 |
13 | Any fonts that LaTeX or matplotlib supports can be used. Do not take
14 | this example as any kind of implied recommendation unless you plan on
15 | announcing a *huge* discovery!
16 |
17 |
18 |
19 | ::
20 |
21 |
22 | from matplotlib import rc
23 |
24 | ff = "comic sans ms"
25 | # ff = "impact"
26 | # ff = "times new roman"
27 |
28 | rc("font", family=ff, size=12)
29 | rc("text", usetex=False)
30 |
31 | import daft
32 |
33 | pgm = daft.PGM([3.6, 1.8], origin=[2.2, 1.6], aspect=2.1)
34 | pgm.add_node(daft.Node("confused", r"confused", 3.0, 3.0))
35 | pgm.add_node(daft.Node("ugly", r"ugly font", 3.0, 2.0, observed=True))
36 | pgm.add_node(daft.Node("bad", r"bad talk", 5.0, 2.0, observed=True))
37 | pgm.add_edge("confused", "ugly")
38 | pgm.add_edge("ugly", "bad")
39 | pgm.add_edge("confused", "bad")
40 | pgm.render()
41 | pgm.figure.savefig("badfont.pdf")
42 | pgm.figure.savefig("badfont.png", dpi=150)
43 |
44 |
45 |
--------------------------------------------------------------------------------
/examples/yike.py:
--------------------------------------------------------------------------------
1 | """
2 | Yike's model
3 | ============
4 |
5 | This is Yike Tang's model for weak lensing.
6 |
7 | """
8 |
9 | from matplotlib import rc
10 | rc("font", family="serif", size=12)
11 | rc("text", usetex=True)
12 |
13 | import daft
14 |
15 | pgm = daft.PGM([5.20, 2.95], origin=[-1.70, 1.65])
16 | pgm.add_node(daft.Node("obs", r"$\epsilon^{\mathrm{obs}}_n$", 2, 3, observed=True))
17 | pgm.add_node(daft.Node("true", r"$\epsilon^{\mathrm{true}}_n$", 1, 3))
18 | pgm.add_edge("true", "obs")
19 | pgm.add_node(daft.Node("alpha", r"$\alpha,\beta$", -0.25, 3))
20 | pgm.add_edge("alpha", "true")
21 | pgm.add_node(daft.Node("shape prior", r"$p(\alpha, \beta)$", -1.25, 3, fixed=True))
22 | pgm.add_edge("shape prior", "alpha")
23 | pgm.add_node(daft.Node("gamma", r"$\gamma_m$", 2, 4))
24 | pgm.add_edge("gamma", "obs")
25 | pgm.add_node(daft.Node("gamma prior", r"$p(\gamma)$", -0.25, 4, fixed=True))
26 | pgm.add_edge("gamma prior", "gamma")
27 | pgm.add_node(daft.Node("sigma", r"$\sigma_{\epsilon}$", 3.25, 3, fixed=True))
28 | pgm.add_edge("sigma", "obs")
29 | pgm.add_plate(daft.Plate([0.5, 2.25, 2, 1.25],
30 | label=r"galaxies $n$"))
31 | pgm.add_plate(daft.Plate([0.25, 1.75, 2.5, 2.75],
32 | label=r"patches $m$"))
33 | pgm.render()
34 | pgm.figure.savefig("yike.pdf")
35 | pgm.figure.savefig("yike.png", dpi=150)
36 |
--------------------------------------------------------------------------------
/examples/nogray.py:
--------------------------------------------------------------------------------
1 | """
2 | Alternative Observed Node Styles
3 | ================================
4 |
5 | .. module:: daft
6 |
7 | This model is the same as `the classic `_ model but the
8 | "observed" :class:`Node` is indicated by a double outline instead of shading.
9 | This particular example uses the ``inner`` style but ``outer`` is also an
10 | option for a different look.
11 |
12 | """
13 |
14 | from matplotlib import rc
15 | rc("font", family="serif", size=12)
16 | rc("text", usetex=True)
17 |
18 | import daft
19 |
20 | pgm = daft.PGM([2.3, 2.05], origin=[0.3, 0.3], observed_style="inner")
21 |
22 | # Hierarchical parameters.
23 | pgm.add_node(daft.Node("alpha", r"$\alpha$", 0.5, 2, fixed=True))
24 | pgm.add_node(daft.Node("beta", r"$\beta$", 1.5, 2))
25 |
26 | # Latent variable.
27 | pgm.add_node(daft.Node("w", r"$w_n$", 1, 1))
28 |
29 | # Data.
30 | pgm.add_node(daft.Node("x", r"$x_n$", 2, 1, observed=True))
31 |
32 | # Add in the edges.
33 | pgm.add_edge("alpha", "beta")
34 | pgm.add_edge("beta", "w")
35 | pgm.add_edge("w", "x")
36 | pgm.add_edge("beta", "x")
37 |
38 | # And a plate.
39 | pgm.add_plate(daft.Plate([0.5, 0.5, 2, 1], label=r"$n = 1, \ldots, N$",
40 | shift=-0.1))
41 |
42 | # Render and save.
43 | pgm.render()
44 | pgm.figure.savefig("nogray.pdf")
45 | pgm.figure.savefig("nogray.png", dpi=150)
46 |
--------------------------------------------------------------------------------
/examples/thicklines.py:
--------------------------------------------------------------------------------
1 | """
2 | T-shirt style
3 | =============
4 |
5 | Don't like dainty thin lines? Need to make graphical-model-themed
6 | conference schwag? Then `line_width` is the parameter for you. Also
7 | check out the `preamble` option in the `matplotlib.rc` command.
8 |
9 | """
10 |
11 | from matplotlib import rc
12 | rc("font", family="serif", size=14)
13 | rc("text", usetex=True)
14 | rc('text.latex',
15 | preamble="\usepackage{amssymb}\usepackage{amsmath}\usepackage{mathrsfs}")
16 |
17 | import daft
18 |
19 | # Instantiate the PGM.
20 | pgm = daft.PGM([2.3, 2.05], origin=[0.3, 0.3], line_width=2.5)
21 |
22 | # Hierarchical parameters.
23 | pgm.add_node(daft.Node("alpha", r"$\boldsymbol{\alpha}$", 0.5, 2, fixed=True))
24 | pgm.add_node(daft.Node("beta", r"$\boldsymbol{\beta}$", 1.5, 2))
25 |
26 | # Latent variable.
27 | pgm.add_node(daft.Node("w", r"$\boldsymbol{w_n}$", 1, 1))
28 |
29 | # Data.
30 | pgm.add_node(daft.Node("x", r"$\boldsymbol{x_n}$", 2, 1, observed=True))
31 |
32 | # Add in the edges.
33 | pgm.add_edge("alpha", "beta")
34 | pgm.add_edge("beta", "w")
35 | pgm.add_edge("w", "x")
36 | pgm.add_edge("beta", "x")
37 |
38 | # And a plate.
39 | pgm.add_plate(daft.Plate([0.5, 0.5, 2, 1], label=r"$\boldsymbol{n = 1, \cdots, N}$",
40 | shift=-0.1))
41 |
42 | # Render and save.
43 | pgm.render()
44 | pgm.figure.savefig("thicklines.pdf")
45 | pgm.figure.savefig("thicklines.png", dpi=150)
46 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 |
4 | try:
5 | from setuptools import setup, Extension
6 | setup, Extension
7 | except ImportError:
8 | from distutils.core import setup
9 | from distutils.extension import Extension
10 | setup, Extension
11 |
12 | import os
13 | import re
14 | import sys
15 |
16 | if sys.argv[-1] == "publish":
17 | os.system("python setup.py sdist upload")
18 | sys.exit()
19 |
20 | vre = re.compile("__version__ = \"(.*?)\"")
21 | m = open(os.path.join(os.path.dirname(os.path.abspath(__file__)),
22 | "daft.py")).read()
23 | version = vre.findall(m)[0]
24 |
25 |
26 | setup(
27 | name="daft",
28 | version=version,
29 | description="PGM rendering at its finest.",
30 | long_description=open("README.rst").read(),
31 | author="David W. Hogg & Daniel Foreman-Mackey",
32 | author_email="danfm@nyu.edu",
33 | url="http://daft-pgm.org",
34 | py_modules=["daft"],
35 | package_data={"": ["LICENSE.rst"]},
36 | include_package_data=True,
37 | install_requires=[
38 | "numpy",
39 | "matplotlib"
40 | ],
41 | classifiers=[
42 | "Development Status :: 3 - Alpha",
43 | "Intended Audience :: Developers",
44 | "Intended Audience :: Science/Research",
45 | "License :: OSI Approved :: MIT License",
46 | "Operating System :: OS Independent",
47 | "Programming Language :: Python",
48 | ],
49 | )
50 |
--------------------------------------------------------------------------------
/docs/examples/classic.rst:
--------------------------------------------------------------------------------
1 | .. _classic:
2 |
3 |
4 | The Quintessential PGM
5 | ======================
6 |
7 | .. figure:: /_static/examples/classic.png
8 |
9 |
10 | The Quintessential PGM
11 | ======================
12 |
13 | This is a demonstration of a very common structure found in graphical models.
14 | It has been rendered using Daft's default settings for all the parameters
15 | and it shows off how much beauty is baked in by default.
16 |
17 |
18 |
19 | ::
20 |
21 |
22 | from matplotlib import rc
23 | rc("font", family="serif", size=12)
24 | rc("text", usetex=True)
25 |
26 | import daft
27 |
28 | # Instantiate the PGM.
29 | pgm = daft.PGM([2.3, 2.05], origin=[0.3, 0.3])
30 |
31 | # Hierarchical parameters.
32 | pgm.add_node(daft.Node("alpha", r"$\alpha$", 0.5, 2, fixed=True))
33 | pgm.add_node(daft.Node("beta", r"$\beta$", 1.5, 2))
34 |
35 | # Latent variable.
36 | pgm.add_node(daft.Node("w", r"$w_n$", 1, 1))
37 |
38 | # Data.
39 | pgm.add_node(daft.Node("x", r"$x_n$", 2, 1, observed=True))
40 |
41 | # Add in the edges.
42 | pgm.add_edge("alpha", "beta")
43 | pgm.add_edge("beta", "w")
44 | pgm.add_edge("w", "x")
45 | pgm.add_edge("beta", "x")
46 |
47 | # And a plate.
48 | pgm.add_plate(daft.Plate([0.5, 0.5, 2, 1], label=r"$n = 1, \cdots, N$",
49 | shift=-0.1))
50 |
51 | # Render and save.
52 | pgm.render()
53 | pgm.figure.savefig("classic.pdf")
54 | pgm.figure.savefig("classic.png", dpi=150)
55 |
56 |
57 |
--------------------------------------------------------------------------------
/examples/weaklensing.py:
--------------------------------------------------------------------------------
1 | """
2 | A model for weak lensing
3 | ========================
4 |
5 | This is (**Daft** co-author) Hogg's model for the obsevational
6 | cosmology method known as *weak gravitational lensing*, if that method
7 | were properly probabilistic (which it usually isn't). Hogg put the
8 | model here for one very important reason: *Because he can*. Oh, and
9 | it demonstrates that you can represent non-trivial scientific projects
10 | with **Daft**.
11 |
12 | """
13 |
14 | from matplotlib import rc
15 | rc("font", family="serif", size=12)
16 | rc("text", usetex=True)
17 |
18 | import daft
19 |
20 | pgm = daft.PGM([4.7, 2.35], origin=[-1.35, 2.2])
21 | pgm.add_node(daft.Node("Omega", r"$\Omega$", -1, 4))
22 | pgm.add_node(daft.Node("gamma", r"$\gamma$", 0, 4))
23 | pgm.add_node(daft.Node("obs", r"$\epsilon^{\mathrm{obs}}_n$", 1, 4,
24 | observed=True))
25 | pgm.add_node(daft.Node("alpha", r"$\alpha$", 3, 4))
26 | pgm.add_node(daft.Node("true", r"$\epsilon^{\mathrm{true}}_n$", 2, 4))
27 | pgm.add_node(daft.Node("sigma", r"$\sigma_n$", 1, 3))
28 | pgm.add_node(daft.Node("Sigma", r"$\Sigma$", 0, 3))
29 | pgm.add_node(daft.Node("x", r"$x_n$", 2, 3, observed=True))
30 | pgm.add_plate(daft.Plate([0.5, 2.25, 2, 2.25],
31 | label=r"galaxies $n$"))
32 | pgm.add_edge("Omega", "gamma")
33 | pgm.add_edge("gamma", "obs")
34 | pgm.add_edge("alpha", "true")
35 | pgm.add_edge("true", "obs")
36 | pgm.add_edge("x", "obs")
37 | pgm.add_edge("Sigma", "sigma")
38 | pgm.add_edge("sigma", "obs")
39 | pgm.render()
40 | pgm.figure.savefig("weaklensing.pdf")
41 | pgm.figure.savefig("weaklensing.png", dpi=150)
42 |
--------------------------------------------------------------------------------
/docs/examples/nogray.rst:
--------------------------------------------------------------------------------
1 | .. _nogray:
2 |
3 |
4 | Alternative Observed Node Styles
5 | ================================
6 |
7 | .. figure:: /_static/examples/nogray.png
8 |
9 |
10 | Alternative Observed Node Styles
11 | ================================
12 |
13 | .. module:: daft
14 |
15 | This model is the same as `the classic `_ model but the
16 | "observed" :class:`Node` is indicated by a double outline instead of shading.
17 | This particular example uses the ``inner`` style but ``outer`` is also an
18 | option for a different look.
19 |
20 |
21 |
22 | ::
23 |
24 |
25 | from matplotlib import rc
26 | rc("font", family="serif", size=12)
27 | rc("text", usetex=True)
28 |
29 | import daft
30 |
31 | pgm = daft.PGM([2.3, 2.05], origin=[0.3, 0.3], observed_style="inner")
32 |
33 | # Hierarchical parameters.
34 | pgm.add_node(daft.Node("alpha", r"$\alpha$", 0.5, 2, fixed=True))
35 | pgm.add_node(daft.Node("beta", r"$\beta$", 1.5, 2))
36 |
37 | # Latent variable.
38 | pgm.add_node(daft.Node("w", r"$w_n$", 1, 1))
39 |
40 | # Data.
41 | pgm.add_node(daft.Node("x", r"$x_n$", 2, 1, observed=True))
42 |
43 | # Add in the edges.
44 | pgm.add_edge("alpha", "beta")
45 | pgm.add_edge("beta", "w")
46 | pgm.add_edge("w", "x")
47 | pgm.add_edge("beta", "x")
48 |
49 | # And a plate.
50 | pgm.add_plate(daft.Plate([0.5, 0.5, 2, 1], label=r"$n = 1, \ldots, N$",
51 | shift=-0.1))
52 |
53 | # Render and save.
54 | pgm.render()
55 | pgm.figure.savefig("nogray.pdf")
56 | pgm.figure.savefig("nogray.png", dpi=150)
57 |
58 |
59 |
--------------------------------------------------------------------------------
/examples/huey_p_newton.py:
--------------------------------------------------------------------------------
1 | """
2 | n-body particle inference
3 | =========================
4 |
5 | Dude.
6 | """
7 |
8 | from matplotlib import rc
9 | rc("font", family="serif", size=12)
10 | rc("text", usetex=True)
11 |
12 | import daft
13 |
14 | pgm = daft.PGM([5.4, 2.0], origin=[0.65, 0.35])
15 |
16 | kx, ky = 1.5, 1.
17 | nx, ny = kx + 3., ky + 0.
18 | hx, hy, dhx = kx - 0.5, ky + 1., 1.
19 |
20 | pgm.add_node(daft.Node("dyn", r"$\theta_{\mathrm{dyn}}$", hx + 0. * dhx, hy + 0.))
21 | pgm.add_node(daft.Node("ic", r"$\theta_{\mathrm{I.C.}}$", hx + 1. * dhx, hy + 0.))
22 | pgm.add_node(daft.Node("sun", r"$\theta_{\odot}$", hx + 2. * dhx, hy + 0.))
23 | pgm.add_node(daft.Node("bg", r"$\theta_{\mathrm{bg}}$", hx + 3. * dhx, hy + 0.))
24 | pgm.add_node(daft.Node("Sigma", r"$\Sigma^2$", hx + 4. * dhx, hy + 0.))
25 |
26 | pgm.add_plate(daft.Plate([kx - 0.5, ky - 0.6, 2., 1.1], label=r"model points $k$"))
27 | pgm.add_node(daft.Node("xk", r"$x_k$", kx + 0., ky + 0.))
28 | pgm.add_edge("dyn", "xk")
29 | pgm.add_edge("ic", "xk")
30 | pgm.add_node(daft.Node("yk", r"$y_k$", kx + 1., ky + 0.))
31 | pgm.add_edge("sun", "yk")
32 | pgm.add_edge("xk", "yk")
33 |
34 | pgm.add_plate(daft.Plate([nx - 0.5, ny - 0.6, 2., 1.1], label=r"data points $n$"))
35 | pgm.add_node(daft.Node("sigman", r"$\sigma^2_n$", nx + 1., ny + 0., observed=True))
36 | pgm.add_node(daft.Node("Yn", r"$Y_n$", nx + 0., ny + 0., observed=True))
37 | pgm.add_edge("bg", "Yn")
38 | pgm.add_edge("Sigma", "Yn")
39 | pgm.add_edge("Sigma", "Yn")
40 | pgm.add_edge("yk", "Yn")
41 | pgm.add_edge("sigman", "Yn")
42 |
43 | # Render and save.
44 | pgm.render()
45 | pgm.figure.savefig("huey_p_newton.pdf")
46 | pgm.figure.savefig("huey_p_newton.png", dpi=150)
47 |
--------------------------------------------------------------------------------
/docs/_themes/daft/search.html:
--------------------------------------------------------------------------------
1 | {% extends "layout.html" %}
2 |
3 | {% set title = _('Search') %}
4 |
5 | {% set script_files = script_files + ['_static/searchtools.js'] %}
6 |
7 | {% block extrahead %}
8 |
11 | {{ super() }}
12 | {% endblock %}
13 |
14 | {% block body %}
15 | {{ _('Search') }}
16 |
17 |
18 |
19 | {% trans %}Please activate JavaScript to enable the search
20 | functionality.{% endtrans %}
21 |
22 |
23 |
24 | {% trans %}From here you can search these documents. Enter your search
25 | words into the box below. Note that the search
26 | function will automatically search for all of the words. Pages
27 | containing fewer words won't appear in the result list.{% endtrans %}
28 |
29 |
33 | {% if search_performed %}
34 | {{ _('Search Results') }}
35 | {% if not search_results %}
36 | {{ _('Your search did not match any results.') }}
37 | {% endif %}
38 | {% endif %}
39 |
40 | {% if search_results %}
41 |
42 | {% for href, caption, context in search_results %}
43 | {{ caption }}
44 | {{ context|e }}
45 |
46 | {% endfor %}
47 |
48 | {% endif %}
49 |
50 | {% endblock %}
51 |
--------------------------------------------------------------------------------
/examples/recursive.py:
--------------------------------------------------------------------------------
1 | """
2 | Recursively generated graph
3 | ===========================
4 |
5 | **Daft** is Python, so you can do anything Python can do. This graph is
6 | generated by recursive code.
7 |
8 | """
9 |
10 | from matplotlib import rc
11 | rc("font", family="serif", size=12)
12 | rc("text", usetex=True)
13 |
14 | import daft
15 |
16 | def recurse(pgm, nodename, level, c):
17 | if level > 4:
18 | return nodename
19 | r = c / 2
20 | r1nodename = "r{0:02d}{1:04d}".format(level, r)
21 | if 2 * r == c:
22 | print("adding {0}".format(r1nodename))
23 | pgm.add_node(daft.Node(r1nodename, r"reduce",
24 | 2 ** level * (r + 0.5) - 0.5,
25 | 3 - 0.7 * level, aspect=1.9))
26 | pgm.add_edge(nodename, r1nodename)
27 | if 2 * r == c:
28 | return recurse(pgm, r1nodename, level + 1, r)
29 |
30 | pgm = daft.PGM([16.2, 8], origin=[-0.6, -1.5])
31 |
32 | pgm.add_node(daft.Node("query", r'\texttt{"kittens?"}', 3, 6., aspect=3.,
33 | plot_params={"ec": "none"}))
34 | pgm.add_node(daft.Node("input", r"input", 7.5, 6., aspect=3.))
35 | pgm.add_edge("query", "input")
36 |
37 | for c in range(16):
38 | nodename = "map {0:02d}".format(c)
39 | pgm.add_node(daft.Node(nodename, str(nodename), c, 3., aspect=1.9))
40 | pgm.add_edge("input", nodename)
41 | level = 1
42 | recurse(pgm, nodename, level, c)
43 |
44 | pgm.add_node(daft.Node("output", r"output", 7.5, -1., aspect=3.))
45 | pgm.add_edge("r040000", "output")
46 | pgm.add_node(daft.Node("answer", r'\texttt{"http://dwh.gg/"}', 12., -1.,
47 | aspect=4.5, plot_params={"ec": "none"}))
48 | pgm.add_edge("output", "answer")
49 |
50 | pgm.render()
51 | pgm.figure.savefig("recursive.pdf")
52 | pgm.figure.savefig("recursive.png", dpi=200)
53 |
--------------------------------------------------------------------------------
/examples/exoplanets.py:
--------------------------------------------------------------------------------
1 | """
2 | The Fergus model of exoplanet detection
3 | =======================================
4 |
5 | Besides being generally awesome, this example also demonstrates how you can
6 | color the nodes and add arbitrary labels to the figure.
7 |
8 | """
9 |
10 | from matplotlib import rc
11 | rc("font", family="serif", size=12)
12 | rc("text", usetex=True)
13 |
14 | import daft
15 |
16 | # Colors.
17 | p_color = {"ec": "#46a546"}
18 | s_color = {"ec": "#f89406"}
19 |
20 | pgm = daft.PGM([3.6, 3.5], origin=[0.7, 0])
21 |
22 | n = daft.Node("phi", r"$\phi$", 1, 3, plot_params=s_color)
23 | n.va = "baseline"
24 | pgm.add_node(n)
25 | pgm.add_node(daft.Node("speckle_coeff", r"$z_i$", 2, 3, plot_params=s_color))
26 | pgm.add_node(daft.Node("speckle_img", r"$x_i$", 2, 2, plot_params=s_color))
27 |
28 | pgm.add_node(daft.Node("spec", r"$s$", 4, 3, plot_params=p_color))
29 | pgm.add_node(daft.Node("shape", r"$g$", 4, 2, plot_params=p_color))
30 | pgm.add_node(daft.Node("planet_pos", r"$\mu_i$", 3, 3, plot_params=p_color))
31 | pgm.add_node(daft.Node("planet_img", r"$p_i$", 3, 2, plot_params=p_color))
32 |
33 | pgm.add_node(daft.Node("pixels", r"$y_i ^j$", 2.5, 1, observed=True))
34 |
35 | # Edges.
36 | pgm.add_edge("phi", "speckle_coeff")
37 | pgm.add_edge("speckle_coeff", "speckle_img")
38 | pgm.add_edge("speckle_img", "pixels")
39 |
40 | pgm.add_edge("spec", "planet_img")
41 | pgm.add_edge("shape", "planet_img")
42 | pgm.add_edge("planet_pos", "planet_img")
43 | pgm.add_edge("planet_img", "pixels")
44 |
45 | # And a plate.
46 | pgm.add_plate(daft.Plate([1.5, 0.2, 2, 3.2], label=r"exposure $i$",
47 | shift=-0.1))
48 | pgm.add_plate(daft.Plate([2, 0.5, 1, 1], label=r"pixel $j$",
49 | shift=-0.1))
50 |
51 | # Render and save.
52 | pgm.render()
53 | pgm.figure.savefig("exoplanets.pdf")
54 | pgm.figure.savefig("exoplanets.png", dpi=150)
55 |
--------------------------------------------------------------------------------
/docs/_themes/daft/layout.html:
--------------------------------------------------------------------------------
1 | {%- extends "basic/layout.html" %}
2 |
3 | {% if not title %}
4 | {% set title = project %}
5 | {% endif %}
6 |
7 | {%- block extrahead %}
8 | {{ super() }}
9 |
10 |
11 |
12 |
13 | {% endblock %}
14 |
15 | {%- block relbar1 %}{% endblock %}
16 | {%- block relbar2 %}{% endblock %}
17 |
18 | {%- block document %}
19 |
20 |
21 |
22 |
{{ theme_tagline }}
23 |
24 |
25 | {{ super() }}
26 |
27 | {% endblock %}
28 |
29 | {%- block footer %}
30 |
31 |
35 |
36 |
37 |
40 |
41 |
42 |
55 |
56 | {%- endblock %}
57 |
--------------------------------------------------------------------------------
/docs/examples/weaklensing.rst:
--------------------------------------------------------------------------------
1 | .. _weaklensing:
2 |
3 |
4 | A model for weak lensing
5 | ========================
6 |
7 | .. figure:: /_static/examples/weaklensing.png
8 |
9 |
10 | A model for weak lensing
11 | ========================
12 |
13 | This is (**Daft** co-author) Hogg's model for the obsevational
14 | cosmology method known as *weak gravitational lensing*, if that method
15 | were properly probabilistic (which it usually isn't). Hogg put the
16 | model here for one very important reason: *Because he can*. Oh, and
17 | it demonstrates that you can represent non-trivial scientific projects
18 | with **Daft**.
19 |
20 |
21 |
22 | ::
23 |
24 |
25 | from matplotlib import rc
26 | rc("font", family="serif", size=12)
27 | rc("text", usetex=True)
28 | rc("./weaklensing.tex")
29 |
30 | import daft
31 |
32 | pgm = daft.PGM([4.7, 2.35], origin=[-1.35, 2.2])
33 | pgm.add_node(daft.Node("Omega", r"$\Omega$", -1, 4))
34 | pgm.add_node(daft.Node("gamma", r"$\gamma$", 0, 4))
35 | pgm.add_node(daft.Node("obs", r"$\epsilon^{\mathrm{obs}}_n$", 1, 4, observed=True))
36 | pgm.add_node(daft.Node("alpha", r"$\alpha$", 3, 4))
37 | pgm.add_node(daft.Node("true", r"$\epsilon^{\mathrm{true}}_n$", 2, 4))
38 | pgm.add_node(daft.Node("sigma", r"$\sigma_n$", 1, 3))
39 | pgm.add_node(daft.Node("Sigma", r"$\Sigma$", 0, 3))
40 | pgm.add_node(daft.Node("x", r"$x_n$", 2, 3, observed=True))
41 | pgm.add_plate(daft.Plate([0.5, 2.25, 2, 2.25],
42 | label=r"galaxies $n$"))
43 | pgm.add_edge("Omega", "gamma")
44 | pgm.add_edge("gamma", "obs")
45 | pgm.add_edge("alpha", "true")
46 | pgm.add_edge("true", "obs")
47 | pgm.add_edge("x", "obs")
48 | pgm.add_edge("Sigma", "sigma")
49 | pgm.add_edge("sigma", "obs")
50 | pgm.render()
51 | pgm.figure.savefig("weaklensing.pdf")
52 | pgm.figure.savefig("weaklensing.png", dpi=150)
53 |
54 |
55 |
--------------------------------------------------------------------------------
/docs/examples/recursive.rst:
--------------------------------------------------------------------------------
1 | .. _recursive:
2 |
3 |
4 | Recursively generated graph
5 | ===========================
6 |
7 | .. figure:: /_static/examples/recursive.png
8 |
9 |
10 | Recursively generated graph
11 | ===========================
12 |
13 | **Daft** is Python, so you can do anything Python can do. This graph is
14 | generated by recursive code.
15 |
16 |
17 |
18 | ::
19 |
20 |
21 | from matplotlib import rc
22 | rc("font", family="serif", size=12)
23 | rc("text", usetex=True)
24 |
25 | import daft
26 |
27 | def recurse(pgm, nodename, level, c):
28 | if level > 4:
29 | return nodename
30 | r = c / 2
31 | r1nodename = "r{0:02d}{1:04d}".format(level, r)
32 | if 2 * r == c:
33 | print("adding {0}".format(r1nodename))
34 | pgm.add_node(daft.Node(r1nodename, r"reduce",
35 | 2 ** level * (r + 0.5) - 0.5,
36 | 3 - 0.7 * level, aspect=1.9))
37 | pgm.add_edge(nodename, r1nodename)
38 | if 2 * r == c:
39 | return recurse(pgm, r1nodename, level + 1, r)
40 |
41 | pgm = daft.PGM([16.2, 8], origin=[-0.6, -1.5])
42 |
43 | pgm.add_node(daft.Node("query", r'\texttt{"kittens?"}', 3, 6., aspect=3.,
44 | plot_params={"ec": "none"}))
45 | pgm.add_node(daft.Node("input", r"input", 7.5, 6., aspect=3.))
46 | pgm.add_edge("query", "input")
47 |
48 | for c in range(16):
49 | nodename = "map {0:02d}".format(c)
50 | pgm.add_node(daft.Node(nodename, str(nodename), c, 3., aspect=1.9))
51 | pgm.add_edge("input", nodename)
52 | level = 1
53 | recurse(pgm, nodename, level, c)
54 |
55 | pgm.add_node(daft.Node("output", r"output", 7.5, -1., aspect=3.))
56 | pgm.add_edge("r040000", "output")
57 | pgm.add_node(daft.Node("answer", r'\texttt{"http://dwh.gg/"}', 12., -1.,
58 | aspect=4.5, plot_params={"ec": "none"}))
59 | pgm.add_edge("output", "answer")
60 |
61 | pgm.render()
62 | pgm.figure.savefig("recursive.pdf")
63 | pgm.figure.savefig("recursive.png", dpi=200)
64 |
65 |
66 |
--------------------------------------------------------------------------------
/docs/examples/exoplanets.rst:
--------------------------------------------------------------------------------
1 | .. _exoplanets:
2 |
3 |
4 | The Fergus model of exoplanet detection
5 | =======================================
6 |
7 | .. figure:: /_static/examples/exoplanets.png
8 |
9 |
10 | The Fergus model of exoplanet detection
11 | =======================================
12 |
13 | Besides being generally awesome, this example also demonstrates how you can
14 | color the nodes and add arbitrary labels to the figure.
15 |
16 |
17 |
18 | ::
19 |
20 |
21 | from matplotlib import rc
22 | rc("font", family="serif", size=12)
23 | rc("text", usetex=True)
24 |
25 | import daft
26 |
27 | # Colors.
28 | p_color = {"ec": "#46a546"}
29 | s_color = {"ec": "#f89406"}
30 |
31 | pgm = daft.PGM([3.6, 3.5], origin=[0.7, 0])
32 |
33 | n = daft.Node("phi", r"$\phi$", 1, 3, plot_params=s_color)
34 | n.va = "baseline"
35 | pgm.add_node(n)
36 | pgm.add_node(daft.Node("speckle_coeff", r"$z_i$", 2, 3, plot_params=s_color))
37 | pgm.add_node(daft.Node("speckle_img", r"$x_i$", 2, 2, plot_params=s_color))
38 |
39 | pgm.add_node(daft.Node("spec", r"$s$", 4, 3, plot_params=p_color))
40 | pgm.add_node(daft.Node("shape", r"$g$", 4, 2, plot_params=p_color))
41 | pgm.add_node(daft.Node("planet_pos", r"$\mu_i$", 3, 3, plot_params=p_color))
42 | pgm.add_node(daft.Node("planet_img", r"$p_i$", 3, 2, plot_params=p_color))
43 |
44 | pgm.add_node(daft.Node("pixels", r"$y_i ^j$", 2.5, 1, observed=True))
45 |
46 | # Edges.
47 | pgm.add_edge("phi", "speckle_coeff")
48 | pgm.add_edge("speckle_coeff", "speckle_img")
49 | pgm.add_edge("speckle_img", "pixels")
50 |
51 | pgm.add_edge("spec", "planet_img")
52 | pgm.add_edge("shape", "planet_img")
53 | pgm.add_edge("planet_pos", "planet_img")
54 | pgm.add_edge("planet_img", "pixels")
55 |
56 | # And a plate.
57 | pgm.add_plate(daft.Plate([1.5, 0.2, 2, 3.2], label=r"exposure $i$",
58 | shift=-0.1))
59 | pgm.add_plate(daft.Plate([2, 0.5, 1, 1], label=r"pixel $j$",
60 | shift=-0.1))
61 |
62 | # Render and save.
63 | pgm.render()
64 | pgm.figure.savefig("exoplanets.pdf")
65 | pgm.figure.savefig("exoplanets.png", dpi=150)
66 |
67 |
68 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | Daft
2 | ====
3 |
4 | .. raw:: html
5 |
6 |
7 |
10 |
11 |
12 |
15 |
16 |
17 | Summary
18 | -------
19 |
20 | **Daft** is a Python package that uses `matplotlib `_
21 | to render pixel-perfect *probabilistic graphical models* for publication
22 | in a journal or on the internet. With a short Python script and an intuitive
23 | model-building syntax you can design directed (Bayesian Networks, directed
24 | acyclic graphs) and undirected (Markov random fields) models and save
25 | them in any formats that matplotlib supports (including PDF, PNG, EPS and
26 | SVG).
27 |
28 |
29 | Installation
30 | ------------
31 |
32 | Installing the most recent stable version of Daft should be pretty easy
33 | if you use `pip `_:
34 |
35 | ::
36 |
37 | pip install daft
38 |
39 | Otherwise, you can download the source (`tar
40 | `_, `zip
41 | `_) and run:
42 |
43 | ::
44 |
45 | python setup.py install
46 |
47 | in the root directory.
48 |
49 | Daft only depends on `matplotlib `_ and
50 | `numpy `_. These are standard components of the
51 | scientific Python stack but if you don't already have them installed ``pip``
52 | will try to install them for you but sometimes it's easier to do that part
53 | yourself.
54 |
55 |
56 | Issues
57 | ------
58 |
59 | If you have any problems or questions, `open an "issue" on Github
60 | `_.
61 |
62 |
63 | Authors & Contributions
64 | -----------------------
65 |
66 | **Daft** is being developed and supported by `Dan Foreman-Mackey
67 | `_ and `David W. Hogg `_.
68 |
69 | For the hackers in the house, development happens on `Github
70 | `_ and we welcome pull requests. In particular,
71 | we'd love to see examples of how you're using Daft in your work.
72 |
73 |
74 | License
75 | -------
76 |
77 | *Copyright 2012 Dan Foreman-Mackey, David W. Hogg, and contributors.*
78 |
79 | **Daft** is free software made available under the *MIT License*. For details
80 | see `the LICENSE file `_.
81 |
82 | If you use Daft in academic projects, acknowledgements are greatly
83 | appreciated.
84 |
85 |
86 | API
87 | ---
88 |
89 | .. toctree::
90 | :maxdepth: 2
91 |
92 | api
93 |
--------------------------------------------------------------------------------
/examples/galex.py:
--------------------------------------------------------------------------------
1 | """
2 | The GALEX Photon Catalog
3 | ========================
4 |
5 | This is the Hogg \& Schiminovich model for how photons turn into
6 | counts in the GALEX satellite data stream. Note the use of relative
7 | positioning.
8 |
9 | """
10 |
11 | from matplotlib import rc
12 | rc("font", family="serif", size=12)
13 | rc("text", usetex=True)
14 | import daft
15 | pgm = daft.PGM([5.4, 5.4], origin=[1.2, 1.2])
16 | wide = 1.5
17 | verywide = 1.5 * wide
18 | dy = 0.75
19 |
20 | # electrons
21 | el_x, el_y = 2., 2.
22 | pgm.add_plate(daft.Plate([el_x - 0.6, el_y - 0.6, 2.2, 2 * dy + 0.3], label="electrons $i$"))
23 | pgm.add_node(daft.Node("xabc", r"xa$_i$,xabc$_i$,ya$_i$,\textit{etc}", el_x + 0.5, el_y + 0 * dy, aspect=2.3 * wide, observed=True))
24 | pgm.add_node(daft.Node("xyti", r"$x_i,y_i,t_i$", el_x + 1., el_y + 1 * dy, aspect=wide))
25 | pgm.add_edge("xyti", "xabc")
26 |
27 | # intensity fields
28 | ph_x, ph_y = el_x + 2.5, el_y + 3 * dy
29 | pgm.add_node(daft.Node("Ixyt", r"$I_{\nu}(x,y,t)$", ph_x, ph_y, aspect=verywide))
30 | pgm.add_edge("Ixyt", "xyti")
31 | pgm.add_node(daft.Node("Ixnt", r"$I_{\nu}(\xi,\eta,t)$", ph_x, ph_y + 1 * dy, aspect=verywide))
32 | pgm.add_edge("Ixnt", "Ixyt")
33 | pgm.add_node(daft.Node("Iadt", r"$I_{\nu}(\alpha,\delta,t)$", ph_x, ph_y + 2 * dy, aspect=verywide))
34 | pgm.add_edge("Iadt", "Ixnt")
35 |
36 | # s/c
37 | sc_x, sc_y = ph_x + 1.5, ph_y - 1.5 * dy
38 | pgm.add_node(daft.Node("dark", r"dark", sc_x, sc_y - 1 * dy, aspect=wide))
39 | pgm.add_edge("dark", "xyti")
40 | pgm.add_node(daft.Node("flat", r"flat", sc_x, sc_y, aspect=wide))
41 | pgm.add_edge("flat", "xyti")
42 | pgm.add_node(daft.Node("att", r"att", sc_x, sc_y + 3 * dy))
43 | pgm.add_edge("att", "Ixnt")
44 | pgm.add_node(daft.Node("optics", r"optics", sc_x, sc_y + 2 * dy, aspect=wide))
45 | pgm.add_edge("optics", "Ixyt")
46 | pgm.add_node(daft.Node("psf", r"psf", sc_x, sc_y + 1 * dy))
47 | pgm.add_edge("psf", "xyti")
48 | pgm.add_node(daft.Node("fee", r"f.e.e.", sc_x, sc_y - 2 * dy, aspect=wide))
49 | pgm.add_edge("fee", "xabc")
50 |
51 | # sky
52 | pgm.add_node(daft.Node("sky", r"sky", sc_x, sc_y + 4 * dy))
53 | pgm.add_edge("sky", "Iadt")
54 |
55 | # stars
56 | star_x, star_y = el_x, el_y + 4 * dy
57 | pgm.add_plate(daft.Plate([star_x - 0.6, star_y - 0.6, 2.2, 2 * dy + 0.3], label="stars $n$"))
58 | pgm.add_node(daft.Node("star adt", r"$I_{\nu,n}(\alpha,\delta,t)$", star_x + 0.5, star_y + 1 * dy, aspect=verywide))
59 | pgm.add_edge("star adt", "Iadt")
60 | pgm.add_node(daft.Node("star L", r"$L_{\nu,n}(t)$", star_x + 1, star_y, aspect=wide))
61 | pgm.add_edge("star L", "star adt")
62 | pgm.add_node(daft.Node("star pos", r"$\vec{x_n}$", star_x, star_y))
63 | pgm.add_edge("star pos", "star adt")
64 |
65 | # done
66 | pgm.render()
67 | pgm.figure.savefig("galex.pdf")
68 | pgm.figure.savefig("galex.png", dpi=150)
69 |
--------------------------------------------------------------------------------
/docs/gen_example.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | from __future__ import print_function
4 |
5 | import os
6 | import sys
7 | import json
8 | from subprocess import check_call
9 |
10 |
11 | this_path = os.path.dirname(os.path.abspath(__file__))
12 | daft_path = os.path.dirname(this_path)
13 | sys.path.insert(0, daft_path)
14 |
15 | example_dir = os.path.join(daft_path, "examples")
16 | out_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "examples")
17 | img_out_dir = os.path.join(this_path, "_static", "examples")
18 |
19 | try:
20 | os.makedirs(out_dir)
21 | except os.error:
22 | pass
23 |
24 | try:
25 | os.makedirs(img_out_dir)
26 | except os.error:
27 | pass
28 |
29 | example_template = """.. _{example}:
30 |
31 | {title}
32 |
33 | .. figure:: /_static/examples/{example}.png
34 |
35 | {doc}
36 |
37 | ::
38 |
39 | {src}
40 |
41 | """
42 |
43 |
44 | def main(fn, thumb_info):
45 | # Run the code.
46 | pyfn = os.path.join(example_dir, fn + ".py")
47 | src = open(pyfn).read()
48 | print("Executing: " + pyfn)
49 |
50 | ns = {}
51 | exec src in ns
52 | pgm = ns["pgm"]
53 |
54 | # Generate the RST source file.
55 | src = src.split("\n")
56 | if ns["__doc__"] is None:
57 | title = fn.title() + "\n" + "=" * len(fn)
58 | doc = ""
59 | else:
60 | doc = ns["__doc__"].split("\n")
61 | title = "\n".join(doc[:3])
62 | doc = "\n".join(doc)
63 | src = src[len(ns["__doc__"].split("\n")):]
64 |
65 | fmt_src = "\n".join([" " + l for l in src])
66 | img_path = os.path.join(img_out_dir, fn + ".png")
67 | thumb_path = os.path.join(img_out_dir, fn + "-thumb.png")
68 |
69 | rst = example_template.format(title=title, doc=doc, example=fn,
70 | src=fmt_src, img_path=img_path)
71 |
72 | # Write the RST file.
73 | rstfn = os.path.join(out_dir, fn + ".rst")
74 | print("Writing: " + rstfn)
75 | with open(rstfn, "w") as f:
76 | f.write(rst)
77 |
78 | # Remove the generated plots.
79 | try:
80 | os.remove(fn + ".png")
81 | except os.error:
82 | pass
83 | try:
84 | os.remove(fn + ".pdf")
85 | except os.error:
86 | pass
87 |
88 | # Save the new figure.
89 | print("Saving: " + img_path)
90 | pgm.figure.savefig(img_path, dpi=150)
91 |
92 | # Crop the thumbnail.
93 | cmd = " ".join(["convert",
94 | "-crop 190x190+{0[0]:d}+{0[1]:d}".format(thumb_info),
95 | img_path, thumb_path])
96 | print(cmd)
97 | check_call(cmd, shell=True)
98 |
99 |
100 | if __name__ == "__main__":
101 | m = json.load(open(os.path.join(this_path, "_static", "examples.json")))
102 | if len(sys.argv) == 1:
103 | # Build all the examples.
104 | argv = m.keys()
105 | else:
106 | argv = sys.argv[1:]
107 |
108 | for k in argv:
109 | assert k in m, "Add {0} to _static/examples.json".format(k)
110 | main(k, m[k])
111 |
--------------------------------------------------------------------------------
/docs/_themes/daft/static/daft.css:
--------------------------------------------------------------------------------
1 | @import url("normalize.css");
2 | @import url(http://fonts.googleapis.com/css?family=Lato:100,300,700,300italic);
3 | @import url(http://fonts.googleapis.com/css?family=Source+Code+Pro:300,400,600);
4 |
5 | body {
6 | font-family: Lato, "Helvetica Neue", Helvetica, sans-serif;
7 | font-weight: 300;
8 | line-height: 1.55;
9 | font-size: 16px;
10 | color: #333;
11 |
12 | background: #dbe0df;
13 | background: -moz-linear-gradient(left, #dbe0df 0%, #ffffff 50%, #dbe0df 100%);
14 | background: -webkit-gradient(linear, left top, right top, color-stop(0%,#dbe0df), color-stop(50%,#ffffff), color-stop(100%,#dbe0df));
15 | background: -webkit-linear-gradient(left, #dbe0df 0%,#ffffff 50%,#dbe0df 100%);
16 | background: -o-linear-gradient(left, #dbe0df 0%,#ffffff 50%,#dbe0df 100%);
17 | background: -ms-linear-gradient(left, #dbe0df 0%,#ffffff 50%,#dbe0df 100%);
18 | background: linear-gradient(to right, #dbe0df 0%,#ffffff 50%,#dbe0df 100%);
19 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#dbe0df', endColorstr='#dbe0df',GradientType=1 );
20 | }
21 |
22 | a {
23 | color: #383;
24 | text-decoration: underline;
25 | }
26 |
27 | a:hover {
28 | color: #5a5;
29 | }
30 |
31 | a.headerlink {
32 | padding-left: 10px;
33 | font-size: 80%;
34 | text-decoration: none;
35 | color: #bbb;
36 | }
37 |
38 | a.headerlink:hover {
39 | color: #aaa;
40 | }
41 |
42 | .pre, pre {
43 | font-size: 14px;
44 | font-weight: 400;
45 | font-family: "Source Code Pro", Courier, monospace;
46 | }
47 |
48 | .document, .footer, .related {
49 | width: 600px;
50 | margin: 0 auto;
51 | }
52 |
53 | .body:first-child h1 {
54 | display: none;
55 | }
56 |
57 | .main-logo {
58 | padding: 30px 0 10px;
59 | border-bottom: 1px dashed #e1e1e1;
60 | text-align: center;
61 | }
62 |
63 | .main-logo h1 {
64 | font-size: 48px;
65 | font-weight: 300;
66 | line-height: 0;
67 | text-transform: uppercase;
68 | }
69 |
70 | .main-logo a, .main-logo a:hover {
71 | color: #333;
72 | text-decoration: none;
73 | }
74 |
75 | .main-logo h2 {
76 | color: #888;
77 | font-size: 16px;
78 | font-weight: 300;
79 | line-height: 1;
80 | text-transform: uppercase;
81 | }
82 |
83 | #examples h2 {
84 | display: none;
85 | }
86 |
87 | #examples {
88 | line-height: 0;
89 | margin-top: 5px;
90 | }
91 |
92 | #examples img {
93 | border: 1px solid #ccc;
94 | margin: 5px 0 5px 0;
95 | }
96 |
97 | #examples a:not(:nth-of-type(3n)) img {
98 | margin-right: 8px;
99 | }
100 |
101 | #summary h2 {
102 | display: none;
103 | }
104 |
105 | .related {
106 | margin: 10px 0 0;
107 | padding: 10px 0 0;
108 | border-top: 1px dashed #e1e1e1;
109 | }
110 |
111 | .related .previous {
112 | float: left;
113 | }
114 |
115 | .related .next {
116 | float: right;
117 | }
118 |
119 | .related:after {
120 | content: ".";
121 | display: block;
122 | clear: both;
123 | visibility: hidden;
124 | line-height: 0;
125 | height: 0;
126 | }
127 |
128 | #searchbox {
129 | margin: 10px 0;
130 | text-align: center;
131 | }
132 |
133 | input.searchfield {
134 | border: 1px solid #999;
135 | -moz-border-radius: 15px;
136 | border-radius: 15px;
137 | padding: 3px 10px;
138 | font-weight: normal;
139 | }
140 |
141 | input.searchfield:focus {
142 | outline: 0;
143 | outline: thin dotted \9;
144 | border-color: #ddd;
145 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 3px #5a5;
146 | -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 3px #5a5;
147 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 3px #5a5;
148 | }
149 |
150 | .footer {
151 | text-align: center;
152 | font-size: 11px;
153 | padding: 20px 0;
154 | }
155 |
156 | .figure {
157 | background: white;
158 | text-align: center;
159 | padding: 15px;
160 | margin: 15px 0;
161 | border: 1px solid #DDD;
162 | overflow: auto;
163 | }
164 |
165 | /* API */
166 |
167 | .field-body {
168 | margin: 0;
169 | padding: 0;
170 | padding-left: 10px;
171 | }
172 |
173 | .field-body ul {
174 | margin: 0;
175 | padding: 0;
176 | list-style: none;
177 | }
178 |
179 | .field-body ul li {
180 | margin: 0;
181 | padding: 0;
182 | }
183 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = sphinx-build
7 | PAPER =
8 | BUILDDIR = _build
9 |
10 | # Internal variables.
11 | PAPEROPT_a4 = -D latex_paper_size=a4
12 | PAPEROPT_letter = -D latex_paper_size=letter
13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
14 | # the i18n builder cannot share the environment and doctrees with the others
15 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
16 |
17 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
18 |
19 | help:
20 | @echo "Please use \`make ' where is one of"
21 | @echo " html to make standalone HTML files"
22 | @echo " dirhtml to make HTML files named index.html in directories"
23 | @echo " singlehtml to make a single large HTML file"
24 | @echo " pickle to make pickle files"
25 | @echo " json to make JSON files"
26 | @echo " htmlhelp to make HTML files and a HTML help project"
27 | @echo " qthelp to make HTML files and a qthelp project"
28 | @echo " devhelp to make HTML files and a Devhelp project"
29 | @echo " epub to make an epub"
30 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
31 | @echo " latexpdf to make LaTeX files and run them through pdflatex"
32 | @echo " text to make text files"
33 | @echo " man to make manual pages"
34 | @echo " texinfo to make Texinfo files"
35 | @echo " info to make Texinfo files and run them through makeinfo"
36 | @echo " gettext to make PO message catalogs"
37 | @echo " changes to make an overview of all changed/added/deprecated items"
38 | @echo " linkcheck to check all external links for integrity"
39 | @echo " doctest to run all doctests embedded in the documentation (if enabled)"
40 |
41 | clean:
42 | -rm -rf $(BUILDDIR)/*
43 |
44 | html:
45 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
46 | @echo
47 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
48 |
49 | dirhtml:
50 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
51 | @echo
52 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
53 |
54 | singlehtml:
55 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
56 | @echo
57 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
58 |
59 | pickle:
60 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
61 | @echo
62 | @echo "Build finished; now you can process the pickle files."
63 |
64 | json:
65 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
66 | @echo
67 | @echo "Build finished; now you can process the JSON files."
68 |
69 | htmlhelp:
70 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
71 | @echo
72 | @echo "Build finished; now you can run HTML Help Workshop with the" \
73 | ".hhp project file in $(BUILDDIR)/htmlhelp."
74 |
75 | qthelp:
76 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
77 | @echo
78 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \
79 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
80 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Daft.qhcp"
81 | @echo "To view the help file:"
82 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Daft.qhc"
83 |
84 | devhelp:
85 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
86 | @echo
87 | @echo "Build finished."
88 | @echo "To view the help file:"
89 | @echo "# mkdir -p $$HOME/.local/share/devhelp/Daft"
90 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Daft"
91 | @echo "# devhelp"
92 |
93 | epub:
94 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
95 | @echo
96 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
97 |
98 | latex:
99 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
100 | @echo
101 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
102 | @echo "Run \`make' in that directory to run these through (pdf)latex" \
103 | "(use \`make latexpdf' here to do that automatically)."
104 |
105 | latexpdf:
106 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
107 | @echo "Running LaTeX files through pdflatex..."
108 | $(MAKE) -C $(BUILDDIR)/latex all-pdf
109 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
110 |
111 | text:
112 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
113 | @echo
114 | @echo "Build finished. The text files are in $(BUILDDIR)/text."
115 |
116 | man:
117 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
118 | @echo
119 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
120 |
121 | texinfo:
122 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
123 | @echo
124 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
125 | @echo "Run \`make' in that directory to run these through makeinfo" \
126 | "(use \`make info' here to do that automatically)."
127 |
128 | info:
129 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
130 | @echo "Running Texinfo files through makeinfo..."
131 | make -C $(BUILDDIR)/texinfo info
132 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
133 |
134 | gettext:
135 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
136 | @echo
137 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
138 |
139 | changes:
140 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
141 | @echo
142 | @echo "The overview file is in $(BUILDDIR)/changes."
143 |
144 | linkcheck:
145 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
146 | @echo
147 | @echo "Link check complete; look for any errors in the above output " \
148 | "or in $(BUILDDIR)/linkcheck/output.txt."
149 |
150 | doctest:
151 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
152 | @echo "Testing of doctests in the sources finished, look at the " \
153 | "results in $(BUILDDIR)/doctest/output.txt."
154 |
155 | examples: ../examples/*.py _static/examples.json
156 | python gen_example.py
157 |
--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import os
4 | import sys
5 |
6 | # If extensions (or modules to document with autodoc) are in another directory,
7 | # add these directories to sys.path here. If the directory is relative to the
8 | # documentation root, use os.path.abspath to make it absolute, like shown here.
9 | sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
10 |
11 |
12 | import daft
13 |
14 |
15 | extensions = ["sphinx.ext.autodoc", "sphinx.ext.intersphinx",
16 | "sphinx.ext.mathjax"]
17 |
18 | # Add any paths that contain templates here, relative to this directory.
19 | templates_path = ["_templates"]
20 |
21 | # The suffix of source filenames.
22 | source_suffix = ".rst"
23 |
24 | # The master toctree document.
25 | master_doc = "index"
26 |
27 | # General information about the project.
28 | project = u"Daft"
29 | copyright = u"2012, Dan Foreman-Mackey & David W. Hogg"
30 | version = daft.__version__
31 | release = daft.__version__
32 |
33 | # There are two options for replacing |today|: either, you set today to some
34 | # non-false value, then it is used:
35 | #today = ''
36 | # Else, today_fmt is used as the format for a strftime call.
37 | #today_fmt = '%B %d, %Y'
38 |
39 | # List of patterns, relative to source directory, that match files and
40 | # directories to ignore when looking for source files.
41 | exclude_patterns = ["_build"]
42 |
43 | # If true, '()' will be appended to :func: etc. cross-reference text.
44 | #add_function_parentheses = True
45 |
46 | # If true, the current module name will be prepended to all description
47 | # unit titles (such as .. function::).
48 | #add_module_names = True
49 |
50 | # If true, sectionauthor and moduleauthor directives will be shown in the
51 | # output. They are ignored by default.
52 | #show_authors = False
53 |
54 | # The name of the Pygments (syntax highlighting) style to use.
55 | pygments_style = "sphinx"
56 |
57 | # A list of ignored prefixes for module index sorting.
58 | #modindex_common_prefix = []
59 |
60 | # The theme to use for HTML and HTML Help pages. See the documentation for
61 | # a list of builtin themes.
62 | html_theme = "daft"
63 |
64 | # Theme options are theme-specific and customize the look and feel of a theme
65 | # further. For a list of options available for each theme, see the
66 | # documentation.
67 | html_theme_options = {
68 | "tagline": "Beautifully rendered probabilistic graphical models.",
69 | }
70 |
71 | # Add any paths that contain custom themes here, relative to this directory.
72 | html_theme_path = ["_themes"]
73 |
74 | # The name for this set of Sphinx documents. If None, it defaults to
75 | # " v documentation".
76 | #html_title = None
77 |
78 | # A shorter title for the navigation bar. Default is the same as html_title.
79 | #html_short_title = None
80 |
81 | # The name of an image file (relative to this directory) to place at the top
82 | # of the sidebar.
83 | #html_logo = None
84 |
85 | # The name of an image file (within the static path) to use as favicon of the
86 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
87 | # pixels large.
88 | #html_favicon = None
89 |
90 | # Add any paths that contain custom static files (such as style sheets) here,
91 | # relative to this directory. They are copied after the builtin static files,
92 | # so a file named "default.css" will overwrite the builtin "default.css".
93 | html_static_path = ["_static"]
94 |
95 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
96 | # using the given strftime format.
97 | #html_last_updated_fmt = '%b %d, %Y'
98 |
99 | # If true, SmartyPants will be used to convert quotes and dashes to
100 | # typographically correct entities.
101 | #html_use_smartypants = True
102 |
103 | # Custom sidebar templates, maps document names to template names.
104 | html_sidebars = {
105 | "**": ["relations.html", "searchbox.html"]
106 | }
107 |
108 | # Additional templates that should be rendered to pages, maps page names to
109 | # template names.
110 | #html_additional_pages = {}
111 |
112 | # If false, no module index is generated.
113 | #html_domain_indices = True
114 |
115 | # If false, no index is generated.
116 | #html_use_index = True
117 |
118 | # If true, the index is split into individual pages for each letter.
119 | #html_split_index = False
120 |
121 | # If true, links to the reST sources are added to the pages.
122 | html_show_sourcelink = False
123 |
124 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
125 | #html_show_sphinx = True
126 |
127 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
128 | #html_show_copyright = True
129 |
130 | # If true, an OpenSearch description file will be output, and all pages will
131 | # contain a tag referring to it. The value of this option must be the
132 | # base URL from which the finished HTML is served.
133 | #html_use_opensearch = ''
134 |
135 | # This is the file name suffix for HTML files (e.g. ".xhtml").
136 | #html_file_suffix = None
137 |
138 | # Output file base name for HTML help builder.
139 | htmlhelp_basename = 'Daftdoc'
140 |
141 | # LaTeX Options.
142 | latex_elements = {
143 | # The paper size ('letterpaper' or 'a4paper').
144 | #'papersize': 'letterpaper',
145 |
146 | # The font size ('10pt', '11pt' or '12pt').
147 | #'pointsize': '10pt',
148 |
149 | # Additional stuff for the LaTeX preamble.
150 | #'preamble': '',
151 | }
152 |
153 | # Grouping the document tree into LaTeX files. List of tuples
154 | # (source start file, target name, title, author, documentclass
155 | # [howto/manual]).
156 | latex_documents = [
157 | ('index', 'Daft.tex', u'Daft Documentation',
158 | u'Dan Foreman-Mackey \\& David W. Hogg', 'manual'),
159 | ]
160 |
161 | # The name of an image file (relative to this directory) to place at the top of
162 | # the title page.
163 | #latex_logo = None
164 |
165 | # For "manual" documents, if this is true, then toplevel headings are parts,
166 | # not chapters.
167 | #latex_use_parts = False
168 |
169 | # If true, show page references after internal links.
170 | #latex_show_pagerefs = False
171 |
172 | # If true, show URL addresses after external links.
173 | #latex_show_urls = False
174 |
175 | # Documents to append as an appendix to all manuals.
176 | #latex_appendices = []
177 |
178 | # If false, no module index is generated.
179 | #latex_domain_indices = True
180 |
181 |
182 | # One entry per manual page. List of tuples
183 | # (source start file, name, description, authors, manual section).
184 | man_pages = [
185 | ('index', 'daft', u'Daft Documentation',
186 | [u'Dan Foreman-Mackey & David W. Hogg'], 1)
187 | ]
188 |
189 | # If true, show URL addresses after external links.
190 | #man_show_urls = False
191 |
192 |
193 | # Grouping the document tree into Texinfo files. List of tuples
194 | # (source start file, target name, title, author,
195 | # dir menu entry, description, category)
196 | texinfo_documents = [
197 | ('index', 'Daft', u'Daft Documentation',
198 | u'Dan Foreman-Mackey & David W. Hogg', 'Daft',
199 | 'One line description of project.', 'Miscellaneous'),
200 | ]
201 |
202 | # Documents to append as an appendix to all manuals.
203 | #texinfo_appendices = []
204 |
205 | # If false, no module index is generated.
206 | #texinfo_domain_indices = True
207 |
208 | # How to display URL addresses: 'footnote', 'no', or 'inline'.
209 | #texinfo_show_urls = 'footnote'
210 |
211 |
212 | # Example configuration for intersphinx: refer to the Python standard library.
213 | intersphinx_mapping = {'http://docs.python.org/': None}
214 |
--------------------------------------------------------------------------------
/examples/astronomy.py:
--------------------------------------------------------------------------------
1 | """
2 | Astronomical imaging
3 | ====================
4 |
5 | This is a model for every pixel of every astronomical image ever
6 | taken. It is incomplete!
7 |
8 | """
9 |
10 | from matplotlib import rc
11 | rc("font", family="serif", size=12)
12 | rc("text", usetex=True)
13 |
14 | import daft
15 |
16 | pgm = daft.PGM([8, 6.75], origin=[0.5, 0.5], grid_unit=4., node_unit=1.4)
17 |
18 | # Start with the plates.
19 | tweak=0.02
20 | rect_params = {"lw": 2}
21 | pgm.add_plate(daft.Plate([1.5+tweak, 0.5+tweak, 6.0-2*tweak, 3.75-2*tweak], label=r"\Large telescope+camera+filter multiplets", rect_params=rect_params))
22 | pgm.add_plate(daft.Plate([2.5+tweak, 1.0+tweak, 4.0-2*tweak, 2.75-2*tweak], label=r"\Large images", rect_params=rect_params))
23 | pgm.add_plate(daft.Plate([3.5+tweak, 1.5+tweak, 2.0-2*tweak, 1.75-2*tweak], label=r"\Large pixel patches", rect_params=rect_params))
24 | pgm.add_plate(daft.Plate([1.0+tweak, 4.25+tweak, 3.5-2*tweak, 1.75-2*tweak], label=r"\Large stars", rect_params=rect_params))
25 | pgm.add_plate(daft.Plate([5.5+tweak, 4.25+tweak, 2.5-2*tweak, 1.75-2*tweak], label=r"\Large galaxies", rect_params=rect_params))
26 |
27 | # ONLY pixels are observed
28 | asp = 2.3
29 | pgm.add_node(daft.Node("true pixels", r"~\\noise-free\\pixel patch", 5.0, 2.5, aspect=asp))
30 | pgm.add_node(daft.Node("pixels", r"pixel patch", 4.0, 2.0, observed=True, aspect=asp))
31 | pgm.add_edge("true pixels", "pixels")
32 |
33 | # The sky
34 | pgm.add_node(daft.Node("sky", r"sky model", 6.0, 2.5, aspect=asp))
35 | pgm.add_edge("sky", "true pixels")
36 | pgm.add_node(daft.Node("sky prior", r"sky priors", 8.0, 2.5, fixed=True))
37 | pgm.add_edge("sky prior", "sky")
38 |
39 | # Stars
40 | pgm.add_node(daft.Node("star patch", r"star patch", 4.0, 3.0, aspect=asp))
41 | pgm.add_edge("star patch", "true pixels")
42 | pgm.add_node(daft.Node("star SED", r"~\\spectral energy\\distribution", 2.5, 4.75, aspect=asp+0.2))
43 | pgm.add_edge("star SED", "star patch")
44 | pgm.add_node(daft.Node("star position", r"position", 4.0, 4.75, aspect=asp))
45 | pgm.add_edge("star position", "star patch")
46 | pgm.add_node(daft.Node("temperature", r"temperature", 1.5, 5.25, aspect=asp))
47 | pgm.add_edge("temperature", "star SED")
48 | pgm.add_node(daft.Node("luminosity", r"luminosity", 2.5, 5.25, aspect=asp))
49 | pgm.add_edge("luminosity", "star SED")
50 | pgm.add_node(daft.Node("metallicity", r"metallicity", 1.5, 5.75, aspect=asp))
51 | pgm.add_edge("metallicity", "star SED")
52 | pgm.add_edge("metallicity", "temperature")
53 | pgm.add_edge("metallicity", "luminosity")
54 | pgm.add_node(daft.Node("mass", r"mass", 2.5, 5.75, aspect=asp))
55 | pgm.add_edge("mass", "temperature")
56 | pgm.add_edge("mass", "luminosity")
57 | pgm.add_node(daft.Node("age", r"age", 3.5, 5.75, aspect=asp))
58 | pgm.add_edge("age", "temperature")
59 | pgm.add_edge("age", "luminosity")
60 | pgm.add_node(daft.Node("star models", r"star models", 1.0, 4.0, fixed=True))
61 | pgm.add_edge("star models", "temperature")
62 | pgm.add_edge("star models", "luminosity")
63 | pgm.add_edge("star models", "star SED")
64 |
65 | # Galaxies
66 | pgm.add_node(daft.Node("galaxy patch", r"galaxy patch", 5.0, 3.0, aspect=asp))
67 | pgm.add_edge("galaxy patch", "true pixels")
68 | pgm.add_node(daft.Node("galaxy SED", r"~\\spectral energy\\distribution", 6.5, 4.75, aspect=asp+0.2))
69 | pgm.add_edge("galaxy SED", "galaxy patch")
70 | pgm.add_node(daft.Node("morphology", r"morphology", 7.5, 4.75, aspect=asp))
71 | pgm.add_edge("morphology", "galaxy patch")
72 | pgm.add_node(daft.Node("SFH", r"~\\star-formation\\history", 7.5, 5.25, aspect=asp))
73 | pgm.add_edge("SFH", "galaxy SED")
74 | pgm.add_edge("SFH", "morphology")
75 | pgm.add_node(daft.Node("galaxy position", r"~\\redshift\\ \& position", 6.0, 5.25, aspect=asp))
76 | pgm.add_edge("galaxy position", "galaxy SED")
77 | pgm.add_edge("galaxy position", "morphology")
78 | pgm.add_edge("galaxy position", "galaxy patch")
79 | pgm.add_node(daft.Node("dynamics", r"orbit structure", 6.5, 5.75, aspect=asp))
80 | pgm.add_edge("dynamics", "morphology")
81 | pgm.add_edge("dynamics", "SFH")
82 | pgm.add_node(daft.Node("galaxy mass", r"mass", 7.5, 5.75, aspect=asp))
83 | pgm.add_edge("galaxy mass", "dynamics")
84 | pgm.add_edge("galaxy mass", "galaxy SED")
85 | pgm.add_edge("galaxy mass", "SFH")
86 |
87 | # Universals
88 | pgm.add_node(daft.Node("extinction model", r"~\\extinction\\model", 5.0, 4.75, aspect=asp))
89 | pgm.add_edge("extinction model", "star patch")
90 | pgm.add_edge("extinction model", "galaxy patch")
91 | pgm.add_node(daft.Node("MW", r"~\\Milky Way\\formation", 4.0, 6.5, aspect=asp))
92 | pgm.add_edge("MW", "metallicity")
93 | pgm.add_edge("MW", "mass")
94 | pgm.add_edge("MW", "age")
95 | pgm.add_edge("MW", "star position")
96 | pgm.add_edge("MW", "extinction model")
97 | pgm.add_node(daft.Node("galaxy formation", r"~\\galaxy\\formation", 5.0, 6.5, aspect=asp))
98 | pgm.add_edge("galaxy formation", "MW")
99 | pgm.add_edge("galaxy formation", "dynamics")
100 | pgm.add_edge("galaxy formation", "galaxy mass")
101 | pgm.add_edge("galaxy formation", "extinction model")
102 | pgm.add_node(daft.Node("LSS", r"~\\large-scale\\structure", 6.0, 6.5, aspect=asp))
103 | pgm.add_edge("LSS", "galaxy position")
104 | pgm.add_node(daft.Node("cosmology", r"~\\cosmological\\parameters", 6.0, 7.0, aspect=asp))
105 | pgm.add_edge("cosmology", "LSS")
106 | pgm.add_edge("cosmology", "galaxy formation")
107 | pgm.add_node(daft.Node("god", r"God", 7.0, 7.0, fixed=True))
108 | pgm.add_edge("god", "cosmology")
109 |
110 | # Sensitivity
111 | pgm.add_node(daft.Node("zeropoint", r"~\\zeropoint\\(photocal)", 3.0, 3.0, aspect=asp))
112 | pgm.add_edge("zeropoint", "true pixels")
113 | pgm.add_node(daft.Node("exposure time", r"exposure time", 3.0, 2.5, observed=True, aspect=asp))
114 | pgm.add_edge("exposure time", "zeropoint")
115 |
116 | # The PSF
117 | pgm.add_node(daft.Node("WCS", r"~\\astrometric\\calibration", 3.0, 2.0, aspect=asp))
118 | pgm.add_edge("WCS", "star patch")
119 | pgm.add_edge("WCS", "galaxy patch")
120 | pgm.add_node(daft.Node("psf", r"PSF model", 3.0, 3.5, aspect=asp))
121 | pgm.add_edge("psf", "star patch")
122 | pgm.add_edge("psf", "galaxy patch")
123 | pgm.add_node(daft.Node("optics", r"optics", 2.0, 3.0, aspect=asp-1.2))
124 | pgm.add_edge("optics", "psf")
125 | pgm.add_edge("optics", "WCS")
126 | pgm.add_node(daft.Node("atmosphere", r"~\\atmosphere\\model", 1.0, 3.5, aspect=asp))
127 | pgm.add_edge("atmosphere", "psf")
128 | pgm.add_edge("atmosphere", "WCS")
129 | pgm.add_edge("atmosphere", "zeropoint")
130 |
131 | # The device
132 | pgm.add_node(daft.Node("flatfield", r"flat-field", 2.0, 1.5, aspect=asp))
133 | pgm.add_edge("flatfield", "pixels")
134 | pgm.add_node(daft.Node("nonlinearity", r"non-linearity", 2.0, 1.0, aspect=asp))
135 | pgm.add_edge("nonlinearity", "pixels")
136 | pgm.add_node(daft.Node("pointing", r"~\\telescope\\pointing etc.", 2.0, 2.0, aspect=asp))
137 | pgm.add_edge("pointing", "WCS")
138 | pgm.add_node(daft.Node("detector", r"detector priors", 1.0, 1.5, fixed=True))
139 | pgm.add_edge("detector", "flatfield")
140 | pgm.add_edge("detector", "nonlinearity")
141 | pgm.add_node(daft.Node("hardware", r"hardware priors", 1.0, 2.5, fixed=True))
142 | pgm.add_edge("hardware", "pointing")
143 | pgm.add_edge("hardware", "exposure time")
144 | pgm.add_edge("hardware", "optics")
145 |
146 | # Noise
147 | pgm.add_node(daft.Node("noise patch", r"noise patch", 5.0, 2.0, aspect=asp))
148 | pgm.add_edge("noise patch", "pixels")
149 | pgm.add_edge("true pixels", "noise patch")
150 | pgm.add_node(daft.Node("noise model", r"noise model", 7.0, 2.0, aspect=asp))
151 | pgm.add_edge("noise model", "noise patch")
152 | pgm.add_node(daft.Node("noise prior", r"noise priors", 8.0, 2.0, fixed=True))
153 | pgm.add_edge("noise prior", "noise model")
154 | pgm.add_node(daft.Node("cosmic rays", r"~\\cosmic-ray\\model", 8.0, 1.5, aspect=asp))
155 | pgm.add_edge("cosmic rays", "noise patch")
156 |
157 | # Render and save.
158 | pgm.render()
159 | pgm.figure.savefig("astronomy.pdf")
160 | pgm.figure.savefig("astronomy.png", dpi=150)
161 |
--------------------------------------------------------------------------------
/docs/_themes/daft/static/normalize.css:
--------------------------------------------------------------------------------
1 | /*! normalize.css v2.0.1 | MIT License | git.io/normalize */
2 |
3 | /* ==========================================================================
4 | HTML5 display definitions
5 | ========================================================================== */
6 |
7 | /*
8 | * Corrects `block` display not defined in IE 8/9.
9 | */
10 |
11 | article,
12 | aside,
13 | details,
14 | figcaption,
15 | figure,
16 | footer,
17 | header,
18 | hgroup,
19 | nav,
20 | section,
21 | summary {
22 | display: block;
23 | }
24 |
25 | /*
26 | * Corrects `inline-block` display not defined in IE 8/9.
27 | */
28 |
29 | audio,
30 | canvas,
31 | video {
32 | display: inline-block;
33 | }
34 |
35 | /*
36 | * Prevents modern browsers from displaying `audio` without controls.
37 | * Remove excess height in iOS 5 devices.
38 | */
39 |
40 | audio:not([controls]) {
41 | display: none;
42 | height: 0;
43 | }
44 |
45 | /*
46 | * Addresses styling for `hidden` attribute not present in IE 8/9.
47 | */
48 |
49 | [hidden] {
50 | display: none;
51 | }
52 |
53 | /* ==========================================================================
54 | Base
55 | ========================================================================== */
56 |
57 | /*
58 | * 1. Sets default font family to sans-serif.
59 | * 2. Prevents iOS text size adjust after orientation change, without disabling
60 | * user zoom.
61 | */
62 |
63 | html {
64 | font-family: sans-serif; /* 1 */
65 | -webkit-text-size-adjust: 100%; /* 2 */
66 | -ms-text-size-adjust: 100%; /* 2 */
67 | }
68 |
69 | /*
70 | * Removes default margin.
71 | */
72 |
73 | body {
74 | margin: 0;
75 | }
76 |
77 | /* ==========================================================================
78 | Links
79 | ========================================================================== */
80 |
81 | /*
82 | * Addresses `outline` inconsistency between Chrome and other browsers.
83 | */
84 |
85 | a:focus {
86 | outline: thin dotted;
87 | }
88 |
89 | /*
90 | * Improves readability when focused and also mouse hovered in all browsers.
91 | */
92 |
93 | a:active,
94 | a:hover {
95 | outline: 0;
96 | }
97 |
98 | /* ==========================================================================
99 | Typography
100 | ========================================================================== */
101 |
102 | /*
103 | * Addresses `h1` font sizes within `section` and `article` in Firefox 4+,
104 | * Safari 5, and Chrome.
105 | */
106 |
107 | h1 {
108 | font-size: 2em;
109 | }
110 |
111 | /*
112 | * Addresses styling not present in IE 8/9, Safari 5, and Chrome.
113 | */
114 |
115 | abbr[title] {
116 | border-bottom: 1px dotted;
117 | }
118 |
119 | /*
120 | * Addresses style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
121 | */
122 |
123 | b,
124 | strong {
125 | font-weight: bold;
126 | }
127 |
128 | /*
129 | * Addresses styling not present in Safari 5 and Chrome.
130 | */
131 |
132 | dfn {
133 | font-style: italic;
134 | }
135 |
136 | /*
137 | * Addresses styling not present in IE 8/9.
138 | */
139 |
140 | mark {
141 | background: #ff0;
142 | color: #000;
143 | }
144 |
145 |
146 | /*
147 | * Corrects font family set oddly in Safari 5 and Chrome.
148 | */
149 |
150 | code,
151 | kbd,
152 | pre,
153 | samp {
154 | font-family: monospace, serif;
155 | font-size: 1em;
156 | }
157 |
158 | /*
159 | * Improves readability of pre-formatted text in all browsers.
160 | */
161 |
162 | pre {
163 | white-space: pre;
164 | white-space: pre-wrap;
165 | word-wrap: break-word;
166 | }
167 |
168 | /*
169 | * Sets consistent quote types.
170 | */
171 |
172 | q {
173 | quotes: "\201C" "\201D" "\2018" "\2019";
174 | }
175 |
176 | /*
177 | * Addresses inconsistent and variable font size in all browsers.
178 | */
179 |
180 | small {
181 | font-size: 80%;
182 | }
183 |
184 | /*
185 | * Prevents `sub` and `sup` affecting `line-height` in all browsers.
186 | */
187 |
188 | sub,
189 | sup {
190 | font-size: 75%;
191 | line-height: 0;
192 | position: relative;
193 | vertical-align: baseline;
194 | }
195 |
196 | sup {
197 | top: -0.5em;
198 | }
199 |
200 | sub {
201 | bottom: -0.25em;
202 | }
203 |
204 | /* ==========================================================================
205 | Embedded content
206 | ========================================================================== */
207 |
208 | /*
209 | * Removes border when inside `a` element in IE 8/9.
210 | */
211 |
212 | img {
213 | border: 0;
214 | }
215 |
216 | /*
217 | * Corrects overflow displayed oddly in IE 9.
218 | */
219 |
220 | svg:not(:root) {
221 | overflow: hidden;
222 | }
223 |
224 | /* ==========================================================================
225 | Figures
226 | ========================================================================== */
227 |
228 | /*
229 | * Addresses margin not present in IE 8/9 and Safari 5.
230 | */
231 |
232 | figure {
233 | margin: 0;
234 | }
235 |
236 | /* ==========================================================================
237 | Forms
238 | ========================================================================== */
239 |
240 | /*
241 | * Define consistent border, margin, and padding.
242 | */
243 |
244 | fieldset {
245 | border: 1px solid #c0c0c0;
246 | margin: 0 2px;
247 | padding: 0.35em 0.625em 0.75em;
248 | }
249 |
250 | /*
251 | * 1. Corrects color not being inherited in IE 8/9.
252 | * 2. Remove padding so people aren't caught out if they zero out fieldsets.
253 | */
254 |
255 | legend {
256 | border: 0; /* 1 */
257 | padding: 0; /* 2 */
258 | }
259 |
260 | /*
261 | * 1. Corrects font family not being inherited in all browsers.
262 | * 2. Corrects font size not being inherited in all browsers.
263 | * 3. Addresses margins set differently in Firefox 4+, Safari 5, and Chrome
264 | */
265 |
266 | button,
267 | input,
268 | select,
269 | textarea {
270 | font-family: inherit; /* 1 */
271 | font-size: 100%; /* 2 */
272 | margin: 0; /* 3 */
273 | }
274 |
275 | /*
276 | * Addresses Firefox 4+ setting `line-height` on `input` using `!important` in
277 | * the UA stylesheet.
278 | */
279 |
280 | button,
281 | input {
282 | line-height: normal;
283 | }
284 |
285 | /*
286 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
287 | * and `video` controls.
288 | * 2. Corrects inability to style clickable `input` types in iOS.
289 | * 3. Improves usability and consistency of cursor style between image-type
290 | * `input` and others.
291 | */
292 |
293 | button,
294 | html input[type="button"], /* 1 */
295 | input[type="reset"],
296 | input[type="submit"] {
297 | -webkit-appearance: button; /* 2 */
298 | cursor: pointer; /* 3 */
299 | }
300 |
301 | /*
302 | * Re-set default cursor for disabled elements.
303 | */
304 |
305 | button[disabled],
306 | input[disabled] {
307 | cursor: default;
308 | }
309 |
310 | /*
311 | * 1. Addresses box sizing set to `content-box` in IE 8/9.
312 | * 2. Removes excess padding in IE 8/9.
313 | */
314 |
315 | input[type="checkbox"],
316 | input[type="radio"] {
317 | box-sizing: border-box; /* 1 */
318 | padding: 0; /* 2 */
319 | }
320 |
321 | /*
322 | * 1. Addresses `appearance` set to `searchfield` in Safari 5 and Chrome.
323 | * 2. Addresses `box-sizing` set to `border-box` in Safari 5 and Chrome
324 | * (include `-moz` to future-proof).
325 | */
326 |
327 | input[type="search"] {
328 | -webkit-appearance: textfield; /* 1 */
329 | -moz-box-sizing: content-box;
330 | -webkit-box-sizing: content-box; /* 2 */
331 | box-sizing: content-box;
332 | }
333 |
334 | /*
335 | * Removes inner padding and search cancel button in Safari 5 and Chrome
336 | * on OS X.
337 | */
338 |
339 | input[type="search"]::-webkit-search-cancel-button,
340 | input[type="search"]::-webkit-search-decoration {
341 | -webkit-appearance: none;
342 | }
343 |
344 | /*
345 | * Removes inner padding and border in Firefox 4+.
346 | */
347 |
348 | button::-moz-focus-inner,
349 | input::-moz-focus-inner {
350 | border: 0;
351 | padding: 0;
352 | }
353 |
354 | /*
355 | * 1. Removes default vertical scrollbar in IE 8/9.
356 | * 2. Improves readability and alignment in all browsers.
357 | */
358 |
359 | textarea {
360 | overflow: auto; /* 1 */
361 | vertical-align: top; /* 2 */
362 | }
363 |
364 | /* ==========================================================================
365 | Tables
366 | ========================================================================== */
367 |
368 | /*
369 | * Remove most spacing between table cells.
370 | */
371 |
372 | table {
373 | border-collapse: collapse;
374 | border-spacing: 0;
375 | }
376 |
--------------------------------------------------------------------------------
/daft.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from __future__ import division, print_function
4 |
5 | __all__ = ["PGM", "Node", "Edge", "Plate"]
6 | __version__ = "0.0.4-dev"
7 |
8 | import matplotlib.pyplot as plt
9 | from matplotlib.patches import Ellipse
10 | from matplotlib.patches import FancyArrow
11 | from matplotlib.patches import Rectangle as Rectangle
12 |
13 | import numpy as np
14 |
15 |
16 | class PGM(object):
17 | """
18 | The base object for building a graphical model representation.
19 |
20 | :param shape:
21 | The number of rows and columns in the grid.
22 |
23 | :param origin:
24 | The coordinates of the bottom left corner of the plot.
25 |
26 | :param grid_unit: (optional)
27 | The size of the grid spacing measured in centimeters.
28 |
29 | :param node_unit: (optional)
30 | The base unit for the node size. This is a number in centimeters that
31 | sets the default diameter of the nodes.
32 |
33 | :param observed_style: (optional)
34 | How should the "observed" nodes be indicated? This must be one of:
35 | ``"shaded"``, ``"inner"`` or ``"outer"`` where ``inner`` and
36 | ``outer`` nodes are shown as double circles with the second circle
37 | plotted inside or outside of the standard one, respectively.
38 |
39 | :param node_ec: (optional)
40 | The default edge color for the nodes.
41 |
42 | :param directed: (optional)
43 | Should the edges be directed by default?
44 |
45 | :param aspect: (optional)
46 | The default aspect ratio for the nodes.
47 |
48 | :param label_params: (optional)
49 | Default node label parameters.
50 |
51 | """
52 | def __init__(self, shape, origin=[0, 0],
53 | grid_unit=2, node_unit=1,
54 | observed_style="shaded",
55 | line_width=1, node_ec="k",
56 | directed=True, aspect=1.0,
57 | label_params={}):
58 | self._nodes = {}
59 | self._edges = []
60 | self._plates = []
61 |
62 | self._ctx = _rendering_context(shape=shape, origin=origin,
63 | grid_unit=grid_unit,
64 | node_unit=node_unit,
65 | observed_style=observed_style,
66 | line_width=line_width,
67 | node_ec=node_ec, directed=directed,
68 | aspect=aspect,
69 | label_params=label_params)
70 |
71 | def add_node(self, node):
72 | """
73 | Add a :class:`Node` to the model.
74 |
75 | :param node:
76 | The :class:`Node` instance to add.
77 |
78 | """
79 | self._nodes[node.name] = node
80 | return node
81 |
82 | def add_edge(self, name1, name2, directed=None, **kwargs):
83 | """
84 | Construct an :class:`Edge` between two named :class:`Node` objects.
85 |
86 | :param name1:
87 | The name identifying the first node.
88 |
89 | :param name2:
90 | The name identifying the second node. If the edge is directed,
91 | the arrow will point to this node.
92 |
93 | :param directed: (optional)
94 | Should this be a directed edge?
95 |
96 | """
97 | if directed is None:
98 | directed = self._ctx.directed
99 |
100 | e = Edge(self._nodes[name1], self._nodes[name2], directed=directed,
101 | plot_params=kwargs)
102 | self._edges.append(e)
103 |
104 | return e
105 |
106 | def add_plate(self, plate):
107 | """
108 | Add a :class:`Plate` object to the model.
109 |
110 | """
111 | self._plates.append(plate)
112 | return None
113 |
114 | def render(self):
115 | """
116 | Render the :class:`Plate`, :class:`Edge` and :class:`Node` objects in
117 | the model. This will create a new figure with the correct dimensions
118 | and plot the model in this area.
119 |
120 | """
121 | self.figure = self._ctx.figure()
122 | self.ax = self._ctx.ax()
123 |
124 | for plate in self._plates:
125 | plate.render(self._ctx)
126 |
127 | for edge in self._edges:
128 | edge.render(self._ctx)
129 |
130 | for name in self._nodes:
131 | self._nodes[name].render(self._ctx)
132 |
133 | return self.ax
134 |
135 |
136 | class Node(object):
137 | """
138 | The representation of a random variable in a :class:`PGM`.
139 |
140 | :param name:
141 | The plain-text identifier for the node.
142 |
143 | :param content:
144 | The display form of the variable.
145 |
146 | :param x:
147 | The x-coordinate of the node in *model units*.
148 |
149 | :param y:
150 | The y-coordinate of the node.
151 |
152 | :param scale: (optional)
153 | The diameter (or height) of the node measured in multiples of
154 | ``node_unit`` as defined by the :class:`PGM` object.
155 |
156 | :param aspect: (optional)
157 | The aspect ratio width/height for elliptical nodes; default 1.
158 |
159 | :param observed: (optional)
160 | Should this be a conditioned variable?
161 |
162 | :param fixed: (optional)
163 | Should this be a fixed (not permitted to vary) variable?
164 | If `True`, modifies or over-rides ``diameter``, ``offset``,
165 | ``facecolor``, and a few other ``plot_params`` settings.
166 | This setting conflicts with ``observed``.
167 |
168 | :param offset: (optional)
169 | The ``(dx, dy)`` offset of the label (in points) from the default
170 | centered position.
171 |
172 | :param plot_params: (optional)
173 | A dictionary of parameters to pass to the
174 | :class:`matplotlib.patches.Ellipse` constructor.
175 |
176 | """
177 | def __init__(self, name, content, x, y, scale=1, aspect=None,
178 | observed=False, fixed=False,
179 | offset=[0, 0], plot_params={}, label_params=None):
180 | # Node style.
181 | assert not (observed and fixed), \
182 | "A node cannot be both 'observed' and 'fixed'."
183 | self.observed = observed
184 | self.fixed = fixed
185 |
186 | # Metadata.
187 | self.name = name
188 | self.content = content
189 |
190 | # Coordinates and dimensions.
191 | self.x, self.y = x, y
192 | self.scale = scale
193 | if self.fixed:
194 | self.scale /= 6.0
195 | self.aspect = aspect
196 |
197 | # Display parameters.
198 | self.plot_params = dict(plot_params)
199 |
200 | # Text parameters.
201 | self.offset = list(offset)
202 | if label_params is not None:
203 | self.label_params = dict(label_params)
204 | else:
205 | self.label_params = None
206 |
207 | def render(self, ctx):
208 | """
209 | Render the node.
210 |
211 | :param ctx:
212 | The :class:`_rendering_context` object.
213 |
214 | """
215 | # Get the axes and default plotting parameters from the rendering
216 | # context.
217 | ax = ctx.ax()
218 |
219 | # Resolve the plotting parameters.
220 | p = dict(self.plot_params)
221 | p["lw"] = _pop_multiple(p, ctx.line_width, "lw", "linewidth")
222 |
223 | p["ec"] = p["edgecolor"] = _pop_multiple(p, ctx.node_ec,
224 | "ec", "edgecolor")
225 |
226 | p["fc"] = _pop_multiple(p, "none", "fc", "facecolor")
227 | fc = p["fc"]
228 |
229 | p["alpha"] = p.get("alpha", 1)
230 |
231 | # And the label parameters.
232 | if self.label_params is None:
233 | l = dict(ctx.label_params)
234 | else:
235 | l = dict(self.label_params)
236 |
237 | l["va"] = _pop_multiple(l, "center", "va", "verticalalignment")
238 | l["ha"] = _pop_multiple(l, "center", "ha", "horizontalalignment")
239 |
240 | # Deal with ``fixed`` nodes.
241 | scale = self.scale
242 | if self.fixed:
243 | # MAGIC: These magic numbers should depend on the grid/node units.
244 | self.offset[1] += 6
245 |
246 | l["va"] = "baseline"
247 | l.pop("verticalalignment", None)
248 | l.pop("ma", None)
249 |
250 | if p["fc"] == "none":
251 | p["fc"] = "k"
252 |
253 | diameter = ctx.node_unit * scale
254 | if self.aspect is not None:
255 | aspect = self.aspect
256 | else:
257 | aspect = ctx.aspect
258 |
259 | # Set up an observed node. Note the fc INSANITY.
260 | if self.observed:
261 | # Update the plotting parameters depending on the style of
262 | # observed node.
263 | h = float(diameter)
264 | w = aspect * float(diameter)
265 | if ctx.observed_style == "shaded":
266 | p["fc"] = "0.7"
267 | elif ctx.observed_style == "outer":
268 | h = diameter + 0.1 * diameter
269 | w = aspect * diameter + 0.1 * diameter
270 | elif ctx.observed_style == "inner":
271 | h = diameter - 0.1 * diameter
272 | w = aspect * diameter - 0.1 * diameter
273 | p["fc"] = fc
274 |
275 | # Draw the background ellipse.
276 | bg = Ellipse(xy=ctx.convert(self.x, self.y),
277 | width=w, height=h, **p)
278 | ax.add_artist(bg)
279 |
280 | # Reset the face color.
281 | p["fc"] = fc
282 |
283 | # Draw the foreground ellipse.
284 | if ctx.observed_style == "inner" and not self.fixed:
285 | p["fc"] = "none"
286 | el = Ellipse(xy=ctx.convert(self.x, self.y),
287 | width=diameter * aspect, height=diameter, **p)
288 | ax.add_artist(el)
289 |
290 | # Reset the face color.
291 | p["fc"] = fc
292 |
293 | # Annotate the node.
294 | ax.annotate(self.content, ctx.convert(self.x, self.y),
295 | xycoords="data",
296 | xytext=self.offset, textcoords="offset points",
297 | **l)
298 |
299 | return el
300 |
301 |
302 | class Edge(object):
303 | """
304 | An edge between two :class:`Node` objects.
305 |
306 | :param node1:
307 | The first :class:`Node`.
308 |
309 | :param node2:
310 | The second :class:`Node`. The arrow will point towards this node.
311 |
312 | :param directed: (optional)
313 | Should the edge be directed from ``node1`` to ``node2``? In other
314 | words: should it have an arrow?
315 |
316 | :param plot_params: (optional)
317 | A dictionary of parameters to pass to the plotting command when
318 | rendering.
319 |
320 | """
321 | def __init__(self, node1, node2, directed=True, plot_params={}):
322 | self.node1 = node1
323 | self.node2 = node2
324 | self.directed = directed
325 | self.plot_params = dict(plot_params)
326 |
327 | def _get_coords(self, ctx):
328 | """
329 | Get the coordinates of the line.
330 |
331 | :param conv:
332 | A callable coordinate conversion.
333 |
334 | :returns:
335 | * ``x0``, ``y0``: the coordinates of the start of the line.
336 | * ``dx0``, ``dy0``: the displacement vector.
337 |
338 | """
339 | # Scale the coordinates appropriately.
340 | x1, y1 = ctx.convert(self.node1.x, self.node1.y)
341 | x2, y2 = ctx.convert(self.node2.x, self.node2.y)
342 |
343 | # Aspect ratios.
344 | a1, a2 = self.node1.aspect, self.node2.aspect
345 | if a1 is None:
346 | a1 = ctx.aspect
347 | if a2 is None:
348 | a2 = ctx.aspect
349 |
350 | # Compute the distances.
351 | dx, dy = x2 - x1, y2 - y1
352 | dist1 = np.sqrt(dy * dy + dx * dx / float(a1 ** 2))
353 | dist2 = np.sqrt(dy * dy + dx * dx / float(a2 ** 2))
354 |
355 | # Compute the fractional effect of the radii of the nodes.
356 | alpha1 = 0.5 * ctx.node_unit * self.node1.scale / dist1
357 | alpha2 = 0.5 * ctx.node_unit * self.node2.scale / dist2
358 |
359 | # Get the coordinates of the starting position.
360 | x0, y0 = x1 + alpha1 * dx, y1 + alpha1 * dy
361 |
362 | # Get the width and height of the line.
363 | dx0 = dx * (1. - alpha1 - alpha2)
364 | dy0 = dy * (1. - alpha1 - alpha2)
365 |
366 | return x0, y0, dx0, dy0
367 |
368 | def render(self, ctx):
369 | """
370 | Render the edge in the given axes.
371 |
372 | :param ctx:
373 | The :class:`_rendering_context` object.
374 |
375 | """
376 | ax = ctx.ax()
377 |
378 | p = self.plot_params
379 | p["linewidth"] = _pop_multiple(p, ctx.line_width,
380 | "lw", "linewidth")
381 |
382 | # Add edge annotation.
383 | if "label" in self.plot_params:
384 | x, y, dx, dy = self._get_coords(ctx)
385 | ax.annotate(self.plot_params["label"],
386 | [x + 0.5 * dx, y + 0.5 * dy], xycoords="data",
387 | xytext=[0, 3], textcoords="offset points",
388 | ha="center", va="center")
389 |
390 | if self.directed:
391 | p["ec"] = _pop_multiple(p, "k", "ec", "edgecolor")
392 | p["fc"] = _pop_multiple(p, "k", "fc", "facecolor")
393 | p["head_length"] = p.get("head_length", 0.25)
394 | p["head_width"] = p.get("head_width", 0.1)
395 |
396 | # Build an arrow.
397 | ar = FancyArrow(*self._get_coords(ctx), width=0,
398 | length_includes_head=True,
399 | **p)
400 |
401 | # Add the arrow to the axes.
402 | ax.add_artist(ar)
403 | return ar
404 | else:
405 | p["color"] = p.get("color", "k")
406 |
407 | # Get the right coordinates.
408 | x, y, dx, dy = self._get_coords(ctx)
409 |
410 | # Plot the line.
411 | line = ax.plot([x, x + dx], [y, y + dy], **p)
412 | return line
413 |
414 |
415 | class Plate(object):
416 | """
417 | A plate to encapsulate repeated independent processes in the model.
418 |
419 | :param rect:
420 | The rectangle describing the plate bounds in model coordinates.
421 |
422 | :param label: (optional)
423 | A string to annotate the plate.
424 |
425 | :param label_offset: (optional)
426 | The x and y offsets of the label text measured in points.
427 |
428 | :param shift: (optional)
429 | The vertical "shift" of the plate measured in model units. This will
430 | move the bottom of the panel by ``shift`` units.
431 |
432 | :param position: (optional)
433 | One of ``"bottom left"`` or ``"bottom right"``.
434 |
435 | :param rect_params: (optional)
436 | A dictionary of parameters to pass to the
437 | :class:`matplotlib.patches.Rectangle` constructor.
438 |
439 | """
440 | def __init__(self, rect, label=None, label_offset=[5, 5], shift=0,
441 | position="bottom left", rect_params={}, bbox={}):
442 | self.rect = rect
443 | self.label = label
444 | self.label_offset = label_offset
445 | self.shift = shift
446 | self.rect_params = dict(rect_params)
447 | self.bbox = dict(bbox)
448 | self.position = position
449 |
450 | def render(self, ctx):
451 | """
452 | Render the plate in the given axes.
453 |
454 | :param ctx:
455 | The :class:`_rendering_context` object.
456 |
457 | """
458 | ax = ctx.ax()
459 |
460 | s = np.array([0, self.shift])
461 | r = np.atleast_1d(self.rect)
462 | bl = ctx.convert(*(r[:2] + s))
463 | tr = ctx.convert(*(r[:2] + r[2:]))
464 | r = np.concatenate([bl, tr - bl])
465 |
466 | p = self.rect_params
467 | p["ec"] = _pop_multiple(p, "k", "ec", "edgecolor")
468 | p["fc"] = _pop_multiple(p, "none", "fc", "facecolor")
469 | p["lw"] = _pop_multiple(p, ctx.line_width, "lw", "linewidth")
470 |
471 | rect = Rectangle(r[:2], *r[2:], **p)
472 | ax.add_artist(rect)
473 |
474 | if self.label is not None:
475 | offset = np.array(self.label_offset)
476 | if self.position == "bottom left":
477 | pos = r[:2]
478 | ha = "left"
479 | elif self.position == "bottom right":
480 | pos = r[:2]
481 | pos[0] += r[2]
482 | ha = "right"
483 | offset[0] -= 2 * offset[0]
484 | else:
485 | raise RuntimeError("Unknown positioning string: {0}"
486 | .format(self.position))
487 |
488 | ax.annotate(self.label, pos, xycoords="data",
489 | xytext=offset, textcoords="offset points",
490 | bbox=self.bbox,
491 | horizontalalignment=ha)
492 |
493 | return rect
494 |
495 |
496 | class _rendering_context(object):
497 | """
498 | :param shape:
499 | The number of rows and columns in the grid.
500 |
501 | :param origin:
502 | The coordinates of the bottom left corner of the plot.
503 |
504 | :param grid_unit:
505 | The size of the grid spacing measured in centimeters.
506 |
507 | :param node_unit:
508 | The base unit for the node size. This is a number in centimeters that
509 | sets the default diameter of the nodes.
510 |
511 | :param observed_style:
512 | How should the "observed" nodes be indicated? This must be one of:
513 | ``"shaded"``, ``"inner"`` or ``"outer"`` where ``inner`` and
514 | ``outer`` nodes are shown as double circles with the second circle
515 | plotted inside or outside of the standard one, respectively.
516 |
517 | :param node_ec:
518 | The default edge color for the nodes.
519 |
520 | :param directed:
521 | Should the edges be directed by default?
522 |
523 | :param aspect:
524 | The default aspect ratio for the nodes.
525 |
526 | :param label_params:
527 | Default node label parameters.
528 |
529 | """
530 | def __init__(self, **kwargs):
531 | # Save the style defaults.
532 | self.line_width = kwargs.get("line_width", 1.0)
533 |
534 | # Make sure that the observed node style is one that we recognize.
535 | self.observed_style = kwargs.get("observed_style", "shaded").lower()
536 | styles = ["shaded", "inner", "outer"]
537 | assert self.observed_style in styles, \
538 | "Unrecognized observed node style: {0}\n".format(
539 | self.observed_style) \
540 | + "\tOptions are: {0}".format(", ".join(styles))
541 |
542 | # Set up the figure and grid dimensions.
543 | self.shape = np.array(kwargs.get("shape", [1, 1]))
544 | self.origin = np.array(kwargs.get("origin", [0, 0]))
545 | self.grid_unit = kwargs.get("grid_unit", 2.0)
546 | self.figsize = self.grid_unit * self.shape / 2.54
547 |
548 | self.node_unit = kwargs.get("node_unit", 1.0)
549 | self.node_ec = kwargs.get("node_ec", "k")
550 | self.directed = kwargs.get("directed", True)
551 | self.aspect = kwargs.get("aspect", 1.0)
552 | self.label_params = dict(kwargs.get("label_params", {}))
553 |
554 | # Initialize the figure to ``None`` to handle caching later.
555 | self._figure = None
556 | self._ax = None
557 |
558 | def figure(self):
559 | if self._figure is not None:
560 | return self._figure
561 | self._figure = plt.figure(figsize=self.figsize)
562 | return self._figure
563 |
564 | def ax(self):
565 | if self._ax is not None:
566 | return self._ax
567 |
568 | # Add a new axis object if it doesn't exist.
569 | self._ax = self.figure().add_axes((0, 0, 1, 1), frameon=False,
570 | xticks=[], yticks=[])
571 |
572 | # Set the bounds.
573 | l0 = self.convert(*self.origin)
574 | l1 = self.convert(*(self.origin + self.shape))
575 | self._ax.set_xlim(l0[0], l1[0])
576 | self._ax.set_ylim(l0[1], l1[1])
577 |
578 | return self._ax
579 |
580 | def convert(self, *xy):
581 | """
582 | Convert from model coordinates to plot coordinates.
583 |
584 | """
585 | assert len(xy) == 2
586 | return self.grid_unit * (np.atleast_1d(xy) - self.origin)
587 |
588 |
589 | def _pop_multiple(d, default, *args):
590 | """
591 | A helper function for dealing with the way that matplotlib annoyingly
592 | allows multiple keyword arguments. For example, ``edgecolor`` and ``ec``
593 | are generally equivalent but no exception is thrown if they are both
594 | used.
595 |
596 | *Note: This function does throw a :class:`ValueError` if more than one
597 | of the equivalent arguments are provided.*
598 |
599 | :param d:
600 | A :class:`dict`-like object to "pop" from.
601 |
602 | :param default:
603 | The default value to return if none of the arguments are provided.
604 |
605 | :param *args:
606 | The arguments to try to retrieve.
607 |
608 | """
609 | assert len(args) > 0, "You must provide at least one argument to 'pop'."
610 |
611 | results = []
612 | for k in args:
613 | try:
614 | results.append((k, d.pop(k)))
615 | except KeyError:
616 | pass
617 |
618 | if len(results) > 1:
619 | raise TypeError("The arguments ({0}) are equivalent, you can only "
620 | .format(", ".join([k for k, v in results]))
621 | + "provide one of them.")
622 |
623 | if len(results) == 0:
624 | return default
625 |
626 | return results[0][1]
627 |
--------------------------------------------------------------------------------
/docs/_static/d3.v2.min.js:
--------------------------------------------------------------------------------
1 | (function(){function e(e,t){try{for(var n in t)Object.defineProperty(e.prototype,n,{value:t[n],enumerable:!1})}catch(r){e.prototype=t}}function t(e){var t=-1,n=e.length,r=[];while(++t=0?e.substring(t):(t=e.length,""),r=[];while(t>0)r.push(e.substring(t-=3,t+3));return r.reverse().join(",")+n}function b(e,t){var n=Math.pow(10,Math.abs(8-t)*3);return{scale:t>8?function(e){return e/n}:function(e){return e*n},symbol:e}}function w(e){return function(t){return t<=0?0:t>=1?1:e(t)}}function E(e){return function(t){return 1-e(1-t)}}function S(e){return function(t){return.5*(t<.5?e(2*t):2-e(2-2*t))}}function x(e){return e}function T(e){return function(t){return Math.pow(t,e)}}function N(e){return 1-Math.cos(e*Math.PI/2)}function C(e){return Math.pow(2,10*(e-1))}function k(e){return 1-Math.sqrt(1-e*e)}function L(e,t){var n;return arguments.length<2&&(t=.45),arguments.length<1?(e=1,n=t/4):n=t/(2*Math.PI)*Math.asin(1/e),function(r){return 1+e*Math.pow(2,10*-r)*Math.sin((r-n)*2*Math.PI/t)}}function A(e){return e||(e=1.70158),function(t){return t*t*((e+1)*t-e)}}function O(e){return e<1/2.75?7.5625*e*e:e<2/2.75?7.5625*(e-=1.5/2.75)*e+.75:e<2.5/2.75?7.5625*(e-=2.25/2.75)*e+.9375:7.5625*(e-=2.625/2.75)*e+.984375}function M(){d3.event.stopPropagation(),d3.event.preventDefault()}function _(){var e=d3.event,t;while(t=e.sourceEvent)e=t;return e}function D(e){var t=new d,n=0,r=arguments.length;while(++n360?e-=360:e<0&&(e+=360),e<60?s+(o-s)*e/60:e<180?o:e<240?s+(o-s)*(240-e)/60:s}function i(e){return Math.round(r(e)*255)}var s,o;return e%=360,e<0&&(e+=360),t=t<0?0:t>1?1:t,n=n<0?0:n>1?1:n,o=n<=.5?n*(1+t):n+t-n*t,s=2*n-o,R(i(e+120),i(e),i(e-120))}function Y(e,t,n){return new Z(e,t,n)}function Z(e,t,n){this.h=e,this.c=t,this.l=n}function et(e,t,n){return tt(n,Math.cos(e*=Math.PI/180)*t,Math.sin(e)*t)}function tt(e,t,n){return new nt(e,t,n)}function nt(e,t,n){this.l=e,this.a=t,this.b=n}function rt(e,t,n){var r=(e+16)/116,i=r+t/500,s=r-n/200;return i=st(i)*ds,r=st(r)*vs,s=st(s)*ms,R(ut(3.2404542*i-1.5371385*r-.4985314*s),ut(-0.969266*i+1.8760108*r+.041556*s),ut(.0556434*i-.2040259*r+1.0572252*s))}function it(e,t,n){return Y(Math.atan2(n,t)/Math.PI*180,Math.sqrt(t*t+n*n),e)}function st(e){return e>.206893034?e*e*e:(e-4/29)/7.787037}function ot(e){return e>.008856?Math.pow(e,1/3):7.787037*e+4/29}function ut(e){return Math.round(255*(e<=.00304?12.92*e:1.055*Math.pow(e,1/2.4)-.055))}function at(e){return Ki(e,Ss),e}function ft(e){return function(){return gs(e,this)}}function lt(e){return function(){return ys(e,this)}}function ct(e,t){function n(){this.removeAttribute(e)}function r(){this.removeAttributeNS(e.space,e.local)}function i(){this.setAttribute(e,t)}function s(){this.setAttributeNS(e.space,e.local,t)}function o(){var n=t.apply(this,arguments);n==null?this.removeAttribute(e):this.setAttribute(e,n)}function u(){var n=t.apply(this,arguments);n==null?this.removeAttributeNS(e.space,e.local):this.setAttributeNS(e.space,e.local,n)}return e=d3.ns.qualify(e),t==null?e.local?r:n:typeof t=="function"?e.local?u:o:e.local?s:i}function ht(e){return new RegExp("(?:^|\\s+)"+d3.requote(e)+"(?:\\s+|$)","g")}function pt(e,t){function n(){var n=-1;while(++n0&&(e=e.substring(0,o)),t?i:r}function Et(e,t){for(var n=0,r=e.length;nt?c():(v.active=t,i.forEach(function(t,n){(n=n.call(e,m,u))&&h.push(n)}),s.start.call(e,m,u),l(r)||d3.timer(l,0,n),1)}function l(n){if(v.active!==t)return c();var r=(n-p)/d,i=o(r),a=h.length;while(a>0)h[--a].call(e,i);if(r>=1)return c(),ks=t,s.end.call(e,m,u),ks=0,1}function c(){return--v.count||delete e.__transition__,1}var h=[],p=e.delay,d=e.duration,v=(e=e.node).__transition__||(e.__transition__={active:0,count:0}),m=e.__data__;++v.count,p<=r?f(r):d3.timer(f,p,n)})},0,n),e}function Tt(e){var t=ks,n=Ds,r=Ms,i=_s;return ks=this.id,Ds=this.ease(),Et(this,function(t,n,r){Ms=t.delay,_s=t.duration,e.call(t=t.node,t.__data__,n,r)}),ks=t,Ds=n,Ms=r,_s=i,this}function Nt(e,t,n){return n!=""&&Ps}function Ct(e,t){return d3.tween(e,F(t))}function kt(){var e,t=Date.now(),n=Hs;while(n)e=t-n.then,e>=n.delay&&(n.flush=n.callback(e)),n=n.next;var r=Lt()-t;r>24?(isFinite(r)&&(clearTimeout(js),js=setTimeout(kt,r)),Bs=0):(Bs=1,Fs(kt))}function Lt(){var e=null,t=Hs,n=Infinity;while(t)t.flush?t=e?e.next=t.next:Hs=t.next:(n=Math.min(n,t.then+t.delay),t=(e=t).next);return n}function At(e,t){var n=e.ownerSVGElement||e;if(n.createSVGPoint){var r=n.createSVGPoint();if(Is<0&&(window.scrollX||window.scrollY)){n=d3.select(document.body).append("svg").style("position","absolute").style("top",0).style("left",0);var i=n[0][0].getScreenCTM();Is=!i.f&&!i.e,n.remove()}return Is?(r.x=t.pageX,r.y=t.pageY):(r.x=t.clientX,r.y=t.clientY),r=r.matrixTransform(e.getScreenCTM().inverse()),[r.x,r.y]}var s=e.getBoundingClientRect();return[t.clientX-s.left-e.clientLeft,t.clientY-s.top-e.clientTop]}function Ot(){}function Mt(e){var t=e[0],n=e[e.length-1];return t2?Ut:Rt,a=r?q:I;return o=i(e,t,a,n),u=i(t,e,a,d3.interpolate),s}function s(e){return o(e)}var o,u;return s.invert=function(e){return u(e)},s.domain=function(t){return arguments.length?(e=t.map(Number),i()):e},s.range=function(e){return arguments.length?(t=e,i()):t},s.rangeRound=function(e){return s.range(e).interpolate(d3.interpolateRound)},s.clamp=function(e){return arguments.length?(r=e,i()):r},s.interpolate=function(e){return arguments.length?(n=e,i()):n},s.ticks=function(t){return It(e,t)},s.tickFormat=function(t){return qt(e,t)},s.nice=function(){return Dt(e,jt),i()},s.copy=function(){return Ht(e,t,n,r)},i()}function Bt(e,t){return d3.rebind(e,t,"range","rangeRound","interpolate","clamp")}function jt(e){return e=Math.pow(10,Math.round(Math.log(e)/Math.LN10)-1),e&&{floor:function(t){return Math.floor(t/e)*e},ceil:function(t){return Math.ceil(t/e)*e}}}function Ft(e,t){var n=Mt(e),r=n[1]-n[0],i=Math.pow(10,Math.floor(Math.log(r/t)/Math.LN10)),s=t/r*i;return s<=.15?i*=10:s<=.35?i*=5:s<=.75&&(i*=2),n[0]=Math.ceil(n[0]/i)*i,n[1]=Math.floor(n[1]/i)*i+i*.5,n[2]=i,n}function It(e,t){return d3.range.apply(d3,Ft(e,t))}function qt(e,t){return d3.format(",."+Math.max(0,-Math.floor(Math.log(Ft(e,t)[2])/Math.LN10+.01))+"f")}function Rt(e,t,n,r){var i=n(e[0],e[1]),s=r(t[0],t[1]);return function(e){return s(i(e))}}function Ut(e,t,n,r){var i=[],s=[],o=0,u=Math.min(e.length,t.length)-1;e[u]0;f--)i.push(r(s)*f)}else{for(;sa;o--);i=i.slice(s,o)}return i},n.tickFormat=function(e,i){arguments.length<2&&(i=qs);if(arguments.length<1)return i;var s=Math.max(.1,e/n.ticks().length),o=t===Xt?(u=-1e-12,Math.floor):(u=1e-12,Math.ceil),u;return function(e){return e/r(o(t(e)+u))<=s?i(e):""}},n.copy=function(){return zt(e.copy(),t)},Bt(n,e)}function Wt(e){return Math.log(e<0?0:e)/Math.LN10}function Xt(e){return-Math.log(e>0?0:-e)/Math.LN10}function Vt(e,t){function n(t){return e(r(t))}var r=$t(t),i=$t(1/t);return n.invert=function(t){return i(e.invert(t))},n.domain=function(t){return arguments.length?(e.domain(t.map(r)),n):e.domain().map(i)},n.ticks=function(e){return It(n.domain(),e)},n.tickFormat=function(e){return qt(n.domain(),e)},n.nice=function(){return n.domain(Dt(n.domain(),jt))},n.exponent=function(e){if(!arguments.length)return t;var s=n.domain();return r=$t(t=e),i=$t(1/t),n.domain(s)},n.copy=function(){return Vt(e.copy(),t)},Bt(n,e)}function $t(e){return function(t){return t<0?-Math.pow(-t,e):Math.pow(t,e)}}function Jt(e,t){function n(t){return o[((s.get(t)||s.set(t,e.push(t)))-1)%o.length]}function i(t,n){return d3.range(e.length).map(function(e){return t+n*e})}var s,o,u;return n.domain=function(i){if(!arguments.length)return e;e=[],s=new r;var o=-1,u=i.length,a;while(++o1){u=t[1],s=e[a],a++,r+="C"+(i[0]+o[0])+","+(i[1]+o[1])+","+(s[0]-u[0])+","+(s[1]-u[1])+","+s[0]+","+s[1];for(var f=2;f9&&(s=n*3/Math.sqrt(s),o[u]=s*r,o[u+1]=s*i));u=-1;while(++u<=a)s=(e[Math.min(a,u+1)][0]-e[Math.max(0,u-1)][0])/(6*(1+o[u]*o[u])),t.push([s||0,o[u]*s||0]);return t}function Nn(e){return e.length<3?un(e):e[0]+dn(e,Tn(e))}function Cn(e){var t,n=-1,r=e.length,i,s;while(++n1){var r=Mt(e.domain()),i,s=-1,o=t.length,u=(t[1]-t[0])/++n,a,f;while(++s0;)(f=+t[s]-a*u)>=r[0]&&i.push(f);for(--s,a=0;++ar&&(n=t,r=i);return n}function ir(e){return e.reduce(sr,0)}function sr(e,t){return e+t[1]}function or(e,t){return ur(e,Math.ceil(Math.log(t.length)/Math.LN2+1))}function ur(e,t){var n=-1,r=+e[0],i=(e[1]-r)/t,s=[];while(++n<=t)s[n]=i*n+r;return s}function ar(e){return[d3.min(e),d3.max(e)]}function fr(e,t){return d3.rebind(e,t,"sort","children","value"),e.links=pr,e.nodes=function(t){return uo=!0,(e.nodes=e)(t)},e}function lr(e){return e.children}function cr(e){return e.value}function hr(e,t){return t.value-e.value}function pr(e){return d3.merge(e.map(function(e){return(e.children||[]).map(function(t){return{source:e,target:t}})}))}function dr(e,t){return e.value-t.value}function vr(e,t){var n=e._pack_next;e._pack_next=t,t._pack_prev=e,t._pack_next=n,n._pack_prev=t}function mr(e,t){e._pack_next=t,t._pack_prev=e}function gr(e,t){var n=t.x-e.x,r=t.y-e.y,i=e.r+t.r;return i*i-n*n-r*r>.001}function yr(e){function t(e){r=Math.min(e.x-e.r,r),i=Math.max(e.x+e.r,i),s=Math.min(e.y-e.r,s),o=Math.max(e.y+e.r,o)}if(!(n=e.children)||!(p=n.length))return;var n,r=Infinity,i=-Infinity,s=Infinity,o=-Infinity,u,a,f,l,c,h,p;n.forEach(br),u=n[0],u.x=-u.r,u.y=0,t(u);if(p>1){a=n[1],a.x=a.r,a.y=0,t(a);if(p>2){f=n[2],Sr(u,a,f),t(f),vr(u,f),u._pack_prev=f,vr(f,a),a=u._pack_next;for(l=3;l0&&(e=r)}return e}function Mr(e,t){return e.x-t.x}function _r(e,t){return t.x-e.x}function Dr(e,t){return e.depth-t.depth}function Pr(e,t){function n(e,r){var i=e.children;if(i&&(a=i.length)){var s,o=null,u=-1,a;while(++u=0)s=r[i]._tree,s.prelim+=t,s.mod+=t,t+=s.shift+(n+=s.change)}function Br(e,t,n){e=e._tree,t=t._tree;var r=n/(t.number-e.number);e.change+=r,t.change-=r,t.shift+=n,t.prelim+=n,t.mod+=n}function jr(e,t,n){return e._tree.ancestor.parent==t.parent?e._tree.ancestor:n}function Fr(e){return{x:e.x,y:e.y,dx:e.dx,dy:e.dy}}function Ir(e,t){var n=e.x+t[3],r=e.y+t[0],i=e.dx-t[1]-t[3],s=e.dy-t[0]-t[2];return i<0&&(n+=i/2,i=0),s<0&&(r+=s/2,s=0),{x:n,y:r,dx:i,dy:s}}function qr(e,t){function n(e,r){d3.text(e,t,function(e){r(e&&n.parse(e))})}function r(t){return t.map(i).join(e)}function i(e){return o.test(e)?'"'+e.replace(/\"/g,'""')+'"':e}var s=new RegExp("\r\n|["+e+"\r\n]","g"),o=new RegExp('["'+e+"\n]"),u=e.charCodeAt(0);return n.parse=function(e){var t;return n.parseRows(e,function(e,n){if(n){var r={},i=-1,s=t.length;while(++i=e.length)return i;if(l)return l=!1,r;var t=s.lastIndex;if(e.charCodeAt(t)===34){var n=t;while(n++0}function ii(e,t,n){return(n[0]-t[0])*(e[1]-t[1])<(n[1]-t[1])*(e[0]-t[0])}function si(e,t,n,r){var i=e[0],s=t[0],o=n[0],u=r[0],a=e[1],f=t[1],l=n[1],c=r[1],h=i-o,p=s-i,d=u-o,v=a-l,m=f-a,g=c-l,y=(d*v-g*h)/(g*p-d*m);return[i+y*p,a+y*m]}function oi(e,t){var n={list:e.map(function(e,t){return{index:t,x:e[0],y:e[1]}}).sort(function(e,t){return e.yt.y?1:e.xt.x?1:0}),bottomSite:null},r={list:[],leftEnd:null,rightEnd:null,init:function(){r.leftEnd=r.createHalfEdge(null,"l"),r.rightEnd=r.createHalfEdge(null,"l"),r.leftEnd.r=r.rightEnd,r.rightEnd.l=r.leftEnd,r.list.unshift(r.leftEnd,r.rightEnd)},createHalfEdge:function(e,t){return{edge:e,side:t,vertex:null,l:null,r:null}},insert:function(e,t){t.l=e,t.r=e.r,e.r.l=t,e.r=t},leftBound:function(e){var t=r.leftEnd;do t=t.r;while(t!=r.rightEnd&&i.rightOf(t,e));return t=t.l,t},del:function(e){e.l.r=e.r,e.r.l=e.l,e.edge=null},right:function(e){return e.r},left:function(e){return e.l},leftRegion:function(e){return e.edge==null?n.bottomSite:e.edge.region[e.side]},rightRegion:function(e){return e.edge==null?n.bottomSite:e.edge.region[ho[e.side]]}},i={bisect:function(e,t){var n={region:{l:e,r:t},ep:{l:null,r:null}},r=t.x-e.x,i=t.y-e.y,s=r>0?r:-r,o=i>0?i:-i;return n.c=e.x*r+e.y*i+(r*r+i*i)*.5,s>o?(n.a=1,n.b=i/r,n.c/=r):(n.b=1,n.a=r/i,n.c/=i),n},intersect:function(e,t){var n=e.edge,r=t.edge;if(!n||!r||n.region.r==r.region.r)return null;var i=n.a*r.b-n.b*r.a;if(Math.abs(i)<1e-10)return null;var s=(n.c*r.b-r.c*n.b)/i,o=(r.c*n.a-n.c*r.a)/i,u=n.region.r,a=r.region.r,f,l;u.y=l.region.r.x;return c&&f.side==="l"||!c&&f.side==="r"?null:{x:s,y:o}},rightOf:function(e,t){var n=e.edge,r=n.region.r,i=t.x>r.x;if(i&&e.side==="l")return 1;if(!i&&e.side==="r")return 0;if(n.a===1){var s=t.y-r.y,o=t.x-r.x,u=0,a=0;!i&&n.b<0||i&&n.b>=0?a=u=s>=n.b*o:(a=t.x+t.y*n.b>n.c,n.b<0&&(a=!a),a||(u=1));if(!u){var f=r.x-n.region.l.x;a=n.b*(o*o-s*s)h*h+p*p}return e.side==="l"?a:!a},endPoint:function(e,n,r){e.ep[n]=r;if(!e.ep[ho[n]])return;t(e)},distance:function(e,t){var n=e.x-t.x,r=e.y-t.y;return Math.sqrt(n*n+r*r)}},s={list:[],insert:function(e,t,n){e.vertex=t,e.ystar=t.y+n;for(var r=0,i=s.list,o=i.length;ru.ystar||e.ystar==u.ystar&&t.x>u.vertex.x)continue;break}i.splice(r,0,e)},del:function(e){for(var t=0,n=s.list,r=n.length;td.y&&(v=p,p=d,d=v,b="r"),y=i.bisect(p,d),h=r.createHalfEdge(y,b),r.insert(l,h),i.endPoint(y,ho[b],g),m=i.intersect(l,h),m&&(s.del(l),s.insert(l,m,i.distance(m,p))),m=i.intersect(h,c),m&&s.insert(h,m,i.distance(m,p))}}for(a=r.right(r.leftEnd);a!=r.rightEnd;a=r.right(a))t(a.edge)}function ui(){return{leaf:!0,nodes:[],point:null}}function ai(e,t,n,r,i,s){if(!e(t,n,r,i,s)){var o=(n+i)*.5,u=(r+s)*.5,a=t.nodes;a[0]&&ai(e,a[0],n,r,o,u),a[1]&&ai(e,a[1],o,r,i,u),a[2]&&ai(e,a[2],n,u,o,s),a[3]&&ai(e,a[3],o,u,i,s)}}function fi(e){return{x:e[0],y:e[1]}}function li(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function ci(e){return e.substring(0,3)}function hi(e,t,n,r){var i,s,o=0,u=t.length,a=n.length;while(o=a)return-1;i=t.charCodeAt(o++);if(i==37){s=Ho[t.charAt(o++)];if(!s||(r=s(e,n,r))<0)return-1}else if(i!=n.charCodeAt(r++))return-1}return r}function pi(e){return new RegExp("^(?:"+e.map(d3.requote).join("|")+")","i")}function di(e){var t=new r,n=-1,i=e.length;while(++n68?1900:2e3)}function Ni(e,t,n){Bo.lastIndex=0;var r=Bo.exec(t.substring(n,n+2));return r?(e.m=r[0]-1,n+=r[0].length):-1}function Ci(e,t,n){Bo.lastIndex=0;var r=Bo.exec(t.substring(n,n+2));return r?(e.d=+r[0],n+=r[0].length):-1}function ki(e,t,n){Bo.lastIndex=0;var r=Bo.exec(t.substring(n,n+2));return r?(e.H=+r[0],n+=r[0].length):-1}function Li(e,t,n){Bo.lastIndex=0;var r=Bo.exec(t.substring(n,n+2));return r?(e.M=+r[0],n+=r[0].length):-1}function Ai(e,t,n){Bo.lastIndex=0;var r=Bo.exec(t.substring(n,n+2));return r?(e.S=+r[0],n+=r[0].length):-1}function Oi(e,t,n){Bo.lastIndex=0;var r=Bo.exec(t.substring(n,n+3));return r?(e.L=+r[0],n+=r[0].length):-1}function Mi(e,t,n){var r=jo.get(t.substring(n,n+=2).toLowerCase());return r==null?-1:(e.p=r,n)}function _i(e){var t=e.getTimezoneOffset(),n=t>0?"-":"+",r=~~(Math.abs(t)/60),i=Math.abs(t)%60;return n+To(r)+To(i)}function Di(e){return e.toISOString()}function Pi(e,t,n){function r(t){var n=e(t),r=s(n,1);return t-n1)while(ot?1:e>=t?0:NaN},d3.descending=function(e,t){return te?1:t>=e?0:NaN},d3.mean=function(e,t){var n=e.length,r,i=0,s=-1,o=0;if(arguments.length===1)while(++s1&&(e=e.map(t)),e=e.filter(f),e.length?d3.quantile(e.sort(d3.ascending),.5):undefined},d3.min=function(e,t){var n=-1,r=e.length,i,s;if(arguments.length===1){while(++ns&&(i=s)}else{while(++ns&&(i=s)}return i},d3.max=function(e,t){var n=-1,r=e.length,i,s;if(arguments.length===1){while(++ni&&(i=s)}else{while(++ni&&(i=s)}return i},d3.extent=function(e,t){var n=-1,r=e.length,i,s,o;if(arguments.length===1){while(++ns&&(i=s),os&&(i=s),o1);return e+t*n*Math.sqrt(-2*Math.log(i)/i)}},logNormal:function(e,t){var n=arguments.length;n<2&&(t=1),n<1&&(e=0);var r=d3.random.normal();return function(){return Math.exp(e+t*r())}},irwinHall:function(e){return function(){for(var t=0,n=0;n>>1;e.call(t,t[s],s)>>1;n0&&(i=s);return i},d3.last=function(e,t){var n=0,r=e.length,i=e[0],s;arguments.length===1&&(t=d3.ascending);while(++n=i.length)return u?u.call(n,t):o?t.sort(o):t;var a=-1,f=t.length,l=i[s++],c,h,p=new r,d,v={};while(++a=i.length)return e;var r=[],o=s[n++],u;for(u in e)r.push({key:u,values:t(e[u],n)});return o&&r.sort(function(e,t){return o(e.key,t.key)}),r}var n={},i=[],s=[],o,u;return n.map=function(t){return e(t,0)},n.entries=function(n){return t(e(n,0),0)},n.key=function(e){return i.push(e),n},n.sortKeys=function(e){return s[i.length-1]=e,n},n.sortValues=function(e){return o=e,n},n.rollup=function(e){return u=e,n},n},d3.keys=function(e){var t=[];for(var n in e)t.push(n);return t},d3.values=function(e){var t=[];for(var n in e)t.push(e[n]);return t},d3.entries=function(e){var t=[];for(var n in e)t.push({key:n,value:e[n]});return t},d3.permute=function(e,t){var n=[],r=-1,i=t.length;while(++rt)r.push(o/i);else while((o=e+n*++s)=200&&e<300||e===304?r:null)}},r.send(null)},d3.text=function(e,t,n){function r(e){n(e&&e.responseText)}arguments.length<3&&(n=t,t=null),d3.xhr(e,t,r)},d3.json=function(e,t){d3.text(e,"application/json",function(e){t(e?JSON.parse(e):null)})},d3.html=function(e,t){d3.text(e,"text/html",function(e){if(e!=null){var n=document.createRange();n.selectNode(document.body),e=n.createContextualFragment(e)}t(e)})},d3.xml=function(e,t,n){function r(e){n(e&&e.responseXML)}arguments.length<3&&(n=t,t=null),d3.xhr(e,t,r)};var es={svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};d3.ns={prefix:es,qualify:function(e){var t=e.indexOf(":"),n=e;return t>=0&&(n=e.substring(0,t),e=e.substring(t+1)),es.hasOwnProperty(n)?{space:es[n],local:e}:e}},d3.dispatch=function(){var e=new d,t=-1,n=arguments.length;while(++t0&&(r=e.substring(n+1),e=e.substring(0,n)),arguments.length<2?this[e].on(r):this[e].on(r,t)},d3.format=function(e){var t=ts.exec(e),n=t[1]||" ",r=t[3]||"",i=t[5],s=+t[6],o=t[7],u=t[8],a=t[9],f=1,l="",c=!1;u&&(u=+u.substring(1)),i&&(n="0",o&&(s-=Math.floor((s-1)/4)));switch(a){case"n":o=!0,a="g";break;case"%":f=100,l="%",a="f";break;case"p":f=100,l="%",a="r";break;case"d":c=!0,u=0;break;case"s":f=-1,a="r"}return a=="r"&&!u&&(a="g"),a=ns.get(a)||g,function(e){if(c&&e%1)return"";var t=e<0&&(e=-e)?"-":r;if(f<0){var h=d3.formatPrefix(e,u);e=h.scale(e),l=h.symbol}else e*=f;e=a(e,u);if(i){var p=e.length+t.length;p=^]))?([+\- ])?(#)?(0)?([0-9]+)?(,)?(\.[0-9]+)?([a-zA-Z%])?/,ns=d3.map({g:function(e,t){return e.toPrecision(t)},e:function(e,t){return e.toExponential(t)},f:function(e,t){return e.toFixed(t)},r:function(e,t){return d3.round(e,t=m(e,t)).toFixed(Math.max(0,Math.min(20,t)))}}),rs=["y","z","a","f","p","n","μ","m","","k","M","G","T","P","E","Z","Y"].map(b);d3.formatPrefix=function(e,t){var n=0;return e&&(e<0&&(e*=-1),t&&(e=d3.round(e,m(e,t))),n=1+Math.floor(1e-12+Math.log(e)/Math.LN10),n=Math.max(-24,Math.min(24,Math.floor((n<=0?n+1:n-1)/3)*3))),rs[8+n/3]};var is=T(2),ss=T(3),os=function(){return x},us=d3.map({linear:os,poly:T,quad:function(){return is},cubic:function(){return ss},sin:function(){return N},exp:function(){return C},circle:function(){return k},elastic:L,back:A,bounce:function(){return O}}),as=d3.map({"in":x,out:E,"in-out":S,"out-in":function(e){return S(E(e))}});d3.ease=function(e){var t=e.indexOf("-"),n=t>=0?e.substring(0,t):e,r=t>=0?e.substring(t+1):"in";return n=us.get(n)||os,r=as.get(r)||x,w(r(n.apply(null,Array.prototype.slice.call(arguments,1))))},d3.event=null,d3.transform=function(e){var t=document.createElementNS(d3.ns.prefix.svg,"g");return(d3.transform=function(e){t.setAttribute("transform",e);var n=t.transform.baseVal.consolidate();return new P(n?n.matrix:ls)})(e)},P.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var fs=180/Math.PI,ls={a:1,b:0,c:0,d:1,e:0,f:0};d3.interpolate=function(e,t){var n=d3.interpolators.length,r;while(--n>=0&&!(r=d3.interpolators[n](e,t)));return r},d3.interpolateNumber=function(e,t){return t-=e,function(n){return e+t*n}},d3.interpolateRound=function(e,t){return t-=e,function(n){return Math.round(e+t*n)}},d3.interpolateString=function(e,t){var n,r,i,s=0,o=0,u=[],a=[],f,l;cs.lastIndex=0;for(r=0;n=cs.exec(t);++r)n.index&&u.push(t.substring(s,o=n.index)),a.push({i:u.length,x:n[0]}),u.push(null),s=cs.lastIndex;s180?l+=360:l-f>180&&(f+=360),r.push({i:n.push(n.pop()+"rotate(",null,")")-2,x:d3.interpolateNumber(f,l)})):l&&n.push(n.pop()+"rotate("+l+")"),c!=h?r.push({i:n.push(n.pop()+"skewX(",null,")")-2,x:d3.interpolateNumber(c,h)}):h&&n.push(n.pop()+"skewX("+h+")"),p[0]!=d[0]||p[1]!=d[1]?(i=n.push(n.pop()+"scale(",null,",",null,")"),r.push({i:i-4,x:d3.interpolateNumber(p[0],d[0])},{i:i-2,x:d3.interpolateNumber(p[1],d[1])})):(d[0]!=1||d[1]!=1)&&n.push(n.pop()+"scale("+d+")"),i=r.length,function(e){var t=-1,s;while(++t180?s-=360:s<-180&&(s+=360),function(e){return G(n+s*e,r+o*e,i+u*e)+""}},d3.interpolateLab=function(e,t){e=d3.lab(e),t=d3.lab(t);var n=e.l,r=e.a,i=e.b,s=t.l-n,o=t.a-r,u=t.b-i;return function(e){return rt(n+s*e,r+o*e,i+u*e)+""}},d3.interpolateHcl=function(e,t){e=d3.hcl(e),t=d3.hcl(t);var n=e.h,r=e.c,i=e.l,s=t.h-n,o=t.c-r,u=t.l-i;return s>180?s-=360:s<-180&&(s+=360),function(e){return et(n+s*e,r+o*e,i+u*e)+""}},d3.interpolateArray=function(e,t){var n=[],r=[],i=e.length,s=t.length,o=Math.min(e.length,t.length),u;for(u=0;u=0;)if(s=n[r])i&&i!==s.nextSibling&&i.parentNode.insertBefore(s,i),i=s;return this},Ss.sort=function(e){e=bt.apply(this,arguments);for(var t=-1,n=this.length;++t=Vs?e?"M0,"+s+"A"+s+","+s+" 0 1,1 0,"+ -s+"A"+s+","+s+" 0 1,1 0,"+s+"M0,"+e+"A"+e+","+e+" 0 1,0 0,"+ -e+"A"+e+","+e+" 0 1,0 0,"+e+"Z":"M0,"+s+"A"+s+","+s+" 0 1,1 0,"+ -s+"A"+s+","+s+" 0 1,1 0,"+s+"Z":e?"M"+s*l+","+s*c+"A"+s+","+s+" 0 "+f+",1 "+s*h+","+s*p+"L"+e*h+","+e*p+"A"+e+","+e+" 0 "+f+",0 "+e*l+","+e*c+"Z":"M"+s*l+","+s*c+"A"+s+","+s+" 0 "+f+",1 "+s*h+","+s*p+"L0,0"+"Z"}var t=Zt,n=en,r=tn,i=nn;return e.innerRadius=function(n){return arguments.length?(t=u(n),e):t},e.outerRadius=function(t){return arguments.length?(n=u(t),e):n},e.startAngle=function(t){return arguments.length?(r=u(t),e):r},e.endAngle=function(t){return arguments.length?(i=u(t),e):i},e.centroid=function(){var e=(t.apply(this,arguments)+n.apply(this,arguments))/2,s=(r.apply(this,arguments)+i.apply(this,arguments))/2+Xs;return[Math.cos(s)*e,Math.sin(s)*e]},e};var Xs=-Math.PI/2,Vs=2*Math.PI-1e-6;d3.svg.line=function(){return rn(i)};var $s=d3.map({linear:un,"linear-closed":an,"step-before":fn,"step-after":ln,basis:mn,"basis-open":gn,"basis-closed":yn,bundle:bn,cardinal:pn,"cardinal-open":cn,"cardinal-closed":hn,monotone:Nn});$s.forEach(function(e,t){t.key=e,t.closed=/-closed$/.test(e)});var Js=[0,2/3,1/3,0],Ks=[0,1/3,2/3,0],Qs=[0,1/6,2/3,1/6];d3.svg.line.radial=function(){var e=rn(Cn);return e.radius=e.x,delete e.x,e.angle=e.y,delete e.y,e},fn.reverse=ln,ln.reverse=fn,d3.svg.area=function(){return kn(i)},d3.svg.area.radial=function(){var e=kn(Cn);return e.radius=e.x,delete e.x,e.innerRadius=e.x0,delete e.x0,e.outerRadius=e.x1,delete e.x1,e.angle=e.y,delete e.y,e.startAngle=e.y0,delete e.y0,e.endAngle=e.y1,delete e.y1,e},d3.svg.chord=function(){function e(e,u){var a=t(this,s,e,u),f=t(this,o,e,u);return"M"+a.p0+r(a.r,a.p1,a.a1-a.a0)+(n(a,f)?i(a.r,a.p1,a.r,a.p0):i(a.r,a.p1,f.r,f.p0)+r(f.r,f.p1,f.a1-f.a0)+i(f.r,f.p1,a.r,a.p0))+"Z"}function t(e,t,n,r){var i=t.call(e,n,r),s=a.call(e,i,r),o=f.call(e,i,r)+Xs,u=l.call(e,i,r)+Xs;return{r:s,a0:o,a1:u,p0:[s*Math.cos(o),s*Math.sin(o)],p1:[s*Math.cos(u),s*Math.sin(u)]}}function n(e,t){return e.a0==t.a0&&e.a1==t.a1}function r(e,t,n){return"A"+e+","+e+" 0 "+ +(n>Math.PI)+",1 "+t}function i(e,t,n,r){return"Q 0,0 "+r}var s=Ln,o=An,a=On,f=tn,l=nn;return e.radius=function(t){return arguments.length?(a=u(t),e):a},e.source=function(t){return arguments.length?(s=u(t),e):s},e.target=function(t){return arguments.length?(o=u(t),e):o},e.startAngle=function(t){return arguments.length?(f=u(t),e):f},e.endAngle=function(t){return arguments.length?(l=u(t),e):l},e},d3.svg.diagonal=function(){function e(e,i){var s=t.call(this,e,i),o=n.call(this,e,i),u=(s.y+o.y)/2,a=[s,{x:s.x,y:u},{x:o.x,y:u},o];return a=a.map(r),"M"+a[0]+"C"+a[1]+" "+a[2]+" "+a[3]}var t=Ln,n=An,r=Dn;return e.source=function(n){return arguments.length?(t=u(n),e):t},e.target=function(t){return arguments.length?(n=u(t),e):n},e.projection=function(t){return arguments.length?(r=t,e):r},e},d3.svg.diagonal.radial=function(){var e=d3.svg.diagonal(),t=Dn,n=e.projection;return e.projection=function(e){return arguments.length?n(Pn(t=e)):t},e},d3.svg.mouse=d3.mouse,d3.svg.touches=d3.touches,d3.svg.symbol=function(){function e(e,r){return(Gs.get(t.call(this,e,r))||jn)(n.call(this,e,r))}var t=Bn,n=Hn;return e.type=function(n){return arguments.length?(t=u(n),e):t},e.size=function(t){return arguments.length?(n=u(t),e):n},e};var Gs=d3.map({circle:jn,cross:function(e){var t=Math.sqrt(e/5)/2;return"M"+ -3*t+","+ -t+"H"+ -t+"V"+ -3*t+"H"+t+"V"+ -t+"H"+3*t+"V"+t+"H"+t+"V"+3*t+"H"+ -t+"V"+t+"H"+ -3*t+"Z"},diamond:function(e){var t=Math.sqrt(e/(2*Zs)),n=t*Zs;return"M0,"+ -t+"L"+n+",0"+" 0,"+t+" "+ -n+",0"+"Z"},square:function(e){var t=Math.sqrt(e)/2;return"M"+ -t+","+ -t+"L"+t+","+ -t+" "+t+","+t+" "+ -t+","+t+"Z"},"triangle-down":function(e){var t=Math.sqrt(e/Ys),n=t*Ys/2;return"M0,"+n+"L"+t+","+ -n+" "+ -t+","+ -n+"Z"},"triangle-up":function(e){var t=Math.sqrt(e/Ys),n=t*Ys/2;return"M0,"+ -n+"L"+t+","+n+" "+ -t+","+n+"Z"}});d3.svg.symbolTypes=Gs.keys();var Ys=Math.sqrt(3),Zs=Math.tan(30*Math.PI/180);d3.svg.axis=function(){function e(e){e.each(function(){var e=d3.select(this),c=a==null?t.ticks?t.ticks.apply(t,u):t.domain():a,h=f==null?t.tickFormat?t.tickFormat.apply(t,u):String:f,p=qn(t,c,l),d=e.selectAll(".minor").data(p,String),v=d.enter().insert("line","g").attr("class","tick minor").style("opacity",1e-6),m=d3.transition(d.exit()).style("opacity",1e-6).remove(),g=d3.transition(d).style("opacity",1),y=e.selectAll("g").data(c,String),b=y.enter().insert("g","path").style("opacity",1e-6),w=d3.transition(y.exit()).style("opacity",1e-6).remove(),E=d3.transition(y).style("opacity",1),S,x=_t(t),T=e.selectAll(".domain").data([0]),N=T.enter().append("path").attr("class","domain"),C=d3.transition(T),k=t.copy(),L=this.__chart__||k;this.__chart__=k,b.append("line").attr("class","tick"),b.append("text");var A=b.select("line"),O=E.select("line"),M=y.select("text").text(h),_=b.select("text"),D=E.select("text");switch(n){case"bottom":S=Fn,v.attr("y2",i),g.attr("x2",0).attr("y2",i),A.attr("y2",r),_.attr("y",Math.max(r,0)+o),O.attr("x2",0).attr("y2",r),D.attr("x",0).attr("y",Math.max(r,0)+o),M.attr("dy",".71em").attr("text-anchor","middle"),C.attr("d","M"+x[0]+","+s+"V0H"+x[1]+"V"+s);break;case"top":S=Fn,v.attr("y2",-i),g.attr("x2",0).attr("y2",-i),A.attr("y2",-r),_.attr("y",-(Math.max(r,0)+o)),O.attr("x2",0).attr("y2",-r),D.attr("x",0).attr("y",-(Math.max(r,0)+o)),M.attr("dy","0em").attr("text-anchor","middle"),C.attr("d","M"+x[0]+","+ -s+"V0H"+x[1]+"V"+ -s);break;case"left":S=In,v.attr("x2",-i),g.attr("x2",-i).attr("y2",0),A.attr("x2",-r),_.attr("x",-(Math.max(r,0)+o)),O.attr("x2",-r).attr("y2",0),D.attr("x",-(Math.max(r,0)+o)).attr("y",0),M.attr("dy",".32em").attr("text-anchor","end"),C.attr("d","M"+ -s+","+x[0]+"H0V"+x[1]+"H"+ -s);break;case"right":S=In,v.attr("x2",i),g.attr("x2",i).attr("y2",0),A.attr("x2",r),_.attr("x",Math.max(r,0)+o),O.attr("x2",r).attr("y2",0),D.attr("x",Math.max(r,0)+o).attr("y",0),M.attr("dy",".32em").attr("text-anchor","start"),C.attr("d","M"+s+","+x[0]+"H0V"+x[1]+"H"+s)}if(t.ticks)b.call(S,L),E.call(S,k),w.call(S,k),v.call(S,L),g.call(S,k),m.call(S,k);else{var P=k.rangeBand()/2,H=function(e){return k(e)+P};b.call(S,H),E.call(S,H)}})}var t=d3.scale.linear(),n="bottom",r=6,i=6,s=6,o=3,u=[10],a=null,f,l=0;return e.scale=function(n){return arguments.length?(t=n,e):t},e.orient=function(t){return arguments.length?(n=t,e):n},e.ticks=function(){return arguments.length?(u=arguments,e):u},e.tickValues=function(t){return arguments.length?(a=t,e):a},e.tickFormat=function(t){return arguments.length?(f=t,e):f},e.tickSize=function(t,n,o){if(!arguments.length)return r;var u=arguments.length-1;return r=+t,i=u>1?+n:r,s=u>0?+arguments[u]:r,e},e.tickPadding=function(t){return arguments.length?(o=+t,e):o},e.tickSubdivide=function(t){return arguments.length?(l=+t,e):l},e},d3.svg.brush=function(){function e(s){s.each(function(){var s=d3.select(this),f=s.selectAll(".background").data([0]),l=s.selectAll(".extent").data([0]),c=s.selectAll(".resize").data(a,String),h;s.style("pointer-events","all").on("mousedown.brush",i).on("touchstart.brush",i),f.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),l.enter().append("rect").attr("class","extent").style("cursor","move"),c.enter().append("g").attr("class",function(e){return"resize "+e}).style("cursor",function(e){return eo[e]}).append("rect").attr("x",function(e){return/[ew]$/.test(e)?-3:null}).attr("y",function(e){return/^[ns]/.test(e)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),c.style("display",e.empty()?"none":null),c.exit().remove(),o&&(h=_t(o),f.attr("x",h[0]).attr("width",h[1]-h[0]),n(s)),u&&(h=_t(u),f.attr("y",h[0]).attr("height",h[1]-h[0]),r(s)),t(s)})}function t(e){e.selectAll(".resize").attr("transform",function(e){return"translate("+f[+/e$/.test(e)][0]+","+f[+/^s/.test(e)][1]+")"})}function n(e){e.select(".extent").attr("x",f[0][0]),e.selectAll(".extent,.n>rect,.s>rect").attr("width",f[1][0]-f[0][0])}function r(e){e.select(".extent").attr("y",f[0][1]),e.selectAll(".extent,.e>rect,.w>rect").attr("height",f[1][1]-f[0][1])}function i(){function i(){var e=d3.event.changedTouches;return e?d3.touches(v,e)[0]:d3.mouse(v)}function a(){d3.event.keyCode==32&&(S||(x=null,T[0]-=f[1][0],T[1]-=f[1][1],S=2),M())}function c(){d3.event.keyCode==32&&S==2&&(T[0]+=f[1][0],T[1]+=f[1][1],S=0,M())}function h(){var e=i(),s=!1;N&&(e[0]+=N[0],e[1]+=N[1]),S||(d3.event.altKey?(x||(x=[(f[0][0]+f[1][0])/2,(f[0][1]+f[1][1])/2]),T[0]=f[+(e[0]0?a=e:a=0:e>0&&(r.start({type:"start",alpha:a=e}),d3.timer(n.tick)),n):a},n.start=function(){function e(e,n){var i=t(r),s=-1,o=i.length,u;while(++si&&(i=u),r.push(u)}for(o=0;o0){s=-1;while(++s=a[0]&&d<=a[1]&&(l=o[d3.bisect(f,d,1,h)-1],l.y+=p,l.push(e[s]))}return o}var t=!0,n=Number,r=ar,i=or;return e.value=function(t){return arguments.length?(n=t,e):n},e.range=function(t){return arguments.length?(r=u(t),e):r},e.bins=function(t){return arguments.length?(i=typeof t=="number"?function(e){return ur(e,t)}:u(t),e):i},e.frequency=function(n){return arguments.length?(t=!!n,e):t},e},d3.layout.hierarchy=function(){function e(t,o,u){var a=i.call(n,t,o),f=uo?t:{data:t};f.depth=o,u.push(f);if(a&&(c=a.length)){var l=-1,c,h=f.children=[],p=0,d=o+1,v;while(++l0){var l=n*f/2;Pr(o,function(e){e.r+=l}),Pr(o,yr),Pr(o,function(e){e.r-=l}),f=Math.max(2*o.r/u,2*o.r/a)}return Er(o,u/2,a/2,1/f),s}var t=d3.layout.hierarchy().sort(dr),n=0,r=[1,1];return e.size=function(t){return arguments.length?(r=t,e):r},e.padding=function(t){return arguments.length?(n=+t,e):n},fr(e,t)},d3.layout.cluster=function(){function e(e,i){var s=t.call(this,e,i),o=s[0],u,a=0,f,l;Pr(o,function(e){var t=e.children;t&&t.length?(e.x=Tr(t),e.y=xr(t)):(e.x=u?a+=n(e,u):0,e.y=0,u=e)});var c=Nr(o),h=Cr(o),p=c.x-n(c,h)/2,d=h.x+n(h,c)/2;return Pr(o,function(e){e.x=(e.x-p)/(d-p)*r[0],e.y=(1-(o.y?e.y/o.y:1))*r[1]}),s}var t=d3.layout.hierarchy().sort(null).value(null),n=kr,r=[1,1];return e.separation=function(t){return arguments.length?(n=t,e):n},e.size=function(t){return arguments.length?(r=t,e):r},fr(e,t)},d3.layout.tree=function(){function e(e,i){function s(e,t){var r=e.children,i=e._tree;if(r&&(o=r.length)){var o,a=r[0],f,l=a,c,h=-1;while(++h0&&(Br(jr(o,e,r),e,h),a+=h,f+=h),l+=o._tree.mod,a+=i._tree.mod,c+=u._tree.mod,f+=s._tree.mod;o&&!Ar(s)&&(s._tree.thread=o,s._tree.mod+=l-f),i&&!Lr(u)&&(u._tree.thread=i,u._tree.mod+=a-c,r=e)}return r}var a=t.call(this,e,i),f=a[0];Pr(f,function(e,t){e._tree={ancestor:e,prelim:0,mod:0,change:0,shift:0,number:t?t._tree.number+1:0}}),s(f),o(f,-f._tree.prelim);var l=Or(f,_r),c=Or(f,Mr),h=Or(f,Dr),p=l.x-n(l,c)/2,d=c.x+n(c,l)/2,v=h.depth||1;return Pr(f,function(e){e.x=(e.x-p)/(d-p)*r[0],e.y=e.depth/v*r[1],delete e._tree}),a}var t=d3.layout.hierarchy().sort(null).value(null),n=kr,r=[1,1];return e.separation=function(t){return arguments.length?(n=t,e):n},e.size=function(t){return arguments.length?(r=t,e):r},fr(e,t)},d3.layout.treemap=function(){function e(e,t){var n=-1,r=e.length,i,s;while(++n0)u.push(f=a[d-1]),u.area+=f.area,(h=r(u,p))<=c?(a.pop(),c=h):(u.area-=u.pop().area,i(u,p,o,!1),p=Math.min(o.dx,o.dy),u.length=u.area=0,c=Infinity);u.length&&(i(u,p,o,!0),u.length=u.area=0),s.forEach(t)}}function n(t){var r=t.children;if(r&&r.length){var s=l(t),o=r.slice(),u,a=[];e(o,s.dx*s.dy/t.value),a.area=0;while(u=o.pop())a.push(u),a.area+=u.area,u.z!=null&&(i(a,u.z?s.dx:s.dy,s,!o.length),a.length=a.area=0);r.forEach(n)}}function r(e,t){var n=e.area,r,i=0,s=Infinity,o=-1,u=e.length;while(++oi&&(i=r)}return n*=n,t*=t,n?Math.max(t*i*p/n,n/(t*s*p)):Infinity}function i(e,t,n,r){var i=-1,s=e.length,o=n.x,a=n.y,f=t?u(e.area/t):0,l;if(t==n.dx){if(r||f>n.dy)f=n.dy;while(++in.dx)f=n.dx;while(++i50?n:s<-140?r:o<21?i:t)(e)}var t=d3.geo.albers(),n=d3.geo.albers().origin([-160,60]).parallels([55,65]),r=d3.geo.albers().origin([-160,20]).parallels([8,18]),i=d3.geo.albers().origin([-60,10]).parallels([8,18]);return e.scale=function(s){return arguments.length?(t.scale(s),n.scale(s*.6),r.scale(s),i.scale(s*1.5),e.translate(t.translate())):t.scale()},e.translate=function(s){if(!arguments.length)return t.translate();var o=t.scale()/1e3,u=s[0],a=s[1];return t.translate(s),n.translate([u-400*o,a+170*o]),r.translate([u-190*o,a+200*o]),i.translate([u+580*o,a+430*o]),e},e.scale(t.scale())},d3.geo.bonne=function(){function e(e){var u=e[0]*ao-r,a=e[1]*ao-i;if(s){var f=o+s-a,l=u*Math.cos(a)/f;u=f*Math.sin(l),a=f*Math.cos(l)-o}else u*=Math.cos(a),a*=-1;return[t*u+n[0],t*a+n[1]]}var t=200,n=[480,250],r,i,s,o;return e.invert=function(e){var i=(e[0]-n[0])/t,u=(e[1]-n[1])/t;if(s){var a=o+u,f=Math.sqrt(i*i+a*a);u=o+s-f,i=r+f*Math.atan2(i,a)/Math.cos(u)}else u*=-1,i/=Math.cos(u);return[i/ao,u/ao]},e.parallel=function(t){return arguments.length?(o=1/Math.tan
4 | (s=t*ao),e):s/ao},e.origin=function(t){return arguments.length?(r=t[0]*ao,i=t[1]*ao,e):[r/ao,i/ao]},e.scale=function(n){return arguments.length?(t=+n,e):t},e.translate=function(t){return arguments.length?(n=[+t[0],+t[1]],e):n},e.origin([0,0]).parallel(45)},d3.geo.equirectangular=function(){function e(e){var r=e[0]/360,i=-e[1]/360;return[t*r+n[0],t*i+n[1]]}var t=500,n=[480,250];return e.invert=function(e){var r=(e[0]-n[0])/t,i=(e[1]-n[1])/t;return[360*r,-360*i]},e.scale=function(n){return arguments.length?(t=+n,e):t},e.translate=function(t){return arguments.length?(n=[+t[0],+t[1]],e):n},e},d3.geo.mercator=function(){function e(e){var r=e[0]/360,i=-(Math.log(Math.tan(Math.PI/4+e[1]*ao/2))/ao)/360;return[t*r+n[0],t*Math.max(-0.5,Math.min(.5,i))+n[1]]}var t=500,n=[480,250];return e.invert=function(e){var r=(e[0]-n[0])/t,i=(e[1]-n[1])/t;return[360*r,2*Math.atan(Math.exp(-360*i*ao))/ao-90]},e.scale=function(n){return arguments.length?(t=+n,e):t},e.translate=function(t){return arguments.length?(n=[+t[0],+t[1]],e):n},e},d3.geo.path=function(){function e(e,t){typeof s=="function"&&(o=Ur(s.apply(this,arguments))),f(e);var n=a.length?a.join(""):null;return a=[],n}function t(e){return u(e).join(",")}function n(e){var t=i(e[0]),n=0,r=e.length;while(++n0){a.push("M");while(++o0){a.push("M");while(++lr&&(r=e),si&&(i=s)}),[[t,n],[r,i]]};var fo={Feature:Wr,FeatureCollection:Xr,GeometryCollection:Vr,LineString:$r,MultiLineString:Jr,MultiPoint:$r,MultiPolygon:Kr,Point:Qr,Polygon:Gr};d3.geo.circle=function(){function e(){}function t(e){return a.distance(e)=l*l+c*c?r[s].index=-1:(r[h].index=-1,d=r[s].angle,h=s,p=o)):(d=r[s].angle,h=s,p=o);i.push(u);for(s=0,o=0;s<2;++o)r[o].index!==-1&&(i.push(r[o].index),s++);v=i.length;for(;o=0?(n=e.ep.r,r=e.ep.l):(n=e.ep.l,r=e.ep.r),e.a===1?(o=n?n.y:-1e6,i=e.c-e.b*o,u=r?r.y:1e6,s=e.c-e.b*u):(i=n?n.x:-1e6,o=e.c-e.a*i,s=r?r.x:1e6,u=e.c-e.a*s);var a=[i,o],f=[s,u];t[e.region.l.index].push(a,f),t[e.region.r.index].push(a,f)}),t.map(function(t,n){var r=e[n][0],i=e[n][1];return t.forEach(function(e){e.angle=Math.atan2(e[0]-r,e[1]-i)}),t.sort(function(e,t){return e.angle-t.angle}).filter(function(e,n){return!n||e.angle-t[n-1].angle>1e-10})})};var ho={l:"r",r:"l"};d3.geom.delaunay=function(e){var t=e.map(function(){return[]}),n=[];return oi(e,function(n){t[n.region.l.index].push(e[n.region.r.index])}),t.forEach(function(t,r){var i=e[r],s=i[0],o=i[1];t.forEach(function(e){e.angle=Math.atan2(e[0]-s,e[1]-o)}),t.sort(function(e,t){return e.angle-t.angle});for(var u=0,a=t.length-1;u=u,l=t.y>=a,c=(l<<1)+f;e.leaf=!1,e=e.nodes[c]||(e.nodes[c]=ui()),f?n=u:i=u,l?r=a:o=a,s(e,t,n,r,i,o)}var u,a=-1,f=e.length;f&&isNaN(e[0].x)&&(e=e.map(fi));if(arguments.length<5)if(arguments.length===3)i=r=n,n=t;else{t=n=Infinity,r=i=-Infinity;while(++ar&&(r=u.x),u.y>i&&(i=u.y);var l=r-t,c=i-n;l>c?i=n+l:r=t+c}var h=ui();return h.add=function(e){s(h,e,t,n,r,i)},h.visit=function(e){ai(e,h,t,n,r,i)},e.forEach(h.add),h},d3.time={};var po=Date,vo=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];li.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){mo.setUTCDate.apply(this._,arguments)},setDay:function(){mo.setUTCDay.apply(this._,arguments)},setFullYear:function(){mo.setUTCFullYear.apply(this._,arguments)},setHours:function(){mo.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){mo.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){mo.setUTCMinutes.apply(this._,arguments)},setMonth:function(){mo.setUTCMonth.apply(this._,arguments)},setSeconds:function(){mo.setUTCSeconds.apply(this._,arguments)},setTime:function(){mo.setTime.apply(this._,arguments)}};var mo=Date.prototype,go="%a %b %e %H:%M:%S %Y",yo="%m/%d/%y",bo="%H:%M:%S",wo=vo,Eo=wo.map(ci),So=["January","February","March","April","May","June","July","August","September","October","November","December"],xo=So.map(ci);d3.time.format=function(e){function t(t){var r=[],i=-1,s=0,o,u;while(++i=12?"PM":"AM"},S:function(e){return To(e.getSeconds())},U:function(e){return To(d3.time.sundayOfYear(e))},w:function(e){return e.getDay()},W:function(e){return To(d3.time.mondayOfYear(e))},x:d3.time.format(yo),X:d3.time.format(bo),y:function(e){return To(e.getFullYear()%100)},Y:function(e){return Co(e.getFullYear()%1e4)},Z:_i,"%":function(e){return"%"}},Ho={a:vi,A:mi,b:gi,B:yi,c:bi,d:Ci,e:Ci,H:ki,I:ki,L:Oi,m:Ni,M:Li,p:Mi,S:Ai,x:wi,X:Ei,y:xi,Y:Si},Bo=/^\s*\d+/,jo=d3.map({am:0,pm:1});d3.time.format.utc=function(e){function t(e){try{po=li;var t=new po;return t._=e,n(t)}finally{po=Date}}var n=d3.time.format(e);return t.parse=function(e){try{po=li;var t=n.parse(e);return t&&t._}finally{po=Date}},t.toString=n.toString,t};var Fo=d3.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ");d3.time.format.iso=Date.prototype.toISOString?Di:Fo,Di.parse=function(e){var t=new Date(e);return isNaN(t)?null:t},Di.toString=Fo.toString,d3.time.second=Pi(function(e){return new po(Math.floor(e/1e3)*1e3)},function(e,t){e.setTime(e.getTime()+Math.floor(t)*1e3)},function(e){return e.getSeconds()}),d3.time.seconds=d3.time.second.range,d3.time.seconds.utc=d3.time.second.utc.range,d3.time.minute=Pi(function(e){return new po(Math.floor(e/6e4)*6e4)},function(e,t){e.setTime(e.getTime()+Math.floor(t)*6e4)},function(e){return e.getMinutes()}),d3.time.minutes=d3.time.minute.range,d3.time.minutes.utc=d3.time.minute.utc.range,d3.time.hour=Pi(function(e){var t=e.getTimezoneOffset()/60;return new po((Math.floor(e/36e5-t)+t)*36e5)},function(e,t){e.setTime(e.getTime()+Math.floor(t)*36e5)},function(e){return e.getHours()}),d3.time.hours=d3.time.hour.range,d3.time.hours.utc=d3.time.hour.utc.range,d3.time.day=Pi(function(e){var t=new po(1970,0);return t.setFullYear(e.getFullYear(),e.getMonth(),e.getDate()),t},function(e,t){e.setDate(e.getDate()+t)},function(e){return e.getDate()-1}),d3.time.days=d3.time.day.range,d3.time.days.utc=d3.time.day.utc.range,d3.time.dayOfYear=function(e){var t=d3.time.year(e);return Math.floor((e-t-(e.getTimezoneOffset()-t.getTimezoneOffset())*6e4)/864e5)},vo.forEach(function(e,t){e=e.toLowerCase(),t=7-t;var n=d3.time[e]=Pi(function(e){return(e=d3.time.day(e)).setDate(e.getDate()-(e.getDay()+t)%7),e},function(e,t){e.setDate(e.getDate()+Math.floor(t)*7)},function(e){var n=d3.time.year(e).getDay();return Math.floor((d3.time.dayOfYear(e)+(n+t)%7)/7)-(n!==t)});d3.time[e+"s"]=n.range,d3.time[e+"s"].utc=n.utc.range,d3.time[e+"OfYear"]=function(e){var n=d3.time.year(e).getDay();return Math.floor((d3.time.dayOfYear(e)+(n+t)%7)/7)}}),d3.time.week=d3.time.sunday,d3.time.weeks=d3.time.sunday.range,d3.time.weeks.utc=d3.time.sunday.utc.range,d3.time.weekOfYear=d3.time.sundayOfYear,d3.time.month=Pi(function(e){return e=d3.time.day(e),e.setDate(1),e},function(e,t){e.setMonth(e.getMonth()+t)},function(e){return e.getMonth()}),d3.time.months=d3.time.month.range,d3.time.months.utc=d3.time.month.utc.range,d3.time.year=Pi(function(e){return e=d3.time.day(e),e.setMonth(0,1),e},function(e,t){e.setFullYear(e.getFullYear()+t)},function(e){return e.getFullYear()}),d3.time.years=d3.time.year.range,d3.time.years.utc=d3.time.year.utc.range;var Io=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],qo=[[d3.time.second,1],[d3.time.second,5],[d3.time.second,15],[d3.time.second,30],[d3.time.minute,1],[d3.time.minute,5],[d3.time.minute,15],[d3.time.minute,30],[d3.time.hour,1],[d3.time.hour,3],[d3.time.hour,6],[d3.time.hour,12],[d3.time.day,1],[d3.time.day,2],[d3.time.week,1],[d3.time.month,1],[d3.time.month,3],[d3.time.year,1]],Ro=[[d3.time.format("%Y"),function(e){return!0}],[d3.time.format("%B"),function(e){return e.getMonth()}],[d3.time.format("%b %d"),function(e){return e.getDate()!=1}],[d3.time.format("%a %d"),function(e){return e.getDay()&&e.getDate()!=1}],[d3.time.format("%I %p"),function(e){return e.getHours()}],[d3.time.format("%I:%M"),function(e){return e.getMinutes()}],[d3.time.format(":%S"),function(e){return e.getSeconds()}],[d3.time.format(".%L"),function(e){return e.getMilliseconds()}]],Uo=d3.scale.linear(),zo=Ii(Ro);qo.year=function(e,t){return Uo.domain(e.map(Ri)).ticks(t).map(qi)},d3.time.scale=function(){return Bi(d3.scale.linear(),qo,zo)};var Wo=qo.map(function(e){return[e[0].utc,e[1]]}),Xo=[[d3.time.format.utc("%Y"),function(e){return!0}],[d3.time.format.utc("%B"),function(e){return e.getUTCMonth()}],[d3.time.format.utc("%b %d"),function(e){return e.getUTCDate()!=1}],[d3.time.format.utc("%a %d"),function(e){return e.getUTCDay()&&e.getUTCDate()!=1}],[d3.time.format.utc("%I %p"),function(e){return e.getUTCHours()}],[d3.time.format.utc("%I:%M"),function(e){return e.getUTCMinutes()}],[d3.time.format.utc(":%S"),function(e){return e.getUTCSeconds()}],[d3.time.format.utc(".%L"),function(e){return e.getUTCMilliseconds()}]],Vo=Ii(Xo);Wo.year=function(e,t){return Uo.domain(e.map(zi)).ticks(t).map(Ui)},d3.time.scale.utc=function(){return Bi(d3.scale.linear(),Wo,Vo)}})();
--------------------------------------------------------------------------------