Visualising SimPy Results: Making Data Speak
<p>Numbers tell the story. Visualisations make people listen.</p> <h2 id="essential-plots">Essential Plots</h2> <p>Every simulation should produce:</p> <ol> <li><strong>Queue length over time</strong> - System behaviour</li> <li><strong>Wait time distribution</strong> - Customer experience</li> <li><strong>Utilisation over time</strong> - Resource efficiency</li> <li><strong>Throughput chart</strong> - System output</li> </ol> <h2 id="setup">Setup</h2> <div class="code-block"><pre><span></span><code><span class="kn">import</span><span class="w"> </span><span class="nn">simpy</span> <span class="kn">import</span><span class="w"> </span><span class="nn">random</span> <span class="kn">import</span><span class="w"> </span><span class="nn">pandas</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nn">pd</span> <span class="kn">import</span><span class="w"> </span><span class="nn">matplotlib.pyplot</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nn">plt</span> <span class="kn">import</span><span class="w"> </span><span class="nn">numpy</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nn">np</span> <span class="c1"># Style</span> <span class="n">plt</span><span class="o">.</span><span class="n">style</span><span class="o">.</span><span class="n">use</span><span class="p">(</span><span class="s1">'seaborn-v0_8-whitegrid'</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">rcParams</span><span class="p">[</span><span class="s1">'figure.figsize'</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">6</span><span class="p">)</span> </code></pre></div> <h2 id="queue-length-over-time">Queue Length Over Time</h2> <div class="code-block"><pre><span></span><code><span class="k">def</span><span class="w"> </span><span class="nf">plot_queue_length</span><span class="p">(</span><span class="n">time_series_df</span><span class="p">):</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span> <span class="n">plt</span><span class="o">.</span><span class="n">step</span><span class="p">(</span><span class="n">time_series_df</span><span class="p">[</span><span class="s1">'time'</span><span class="p">],</span> <span class="n">time_series_df</span><span class="p">[</span><span class="s1">'queue_length'</span><span class="p">],</span> <span class="n">where</span><span class="o">=</span><span class="s1">'post'</span><span class="p">,</span> <span class="n">linewidth</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">fill_between</span><span class="p">(</span><span class="n">time_series_df</span><span class="p">[</span><span class="s1">'time'</span><span class="p">],</span> <span class="n">time_series_df</span><span class="p">[</span><span class="s1">'queue_length'</span><span class="p">],</span> <span class="n">step</span><span class="o">=</span><span class="s1">'post'</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s1">'Time'</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s1">'Queue Length'</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s1">'Queue Length Over Time'</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">tight_layout</span><span class="p">()</span> <span class="n">plt</span><span class="o">.</span><span class="n">savefig</span><span class="p">(</span><span class="s1">'queue_length.png'</span><span class="p">,</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> </code></pre></div> <h2 id="wait-time-histogram">Wait Time Histogram</h2> <div class="code-block"><pre><span></span><code><span class="k">def</span><span class="w"> </span><span class="nf">plot_wait_distribution</span><span class="p">(</span><span class="n">wait_times</span><span class="p">):</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span> <span class="n">plt</span><span class="o">.</span><span class="n">hist</span><span class="p">(</span><span class="n">wait_times</span><span class="p">,</span> <span class="n">bins</span><span class="o">=</span><span class="mi">30</span><span class="p">,</span> <span class="n">edgecolor</span><span class="o">=</span><span class="s1">'white'</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.7</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">axvline</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">mean</span><span class="p">(</span><span class="n">wait_times</span><span class="p">),</span> <span class="n">color</span><span class="o">=</span><span class="s1">'red'</span><span class="p">,</span> <span class="n">linestyle</span><span class="o">=</span><span class="s1">'--'</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s1">'Mean: </span><span class="si">{</span><span class="n">np</span><span class="o">.</span><span class="n">mean</span><span class="p">(</span><span class="n">wait_times</span><span class="p">)</span><span class="si">:</span><span class="s1">.2f</span><span class="si">}</span><span class="s1">'</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">axvline</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">percentile</span><span class="p">(</span><span class="n">wait_times</span><span class="p">,</span> <span class="mi">95</span><span class="p">),</span> <span class="n">color</span><span class="o">=</span><span class="s1">'orange'</span><span class="p">,</span> <span class="n">linestyle</span><span class="o">=</span><span class="s1">'--'</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s1">'95th percentile: </span><span class="si">{</span><span class="n">np</span><span class="o">.</span><span class="n">percentile</span><span class="p">(</span><span class="n">wait_times</span><span class="p">,</span><span class="w"> </span><span class="mi">95</span><span class="p">)</span><span class="si">:</span><span class="s1">.2f</span><span class="si">}</span><span class="s1">'</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s1">'Wait Time'</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s1">'Frequency'</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s1">'Distribution of Wait Times'</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span> <span class="n">plt</span><span class="o">.</span><span class="n">tight_layout</span><span class="p">()</span> <span class="n">plt</span><span class="o">.</span><span class="n">savefig</span><span class="p">(</span><span class="s1">'wait_distribution.png'</span><span class="p">,</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> </code></pre></div> <h2 id="utilisation-chart">Utilisation Chart</h2> <div class="code-block"><pre><span></span><code><span class="k">def</span><span class="w"> </span><span class="nf">plot_utilisation</span><span class="p">(</span><span class="n">time_series_df</span><span class="p">,</span> <span class="n">resource_name</span><span class="o">=</span><span class="s1">'server'</span><span class="p">):</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span> <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">time_series_df</span><span class="p">[</span><span class="s1">'time'</span><span class="p">],</span> <span class="n">time_series_df</span><span class="p">[</span><span class="sa">f</span><span class="s1">'</span><span class="si">{</span><span class="n">resource_name</span><span class="si">}</span><span class="s1">_utilisation'</span><span class="p">],</span> <span class="n">linewidth</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">fill_between</span><span class="p">(</span><span class="n">time_series_df</span><span class="p">[</span><span class="s1">'time'</span><span class="p">],</span> <span class="n">time_series_df</span><span class="p">[</span><span class="sa">f</span><span class="s1">'</span><span class="si">{</span><span class="n">resource_name</span><span class="si">}</span><span class="s1">_utilisation'</span><span class="p">],</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">)</span> <span class="n">avg_util</span> <span class="o">=</span> <span class="n">time_series_df</span><span class="p">[</span><span class="sa">f</span><span class="s1">'</span><span class="si">{</span><span class="n">resource_name</span><span class="si">}</span><span class="s1">_utilisation'</span><span class="p">]</span><span class="o">.</span><span class="n">mean</span><span class="p">()</span> <span class="n">plt</span><span class="o">.</span><span class="n">axhline</span><span class="p">(</span><span class="n">avg_util</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s1">'red'</span><span class="p">,</span> <span class="n">linestyle</span><span class="o">=</span><span class="s1">'--'</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s1">'Average: </span><span class="si">{</span><span class="n">avg_util</span><span class="si">:</span><span class="s1">.1%</span><span class="si">}</span><span class="s1">'</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s1">'Time'</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s1">'Utilisation'</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">ylim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mf">1.1</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="sa">f</span><span class="s1">'</span><span class="si">{</span><span class="n">resource_name</span><span class="o">.</span><span class="n">title</span><span class="p">()</span><span class="si">}</span><span class="s1"> Utilisation Over Time'</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span> <span class="n">plt</span><span class="o">.</span><span class="n">tight_layout</span><span class="p">()</span> <span class="n">plt</span><span class="o">.</span><span class="n">savefig</span><span class="p">(</span><span class="s1">'utilisation.png'</span><span class="p">,</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> </code></pre></div> <h2 id="box-plot-comparison">Box Plot Comparison</h2> <p>Compare scenarios:</p> <div class="code-block"><pre><span></span><code><span class="k">def</span><span class="w"> </span><span class="nf">plot_scenario_comparison</span><span class="p">(</span><span class="n">results_dict</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""results_dict = {'Scenario A': wait_times_a, 'Scenario B': wait_times_b}"""</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span> <span class="n">data</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">results_dict</span><span class="o">.</span><span class="n">values</span><span class="p">())</span> <span class="n">labels</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">results_dict</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span> <span class="n">plt</span><span class="o">.</span><span class="n">boxplot</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">labels</span><span class="o">=</span><span class="n">labels</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s1">'Wait Time'</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s1">'Wait Time Comparison Across Scenarios'</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">tight_layout</span><span class="p">()</span> <span class="n">plt</span><span class="o">.</span><span class="n">savefig</span><span class="p">(</span><span class="s1">'comparison.png'</span><span class="p">,</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> </code></pre></div> <h2 id="throughput-over-time">Throughput Over Time</h2> <div class="code-block"><pre><span></span><code><span class="k">def</span><span class="w"> </span><span class="nf">plot_throughput</span><span class="p">(</span><span class="n">entity_df</span><span class="p">,</span> <span class="n">window</span><span class="o">=</span><span class="mi">50</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""Cumulative completions and rolling throughput."""</span> <span class="n">fig</span><span class="p">,</span> <span class="p">(</span><span class="n">ax1</span><span class="p">,</span> <span class="n">ax2</span><span class="p">)</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">8</span><span class="p">))</span> <span class="c1"># Cumulative completions</span> <span class="n">entity_df</span> <span class="o">=</span> <span class="n">entity_df</span><span class="o">.</span><span class="n">sort_values</span><span class="p">(</span><span class="s1">'departure'</span><span class="p">)</span> <span class="n">entity_df</span><span class="p">[</span><span class="s1">'cumulative'</span><span class="p">]</span> <span class="o">=</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">entity_df</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="n">ax1</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">entity_df</span><span class="p">[</span><span class="s1">'departure'</span><span class="p">],</span> <span class="n">entity_df</span><span class="p">[</span><span class="s1">'cumulative'</span><span class="p">])</span> <span class="n">ax1</span><span class="o">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s1">'Time'</span><span class="p">)</span> <span class="n">ax1</span><span class="o">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s1">'Cumulative Completions'</span><span class="p">)</span> <span class="n">ax1</span><span class="o">.</span><span class="n">set_title</span><span class="p">(</span><span class="s1">'Cumulative Throughput'</span><span class="p">)</span> <span class="c1"># Rolling throughput</span> <span class="n">entity_df</span><span class="p">[</span><span class="s1">'throughput'</span><span class="p">]</span> <span class="o">=</span> <span class="n">entity_df</span><span class="p">[</span><span class="s1">'cumulative'</span><span class="p">]</span> <span class="o">/</span> <span class="n">entity_df</span><span class="p">[</span><span class="s1">'departure'</span><span class="p">]</span> <span class="n">ax2</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">entity_df</span><span class="p">[</span><span class="s1">'departure'</span><span class="p">],</span> <span class="n">entity_df</span><span class="p">[</span><span class="s1">'throughput'</span><span class="p">])</span> <span class="n">ax2</span><span class="o">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s1">'Time'</span><span class="p">)</span> <span class="n">ax2</span><span class="o">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s1">'Throughput (per time unit)'</span><span class="p">)</span> <span class="n">ax2</span><span class="o">.</span><span class="n">set_title</span><span class="p">(</span><span class="s1">'Throughput Rate'</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">tight_layout</span><span class="p">()</span> <span class="n">plt</span><span class="o">.</span><span class="n">savefig</span><span class="p">(</span><span class="s1">'throughput.png'</span><span class="p">,</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> </code></pre></div> <h2 id="multiple-resources">Multiple Resources</h2> <div class="code-block"><pre><span></span><code><span class="k">def</span><span class="w"> </span><span class="nf">plot_multiple_resources</span><span class="p">(</span><span class="n">time_series_df</span><span class="p">,</span> <span class="n">resources</span><span class="p">):</span> <span class="n">fig</span><span class="p">,</span> <span class="n">axes</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">resources</span><span class="p">),</span> <span class="mi">1</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">4</span><span class="o">*</span><span class="nb">len</span><span class="p">(</span><span class="n">resources</span><span class="p">)))</span> <span class="k">for</span> <span class="n">ax</span><span class="p">,</span> <span class="n">resource</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">axes</span><span class="p">,</span> <span class="n">resources</span><span class="p">):</span> <span class="n">ax</span><span class="o">.</span><span class="n">step</span><span class="p">(</span><span class="n">time_series_df</span><span class="p">[</span><span class="s1">'time'</span><span class="p">],</span> <span class="n">time_series_df</span><span class="p">[</span><span class="sa">f</span><span class="s1">'</span><span class="si">{</span><span class="n">resource</span><span class="si">}</span><span class="s1">_queue'</span><span class="p">],</span> <span class="n">where</span><span class="o">=</span><span class="s1">'post'</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s1">'Queue'</span><span class="p">)</span> <span class="n">ax</span><span class="o">.</span><span class="n">step</span><span class="p">(</span><span class="n">time_series_df</span><span class="p">[</span><span class="s1">'time'</span><span class="p">],</span> <span class="n">time_series_df</span><span class="p">[</span><span class="sa">f</span><span class="s1">'</span><span class="si">{</span><span class="n">resource</span><span class="si">}</span><span class="s1">_busy'</span><span class="p">],</span> <span class="n">where</span><span class="o">=</span><span class="s1">'post'</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s1">'In Service'</span><span class="p">)</span> <span class="n">ax</span><span class="o">.</span><span class="n">set_xlabel</span><span class="p">(</span><span class="s1">'Time'</span><span class="p">)</span> <span class="n">ax</span><span class="o">.</span><span class="n">set_ylabel</span><span class="p">(</span><span class="s1">'Count'</span><span class="p">)</span> <span class="n">ax</span><span class="o">.</span><span class="n">set_title</span><span class="p">(</span><span class="sa">f</span><span class="s1">'</span><span class="si">{</span><span class="n">resource</span><span class="o">.</span><span class="n">title</span><span class="p">()</span><span class="si">}</span><span class="s1">'</span><span class="p">)</span> <span class="n">ax</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span> <span class="n">plt</span><span class="o">.</span><span class="n">tight_layout</span><span class="p">()</span> <span class="n">plt</span><span class="o">.</span><span class="n">savefig</span><span class="p">(</span><span class="s1">'resources.png'</span><span class="p">,</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> </code></pre></div> <h2 id="heatmap-of-arrivals">Heatmap of Arrivals</h2> <div class="code-block"><pre><span></span><code><span class="k">def</span><span class="w"> </span><span class="nf">plot_arrival_heatmap</span><span class="p">(</span><span class="n">entity_df</span><span class="p">,</span> <span class="n">bins_x</span><span class="o">=</span><span class="mi">24</span><span class="p">,</span> <span class="n">bins_y</span><span class="o">=</span><span class="mi">7</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""Show arrival patterns (e.g., hour of day vs day of week)."""</span> <span class="c1"># Assuming arrival times can be converted to hour/day</span> <span class="n">entity_df</span><span class="p">[</span><span class="s1">'hour'</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">entity_df</span><span class="p">[</span><span class="s1">'arrival'</span><span class="p">]</span> <span class="o">%</span> <span class="mi">24</span><span class="p">)</span><span class="o">.</span><span class="n">astype</span><span class="p">(</span><span class="nb">int</span><span class="p">)</span> <span class="n">entity_df</span><span class="p">[</span><span class="s1">'day'</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">entity_df</span><span class="p">[</span><span class="s1">'arrival'</span><span class="p">]</span> <span class="o">//</span> <span class="mi">24</span> <span class="o">%</span> <span class="mi">7</span><span class="p">)</span><span class="o">.</span><span class="n">astype</span><span class="p">(</span><span class="nb">int</span><span class="p">)</span> <span class="n">heatmap_data</span> <span class="o">=</span> <span class="n">entity_df</span><span class="o">.</span><span class="n">groupby</span><span class="p">([</span><span class="s1">'day'</span><span class="p">,</span> <span class="s1">'hour'</span><span class="p">])</span><span class="o">.</span><span class="n">size</span><span class="p">()</span><span class="o">.</span><span class="n">unstack</span><span class="p">(</span><span class="n">fill_value</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span> <span class="mi">5</span><span class="p">))</span> <span class="n">plt</span><span class="o">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">heatmap_data</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="s1">'auto'</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s1">'YlOrRd'</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">colorbar</span><span class="p">(</span><span class="n">label</span><span class="o">=</span><span class="s1">'Arrivals'</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s1">'Hour of Day'</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s1">'Day of Week'</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s1">'Arrival Pattern Heatmap'</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">tight_layout</span><span class="p">()</span> <span class="n">plt</span><span class="o">.</span><span class="n">savefig</span><span class="p">(</span><span class="s1">'heatmap.png'</span><span class="p">,</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> </code></pre></div> <h2 id="cdf-plot">CDF Plot</h2> <div class="code-block"><pre><span></span><code><span class="k">def</span><span class="w"> </span><span class="nf">plot_cdf</span><span class="p">(</span><span class="n">wait_times</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s1">'Wait Time'</span><span class="p">):</span> <span class="n">sorted_data</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">wait_times</span><span class="p">)</span> <span class="n">cdf</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">sorted_data</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">/</span> <span class="nb">len</span><span class="p">(</span><span class="n">sorted_data</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span> <span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">sorted_data</span><span class="p">,</span> <span class="n">cdf</span><span class="p">,</span> <span class="n">linewidth</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="n">label</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s1">'Cumulative Probability'</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="sa">f</span><span class="s1">'Cumulative Distribution of </span><span class="si">{</span><span class="n">label</span><span class="si">}</span><span class="s1">'</span><span class="p">)</span> <span class="c1"># Mark key percentiles</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="p">[</span><span class="mi">50</span><span class="p">,</span> <span class="mi">90</span><span class="p">,</span> <span class="mi">95</span><span class="p">,</span> <span class="mi">99</span><span class="p">]:</span> <span class="n">val</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">percentile</span><span class="p">(</span><span class="n">wait_times</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">axhline</span><span class="p">(</span><span class="n">p</span><span class="o">/</span><span class="mi">100</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s1">'gray'</span><span class="p">,</span> <span class="n">linestyle</span><span class="o">=</span><span class="s1">':'</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.5</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">axvline</span><span class="p">(</span><span class="n">val</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s1">'gray'</span><span class="p">,</span> <span class="n">linestyle</span><span class="o">=</span><span class="s1">':'</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.5</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="sa">f</span><span class="s1">'</span><span class="si">{</span><span class="n">p</span><span class="si">}</span><span class="s1">%: </span><span class="si">{</span><span class="n">val</span><span class="si">:</span><span class="s1">.1f</span><span class="si">}</span><span class="s1">'</span><span class="p">,</span> <span class="n">xy</span><span class="o">=</span><span class="p">(</span><span class="n">val</span><span class="p">,</span> <span class="n">p</span><span class="o">/</span><span class="mi">100</span><span class="p">),</span> <span class="n">xytext</span><span class="o">=</span><span class="p">(</span><span class="n">val</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">p</span><span class="o">/</span><span class="mi">100</span> <span class="o">-</span> <span class="mf">0.05</span><span class="p">))</span> <span class="n">plt</span><span class="o">.</span><span class="n">tight_layout</span><span class="p">()</span> <span class="n">plt</span><span class="o">.</span><span class="n">savefig</span><span class="p">(</span><span class="s1">'cdf.png'</span><span class="p">,</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> </code></pre></div> <h2 id="confidence-interval-plot">Confidence Interval Plot</h2> <div class="code-block"><pre><span></span><code><span class="k">def</span><span class="w"> </span><span class="nf">plot_confidence_intervals</span><span class="p">(</span><span class="n">replication_results</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""replication_results = list of mean wait times from each replication."""</span> <span class="n">n</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">replication_results</span><span class="p">)</span> <span class="n">mean</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">mean</span><span class="p">(</span><span class="n">replication_results</span><span class="p">)</span> <span class="n">std</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">std</span><span class="p">(</span><span class="n">replication_results</span><span class="p">,</span> <span class="n">ddof</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> <span class="n">ci</span> <span class="o">=</span> <span class="mf">1.96</span> <span class="o">*</span> <span class="n">std</span> <span class="o">/</span> <span class="n">np</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span> <span class="n">plt</span><span class="o">.</span><span class="n">bar</span><span class="p">([</span><span class="s1">'Mean Wait Time'</span><span class="p">],</span> <span class="p">[</span><span class="n">mean</span><span class="p">],</span> <span class="n">yerr</span><span class="o">=</span><span class="p">[</span><span class="n">ci</span><span class="p">],</span> <span class="n">capsize</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s1">'steelblue'</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s1">'Time'</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="sa">f</span><span class="s1">'Mean Wait Time with 95% CI</span><span class="se">\n</span><span class="s1">(n=</span><span class="si">{</span><span class="n">n</span><span class="si">}</span><span class="s1"> replications)'</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">tight_layout</span><span class="p">()</span> <span class="n">plt</span><span class="o">.</span><span class="n">savefig</span><span class="p">(</span><span class="s1">'confidence.png'</span><span class="p">,</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">150</span><span class="p">)</span> <span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> </code></pre></div> <h2 id="interactive-with-plotly">Interactive with Plotly</h2> <p>For exploration:</p> <div class="code-block"><pre><span></span><code><span class="kn">import</span><span class="w"> </span><span class="nn">plotly.express</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nn">px</span> <span class="kn">import</span><span class="w"> </span><span class="nn">plotly.graph_objects</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nn">go</span> <span class="k">def</span><span class="w"> </span><span class="nf">interactive_queue</span><span class="p">(</span><span class="n">time_series_df</span><span class="p">):</span> <span class="n">fig</span> <span class="o">=</span> <span class="n">px</span><span class="o">.</span><span class="n">line</span><span class="p">(</span><span class="n">time_series_df</span><span class="p">,</span> <span class="n">x</span><span class="o">=</span><span class="s1">'time'</span><span class="p">,</span> <span class="n">y</span><span class="o">=</span><span class="s1">'queue_length'</span><span class="p">,</span> <span class="n">title</span><span class="o">=</span><span class="s1">'Queue Length Over Time'</span><span class="p">)</span> <span class="n">fig</span><span class="o">.</span><span class="n">update_traces</span><span class="p">(</span><span class="n">line_shape</span><span class="o">=</span><span class="s1">'hv'</span><span class="p">)</span> <span class="c1"># Step plot</span> <span class="n">fig</span><span class="o">.</span><span class="n">write_html</span><span class="p">(</span><span class="s1">'queue_interactive.html'</span><span class="p">)</span> <span class="n">fig</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> </code></pre></div> <h2 id="complete-visualisation-suite">Complete Visualisation Suite</h2> <div class="code-block"><pre><span></span><code><span class="k">def</span><span class="w"> </span><span class="nf">generate_all_plots</span><span class="p">(</span><span class="n">entity_df</span><span class="p">,</span> <span class="n">time_series_df</span><span class="p">,</span> <span class="n">resources</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""Generate all standard visualisations."""</span> <span class="c1"># 1. Queue length</span> <span class="k">for</span> <span class="n">resource</span> <span class="ow">in</span> <span class="n">resources</span><span class="p">:</span> <span class="n">plot_queue_length</span><span class="p">(</span><span class="n">time_series_df</span><span class="o">.</span><span class="n">rename</span><span class="p">(</span> <span class="n">columns</span><span class="o">=</span><span class="p">{</span><span class="sa">f</span><span class="s1">'</span><span class="si">{</span><span class="n">resource</span><span class="si">}</span><span class="s1">_queue'</span><span class="p">:</span> <span class="s1">'queue_length'</span><span class="p">}</span> <span class="p">))</span> <span class="c1"># 2. Wait distribution</span> <span class="n">plot_wait_distribution</span><span class="p">(</span><span class="n">entity_df</span><span class="p">[</span><span class="s1">'wait'</span><span class="p">]</span><span class="o">.</span><span class="n">values</span><span class="p">)</span> <span class="c1"># 3. Utilisation</span> <span class="k">for</span> <span class="n">resource</span> <span class="ow">in</span> <span class="n">resources</span><span class="p">:</span> <span class="n">plot_utilisation</span><span class="p">(</span><span class="n">time_series_df</span><span class="p">,</span> <span class="n">resource</span><span class="p">)</span> <span class="c1"># 4. CDF</span> <span class="n">plot_cdf</span><span class="p">(</span><span class="n">entity_df</span><span class="p">[</span><span class="s1">'wait'</span><span class="p">]</span><span class="o">.</span><span class="n">values</span><span class="p">)</span> <span class="c1"># 5. Throughput</span> <span class="n">plot_throughput</span><span class="p">(</span><span class="n">entity_df</span><span class="p">)</span> <span class="nb">print</span><span class="p">(</span><span class="s2">"All plots generated!"</span><span class="p">)</span> </code></pre></div> <h2 id="summary">Summary</h2> <p>Good visualisations: - Show trends over time (not just averages) - Include distributions (not just means) - Compare scenarios side-by-side - Mark key thresholds and targets</p> <p>Numbers inform. Pictures convince.</p> <h2 id="next-steps">Next Steps</h2> <ul> <li><a href="/blog_posts/simpy-collect-statistics.html">Collecting Statistics</a></li> <li><a href="/blog_posts/simpy-run-multiple-replications.html">Running Multiple Replications</a></li> <li><a href="/blog_posts/simpy-with-pandas.html">SimPy with pandas</a></li> </ul>Discover the Power of Simulation
Want to become a go-to expert in simulation with Python? The Complete Simulation Bootcamp will show you how simulation can transform your career and your projects.
Explore the Bootcamp