Procházet zdrojové kódy

Added Seaborn to plotting

Also tried Q learning again... no dice... sadly
rparedis před 4 roky
rodič
revize
315973dc77

binární
doc/_build/doctrees/CBD.realtime.plotting.doctree


binární
doc/_build/doctrees/CBD.simulator.doctree


binární
doc/_build/doctrees/environment.pickle


binární
doc/_build/doctrees/examples/LivePlot.doctree


binární
doc/_build/doctrees/install.doctree


+ 72 - 4
doc/_build/html/CBD.realtime.plotting.html

@@ -318,16 +318,60 @@ of any internal workings.</p>
 </div>
 <div class="admonition attention">
 <p class="first admonition-title">Attention</p>
-<p class="last">This backend is still in beta.</p>
+<p class="last">This backend is still in active development. Some features may not work as expected.</p>
 </div>
 </dd></dl>
 
+<dl class="attribute">
+<dt id="CBD.realtime.plotting.Backend.SNS">
+<code class="descname">SNS</code><em class="property"> = 3</em><a class="headerlink" href="#CBD.realtime.plotting.Backend.SNS" title="Permalink to this definition">¶</a></dt>
+<dd><p>Use <a class="reference external" href="https://seaborn.pydata.org/">Seaborn</a>.</p>
+</dd></dl>
+
+<dl class="attribute">
+<dt id="CBD.realtime.plotting.Backend.SEABORN">
+<code class="descname">SEABORN</code><em class="property"> = 3</em><a class="headerlink" href="#CBD.realtime.plotting.Backend.SEABORN" title="Permalink to this definition">¶</a></dt>
+<dd><p>Use <a class="reference external" href="https://seaborn.pydata.org/">Seaborn</a>.</p>
+</dd></dl>
+
 <dl class="staticmethod">
 <dt id="CBD.realtime.plotting.Backend.exists">
 <em class="property">static </em><code class="descname">exists</code><span class="sig-paren">(</span><em>value</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/CBD/realtime/plotting.html#Backend.exists"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#CBD.realtime.plotting.Backend.exists" title="Permalink to this definition">¶</a></dt>
 <dd><p>Checks that a given backend exists.</p>
 </dd></dl>
 
+<dl class="staticmethod">
+<dt id="CBD.realtime.plotting.Backend.compare">
+<em class="property">static </em><code class="descname">compare</code><span class="sig-paren">(</span><em>name</em>, <em>value</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/CBD/realtime/plotting.html#Backend.compare"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#CBD.realtime.plotting.Backend.compare" title="Permalink to this definition">¶</a></dt>
+<dd><p>Compares the value against a backend name.</p>
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
+<li><strong>name</strong> (<em>str</em>) – The name of the backend to check for.</li>
+<li><strong>value</strong> (<em>int</em>) – The value to compare.</li>
+</ul>
+</td>
+</tr>
+</tbody>
+</table>
+</dd></dl>
+
+<dl class="staticmethod">
+<dt id="CBD.realtime.plotting.Backend.get">
+<em class="property">static </em><code class="descname">get</code><span class="sig-paren">(</span><em>name</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/CBD/realtime/plotting.html#Backend.get"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#CBD.realtime.plotting.Backend.get" title="Permalink to this definition">¶</a></dt>
+<dd><p>Gets the backend with a specific name if it exists and if it’s installed.</p>
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>name</strong> (<em>str</em>) – The name of the backend to get.</td>
+</tr>
+</tbody>
+</table>
+</dd></dl>
+
 </dd></dl>
 
 <dl class="class">
@@ -352,7 +396,7 @@ overhead in your code.</p>
 </div>
 <div class="admonition warning">
 <p class="first admonition-title">Warning</p>
-<p class="last">Bokeh is still in beta. Not all features will work as required.</p>
+<p class="last">Bokeh is still in active development. Not all features will work as required.</p>
 </div>
 <table class="docutils field-list" frame="void" rules="none">
 <col class="field-name" />
@@ -635,7 +679,12 @@ that they only need to change the figure information.</p>
 <col class="field-body" />
 <tbody valign="top">
 <tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
-<li><strong>*args</strong> – The arguments to add to the ‘shape’, excluding the data points.</li>
+<li><strong>*args</strong> – <p>The arguments to add to the ‘shape’, excluding the data points.</p>
+<div class="admonition note">
+<p class="first admonition-title">Note</p>
+<p class="last">The <code class="code docutils literal notranslate"><span class="pre">seaborn</span></code> backend does not require any normal args.</p>
+</div>
+</li>
 <li><strong>**kwargs</strong> – The keyword arguments to add to the ‘shape’.</li>
 </ul>
 </td>
@@ -653,7 +702,7 @@ that they only need to change the figure information.</p>
 </div>
 <dl class="method">
 <dt id="CBD.realtime.plotting.PlotKind.is_backend">
-<code class="descname">is_backend</code><span class="sig-paren">(</span><em>backend</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/CBD/realtime/plotting.html#PlotKind.is_backend"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#CBD.realtime.plotting.PlotKind.is_backend" title="Permalink to this definition">¶</a></dt>
+<code class="descname">is_backend</code><span class="sig-paren">(</span><em>*backends</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/CBD/realtime/plotting.html#PlotKind.is_backend"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#CBD.realtime.plotting.PlotKind.is_backend" title="Permalink to this definition">¶</a></dt>
 <dd><p>Checks the backend for the plot.</p>
 </dd></dl>
 
@@ -702,6 +751,7 @@ method.</li>
 <dd><ul class="first last simple">
 <li><strong>matplotlib:</strong> <code class="xref py py-func docutils literal notranslate"><span class="pre">matplotlib.axes.Axes.plot()</span></code></li>
 <li><strong>bokeh:</strong> <code class="xref py py-func docutils literal notranslate"><span class="pre">bokeh.plotting.Figure.line()</span></code></li>
+<li><strong>seaborn:</strong> <code class="xref py py-func docutils literal notranslate"><span class="pre">seaborn.lineplot()</span></code></li>
 </ul>
 </dd>
 </dl>
@@ -759,6 +809,7 @@ See the corresponding backend information to change the step “levels”.</p>
 <dd><ul class="first last simple">
 <li><strong>matplotlib:</strong> <code class="xref py py-func docutils literal notranslate"><span class="pre">matplotlib.axes.Axes.step()</span></code></li>
 <li><strong>bokeh:</strong> <code class="xref py py-func docutils literal notranslate"><span class="pre">bokeh.plotting.Figure.step()</span></code></li>
+<li><strong>seaborn:</strong> <code class="xref py py-func docutils literal notranslate"><span class="pre">seaborn.lineplot()</span></code> with <code class="code docutils literal notranslate"><span class="pre">drawstyle='steps-pre'</span></code></li>
 </ul>
 </dd>
 </dl>
@@ -816,6 +867,7 @@ See the corresponding backend information to change the shape of the indicators.
 <dd><ul class="first last simple">
 <li><strong>matplotlib:</strong> <code class="xref py py-func docutils literal notranslate"><span class="pre">matplotlib.axes.Axes.scatter()</span></code></li>
 <li><strong>bokeh:</strong> <code class="xref py py-func docutils literal notranslate"><span class="pre">bokeh.plotting.Figure.scatter()</span></code></li>
+<li><strong>seaborn:</strong> <code class="xref py py-func docutils literal notranslate"><span class="pre">seaborn.scatterplot()</span></code></li>
 </ul>
 </dd>
 </dl>
@@ -866,6 +918,16 @@ method.</li>
 <dt id="CBD.realtime.plotting.Arrow">
 <em class="property">class </em><code class="descclassname">CBD.realtime.plotting.</code><code class="descname">Arrow</code><span class="sig-paren">(</span><em>size</em>, <em>*args</em>, <em>**kwargs</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/CBD/realtime/plotting.html#Arrow"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#CBD.realtime.plotting.Arrow" title="Permalink to this definition">¶</a></dt>
 <dd><p>Bases: <a class="reference internal" href="#CBD.realtime.plotting.PlotKind" title="CBD.realtime.plotting.PlotKind"><code class="xref py py-class docutils literal notranslate"><span class="pre">CBD.realtime.plotting.PlotKind</span></code></a></p>
+<p>Draws a vector at the given position</p>
+<dl class="docutils">
+<dt>Backend Information:</dt>
+<dd><ul class="first last simple">
+<li><strong>matplotlib:</strong> <code class="xref py py-func docutils literal notranslate"><span class="pre">matplotlib.axes.Axes.scatter()</span></code></li>
+<li><strong>bokeh:</strong> Not available.</li>
+<li><strong>seaborn:</strong> Not available.</li>
+</ul>
+</dd>
+</dl>
 <dl class="method">
 <dt id="CBD.realtime.plotting.Arrow.create">
 <code class="descname">create</code><span class="sig-paren">(</span><em>figure</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/CBD/realtime/plotting.html#Arrow.create"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#CBD.realtime.plotting.Arrow.create" title="Permalink to this definition">¶</a></dt>
@@ -1049,6 +1111,12 @@ constructor.</li>
 <dd><p>Example usage for a bokeh backend.</p>
 </dd></dl>
 
+<dl class="function">
+<dt id="CBD.realtime.plotting.sea">
+<code class="descclassname">CBD.realtime.plotting.</code><code class="descname">sea</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="_modules/CBD/realtime/plotting.html#sea"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#CBD.realtime.plotting.sea" title="Permalink to this definition">¶</a></dt>
+<dd><p>Example usage for a seaborn backend.</p>
+</dd></dl>
+
 </div>
 
 

+ 44 - 8
doc/_build/html/CBD.simulator.html

@@ -278,14 +278,18 @@
 <span id="cbd-simulator-module"></span><h1>CBD.simulator module<a class="headerlink" href="#module-CBD.simulator" title="Permalink to this headline">¶</a></h1>
 <dl class="class">
 <dt id="CBD.simulator.Clock">
-<em class="property">class </em><code class="descclassname">CBD.simulator.</code><code class="descname">Clock</code><span class="sig-paren">(</span><em>delta_t</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/CBD/simulator.html#Clock"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#CBD.simulator.Clock" title="Permalink to this definition">¶</a></dt>
+<em class="property">class </em><code class="descclassname">CBD.simulator.</code><code class="descname">Clock</code><span class="sig-paren">(</span><em>delta_t</em>, <em>time=0.0</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/CBD/simulator.html#Clock"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#CBD.simulator.Clock" title="Permalink to this definition">¶</a></dt>
 <dd><p>Bases: <code class="xref py py-class docutils literal notranslate"><span class="pre">object</span></code></p>
 <p>The clock of the simulation.</p>
 <table class="docutils field-list" frame="void" rules="none">
 <col class="field-name" />
 <col class="field-body" />
 <tbody valign="top">
-<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>delta_t</strong> (<em>float</em>) – Delay in-between timesteps in the simulation.</td>
+<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
+<li><strong>delta_t</strong> (<em>float</em>) – Delay in-between timesteps in the simulation.</li>
+<li><strong>time</strong> (<em>float</em>) – The time to start the clock at.</li>
+</ul>
+</td>
 </tr>
 </tbody>
 </table>
@@ -295,6 +299,12 @@
 <dd><p>Gets the current simulation time.</p>
 </dd></dl>
 
+<dl class="method">
+<dt id="CBD.simulator.Clock.getStartTime">
+<code class="descname">getStartTime</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="_modules/CBD/simulator.html#Clock.getStartTime"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#CBD.simulator.Clock.getStartTime" title="Permalink to this definition">¶</a></dt>
+<dd><p>Gets the starting simulation time.</p>
+</dd></dl>
+
 <dl class="method">
 <dt id="CBD.simulator.Clock.step">
 <code class="descname">step</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="_modules/CBD/simulator.html#Clock.step"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#CBD.simulator.Clock.step" title="Permalink to this definition">¶</a></dt>
@@ -339,14 +349,20 @@ This class implements the semantics of CBDs.</p>
 </table>
 <dl class="method">
 <dt id="CBD.simulator.Simulator.run">
-<code class="descname">run</code><span class="sig-paren">(</span><em>term_time=None</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/CBD/simulator.html#Simulator.run"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#CBD.simulator.Simulator.run" title="Permalink to this definition">¶</a></dt>
+<code class="descname">run</code><span class="sig-paren">(</span><em>term_time=None</em>, <em>start_time=0.0</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/CBD/simulator.html#Simulator.run"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#CBD.simulator.Simulator.run" title="Permalink to this definition">¶</a></dt>
 <dd><p>Simulates the model.</p>
 <table class="docutils field-list" frame="void" rules="none">
 <col class="field-name" />
 <col class="field-body" />
 <tbody valign="top">
-<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>term_time</strong> (<em>float</em>) – When not <code class="code docutils literal notranslate"><span class="pre">None</span></code>, overwrites the
-termination time with the new value.</td>
+<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
+<li><strong>term_time</strong> (<em>float</em>) – When not <code class="code docutils literal notranslate"><span class="pre">None</span></code>, overwrites the
+termination time with the new value.</li>
+<li><strong>start_time</strong> (<em>float</em>) – The time at which to start the simulation.
+I.e. at the beginning, this amount of
+time has passed. Defaults to 0.</li>
+</ul>
+</td>
 </tr>
 </tbody>
 </table>
@@ -368,6 +384,7 @@ alive, or to interact from external sources.</p>
 <p class="first admonition-title">See also</p>
 <ul class="last simple">
 <li><a class="reference internal" href="#CBD.simulator.Simulator.getTime" title="CBD.simulator.Simulator.getTime"><code class="xref py py-func docutils literal notranslate"><span class="pre">getTime()</span></code></a></li>
+<li><a class="reference internal" href="#CBD.simulator.Simulator.getRelativeTime" title="CBD.simulator.Simulator.getRelativeTime"><code class="xref py py-func docutils literal notranslate"><span class="pre">getRelativeTime()</span></code></a></li>
 <li><a class="reference internal" href="#CBD.simulator.Simulator.getDeltaT" title="CBD.simulator.Simulator.getDeltaT"><code class="xref py py-func docutils literal notranslate"><span class="pre">getDeltaT()</span></code></a></li>
 <li><a class="reference internal" href="#CBD.simulator.Simulator.setDeltaT" title="CBD.simulator.Simulator.setDeltaT"><code class="xref py py-func docutils literal notranslate"><span class="pre">setDeltaT()</span></code></a></li>
 <li><a class="reference internal" href="#CBD.simulator.Clock" title="CBD.simulator.Clock"><code class="xref py py-class docutils literal notranslate"><span class="pre">Clock</span></code></a></li>
@@ -383,6 +400,23 @@ alive, or to interact from external sources.</p>
 <p class="first admonition-title">See also</p>
 <ul class="last simple">
 <li><a class="reference internal" href="#CBD.simulator.Simulator.getClock" title="CBD.simulator.Simulator.getClock"><code class="xref py py-func docutils literal notranslate"><span class="pre">getClock()</span></code></a></li>
+<li><a class="reference internal" href="#CBD.simulator.Simulator.getRelativeTime" title="CBD.simulator.Simulator.getRelativeTime"><code class="xref py py-func docutils literal notranslate"><span class="pre">getRelativeTime()</span></code></a></li>
+<li><a class="reference internal" href="#CBD.simulator.Simulator.getDeltaT" title="CBD.simulator.Simulator.getDeltaT"><code class="xref py py-func docutils literal notranslate"><span class="pre">getDeltaT()</span></code></a></li>
+<li><a class="reference internal" href="#CBD.simulator.Simulator.setDeltaT" title="CBD.simulator.Simulator.setDeltaT"><code class="xref py py-func docutils literal notranslate"><span class="pre">setDeltaT()</span></code></a></li>
+<li><a class="reference internal" href="#CBD.simulator.Clock" title="CBD.simulator.Clock"><code class="xref py py-class docutils literal notranslate"><span class="pre">Clock</span></code></a></li>
+</ul>
+</div>
+</dd></dl>
+
+<dl class="method">
+<dt id="CBD.simulator.Simulator.getRelativeTime">
+<code class="descname">getRelativeTime</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="_modules/CBD/simulator.html#Simulator.getRelativeTime"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#CBD.simulator.Simulator.getRelativeTime" title="Permalink to this definition">¶</a></dt>
+<dd><p>Gets the current simulation time, ignoring a starting offset.</p>
+<div class="admonition seealso">
+<p class="first admonition-title">See also</p>
+<ul class="last simple">
+<li><a class="reference internal" href="#CBD.simulator.Simulator.getClock" title="CBD.simulator.Simulator.getClock"><code class="xref py py-func docutils literal notranslate"><span class="pre">getClock()</span></code></a></li>
+<li><a class="reference internal" href="#CBD.simulator.Simulator.getTime" title="CBD.simulator.Simulator.getTime"><code class="xref py py-func docutils literal notranslate"><span class="pre">getTime()</span></code></a></li>
 <li><a class="reference internal" href="#CBD.simulator.Simulator.getDeltaT" title="CBD.simulator.Simulator.getDeltaT"><code class="xref py py-func docutils literal notranslate"><span class="pre">getDeltaT()</span></code></a></li>
 <li><a class="reference internal" href="#CBD.simulator.Simulator.setDeltaT" title="CBD.simulator.Simulator.setDeltaT"><code class="xref py py-func docutils literal notranslate"><span class="pre">setDeltaT()</span></code></a></li>
 <li><a class="reference internal" href="#CBD.simulator.Clock" title="CBD.simulator.Clock"><code class="xref py py-class docutils literal notranslate"><span class="pre">Clock</span></code></a></li>
@@ -407,6 +441,7 @@ alive, or to interact from external sources.</p>
 <ul class="last simple">
 <li><a class="reference internal" href="#CBD.simulator.Simulator.getClock" title="CBD.simulator.Simulator.getClock"><code class="xref py py-func docutils literal notranslate"><span class="pre">getClock()</span></code></a></li>
 <li><a class="reference internal" href="#CBD.simulator.Simulator.getTime" title="CBD.simulator.Simulator.getTime"><code class="xref py py-func docutils literal notranslate"><span class="pre">getTime()</span></code></a></li>
+<li><a class="reference internal" href="#CBD.simulator.Simulator.getRelativeTime" title="CBD.simulator.Simulator.getRelativeTime"><code class="xref py py-func docutils literal notranslate"><span class="pre">getRelativeTime()</span></code></a></li>
 <li><a class="reference internal" href="#CBD.simulator.Simulator.getDeltaT" title="CBD.simulator.Simulator.getDeltaT"><code class="xref py py-func docutils literal notranslate"><span class="pre">getDeltaT()</span></code></a></li>
 <li><a class="reference internal" href="#CBD.simulator.Clock" title="CBD.simulator.Clock"><code class="xref py py-class docutils literal notranslate"><span class="pre">Clock</span></code></a></li>
 </ul>
@@ -422,6 +457,7 @@ alive, or to interact from external sources.</p>
 <ul class="last simple">
 <li><a class="reference internal" href="#CBD.simulator.Simulator.getClock" title="CBD.simulator.Simulator.getClock"><code class="xref py py-func docutils literal notranslate"><span class="pre">getClock()</span></code></a></li>
 <li><a class="reference internal" href="#CBD.simulator.Simulator.getTime" title="CBD.simulator.Simulator.getTime"><code class="xref py py-func docutils literal notranslate"><span class="pre">getTime()</span></code></a></li>
+<li><a class="reference internal" href="#CBD.simulator.Simulator.getRelativeTime" title="CBD.simulator.Simulator.getRelativeTime"><code class="xref py py-func docutils literal notranslate"><span class="pre">getRelativeTime()</span></code></a></li>
 <li><a class="reference internal" href="#CBD.simulator.Simulator.setDeltaT" title="CBD.simulator.Simulator.setDeltaT"><code class="xref py py-func docutils literal notranslate"><span class="pre">setDeltaT()</span></code></a></li>
 <li><a class="reference internal" href="#CBD.simulator.Clock" title="CBD.simulator.Clock"><code class="xref py py-class docutils literal notranslate"><span class="pre">Clock</span></code></a></li>
 </ul>
@@ -562,8 +598,8 @@ set the Python Threading backend.</p>
 <code class="descname">setRealTimePlatformGameLoop</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="_modules/CBD/simulator.html#Simulator.setRealTimePlatformGameLoop"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#CBD.simulator.Simulator.setRealTimePlatformGameLoop" title="Permalink to this definition">¶</a></dt>
 <dd><p>Wrapper around the <a class="reference internal" href="#CBD.simulator.Simulator.setRealTimePlatform" title="CBD.simulator.Simulator.setRealTimePlatform"><code class="xref py py-func docutils literal notranslate"><span class="pre">setRealTimePlatform()</span></code></a> call to automatically
 set the Game Loop backend. Using this backend, it is expected the user
-will provide the required delay. Call the <a class="reference internal" href="#CBD.simulator.Simulator.realtime_gameloop_call" title="CBD.simulator.Simulator.realtime_gameloop_call"><code class="xref py py-func docutils literal notranslate"><span class="pre">realtime_gameloop_call()</span></code></a>
-method to update the simulation step.</p>
+will periodically call the <a class="reference internal" href="#CBD.simulator.Simulator.realtime_gameloop_call" title="CBD.simulator.Simulator.realtime_gameloop_call"><code class="xref py py-func docutils literal notranslate"><span class="pre">realtime_gameloop_call()</span></code></a> method to
+update the simulation step. Timing is still maintained internally.</p>
 <p>Calling this function automatically sets the simulation to realtime.</p>
 <div class="admonition seealso">
 <p class="first admonition-title">See also</p>
@@ -632,7 +668,7 @@ after the <a class="reference internal" href="#CBD.simulator.Simulator.run" titl
 
 <dl class="method">
 <dt id="CBD.simulator.Simulator.connect">
-<code class="descname">connect</code><span class="sig-paren">(</span><em>name: str</em>, <em>function</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/CBD/simulator.html#Simulator.connect"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#CBD.simulator.Simulator.connect" title="Permalink to this definition">¶</a></dt>
+<code class="descname">connect</code><span class="sig-paren">(</span><em>name</em>, <em>function</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/CBD/simulator.html#Simulator.connect"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#CBD.simulator.Simulator.connect" title="Permalink to this definition">¶</a></dt>
 <dd><p>Connect an event with an additional function.</p>
 <p>The functions will be called in the order they were connected to the
 events, with the associated arguments. The accepted signals are:</p>

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 8 - 5
doc/_build/html/_modules/CBD/lib/io.html


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 122 - 37
doc/_build/html/_modules/CBD/realtime/plotting.html


+ 42 - 10
doc/_build/html/_modules/CBD/simulator.html

@@ -293,10 +293,12 @@
 
 <span class="sd">	Args:</span>
 <span class="sd">		delta_t (float):    Delay in-between timesteps in the simulation.</span>
+<span class="sd">		time (float):       The time to start the clock at.</span>
 <span class="sd">	&quot;&quot;&quot;</span>
-	<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">delta_t</span><span class="p">):</span>
+	<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">delta_t</span><span class="p">,</span> <span class="n">time</span><span class="o">=</span><span class="mf">0.0</span><span class="p">):</span>
 		<span class="bp">self</span><span class="o">.</span><span class="n">__delta_t</span> <span class="o">=</span> <span class="n">delta_t</span>
-		<span class="bp">self</span><span class="o">.</span><span class="n">__time</span> <span class="o">=</span> <span class="mf">0.0</span>
+		<span class="bp">self</span><span class="o">.</span><span class="n">__time</span> <span class="o">=</span> <span class="n">time</span>
+		<span class="bp">self</span><span class="o">.</span><span class="n">__start_time</span> <span class="o">=</span> <span class="n">time</span>
 
 <div class="viewcode-block" id="Clock.getTime"><a class="viewcode-back" href="../../CBD.simulator.html#CBD.simulator.Clock.getTime">[docs]</a>	<span class="k">def</span> <span class="nf">getTime</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
 		<span class="sd">&quot;&quot;&quot;</span>
@@ -304,6 +306,12 @@
 <span class="sd">		&quot;&quot;&quot;</span>
 		<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">__time</span></div>
 
+<div class="viewcode-block" id="Clock.getStartTime"><a class="viewcode-back" href="../../CBD.simulator.html#CBD.simulator.Clock.getStartTime">[docs]</a>	<span class="k">def</span> <span class="nf">getStartTime</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+		<span class="sd">&quot;&quot;&quot;</span>
+<span class="sd">		Gets the starting simulation time.</span>
+<span class="sd">		&quot;&quot;&quot;</span>
+		<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">__start_time</span></div>
+
 <div class="viewcode-block" id="Clock.step"><a class="viewcode-back" href="../../CBD.simulator.html#CBD.simulator.Clock.step">[docs]</a>	<span class="k">def</span> <span class="nf">step</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
 		<span class="sd">&quot;&quot;&quot;</span>
 <span class="sd">		Executes a timestep on the simulation.</span>
@@ -376,16 +384,19 @@
 		<span class="c1"># TODO: make this variable, given more solver implementations</span>
 		<span class="bp">self</span><span class="o">.</span><span class="n">__solver</span> <span class="o">=</span> <span class="n">GaussianJordanLinearSolver</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">__logger</span><span class="p">)</span>
 
-<div class="viewcode-block" id="Simulator.run"><a class="viewcode-back" href="../../CBD.simulator.html#CBD.simulator.Simulator.run">[docs]</a>	<span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">term_time</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
+<div class="viewcode-block" id="Simulator.run"><a class="viewcode-back" href="../../CBD.simulator.html#CBD.simulator.Simulator.run">[docs]</a>	<span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">term_time</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">start_time</span><span class="o">=</span><span class="mf">0.0</span><span class="p">):</span>
 		<span class="sd">&quot;&quot;&quot;</span>
 <span class="sd">		Simulates the model.</span>
 
 <span class="sd">		Args:</span>
 <span class="sd">			term_time (float):  When not :code:`None`, overwrites the</span>
 <span class="sd">								termination time with the new value.</span>
+<span class="sd">			start_time (float): The time at which to start the simulation.</span>
+<span class="sd">								I.e. at the beginning, this amount of</span>
+<span class="sd">								time has passed. Defaults to 0.</span>
 <span class="sd">		&quot;&quot;&quot;</span>
 		<span class="bp">self</span><span class="o">.</span><span class="n">__finished</span> <span class="o">=</span> <span class="kc">False</span>
-		<span class="bp">self</span><span class="o">.</span><span class="n">model</span><span class="o">.</span><span class="n">setClock</span><span class="p">(</span><span class="n">Clock</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">getDeltaT</span><span class="p">()))</span>
+		<span class="bp">self</span><span class="o">.</span><span class="n">model</span><span class="o">.</span><span class="n">setClock</span><span class="p">(</span><span class="n">Clock</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">getDeltaT</span><span class="p">(),</span> <span class="n">start_time</span><span class="p">))</span>
 		<span class="k">if</span> <span class="n">term_time</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
 			<span class="bp">self</span><span class="o">.</span><span class="n">__termination_time</span> <span class="o">=</span> <span class="n">term_time</span>
 
@@ -408,7 +419,10 @@
 			<span class="bp">self</span><span class="o">.</span><span class="n">__lasttime</span> <span class="o">=</span> <span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">getDeltaT</span><span class="p">()</span>     <span class="c1"># Schedule next event at time 0</span>
 
 		<span class="bp">self</span><span class="o">.</span><span class="n">signal</span><span class="p">(</span><span class="s2">&quot;started&quot;</span><span class="p">)</span>
-		<span class="bp">self</span><span class="o">.</span><span class="n">__runsim</span><span class="p">()</span></div>
+		<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">__realtime</span><span class="p">:</span>
+			<span class="bp">self</span><span class="o">.</span><span class="n">__threading_backend</span><span class="o">.</span><span class="n">wait</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">__runsim</span><span class="p">)</span>
+		<span class="k">else</span><span class="p">:</span>
+			<span class="bp">self</span><span class="o">.</span><span class="n">__runsim</span><span class="p">()</span></div>
 
 	<span class="k">def</span> <span class="nf">__finish</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
 		<span class="sd">&quot;&quot;&quot;</span>
@@ -429,9 +443,10 @@
 <span class="sd">			:code:`True` if the simulation needs to be terminated and</span>
 <span class="sd">			:code:`False` otherwise.</span>
 <span class="sd">		&quot;&quot;&quot;</span>
+		<span class="n">ret</span> <span class="o">=</span> <span class="kc">False</span>
 		<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">__termination_condition</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
-			<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">__termination_condition</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">model</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">__sim_data</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span>
-		<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">__termination_time</span> <span class="o">&lt;=</span> <span class="bp">self</span><span class="o">.</span><span class="n">getTime</span><span class="p">()</span>
+			<span class="n">ret</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__termination_condition</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">model</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">__sim_data</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span>
+		<span class="k">return</span> <span class="n">ret</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">__termination_time</span> <span class="o">&lt;=</span> <span class="bp">self</span><span class="o">.</span><span class="n">getTime</span><span class="p">()</span>
 
 <div class="viewcode-block" id="Simulator.is_running"><a class="viewcode-back" href="../../CBD.simulator.html#CBD.simulator.Simulator.is_running">[docs]</a>	<span class="k">def</span> <span class="nf">is_running</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
 		<span class="sd">&quot;&quot;&quot;</span>
@@ -447,6 +462,7 @@
 
 <span class="sd">		See Also:</span>
 <span class="sd">			- :func:`getTime`</span>
+<span class="sd">			- :func:`getRelativeTime`</span>
 <span class="sd">			- :func:`getDeltaT`</span>
 <span class="sd">			- :func:`setDeltaT`</span>
 <span class="sd">			- :class:`Clock`</span>
@@ -459,12 +475,26 @@
 
 <span class="sd">		See Also:</span>
 <span class="sd">			- :func:`getClock`</span>
+<span class="sd">			- :func:`getRelativeTime`</span>
 <span class="sd">			- :func:`getDeltaT`</span>
 <span class="sd">			- :func:`setDeltaT`</span>
 <span class="sd">			- :class:`Clock`</span>
 <span class="sd">		&quot;&quot;&quot;</span>
 		<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">getClock</span><span class="p">()</span><span class="o">.</span><span class="n">getTime</span><span class="p">()</span></div>
 
+<div class="viewcode-block" id="Simulator.getRelativeTime"><a class="viewcode-back" href="../../CBD.simulator.html#CBD.simulator.Simulator.getRelativeTime">[docs]</a>	<span class="k">def</span> <span class="nf">getRelativeTime</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+		<span class="sd">&quot;&quot;&quot;</span>
+<span class="sd">		Gets the current simulation time, ignoring a starting offset.</span>
+
+<span class="sd">		See Also:</span>
+<span class="sd">			- :func:`getClock`</span>
+<span class="sd">			- :func:`getTime`</span>
+<span class="sd">			- :func:`getDeltaT`</span>
+<span class="sd">			- :func:`setDeltaT`</span>
+<span class="sd">			- :class:`Clock`</span>
+<span class="sd">		&quot;&quot;&quot;</span>
+		<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">getClock</span><span class="p">()</span><span class="o">.</span><span class="n">getTime</span><span class="p">()</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">getClock</span><span class="p">()</span><span class="o">.</span><span class="n">getStartTime</span><span class="p">()</span></div>
+
 <div class="viewcode-block" id="Simulator.setDeltaT"><a class="viewcode-back" href="../../CBD.simulator.html#CBD.simulator.Simulator.setDeltaT">[docs]</a>	<span class="k">def</span> <span class="nf">setDeltaT</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">delta_t</span><span class="p">):</span>
 		<span class="sd">&quot;&quot;&quot;</span>
 <span class="sd">		Sets the delta in-between iteration steps.</span>
@@ -475,6 +505,7 @@
 <span class="sd">		See Also:</span>
 <span class="sd">			- :func:`getClock`</span>
 <span class="sd">			- :func:`getTime`</span>
+<span class="sd">			- :func:`getRelativeTime`</span>
 <span class="sd">			- :func:`getDeltaT`</span>
 <span class="sd">			- :class:`Clock`</span>
 <span class="sd">		&quot;&quot;&quot;</span>
@@ -490,6 +521,7 @@
 <span class="sd">		See Also:</span>
 <span class="sd">			- :func:`getClock`</span>
 <span class="sd">			- :func:`getTime`</span>
+<span class="sd">			- :func:`getRelativeTime`</span>
 <span class="sd">			- :func:`setDeltaT`</span>
 <span class="sd">			- :class:`Clock`</span>
 <span class="sd">		&quot;&quot;&quot;</span>
@@ -598,8 +630,8 @@
 		<span class="sd">&quot;&quot;&quot;</span>
 <span class="sd">		Wrapper around the :func:`setRealTimePlatform` call to automatically</span>
 <span class="sd">		set the Game Loop backend. Using this backend, it is expected the user</span>
-<span class="sd">		will provide the required delay. Call the :func:`realtime_gameloop_call`</span>
-<span class="sd">		method to update the simulation step.</span>
+<span class="sd">		will periodically call the :func:`realtime_gameloop_call` method to</span>
+<span class="sd">		update the simulation step. Timing is still maintained internally.</span>
 
 <span class="sd">		Calling this function automatically sets the simulation to realtime.</span>
 
@@ -785,7 +817,7 @@
 		<span class="c1"># TODO: prints immediately after break pbar...</span>
 		<span class="bp">self</span><span class="o">.</span><span class="n">__progress_finished</span> <span class="o">=</span> <span class="kc">True</span>
 
-<div class="viewcode-block" id="Simulator.connect"><a class="viewcode-back" href="../../CBD.simulator.html#CBD.simulator.Simulator.connect">[docs]</a>	<span class="k">def</span> <span class="nf">connect</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">function</span><span class="p">):</span>
+<div class="viewcode-block" id="Simulator.connect"><a class="viewcode-back" href="../../CBD.simulator.html#CBD.simulator.Simulator.connect">[docs]</a>	<span class="k">def</span> <span class="nf">connect</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">function</span><span class="p">):</span>
 		<span class="sd">&quot;&quot;&quot;</span>
 <span class="sd">		Connect an event with an additional function.</span>
 

+ 21 - 0
doc/_build/html/_sources/examples/LivePlot.rst.txt

@@ -92,6 +92,27 @@ builtin plotting window.
 .. figure:: ../_figures/sine-wave-mpl.gif
     :width: 400
 
+Seaborn
+^^^^^^^
+`Seaborn <https://seaborn.pydata.org/>`_ is a data visualization library, built on top of `MatPlotLib`.
+Hence, it can be easily integrated and used for plotting live data. It can simply be used by providing
+the :code:`PlotManager`'s constructor with a backend argument:
+
+.. code-block:: python
+
+    manager = PlotManager(Backend.SNS)
+
+That's it. To change the theme to a `Seaborn` theme, you can either
+`use a MatPlotLib theme <https://matplotlib.org/stable/gallery/style_sheets/style_sheets_reference.html>`_ theme,
+or place the following code before the creation of the figure (see also
+`Seaborn's documentation <https://seaborn.pydata.org/generated/seaborn.set_theme.html#seaborn.set_theme>`_ on
+this topic):
+
+.. code-block:: python
+
+    import seaborn as sns
+    sns.set_theme(style="darkgrid")  # or any of whitegrid, dark, white, ticks
+
 Jupyter Notebook
 ^^^^^^^^^^^^^^^^
 These days, `Jupyter Notebooks <https://jupyter.org/>`_ are the most common way of modelling. Luckily,

+ 1 - 0
doc/_build/html/_sources/install.rst.txt

@@ -18,6 +18,7 @@ Next, there are some additional optional requirements:
 * `GraphViz <https://www.graphviz.org/download/>`_ for generating a graphical version of the dependency graph.
 * `MatPlotLib <https://matplotlib.org/>`_ for plotting data in Matplotlib.
 * `Bokeh <https://docs.bokeh.org/en/latest/index.html>`_ for plotting data in Bokeh.
+* `Seaborn <https://seaborn.pydata.org/>`_ for plotting data using Seaborn.
 
 Installation
 ------------

+ 4 - 0
doc/_build/html/_static/style.css

@@ -74,3 +74,7 @@ article.catalyst-article .class table tbody tr td.field-body p {
 .figure {
 	display: unset !important;
 }
+
+article.catalyst-article .class dl dt em.property {
+	padding-right: 12px !important;
+}

+ 19 - 0
doc/_build/html/examples/LivePlot.html

@@ -360,6 +360,24 @@ builtin plotting window.</p>
 <a class="reference internal image-reference" href="../_images/sine-wave-mpl.gif"><img alt="../_images/sine-wave-mpl.gif" src="../_images/sine-wave-mpl.gif" style="width: 400px;" /></a>
 </div>
 </div>
+<div class="section" id="seaborn">
+<h3>Seaborn<a class="headerlink" href="#seaborn" title="Permalink to this headline">¶</a></h3>
+<p><a class="reference external" href="https://seaborn.pydata.org/">Seaborn</a> is a data visualization library, built on top of <cite>MatPlotLib</cite>.
+Hence, it can be easily integrated and used for plotting live data. It can simply be used by providing
+the <code class="code docutils literal notranslate"><span class="pre">PlotManager</span></code>’s constructor with a backend argument:</p>
+<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">manager</span> <span class="o">=</span> <span class="n">PlotManager</span><span class="p">(</span><span class="n">Backend</span><span class="o">.</span><span class="n">SNS</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>That’s it. To change the theme to a <cite>Seaborn</cite> theme, you can either
+<a class="reference external" href="https://matplotlib.org/stable/gallery/style_sheets/style_sheets_reference.html">use a MatPlotLib theme</a> theme,
+or place the following code before the creation of the figure (see also
+<a class="reference external" href="https://seaborn.pydata.org/generated/seaborn.set_theme.html#seaborn.set_theme">Seaborn’s documentation</a> on
+this topic):</p>
+<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">seaborn</span> <span class="k">as</span> <span class="nn">sns</span>
+<span class="n">sns</span><span class="o">.</span><span class="n">set_theme</span><span class="p">(</span><span class="n">style</span><span class="o">=</span><span class="s2">&quot;darkgrid&quot;</span><span class="p">)</span>  <span class="c1"># or any of whitegrid, dark, white, ticks</span>
+</pre></div>
+</div>
+</div>
 <div class="section" id="jupyter-notebook">
 <h3>Jupyter Notebook<a class="headerlink" href="#jupyter-notebook" title="Permalink to this headline">¶</a></h3>
 <p>These days, <a class="reference external" href="https://jupyter.org/">Jupyter Notebooks</a> are the most common way of modelling. Luckily,
@@ -519,6 +537,7 @@ for this problem.</p>
 <li><a class="reference internal" href="#example-model">Example Model</a></li>
 <li><a class="reference internal" href="#using-matplotlib">Using MatPlotLib</a><ul>
 <li><a class="reference internal" href="#default">Default</a></li>
+<li><a class="reference internal" href="#seaborn">Seaborn</a></li>
 <li><a class="reference internal" href="#jupyter-notebook">Jupyter Notebook</a></li>
 <li><a class="reference internal" href="#tkinter">TkInter</a></li>
 </ul>

+ 19 - 3
doc/_build/html/genindex.html

@@ -415,6 +415,8 @@
       <li><a href="CBD.realtime.plotting.html#CBD.realtime.plotting.PlotHandler.close_event">close_event() (CBD.realtime.plotting.PlotHandler method)</a>
 </li>
       <li><a href="CBD.lib.endpoints.html#CBD.lib.endpoints.CollectorBlock">CollectorBlock (class in CBD.lib.endpoints)</a>
+</li>
+      <li><a href="CBD.realtime.plotting.html#CBD.realtime.plotting.Backend.compare">compare() (CBD.realtime.plotting.Backend static method)</a>
 </li>
       <li><a href="CBD.CBD.html#CBD.CBD.BaseBlock.compute">compute() (CBD.CBD.BaseBlock method)</a>
 
@@ -610,8 +612,12 @@
 </li>
       <li><a href="CBD.lib.std.html#CBD.lib.std.GenericBlock">GenericBlock (class in CBD.lib.std)</a>
 </li>
-      <li><a href="CBD.realtime.plotting.html#CBD.realtime.plotting.PlotManager.get">get() (CBD.realtime.plotting.PlotManager method)</a>
+      <li><a href="CBD.realtime.plotting.html#CBD.realtime.plotting.Backend.get">get() (CBD.realtime.plotting.Backend static method)</a>
+
+      <ul>
+        <li><a href="CBD.realtime.plotting.html#CBD.realtime.plotting.PlotManager.get">(CBD.realtime.plotting.PlotManager method)</a>
 </li>
+      </ul></li>
       <li><a href="CBD.realtime.plotting.html#CBD.realtime.plotting.PlotHandler.get_animation">get_animation() (CBD.realtime.plotting.PlotHandler method)</a>
 </li>
       <li><a href="CBD.realtime.plotting.html#CBD.realtime.plotting.PlotHandler.get_data">get_data() (CBD.realtime.plotting.PlotHandler method)</a>
@@ -683,6 +689,8 @@
       <li><a href="CBD.CBD.html#CBD.CBD.BaseBlock.getOutputNameOfInput">getOutputNameOfInput() (CBD.CBD.BaseBlock method)</a>
 </li>
       <li><a href="CBD.CBD.html#CBD.CBD.BaseBlock.getPath">getPath() (CBD.CBD.BaseBlock method)</a>
+</li>
+      <li><a href="CBD.simulator.html#CBD.simulator.Simulator.getRelativeTime">getRelativeTime() (CBD.simulator.Simulator method)</a>
 </li>
       <li><a href="CBD.CBD.html#CBD.CBD.BaseBlock.getSignal">getSignal() (CBD.CBD.BaseBlock method)</a>
 
@@ -691,6 +699,8 @@
 </li>
       </ul></li>
       <li><a href="CBD.CBD.html#CBD.CBD.BaseBlock.getSignals">getSignals() (CBD.CBD.BaseBlock method)</a>
+</li>
+      <li><a href="CBD.simulator.html#CBD.simulator.Clock.getStartTime">getStartTime() (CBD.simulator.Clock method)</a>
 </li>
       <li><a href="CBD.depGraph.html#CBD.depGraph.DepGraph.getStrongComponents">getStrongComponents() (CBD.depGraph.DepGraph method)</a>
 </li>
@@ -907,6 +917,10 @@
 <table style="width: 100%" class="indextable genindextable"><tr>
   <td style="width: 33%; vertical-align: top;"><ul>
       <li><a href="CBD.realtime.plotting.html#CBD.realtime.plotting.ScatterPlot">ScatterPlot (class in CBD.realtime.plotting)</a>
+</li>
+      <li><a href="CBD.realtime.plotting.html#CBD.realtime.plotting.sea">sea() (in module CBD.realtime.plotting)</a>
+</li>
+      <li><a href="CBD.realtime.plotting.html#CBD.realtime.plotting.Backend.SEABORN">SEABORN (CBD.realtime.plotting.Backend attribute)</a>
 </li>
       <li><a href="CBD.CBD.html#CBD.CBD.SequenceBlock">SequenceBlock (class in CBD.CBD)</a>
 </li>
@@ -945,11 +959,11 @@
       <li><a href="CBD.simulator.html#CBD.simulator.Simulator.setTerminationCondition">setTerminationCondition() (CBD.simulator.Simulator method)</a>
 </li>
       <li><a href="CBD.simulator.html#CBD.simulator.Simulator.setTerminationTime">setTerminationTime() (CBD.simulator.Simulator method)</a>
-</li>
-      <li><a href="CBD.lib.std.html#CBD.lib.std.ConstantBlock.setValue">setValue() (CBD.lib.std.ConstantBlock method)</a>
 </li>
   </ul></td>
   <td style="width: 33%; vertical-align: top;"><ul>
+      <li><a href="CBD.lib.std.html#CBD.lib.std.ConstantBlock.setValue">setValue() (CBD.lib.std.ConstantBlock method)</a>
+</li>
       <li><a href="CBD.CBD.html#CBD.CBD.Signal">Signal (class in CBD.CBD)</a>
 </li>
       <li><a href="CBD.realtime.plotting.html#CBD.realtime.plotting.PlotHandler.signal">signal() (CBD.realtime.plotting.PlotHandler method)</a>
@@ -963,6 +977,8 @@
       <li><a href="CBD.simulator.html#CBD.simulator.Simulator">Simulator (class in CBD.simulator)</a>
 </li>
       <li><a href="CBD.realtime.accurate_time.html#CBD.realtime.accurate_time.sleep">sleep() (in module CBD.realtime.accurate_time)</a>
+</li>
+      <li><a href="CBD.realtime.plotting.html#CBD.realtime.plotting.Backend.SNS">SNS (CBD.realtime.plotting.Backend attribute)</a>
 </li>
       <li><a href="CBD.solver.html#CBD.solver.GaussianJordanLinearSolver.solve">solve() (CBD.solver.GaussianJordanLinearSolver method)</a>
 

+ 1 - 0
doc/_build/html/install.html

@@ -291,6 +291,7 @@ using the <code class="code docutils literal notranslate"><span class="pre">Tk</
 <li><a class="reference external" href="https://www.graphviz.org/download/">GraphViz</a> for generating a graphical version of the dependency graph.</li>
 <li><a class="reference external" href="https://matplotlib.org/">MatPlotLib</a> for plotting data in Matplotlib.</li>
 <li><a class="reference external" href="https://docs.bokeh.org/en/latest/index.html">Bokeh</a> for plotting data in Bokeh.</li>
+<li><a class="reference external" href="https://seaborn.pydata.org/">Seaborn</a> for plotting data using Seaborn.</li>
 </ul>
 </div>
 <div class="section" id="installation">

binární
doc/_build/html/objects.inv


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
doc/_build/html/searchindex.js


+ 4 - 0
doc/_static/style.css

@@ -74,3 +74,7 @@ article.catalyst-article .class table tbody tr td.field-body p {
 .figure {
 	display: unset !important;
 }
+
+article.catalyst-article .class dl dt em.property {
+	padding-right: 12px !important;
+}

+ 21 - 0
doc/examples/LivePlot.rst

@@ -92,6 +92,27 @@ builtin plotting window.
 .. figure:: ../_figures/sine-wave-mpl.gif
     :width: 400
 
+Seaborn
+^^^^^^^
+`Seaborn <https://seaborn.pydata.org/>`_ is a data visualization library, built on top of `MatPlotLib`.
+Hence, it can be easily integrated and used for plotting live data. It can simply be used by providing
+the :code:`PlotManager`'s constructor with a backend argument:
+
+.. code-block:: python
+
+    manager = PlotManager(Backend.SNS)
+
+That's it. To change the theme to a `Seaborn` theme, you can either
+`use a MatPlotLib theme <https://matplotlib.org/stable/gallery/style_sheets/style_sheets_reference.html>`_ theme,
+or place the following code before the creation of the figure (see also
+`Seaborn's documentation <https://seaborn.pydata.org/generated/seaborn.set_theme.html#seaborn.set_theme>`_ on
+this topic):
+
+.. code-block:: python
+
+    import seaborn as sns
+    sns.set_theme(style="darkgrid")  # or any of whitegrid, dark, white, ticks
+
 Jupyter Notebook
 ^^^^^^^^^^^^^^^^
 These days, `Jupyter Notebooks <https://jupyter.org/>`_ are the most common way of modelling. Luckily,

+ 1 - 0
doc/install.rst

@@ -18,6 +18,7 @@ Next, there are some additional optional requirements:
 * `GraphViz <https://www.graphviz.org/download/>`_ for generating a graphical version of the dependency graph.
 * `MatPlotLib <https://matplotlib.org/>`_ for plotting data in Matplotlib.
 * `Bokeh <https://docs.bokeh.org/en/latest/index.html>`_ for plotting data in Bokeh.
+* `Seaborn <https://seaborn.pydata.org/>`_ for plotting data using Seaborn.
 
 Installation
 ------------

+ 43 - 19
examples/AGV/AGVEnv.py

@@ -31,6 +31,9 @@ class AGVEnv(gym.Env):
 		self.label = self.ax.text(0.02, 0.95, '', transform=self.ax.transAxes)
 		self.same_actions = 0
 
+		self.finished = False
+		plt.connect('close_event', lambda evt: self.close_event())
+
 		plt.ion()
 		plt.show()
 
@@ -74,17 +77,19 @@ class AGVEnv(gym.Env):
 
 		moment = self.physical[self.physical["time"] <= self.time].iloc[-1]
 		offset = self.euclidean(moment["x"], moment["y"], state[0], state[1])
-		# if offset > 0.1:
-		# 	reward -= 10000
-		# else:
-		reward -= (offset * 100) ** 2
+		if offset > 0.1:
+			reward -= (offset * 1000) ** 2
+		elif offset == 0:
+			reward += 10000
+		else:
+			reward += 1/(offset ** 2)
 		reward += self.euclidean(state[0], state[1], last_state[0], last_state[1])
 
 		TCP = agv.getBlockByName("TCP")
 		end_time = TCP.data[TCP.time_col][-1]
 
 
-		return state, reward, ((self.time >= end_time) or (reward < -500)), {}
+		return state, reward, (self.time >= end_time), {}
 
 	def reset(self):
 		self.time = self.physical["time"][0]
@@ -100,8 +105,9 @@ class AGVEnv(gym.Env):
 	def render(self, mode='human'):
 		# plt.draw()
 		# plt.pause(0.001)
-		self.fig.canvas.draw_idle()
-		self.fig.canvas.start_event_loop(0.001)
+		if not self.finished:
+			self.fig.canvas.draw_idle()
+			self.fig.canvas.start_event_loop(0.001)
 
 	# def close(self):
 	# 	pass
@@ -131,6 +137,10 @@ class AGVEnv(gym.Env):
 				to_drop.append(idx)
 		self.physical.drop(to_drop, inplace=True)
 
+	def close_event(self):
+		self.finished = True
+		self.close()
+
 	@staticmethod
 	def euclidean(x1, y1, x2, y2):
 		dx = x2 - x1
@@ -140,6 +150,7 @@ class AGVEnv(gym.Env):
 
 if __name__ == '__main__':
 	import random, os
+
 	env = AGVEnv()
 
 	action_space_size = env.action_space.n
@@ -148,13 +159,14 @@ if __name__ == '__main__':
 	if os.path.isfile("data.npz"):
 		file = np.load("data.npz")
 		q_table = file['Q']
-		exploration_rate = file['rate'][0]
-		print("READ FROM FILE")
+		exploration_rate = file['rate']
+		e_start = file['episode']
 	else:
 		q_table = np.zeros((state_space_size, action_space_size))
 		exploration_rate = 1
+		e_start = 0
 
-	num_episodes = 1000
+	num_episodes = 3000
 	max_steps_per_episode = 100 # but it won't go higher than 1
 
 	learning_rate = 0.1
@@ -164,15 +176,19 @@ if __name__ == '__main__':
 	max_exploration_rate = 1
 	min_exploration_rate = 0.01
 
-	exploration_decay_rate = 0.01 # if we decrease it, will learn slower
+	exploration_decay_rate = 0.001 # if we decrease it, will learn slower
 	rewards_all_episodes = []
 
+	best_reward = float('-inf')
+	best_trace = []
+
 	def discretize(state):
 		return int(state[0] * 100), int(state[1] * 100), int(np.degrees(3 * np.pi) + np.degrees(state[2]))
 
 	# Q-Learning algorithm
 	try:
-		for episode in range(num_episodes):
+		for episode in range(e_start, num_episodes):
+			if env.finished: break
 			state = env.reset()
 			dstate = discretize(state)
 			env.label.set_text(f"Episode: {episode}\nR: {exploration_rate:.4f}")
@@ -181,6 +197,7 @@ if __name__ == '__main__':
 			rewards_current_episode = 0
 
 			for step in range(max_steps_per_episode):
+				if env.finished: break
 				env.render()
 
 				# Exploration-exploitation trade-off
@@ -208,25 +225,32 @@ if __name__ == '__main__':
 			                   (max_exploration_rate - min_exploration_rate) * np.exp(-exploration_decay_rate * episode)
 
 			rewards_all_episodes.append(rewards_current_episode)
+			if rewards_current_episode > best_reward:
+				best_reward = rewards_current_episode
+				best_trace = env.states
 	except BaseException as e:
 		print("ERROR!", e)
 
 	# Calculate and print the average reward per 10 episodes
-	rewards_per_thousand_episodes = np.split(np.array(rewards_all_episodes), num_episodes / 100)
-	count = 100
-	print("********** Average  reward per thousand episodes **********\n")
+	try:
+		rewards_per_thousand_episodes = np.split(np.array(rewards_all_episodes), num_episodes // 100)
+		count = 100
+		print("********** Average  reward per thousand episodes **********\n")
 
-	for r in rewards_per_thousand_episodes:
-		print(count, ": ", str(sum(r / 100)))
-		count += 100
+		for r in rewards_per_thousand_episodes:
+			print(count, ": ", str(sum(r / 100)))
+			count += 100
+	except ValueError as e:
+		print(e, "-- Skipping...")
 
 	print("\n\n********** Vars **********\n")
 	print("Exploration Rate:", exploration_rate)
+	print("Episode:", episode)
 
 	# Print updated Q-table
 	# print("\n\n********** Q-table **********\n")
 	# print(q_table)
-	np.savez_compressed("data.npz", Q=q_table, actions=np.asarray(env.actions), rate=np.array([exploration_rate]))
+	np.savez_compressed("data.npz", Q=q_table, actions=np.asarray(best_trace), rate=exploration_rate, episode=episode)
 	# np.save("Q.npy", q_table)
 	# with open("actions.csv", 'w') as file:
 	# 	file.write(f"r,d\n")

binární
examples/AGV/data.npz


binární
examples/AGV/data2.npz


+ 1 - 0
requirements.txt

@@ -1,3 +1,4 @@
 matplotlib
 bokeh
 tqdm  # for progress bar
+socket

+ 1 - 1
src/CBD/lib/io.py

@@ -200,7 +200,7 @@ class WriteCSV(BaseBlock):
 	"""
 	def __init__(self, block_name, filename, columns, time_col="time", **kwargs):
 		BaseBlock.__init__(self, block_name, [c for c in columns if c != time_col], [])
-		self.file = open(filename, 'w')
+		self.file = open(filename, 'w', newline='')
 		self.columns = columns
 		self.time_col = time_col
 		if time_col not in columns:

+ 139 - 7
src/CBD/lib/network.py

@@ -1,10 +1,31 @@
 """
 This file contains the CBD building blocks that can be used in networking communications.
+
+Danger:
+    This code is currenly in beta and not yet ready to be used in applications. Many parts
+    may be subject to change.
+
+Note:
+    Future releases may also include non-TCP sockets.
 """
 from CBD.CBD import BaseBlock
 import socket
 
 class TCPClientSocket:
+    """
+    Client socket for a TCP connection. This class provides a simple interface
+    for the required features.
+
+    Args:
+        host (str):         The hostname of the server to connect to.
+        port (str or int):  The port of the server connection.
+
+    See Also:
+        - :class:`TCPServerSocket`
+        - :class:`ClientSender`
+        - :class:`ClientReceiver`
+        - `:code:`socket` module documentation <https://docs.python.org/3/library/socket.html>`_
+    """
     def __init__(self, host, port):
         self.address = host, port
         self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -14,18 +35,59 @@ class TCPClientSocket:
         self.socket.close()
 
     def setblocking(self, val):
+        """
+        Sets whether or not the socket must be blocking.
+
+        Args:
+            val (bool): Blocking or not.
+        """
         self.socket.setblocking(val)
 
     def send(self, data, enc="utf-8"):
+        """
+        Sends data in a certain encoding over the socket connection.
+
+        Args:
+            data (str): Message to send.
+            enc (str):  The encoding to use. When :code:`None`, no encoding will be
+                        done. This should be used if :attr:`data` is a :code:`bytes`
+                        object instead. Defaults to :code:`"utf-8"`.
+        """
         if enc is not None:
             data = data.encode(enc)
         self.socket.send(data)
 
     def recv(self, buffer_size, enc="utf-8"):
-        return self.socket.recv(buffer_size).decode(enc)
+        """
+        Receives data in a certain encoding from the socket connection.
+
+        Args:
+            buffer_size (int):  The maximum amount of data to receive.
+            enc (str):          The encoding to use. When :code:`None`, no decoding will be
+                                done. Defaults to :code:`"utf-8"`.
+        """
+        val = self.socket.recv(buffer_size)
+        if enc is not None:
+            val = val.decode(enc)
+        return val
 
 
 class TCPServerSocket:
+    """
+    Server socket for a TCP connection. This class provides a simple interface
+    for the required features.
+
+    Args:
+        host (str):         The hostname of the server to connect to.
+        port (str or int):  The port of the server connection.
+        connections (int):  The amount of clients to wait for. Defaults to 1.
+
+    See Also:
+        - :class:`TCPServerSocket`
+        - :class:`ClientSender`
+        - :class:`ClientReceiver`
+        - `:code:`socket` module documentation <https://docs.python.org/3/library/socket.html>`_
+    """
     def __init__(self, host, port, connections=1):
         self.address = host, port
         self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -33,26 +95,64 @@ class TCPServerSocket:
 
         self.socket.listen(connections)
         self.clients = []
-        for _ in range(connections):
+        clen = len(str(connections))
+        for i in range(connections):
             self.clients.append(self.socket.accept())
-            print("Connected to", self.clients[-1][1])
+            print("[{}/{}] Connected to".format((" " * clen + str(i))[-clen:], connections), self.clients[-1][1])
 
     def __del__(self):
         self.socket.close()
 
     def setblocking(self, val):
+        """
+        Sets whether or not the socket must be blocking.
+
+        Args:
+            val (bool): Blocking or not.
+        """
         self.socket.setblocking(val)
 
     def send(self, data, enc="utf-8"):
+        """
+        Sends data in a certain encoding over the socket connection.
+
+        Args:
+            data (str): Message to send.
+            enc (str):  The encoding to use. When :code:`None`, no encoding will be
+                        done. This should be used if :attr:`data` is a :code:`bytes`
+                        object instead. Defaults to :code:`"utf-8"`.
+        """
         if enc is not None:
             data = data.encode(enc)
         self.socket.send(data)
 
     def recv(self, client_id, buffer_size, enc="utf-8"):
-        return self.clients[client_id][0].recv(buffer_size).decode(enc)
+        """
+        Receives data in a certain encoding from the socket connection.
+
+        Args:
+            client_id (int):    Client id to receive data from.
+            buffer_size (int):  The maximum amount of data to receive.
+            enc (str):          The encoding to use. When :code:`None`, no decoding will be
+                                done. Defaults to :code:`"utf-8"`.
+        """
+        msg = self.clients[client_id][0].recv(buffer_size)
+        if enc is not None:
+            msg = msg.decode(enc)
+        return msg
 
 
 class ClientSender(BaseBlock):
+    """
+    Sends data over a socket connection.
+
+    Args:
+        block_name (str):           Name of the block.
+        socket (TCPClientSocket):   Socket to send the data over.
+        format (str):               Format of the data to send. Use :code:`{}` to refer
+                                    to the obtained data. Defaults to :code:`"{}"` (simple
+                                    string conversion).
+    """
     def __init__(self, block_name, socket, format="{}"):
         BaseBlock.__init__(self, block_name, ["IN1"], [])
         self.format = format
@@ -64,6 +164,21 @@ class ClientSender(BaseBlock):
 
 
 class ClientReceiver(BaseBlock):
+    """
+    Receives data over a socket connection. If no data can be obtained, the previous
+    value will be outputted.
+
+    Note:
+        The socket used will automatically be converted to a non-blocking socket.
+
+    Args:
+        block_name (str):           Name of the block.
+        socket (TCPClientSocket):   Socket to send the data over.
+        buffer_size (int):          The maximum amount of data to receive.
+        convert:                    Conversion function that's executed on all received
+                                    data. Defaults to :code:`lambda x:x` (no conversion).
+        initial (Any):              The initial value to use.
+    """
     def __init__(self, block_name, socket, buffer_size, convert=lambda x: x, initial=""):
         BaseBlock.__init__(self, block_name, [], ["OUT1"])
         self.buffer_size = buffer_size
@@ -81,6 +196,7 @@ class ClientReceiver(BaseBlock):
 
 
 class ServerSender(BaseBlock):
+    """"""
     def __init__(self, block_name, socket, format="{}"):
         BaseBlock.__init__(self, block_name, ["IN1"], [])
         self.format = format
@@ -94,17 +210,34 @@ class ServerSender(BaseBlock):
 
 
 class ServerReceiver(BaseBlock):
-    def __init__(self, block_name, socket, buffer_size, convert=lambda x: x, initial=[""]):
+    """
+    Receives data over a socket connection. If no data can be obtained, the previous
+    value will be outputted. Messages are assumed to be newline-separated.
+
+    Note:
+        The socket used will automatically be converted to a non-blocking socket.
+
+    Args:
+        block_name (str):           Name of the block.
+        socket (TCPServerSocket):   Socket to send the data over.
+        buffer_size (int):          The maximum amount of data to receive.
+        convert:                    Conversion function that's executed on all received
+                                    data. Defaults to :code:`lambda x:x` (no conversion).
+        initial (list):             The initial values to use (one for each connection).
+                                    Defaults to :code:`None` (i.e. uses a list of empty strings).
+    """
+    def __init__(self, block_name, socket, buffer_size, convert=lambda x: x, initial=None):
         BaseBlock.__init__(self, block_name, [], ["OUT%d" % (x + 1) for x in range(len(socket.clients))])
         self.buffer_size = buffer_size
         self.convert = convert
-        self.values = initial
+        self.values = [""] * len(socket.clients) if initial is None else initial
         self.last = ""
 
         self.socket = socket
         self.socket.setblocking(False)
 
     def compute(self, curIteration):
+        # TODO: clean up; add message separator...
         for i in range(len(self.socket.clients)):
             try:
                 self.last += self.socket.recv(i, self.buffer_size)
@@ -113,7 +246,6 @@ class ServerReceiver(BaseBlock):
                     self.last = sp.pop()
                     self.values[i] = self.convert(sp.pop())
             except socket.error as e: pass
-            print("OUTPUTTING:", self.values[i])
             self.appendToSignal(self.values[i], "OUT%d" % (i + 1))
 
 

+ 118 - 33
src/CBD/realtime/plotting.py

@@ -7,8 +7,17 @@ import math
 try:
 	import matplotlib.pyplot as plt
 	import matplotlib.animation as animation
+	import matplotlib
 	from matplotlib.patches import Arrow as mplArrow
 	_MPL_FOUND = True
+
+	try:
+		# Note: Seaborn is built on top of matplotlib
+		import seaborn as sns
+
+		_SNS_FOUND = True
+	except ImportError:
+		_SNS_FOUND = False
 except ImportError:
 	_MPL_FOUND = False
 
@@ -18,8 +27,8 @@ try:
 except ImportError:
 	_BOKEH_FOUND = False
 
-# TODO: Bokeh (see TODOs), GGplot, Seaborn
-# Note: Seaborn is built on top of matplotlib
+# TODO: Bokeh (see TODOs), GGplot
+# TODO: More Plot Kinds
 
 class Backend:
 	"""
@@ -49,9 +58,15 @@ class Backend:
 			|
 			
 		Attention:
-			This backend is still in beta.
+			This backend is still in active development. Some features may not work as expected.
 		"""
 
+	if _SNS_FOUND:
+		SNS         = 3
+		""" : : Use `Seaborn <https://seaborn.pydata.org/>`_."""
+		SEABORN     = 3
+		""" : : Use `Seaborn <https://seaborn.pydata.org/>`_."""
+
 	@staticmethod
 	def exists(value):
 		"""
@@ -59,6 +74,26 @@ class Backend:
 		"""
 		return value in [getattr(Backend, x) for x in dir(Backend) if not x.startswith("_") and \
 		                                                                not callable(getattr(Backend, x))]
+	@staticmethod
+	def compare(name, value):
+		"""
+		Compares the value against a backend name.
+
+		Args:
+			name (str):     The name of the backend to check for.
+			value (int):    The value to compare.
+		"""
+		return name in dir(Backend) and Backend.exists(value) and getattr(Backend, name) == value
+
+	@staticmethod
+	def get(name):
+		"""
+		Gets the backend with a specific name if it exists and if it's installed.
+
+		Args:
+			name (str):     The name of the backend to get.
+		"""
+		return getattr(Backend, name) if name in dir(Backend) else None
 
 
 class PlotHandler:
@@ -81,7 +116,7 @@ class PlotHandler:
 		:class:`PlotManager`.
 
 	Warning:
-		Bokeh is still in beta. Not all features will work as required.
+		Bokeh is still in active development. Not all features will work as required.
 
 	Raises:
 		AssertionError: if the backend cannot be located.
@@ -133,11 +168,11 @@ class PlotHandler:
 		}
 
 		# backend info:
-		if backend == Backend.MPL:
+		if Backend.compare("MPL", backend) or Backend.compare("SNS", backend):
 			self.__ani = animation.FuncAnimation(figure[0], lambda _: self.update(),
 			                                     interval=interval, frames=frames)
 			figure[0].canvas.mpl_connect('close_event', lambda evt: self.__close_event())
-		elif backend == Backend.BOKEH:
+		elif Backend.compare("BOKEH", backend):
 			curdoc().add_periodic_callback(lambda: self.update(), interval)
 			# TODO (is this even possible?):
 			curdoc().on_session_destroyed(lambda ctx: self.__close_event())
@@ -232,9 +267,9 @@ class PlotHandler:
 		See Also:
 			:func:`PlotHandler.close_event`
 		"""
-		if self.kind.is_backend(Backend.MPL):
+		if self.kind.is_backend("MPL", "SNS"):
 			plt.close(self.figure[0])
-		elif self.kind.is_backend(Backend.BOKEH):
+		elif self.kind.is_backend("BOKEH"):
 			# TODO
 			pass
 		# Make sure we close the plot if the backend fails to do so
@@ -283,7 +318,7 @@ class PlotHandler:
 		"""
 		Stops polling for updates, but keeps the plot alive.
 		"""
-		if self.kind.is_backend(Backend.MPL):
+		if self.kind.is_backend(Backend.MPL, Backend.SNS):
 			self.__ani.event_source.stop()
 		elif self.kind.is_backend(Backend.BOKEH):
 			# TODO
@@ -404,6 +439,10 @@ class PlotKind:
 
 	Args:
 		*args:      The arguments to add to the 'shape', excluding the data points.
+
+					.. note::
+						The :code:`seaborn` backend does not require any normal args.
+
 		**kwargs:   The keyword arguments to add to the 'shape'.
 
 	See Also:
@@ -417,11 +456,14 @@ class PlotKind:
 		self.args = args
 		self.kwargs = kwargs
 
-	def is_backend(self, backend):
+	def is_backend(self, *backends):
 		"""
 		Checks the backend for the plot.
 		"""
-		return self._backend == backend
+		for back in backends:
+			if Backend.compare(back, self._backend):
+				return True
+		return False
 
 	def create(self, figure):
 		"""
@@ -451,6 +493,7 @@ class LinePlot(PlotKind):
 	Backend Information:
 		- **matplotlib:** :func:`matplotlib.axes.Axes.plot`
 		- **bokeh:** :func:`bokeh.plotting.Figure.line`
+		- **seaborn:** :func:`seaborn.lineplot`
 
 	See Also:
 		- :class:`PlotKind`
@@ -458,17 +501,21 @@ class LinePlot(PlotKind):
 		- :class:`ScatterPlot`
 	"""
 	def create(self, figure):
-		if self.is_backend(Backend.MPL):
+		if self.is_backend("MPL"):
 			# matplotlib: figure[1] is the axis
 			line, = figure[1].plot([], [], *self.args, **self.kwargs)
 			return line
-		elif self.is_backend(Backend.BOKEH):
+		elif self.is_backend("BOKEH"):
 			return figure.line([], [], *self.args, **self.kwargs)
+		elif self.is_backend("SNS"):
+			# matplotlib: figure[1] is the axis
+			a = sns.lineplot(x=[0], y=[0], ax=figure[1], **self.kwargs)
+			return a.get_lines()[-1]
 
 	def update(self, element, *data):
-		if self.is_backend(Backend.MPL):
+		if self.is_backend("MPL", "SNS"):
 			element.set_data(data[0], data[1])
-		elif self.is_backend(Backend.BOKEH):
+		elif self.is_backend("BOKEH"):
 			element.data_source.data.update(x=data[0], y=data[1])
 
 
@@ -480,6 +527,7 @@ class StepPlot(PlotKind):
 	Backend Information:
 		- **matplotlib:** :func:`matplotlib.axes.Axes.step`
 		- **bokeh:** :func:`bokeh.plotting.Figure.step`
+		- **seaborn:** :func:`seaborn.lineplot` with :code:`drawstyle='steps-pre'`
 
 	See Also:
 		- :class:`PlotKind`
@@ -487,17 +535,21 @@ class StepPlot(PlotKind):
 		- :class:`StepPlot`
 	"""
 	def create(self, figure):
-		if self.is_backend(Backend.MPL):
+		if self.is_backend("MPL"):
 			# matplotlib: figure[1] is the axis
 			line, = figure[1].step([], [], *self.args, **self.kwargs)
 			return line
-		elif self.is_backend(Backend.BOKEH):
+		elif self.is_backend("BOKEH"):
 			return figure.step([], [], *self.args, **self.kwargs)
+		elif self.is_backend("SNS"):
+			# matplotlib: figure[1] is the axis
+			a = sns.lineplot(x=[], y=[], ax=figure[1], drawstyle='steps-pre', **self.kwargs)
+			return a.get_lines()[-1]
 
 	def update(self, element, *data):
-		if self.is_backend(Backend.MPL):
+		if self.is_backend("MPL", "SNS"):
 			element.set_data(data[0], data[1])
-		elif self.is_backend(Backend.BOKEH):
+		elif self.is_backend("BOKEH"):
 			element.data_source.data.update(x=data[0], y=data[1])
 
 
@@ -509,6 +561,7 @@ class ScatterPlot(PlotKind):
 	Backend Information:
 		- **matplotlib:** :func:`matplotlib.axes.Axes.scatter`
 		- **bokeh:** :func:`bokeh.plotting.Figure.scatter`
+		- **seaborn:** :func:`seaborn.scatterplot`
 
 	See Also:
 		- :class:`PlotKind`
@@ -516,50 +569,63 @@ class ScatterPlot(PlotKind):
 		- :class:`StepPlot`
 	"""
 	def create(self, figure):
-		if self.is_backend(Backend.MPL):
+		if self.is_backend("MPL"):
 			# matplotlib: figure[1] is the axis
 			pathc = figure[1].scatter([], [], *self.args, **self.kwargs)
 			return pathc
-		elif self.is_backend(Backend.BOKEH):
+		elif self.is_backend("BOKEH"):
 			return figure.scatter([], [], *self.args, **self.kwargs)
+		elif self.is_backend("SNS"):
+			# matplotlib: figure[1] is the axis
+			a = sns.scatterplot(x=[0], y=[0], ax=figure[1], **self.kwargs)
+			return a.findobj(matplotlib.collections.PathCollection)[-1]
+
 
 	def update(self, element, *data):
-		if self.is_backend(Backend.MPL):
+		if self.is_backend("MPL", "SNS"):
 			element.set_offsets(list(zip(*data)))
-		elif self.is_backend(Backend.BOKEH):
+		elif self.is_backend("BOKEH"):
 			element.data_source.data.update(x=data[0], y=data[1])
 
 
 class Arrow(PlotKind):
+	"""
+	Draws a vector at the given position
+
+	Backend Information:
+		- **matplotlib:** :func:`matplotlib.axes.Axes.scatter`
+		- **bokeh:** Not available.
+		- **seaborn:** Not available.
+	"""
 	def __init__(self, size, *args, **kwargs):
 		PlotKind.__init__(self, *args, **kwargs)
 		self.position = 0.0, 0.0
 		self.size = size
 
 	def create(self, figure):
-		if self.is_backend(Backend.MPL):
+		if self.is_backend("MPL"):
 			# matplotlib: figure[1] is the axis
 			arrow = mplArrow(*self.position, self.size, self.size, *self.args, **self.kwargs)
 			line = figure[1].add_patch(arrow)
 			line.set_zorder(20)
 			return line
-		elif self.is_backend(Backend.BOKEH):
-			raise NotImplementedError("This feature is not yet available.")
+		elif self.is_backend("BOKEH", "SNS"):
+			raise NotImplementedError("This feature is not (yet) available for this backend.")
 
 	def update(self, element, *data):
 		heading = data[1]
 		x = math.cos(heading[-1]) * self.size
 		y = math.sin(heading[-1]) * self.size
 
-		if self.is_backend(Backend.MPL):
+		if self.is_backend("MPL"):
 			ax = element.axes
 			element.remove()
 			arrow = mplArrow(*self.position, x, y, *self.args, **self.kwargs)
 			line = ax.add_patch(arrow)
 			line.set_zorder(20)
 			return line
-		elif self.is_backend(Backend.BOKEH):
-			raise NotImplementedError("This feature is not yet available.")
+		elif self.is_backend("BOKEH", "SNS"):
+			raise NotImplementedError("This feature is not (yet) available for this backend.")
 
 
 class PlotManager:
@@ -577,7 +643,7 @@ class PlotManager:
 		- :class:`Backend`
 		- :class:`PlotHandler`
 	"""
-	def __init__(self, backend=Backend.MPL):
+	def __init__(self, backend=Backend.get("MPL")):
 		assert Backend.exists(backend), "Invalid backend."
 		self.__handlers = {}
 		self.backend = backend
@@ -702,7 +768,7 @@ def mpl():
 	manager = PlotManager()
 	manager.register("sin", __Block('sin'), (fig, ax), ScatterPlot())
 	manager.register("cos", __Block('cos'), (fig, ax), LinePlot(c='red'))
-	manager.connect('sin', 'update', lambda d, axis=ax: axis.set_xlim(PlotHandler.follow(d[0], 10.0, 0.0)))
+	manager.connect('sin', 'update', lambda d, axis=ax: axis.set_xlim(follow(d[0], 10.0, 0.0)))
 
 	plt.show()
 
@@ -725,7 +791,7 @@ def bkh():
 		lower, upper = limits
 		fig.x_range.start = lower
 		fig.x_range.end = upper
-	manager.connect('sin', 'update', lambda d: set_xlim(PlotHandler.follow(d[0], 10.0, 0.0)))
+	manager.connect('sin', 'update', lambda d: set_xlim(follow(d[0], 10.0, 0.0)))
 
 	session = push_session(curdoc())
 	session.show()
@@ -737,5 +803,24 @@ def bkh():
 		time.sleep(0.1)
 
 
+def sea():
+	"""
+	Example usage for a seaborn backend.
+	"""
+	sns.set_theme(style="darkgrid")
+
+	import matplotlib.pyplot as plt
+	fig = plt.figure(figsize=(5, 5), dpi=100)
+	ax = fig.add_subplot(111)
+	ax.set_ylim((-1, 1))
+
+	manager = PlotManager(Backend.SNS)
+	manager.register("sin", __Block('sin'), (fig, ax), ScatterPlot())
+	manager.register("cos", __Block('cos'), (fig, ax), LinePlot(color='red'))
+	manager.connect('sin', 'update', lambda d, axis=ax: axis.set_xlim(follow(d[0], 10.0, 0.0)))
+
+	plt.show()
+
+
 if __name__ == '__main__':
-	bkh()
+	sea()

+ 3 - 3
src/CBD/simulator.py

@@ -357,8 +357,8 @@ class Simulator:
 		"""
 		Wrapper around the :func:`setRealTimePlatform` call to automatically
 		set the Game Loop backend. Using this backend, it is expected the user
-		will provide the required delay. Call the :func:`realtime_gameloop_call`
-		method to update the simulation step.
+		will periodically call the :func:`realtime_gameloop_call` method to
+		update the simulation step. Timing is still maintained internally.
 
 		Calling this function automatically sets the simulation to realtime.
 
@@ -544,7 +544,7 @@ class Simulator:
 		# TODO: prints immediately after break pbar...
 		self.__progress_finished = True
 
-	def connect(self, name: str, function):
+	def connect(self, name, function):
 		"""
 		Connect an event with an additional function.