diff --git a/.gitignore b/.gitignore
index 15fb17b133b4c707651b8411b4934d2734968688..a003eda10b9827f972a29ecccbe9b67c3cfa7de1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -109,3 +109,4 @@ ENV/
 
 
 images/test/
+test_save.dat
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index c722f3c334d412eb2796cff2d46e4e01f063e18d..885f2a32267882160943c6fe20f5b199c244de25 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -25,6 +25,7 @@ tests:
         - apt update
         - apt install -y libgl1-mesa-glx xvfb
         - pip install tox
+        - apt install -y graphviz xdg-utils
         - xvfb-run -s "-screen 0 800x600x24" tox
 
 build_and_deploy_docs:
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
index f552f7626cfffca9a4422cb9337c9cdc27d83867..7ae26bcc3d4e0f4a5cbbcfafd055e2c084a42345 100644
--- a/CONTRIBUTING.rst
+++ b/CONTRIBUTING.rst
@@ -79,7 +79,7 @@ Ready to contribute? Here's how to set up `flatland` for local development.
 5. When you're done making changes, check that your changes pass flake8 and the
    tests, including testing other Python versions with tox::
 
-    $ flake8 flatland tests
+    $ flake8 flatland tests examples
     $ python setup.py test or py.test
     $ tox
 
@@ -125,4 +125,4 @@ $ bumpversion patch # possible: major / minor / patch
 $ git push
 $ git push --tags
 
-Travis will then deploy to PyPI if tests pass. (To be configured properly by Mohanty)
\ No newline at end of file
+Travis will then deploy to PyPI if tests pass. (To be configured properly by Mohanty)
diff --git a/MANIFEST.in b/MANIFEST.in
index 965b2dda7db7c49f68857dc3aea9af37e30a745e..30bf97cf0de32bad7e630a80e2b977eb85d48911 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -3,6 +3,7 @@ include CONTRIBUTING.rst
 include HISTORY.rst
 include LICENSE
 include README.rst
+include requirements_dev.txt
 
 recursive-include tests *
 recursive-exclude * __pycache__
diff --git a/Makefile b/Makefile
index 42a8a430671f9464101ba0799bb6ac4e4f35be20..69ad1b42fd51ef9ec9420f5473dc8acef5468572 100644
--- a/Makefile
+++ b/Makefile
@@ -51,7 +51,7 @@ clean-test: ## remove test and coverage artifacts
 	rm -fr .pytest_cache
 
 lint: ## check style with flake8
-	flake8 flatland tests
+	flake8 flatland tests examples
 
 test: ## run tests quickly with the default Python
 	echo "$$DISPLAY"
@@ -72,6 +72,7 @@ docs: ## generate Sphinx HTML documentation, including API docs
 	sphinx-apidoc -o docs/ flatland
 	$(MAKE) -C docs clean
 	$(MAKE) -C docs html
+	pydeps --no-config --noshow flatland -o docs/_build/html/flatland.svg
 	$(BROWSER) docs/_build/html/index.html
 
 servedocs: docs ## compile the docs watching for changes
diff --git a/README.rst b/README.rst
index b4d3193c1b4fb55327216164c602d75cc92e3fdb..11b35adc127b2b5b8b22c55fd0f494871aee56cd 100644
--- a/README.rst
+++ b/README.rst
@@ -92,6 +92,10 @@ flatland
 ========
 TODO: explain the interface here
 
+Module Dependencies
+===================
+.. image:: flatland.svg
+
 
 Authors
 --------
@@ -102,6 +106,7 @@ Authors
 * Erik Nygren <erik.nygren@sbb.ch>
 * Adrian Egli <adrian.egli@sbb.ch>
 * Vaibhav Agrawal <theinfamouswayne@gmail.com>
+* Christian Eichenberger <christian.markus.eichenberger@sbb.ch>
 
 
 <please fill yourself in>
diff --git a/examples/play_model.py b/examples/play_model.py
index bbbcfffdccf4493bc08da013027f4fdc31ca5aa7..34c6aadfeefd44771fd335e2957e1fbd0b2f740f 100644
--- a/examples/play_model.py
+++ b/examples/play_model.py
@@ -1,12 +1,14 @@
-from flatland.envs.rail_env import RailEnv
-from flatland.envs.generators import complex_rail_generator
-from flatland.utils.rendertools import RenderTool
-# from flatland.baselines.dueling_double_dqn import Agent
-from collections import deque
 # import torch
 import random
-import numpy as np
 import time
+# from flatland.baselines.dueling_double_dqn import Agent
+from collections import deque
+
+import numpy as np
+
+from flatland.envs.generators import complex_rail_generator
+from flatland.envs.rail_env import RailEnv
+from flatland.utils.rendertools import RenderTool
 
 
 class Player(object):
@@ -25,7 +27,7 @@ class Player(object):
         self.done_window = deque(maxlen=100)
         self.scores = []
         self.dones_list = []
-        self.action_prob = [0]*4
+        self.action_prob = [0] * 4
 
         # Removing refs to a real agent for now.
         # self.agent = Agent(self.state_size, self.action_size, "FC", 0)
@@ -35,7 +37,7 @@ class Player(object):
 
         self.iFrame = 0
         self.tStart = time.time()
-        
+
         # Reset environment
         # self.obs = self.env.reset()
         self.env.obs_builder.reset()
@@ -70,7 +72,7 @@ class Player(object):
         # Environment step - pass the agent actions to the environment,
         # retrieve the response - observations, rewards, dones
         next_obs, all_rewards, done, _ = self.env.step(self.action_dict)
-        
+
         for handle in env.get_agent_handles():
             norm = max(1, max_lt(next_obs[handle], np.inf))
             next_obs[handle] = np.clip(np.array(next_obs[handle]) / norm, -1, 1)
@@ -79,8 +81,8 @@ class Player(object):
         if False:
             for handle in self.env.get_agent_handles():
                 self.agent.step(self.obs[handle], self.action_dict[handle],
-                    all_rewards[handle], next_obs[handle], done[handle],
-                    train=False)
+                                all_rewards[handle], next_obs[handle], done[handle],
+                                train=False)
                 self.score += all_rewards[handle]
 
         self.iFrame += 1
@@ -96,7 +98,7 @@ def max_lt(seq, val):
     None is returned if seq was empty or all items in seq were >= val.
     """
 
-    idx = len(seq)-1
+    idx = len(seq) - 1
     while idx >= 0:
         if seq[idx] < val and seq[idx] >= 0:
             return seq[idx]
@@ -135,16 +137,16 @@ def main(render=True, delay=0.0, n_trials=3, n_steps=50, sGL="QT"):
             oPlayer.step()
             if render:
                 env_renderer.renderEnv(show=True, frames=True, iEpisode=trials, iStep=step,
-                    action_dict=oPlayer.action_dict)
+                                       action_dict=oPlayer.action_dict)
                 # time.sleep(10)
                 if delay > 0:
                     time.sleep(delay)
 
-            
+
 def main_old(render=True, delay=0.0):
     ''' DEPRECATED main which drives agent directly
         Please use the new main() which creates a Player object which is also used by the Editor.
-        Please fix any bugs in main() and Player rather than here. 
+        Please fix any bugs in main() and Player rather than here.
         Will delete this one shortly.
     '''
 
@@ -169,7 +171,7 @@ def main_old(render=True, delay=0.0):
     done_window = deque(maxlen=100)
     scores = []
     dones_list = []
-    action_prob = [0]*4
+    action_prob = [0] * 4
 
     # Real Agent
     # state_size = 105
@@ -183,7 +185,7 @@ def main_old(render=True, delay=0.0):
         None is returned if seq was empty or all items in seq were >= val.
         """
 
-        idx = len(seq)-1
+        idx = len(seq) - 1
         while idx >= 0:
             if seq[idx] < val and seq[idx] >= 0:
                 return seq[idx]
@@ -196,7 +198,8 @@ def main_old(render=True, delay=0.0):
 
         # Reset environment
         obs = env.reset()
-        env_renderer.set_new_rail()
+        if render:
+            env_renderer.set_new_rail()
 
         for a in range(env.get_num_agents()):
             norm = max(1, max_lt(obs[a], np.inf))
@@ -252,25 +255,25 @@ def main_old(render=True, delay=0.0):
 
         print(('\rTraining {} Agents.\tEpisode {}\tAverage Score: {:.0f}\tDones: {:.2f}%' +
                '\tEpsilon: {:.2f} \t Action Probabilities: \t {}').format(
-               env.get_num_agents(),
-               trials,
-               np.mean(scores_window),
-               100 * np.mean(done_window),
-               eps, action_prob/np.sum(action_prob)),
+            env.get_num_agents(),
+            trials,
+            np.mean(scores_window),
+            100 * np.mean(done_window),
+            eps, action_prob / np.sum(action_prob)),
             end=" ")
         if trials % 100 == 0:
             tNow = time.time()
             rFps = iFrame / (tNow - tStart)
             print(('\rTraining {} Agents.\tEpisode {}\tAverage Score: {:.0f}\tDones: {:.2f}%' +
                    '\tEpsilon: {:.2f} fps: {:.2f} \t Action Probabilities: \t {}').format(
-                   env.get_num_agents(),
-                   trials,
-                   np.mean(scores_window),
-                   100 * np.mean(done_window),
-                   eps, rFps, action_prob / np.sum(action_prob)))
+                env.get_num_agents(),
+                trials,
+                np.mean(scores_window),
+                100 * np.mean(done_window),
+                eps, rFps, action_prob / np.sum(action_prob)))
             # torch.save(agent.qnetwork_local.state_dict(),
             #         '../flatland/baselines/Nets/avoid_checkpoint' + str(trials) + '.pth')
-            action_prob = [1]*4
+            action_prob = [1] * 4
 
 
 if __name__ == "__main__":
diff --git a/examples/qt2.py b/examples/qt2.py
index 6074106523c7fbe503f79b6bc7604f055dc27b35..ee3ea0cd123a3e6d0b1fc970eced219ed8503203 100644
--- a/examples/qt2.py
+++ b/examples/qt2.py
@@ -1,9 +1,8 @@
-
-
 import sys
+
 from PyQt5 import QtSvg
-from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow, QGridLayout, QWidget
 from PyQt5.QtCore import Qt, QByteArray
+from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow, QGridLayout, QWidget
 
 from flatland.utils import svg
 
@@ -75,4 +74,3 @@ window = MainWindow()
 window.show()
 
 app.exec_()
-
diff --git a/examples/temporary_example.py b/examples/temporary_example.py
index 1f3504f221d59d0205974bb135c2237364a22e07..862369411056d87d411c3e173bd479e9a7e93e01 100644
--- a/examples/temporary_example.py
+++ b/examples/temporary_example.py
@@ -1,11 +1,9 @@
 import random
-import numpy as np
-import matplotlib.pyplot as plt
 
-from flatland.envs.rail_env import *
-from flatland.envs.generators import *
-from flatland.envs.observations import TreeObsForRailEnv
-from flatland.utils.rendertools import *
+from flatland.envs.generators import random_rail_generator
+from flatland.envs.rail_env import RailEnv
+from flatland.utils.rendertools import RenderTool
+import numpy as np
 
 random.seed(0)
 np.random.seed(0)
@@ -94,7 +92,7 @@ env = RailEnv(width=7,
 #     print(env.obs_builder.distance_map[0, :, :, i])
 
 # Print the observation vector for agent 0
-obs, all_rewards, done, _ = env.step({0:0})
+obs, all_rewards, done, _ = env.step({0: 0})
 for i in range(env.get_num_agents()):
     env.obs_builder.util_print_obs_subtree(tree=obs[i], num_features_per_node=5)
 
@@ -113,6 +111,7 @@ for step in range(100):
     while i < len(cmds):
         if cmds[i] == 'q':
             import sys
+
             sys.exit()
         elif cmds[i] == 's':
             obs, all_rewards, done, _ = env.step(action_dict)
@@ -120,9 +119,9 @@ for step in range(100):
             print("Rewards: ", all_rewards, "  [done=", done, "]")
         else:
             agent_id = int(cmds[i])
-            action = int(cmds[i+1])
+            action = int(cmds[i + 1])
             action_dict[agent_id] = action
-            i = i+1
+            i = i + 1
         i += 1
 
     env_renderer.renderEnv(show=True)
diff --git a/examples/training_navigation.py b/examples/training_navigation.py
index cabb655e3eb2bc2d12d908559b0102b072163052..85f9531b8820139e5559081feee4a93c4e01ac6c 100644
--- a/examples/training_navigation.py
+++ b/examples/training_navigation.py
@@ -1,11 +1,15 @@
-from flatland.envs.rail_env import *
-from flatland.envs.generators import *
-from flatland.envs.observations import TreeObsForRailEnv
-from flatland.utils.rendertools import *
-from flatland.baselines.dueling_double_dqn import Agent
-from collections import deque
-import torch, random
+import random
 import time
+from collections import deque
+
+import numpy as np
+import torch
+
+from flatland.baselines.dueling_double_dqn import Agent
+from flatland.envs.generators import complex_rail_generator
+from flatland.envs.rail_env import RailEnv
+from flatland.utils.rendertools import RenderTool
+
 random.seed(1)
 np.random.seed(1)
 
@@ -190,25 +194,34 @@ for trials in range(1, n_trials + 1):
     dones_list.append((np.mean(done_window)))
 
     print(
-        '\rTraining {} Agents.\tEpisode {}\tAverage Score: {:.0f}\tDones: {:.2f}%\tEpsilon: {:.2f} \t Action Probabilities: \t {}'.format(
+        '\rTraining {} Agents.\t' +
+        'Episode {}\t' +
+        'Average Score: {:.0f}\t' +
+        'Dones: {:.2f}%\t' +
+        'Epsilon: {:.2f} \t ' +
+        'Action Probabilities: \t ' +
+        '{}'.format(
             env.get_num_agents(),
             trials,
-            np.mean(
-                scores_window),
-            100 * np.mean(
-                done_window),
+            np.mean(scores_window),
+            100 * np.mean(done_window),
             eps, action_prob / np.sum(action_prob)),
         end=" ")
     if trials % 100 == 0:
         print(
-            '\rTraining {} Agents.\tEpisode {}\tAverage Score: {:.0f}\tDones: {:.2f}%\tEpsilon: {:.2f} \t Action Probabilities: \t {}'.format(
+            '\rTraining {} Agents.\t' +
+            'Episode {}\t' +
+            'Average Score: {:.0f}\t' +
+            'Dones: {:.2f}%\t' +
+            'Epsilon: {:.2f} \t ' +
+            'Action Probabilities: \t ' +
+            '{}'.format(
                 env.get_num_agents(),
                 trials,
-                np.mean(
-                    scores_window),
-                100 * np.mean(
-                    done_window),
-                eps, action_prob / np.sum(action_prob)))
+                np.mean(scores_window),
+                100 * np.mean(done_window),
+                eps,
+                action_prob / np.sum(action_prob)))
         torch.save(agent.qnetwork_local.state_dict(),
                    '../flatland/baselines/Nets/avoid_checkpoint' + str(trials) + '.pth')
         action_prob = [1] * 4
diff --git a/flatland/envs/observations.py b/flatland/envs/observations.py
index 651d83520ee1f492ea71ba6ddf82cfa5f9093964..fa77b58a53ef63767c2690edc782b6699f6c8459 100644
--- a/flatland/envs/observations.py
+++ b/flatland/envs/observations.py
@@ -492,8 +492,11 @@ class GlobalObsForRailEnv(ObservationBuilder):
         self.rail_obs = np.zeros((self.env.height, self.env.width, 16))
         for i in range(self.rail_obs.shape[0]):
             for j in range(self.rail_obs.shape[1]):
-                self.rail_obs[i, j] = np.array(
-                    list(f'{self.env.rail.get_transitions((i, j)):016b}')).astype(int)
+                bitlist = [int(digit) for digit in bin(self.env.rail.get_transitions((i, j)))[2:]]
+                bitlist = [0] * (16 - len(bitlist)) + bitlist
+                self.rail_obs[i, j] = np.array(bitlist)
+                # self.rail_obs[i, j] = np.array(
+                #     list(f'{self.env.rail.get_transitions((i, j)):016b}')).astype(int)
 
         # self.targets = np.zeros(self.env.height, self.env.width)
         # for target_pos in self.env.agents_target:
diff --git a/make_docs.py b/make_docs.py
index 7ccbdb736b9b53743b58cfd985538705c5e79f08..8cc1124a6fe624fe5afff416450a0a5d30d654ca 100644
--- a/make_docs.py
+++ b/make_docs.py
@@ -25,5 +25,6 @@ os.environ["SPHINXPROJ"] = "flatland"
 os.chdir('docs')
 subprocess.call(['python', '-msphinx', '-M', 'clean', '.', '_build'])
 subprocess.call(['python', '-msphinx', '-M', 'html', '.', '_build'])
+subprocess.call(['python', '-mpydeps', '../flatland', '-o', '_build/html/flatland.svg'])
 
 browser('_build/html/index.html')
diff --git a/requirements_dev.txt b/requirements_dev.txt
index 08fcc9d17a409f4df71b0b67e037dde5ae042f8a..4b288cee88f4231f330c51f70b1cd9c9f9d05389 100644
--- a/requirements_dev.txt
+++ b/requirements_dev.txt
@@ -2,6 +2,7 @@ bumpversion==0.5.3
 wheel==0.32.1
 watchdog==0.9.0
 flake8==3.5.0
+pydeps==1.7.2
 tox==3.5.2
 coverage==4.5.1
 Sphinx==1.8.1
diff --git a/setup.py b/setup.py
index 96afbe85dc99aa47533936d2a001b9d74717ec58..d14070351559b5e59ed677751b70c20891dbc2f4 100644
--- a/setup.py
+++ b/setup.py
@@ -2,7 +2,7 @@
 # -*- coding: utf-8 -*-
 
 """The setup script."""
-
+import os
 from setuptools import setup, find_packages
 
 with open('README.rst') as readme_file:
@@ -11,11 +11,19 @@ with open('README.rst') as readme_file:
 with open('HISTORY.rst') as history_file:
     history = history_file.read()
 
-requirements = ['Click>=6.0', ]
-
-setup_requirements = ['pytest-runner', ]
-
-test_requirements = ['pytest', ]
+# Gather requirements from requirements_dev.txt
+# TODO : We could potentially split up the test/dev dependencies later
+install_reqs = []
+requirements_path = 'requirements_dev.txt'
+with open(requirements_path, 'r') as f:
+    install_reqs += [
+        s for s in [
+            line.strip(' \n') for line in f
+        ] if not s.startswith('#') and s != ''
+    ]
+requirements = install_reqs
+setup_requirements = install_reqs
+test_requirements = install_reqs
 
 setup(
     author="S.P. Mohanty",
diff --git a/tests/test_rendertools.py b/tests/test_rendertools.py
index 7d3ddf63226b55217edd28bf25aed0307377433b..8204a305328df746a772d034f3c763c848cceb93 100644
--- a/tests/test_rendertools.py
+++ b/tests/test_rendertools.py
@@ -4,14 +4,14 @@
 Tests for `flatland` package.
 """
 
-from flatland.envs.rail_env import RailEnv, random_rail_generator
-import numpy as np
 import sys
 
 import matplotlib.pyplot as plt
+import numpy as np
 
 import flatland.utils.rendertools as rt
 from flatland.envs.observations import TreeObsForRailEnv
+from flatland.envs.rail_env import RailEnv, random_rail_generator
 
 
 def checkFrozenImage(oRT, sFileImage, resave=False):
diff --git a/tox.ini b/tox.ini
index e97f8ab022c69cf7ff7aa65d782dddafbecfc90f..6dd011aadeb2e7ba802ff692278aa763fb665f10 100644
--- a/tox.ini
+++ b/tox.ini
@@ -8,12 +8,12 @@ python =
 
 [flake8]
 max-line-length = 120
-ignore = E121 E126 E123 E128 E133 E226 E241 E242 E704 W291 W293 W391 W503 W504 W505 
+ignore = E121 E126 E123 E128 E133 E226 E241 E242 E704 W291 W293 W391 W503 W504 W505
 
 [testenv:flake8]
 basepython = python
 deps = flake8
-commands = flake8 flatland
+commands = flake8 flatland tests examples
 
 [testenv:docs]
 basepython = python
@@ -23,12 +23,15 @@ commands = make docs
 [testenv:coverage]
 basepython = python
 whitelist_externals = make
-commands = make coverage
+commands =
+    pip install -U pip
+    pip install -r requirements_dev.txt
+    make coverage
 
 [testenv]
 whitelist_externals = xvfb-run
-    sh
-    pip
+                      sh
+                      pip
 setenv =
     PYTHONPATH = {toxinidir}
 deps =
@@ -38,6 +41,7 @@ deps =
 ;     -r{toxinidir}/requirements.txt
 commands =
     pip install -U pip
+    pip install -r requirements_dev.txt
     sh -c 'echo DISPLAY: $DISPLAY'
     xvfb-run -a py.test --basetemp={envtmpdir}