diff --git a/pyrobolearn/plotting/README.rst b/pyrobolearn/plotting/README.rst
new file mode 100644
index 0000000..33a5000
--- /dev/null
+++ b/pyrobolearn/plotting/README.rst
@@ -0,0 +1,14 @@
+Plotting Tools
+==============
+
+Plotting tools are extremely important in research. For this purpose, we plan to provide plotting tools that allows to
+plot in real-time different quantities that can be observed in the simulator, like the joint states, the position and
+orientation of each body in the world by plotting their reference frame, the position and orientation of links of a
+specific body, the resulting trajectories in the 3D Cartesian space, etc.
+
+Warnings: THIS IS CURRENTLY AN EXPERIMENTAL STAGE.
+
+References
+
+- `matplotlib `_: The standard Python plotting library.
+- `Seaborn `_: Seaborn is a Python data visualization library built on top of matplotlib.
diff --git a/pyrobolearn/plotting/__init__.py b/pyrobolearn/plotting/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/pyrobolearn/plotting/plot.py b/pyrobolearn/plotting/plot.py
new file mode 100644
index 0000000..fe7bfc3
--- /dev/null
+++ b/pyrobolearn/plotting/plot.py
@@ -0,0 +1,239 @@
+#!/usr/bin/env python
+"""Define the Plot class.
+
+Warnings: THIS IS EXPERIMENTAL.
+
+Dependencies:
+- `matplotlib`
+"""
+
+# TODO
+
+import numpy as np
+from matplotlib import pyplot as plt
+from matplotlib import animation
+import time
+import multiprocessing
+
+
+__author__ = "Brian Delhaisse"
+__copyright__ = "Copyright 2019, PyRoboLearn"
+__credits__ = ["Brian Delhaisse"]
+__license__ = "GNU GPLv3"
+__version__ = "1.0.0"
+__maintainer__ = "Brian Delhaisse"
+__email__ = "briandelhaisse@gmail.com"
+__status__ = "Development"
+
+
+class Plot(object):
+ """Plot (abstract) class.
+
+ The plotter allows to plot different things. Notably, it can plot in real-time the joint values, the orientation
+ frame of each body.
+ """
+ pass
+
+
+class RealTimePlot(Plot):
+ """Real-time plotter
+
+ This plotter spawns a new process that is responsible to update a plot in real-time. To achieve that goal, the
+ master process sent the data (through the `RealTimePlot.update` method) through a pipe to the new process which
+ updates the plot.
+ """
+ pass
+ # def __init__(self, ticks=1, blit=True):
+ # # create pipe, queue, and process
+ # self.pipe, pipe = multiprocessing.Pipe()
+ # self.queue = multiprocessing.Queue()
+ # self.process = multiprocessing.Process(target=self._plot, args=(pipe, self.queue))
+ #
+ # # start process
+ # self.process.start()
+ #
+ # def _plot(self, pipe, queue):
+ # """To be implemented in the child class."""
+ # pass
+ #
+ # def update(self):
+ # """To be implemented in the child class."""
+ # pass
+ #
+ # def close(self):
+ # """close the plotter."""
+ # # notify the plot child process
+ # self.pipe.send('END')
+ #
+ # # wait for the child process to close
+ # self.process.join()
+ #
+ # # close queue and pipe
+ # self.queue.close()
+ # self.pipe.close()
+ #
+ # def __del__(self):
+ # """Closing the plotter."""
+ # self.close()
+
+
+class BodyPlot(RealTimePlot):
+ r"""Body plotter.
+
+ The Body plotter draws the joint positions with their corresponding frame in a 3D plot.
+ """
+ pass
+
+
+class JointPlot(RealTimePlot):
+ r"""Joint plotter
+
+ The Joint plotter plots the joint position, velocity, acceleration and torque values.
+ """
+
+ def __init__(self, robot, joint_ids=None, position=False, velocity=False, acceleration=False, torque=False,
+ ticks=1, blit=True):
+ """
+ Initialize the joint plotter.
+
+ Args:
+ robot (Robot): robot instance.
+ joint_ids (list of int, int, None): joint id(s) to plot.
+ position (bool): if True, it will plot the joint positions.
+ velocity (bool): if True, it will plot the joint velocities.
+ acceleration (bool): if True, it will plot the joint accelerations.
+ torque (bool): if True, it will plot the joint torques.
+ ticks (int): number of ticks to sleep before sending the new data.
+ blit (bool): if we should use blit, that is, if we should re-draw only the parts that have changed.
+ If blit = True, it plots faster but can only update what is inside the plot (so not the xticks,
+ yticks, xlabel, etc).
+ """
+ # set variable
+ self.robot = robot
+ self.joint_ids = joint_ids
+ self.plot_position = position
+ self.plot_velocity = velocity
+ self.plot_acceleration = acceleration
+ self.plot_torque = torque
+ self.ticks = ticks
+ self.cnt = 0
+ self.blit = blit
+
+ self.plot_exist = True
+
+ # create pipe, queue, and process
+ self.pipe, pipe = multiprocessing.Pipe()
+ self.queue = multiprocessing.Queue()
+ self.plot_process = multiprocessing.Process(target=self._plot, args=(pipe, self.queue))
+ self.plot_process.start()
+
+ def _plot(self, pipe, queue):
+ """Plot the streamed data."""
+
+ # set pipe and queue
+ self.pipe = pipe
+ self.queue = queue
+
+ # create figure, subplots, axes, titles,...
+ fig = plt.figure()
+ ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
+
+ # create line
+ line, = ax.plot([], [], lw=2)
+
+ self.x = []
+ self.y = []
+
+ # initialization function: plot the background of each frame
+ def init():
+ line.set_data([], [])
+ return line,
+
+ # def gen():
+ # states = self.pipe.recv()
+ # if not (isinstance(states, bool) and states):
+ # yield states
+ # else:
+ # print("Over")
+
+ # animation function. This is called sequentially
+ def animate(i):
+ states = self.pipe.recv()
+ # if isinstance(states, bool) and states:
+ # self.anim.event_source.stop()
+
+ # print("Received states: {}".format(states))
+
+ self.y.append(states['q'][0])
+ self.y = self.y[-10:]
+
+ # print(self.y[:3])
+
+ line.set_data(range(len(self.y)), self.y)
+ # ax.set_xlim(0 + 0.01 * i, 2 + 0.01 * i)
+ # ax.set_xticklabels(np.linspace(0.01 * i, 2 + 0.01 * i, 5))
+ return line,
+
+ # create funcanimation
+ anim = animation.FuncAnimation(fig, animate, init_func=init,
+ frames=None, interval=0.0001, blit=self.blit)
+ plt.show()
+
+ # if we get out of the animation, notify the master process
+ self.queue.put(True)
+ self.pipe.close()
+ self.queue.close()
+
+ def update(self):
+ """Update the plot by getting the """
+ if self.cnt % self.ticks == 0 and self.plot_exist:
+
+ # get useful information
+ states = {}
+ if self.plot_position:
+ states['q'] = self.robot.get_joint_positions(joint_ids=self.joint_ids)
+ if self.plot_velocity:
+ states['dq'] = self.robot.get_joint_velocities(joint_ids=self.joint_ids)
+ if self.plot_acceleration:
+ states['ddq'] = self.robot.get_joint_accelerations(joint_ids=self.joint_ids)
+
+ # send the data to the process
+ self.pipe.send(states)
+
+ self.cnt += 1
+
+ if not self.queue.empty():
+ result = self.queue.get()
+ if result:
+ print("The animation has finished. Closing process...")
+ self.plot_process.join()
+ print("Process has been closed.")
+ else:
+ print("Got result: {}".format(result))
+
+
+class LinkPlot(RealTimePlot):
+ r"""Link plotter
+
+ The Link plotter plots a link position, velocity, acceleration, force along the 3 axis (x,y,z).
+ """
+ pass
+
+
+# Tests
+if __name__ == '__main__':
+
+ # Try to move the robot in the simulator
+
+ from itertools import count
+ import pyrobolearn as prl
+
+ sim = prl.simulators.Bullet()
+ world = prl.worlds.BasicWorld(sim)
+ robot = world.load_robot('kuka_iiwa')
+
+ plot = JointPlot(robot, joint_ids=[3], position=True, ticks=24)
+
+ for t in count():
+ plot.update()
+ world.step(sim.dt)