Plotting¶
The plotting module contains a few classes you can use to quickly generate plots of an experiment, as well as plot data live during the experiment. In this example, we will assume that you are familiar with the workings of the ShieldController class. If not, check this example.
The Plotter and LivePlotter can be imported from the plotting module
1%%capture
2
3from automationshield import AeroShield, ShieldController
4from automationshield.plotting import Plotter, LivePlotter
We’re reusing the PID controller of the ShieldController example, shown again below.
1class PIDController(ShieldController):
2 def variables(self) -> None:
3 # preface every variable defined in subclass with var_ to avoid overwrites.
4 self.var_kp = 1
5 self.var_ki = .25
6 self.var_kd = .25
7
8 self.var_total_error = 0
9 self.var_prev_error = 0
10
11 def controller(self, t: float, dt: float, ref: float, pot: float, angle: float) -> float:
12 error = ref - angle
13 self.var_total_error += error * dt
14
15 proportional = self.var_kp * error
16 integral = self.var_kp/self.var_ki * self.var_total_error
17
18 if dt > 0:
19 differential = self.var_kp*self.var_kd*(error - self.var_prev_error)/dt
20 else:
21 differential = 0
22
23 motor = proportional + integral + differential
24
25 self.var_prev_error = error
26
27 return motor
Here, we create a shield and controller instance and define the frequency, cycles and reference we will use for an experiment.
1shield = AeroShield()
2pid_controller = PIDController(shield)
3
4freq = 200
5cycles = 1000
6ref = 45
LivePlotter¶
Because this tutorial is written in Jupyter, we need to jump through some hoops to make this work smoothly. A live plot must be placed in a separate window. We achieve this by using the magic command. After the magic command, we should import matplotlib again to change the backend.
We then create an instance of the LivePlotter class. There are several customisation options, some of which are used here. In a Jupyter environment, hold must always be set to False (the default), otherwise the plot window will stop responding and cause the kernel to crash. Please refer to the API Documentation for a complete list of options.
The run method of the controller takes an optional live_plotter keyword argument. Passing a LivePlotter instance to it is all that is needed to get a live plot as the experiment is running.
1# set matplotlib to use separate plotting window
2%matplotlib
3# we call the magic command twice because the internet says so. ¯\_(ツ)_/¯
4%matplotlib
5
6# we need to import matplotlib again after the magic command
7from matplotlib import pyplot as plt
8
9
10live_plotter = LivePlotter(shield, show_dt=True, show_pot=False, hold=False)
11results = pid_controller.run(freq, cycles, ref, live_plotter=live_plotter)
Using matplotlib backend: <object object at 0x00000186EE7442C0>
Using matplotlib backend: QtAgg
Plotter¶
If you just (or also) want a plot with the results of the experiment when it’s finished, you can use the Plotter class. In Jupyter, we can change the matplotlib to inline such that the plot is shown below the code block. The Plotter takes the same arguments as LivePlotter (which actually inherits from Plotter), except the hold argument.
1# set matplotlib to use inline plotting
2%matplotlib inline
3%matplotlib inline
4
5# we need to import matplotlib again after the magic command
6from matplotlib import pyplot as plt
7
8
9# results = pid_controller.run(freq, cycles, ref)
10fig, ax = Plotter(shield).plot(results)
Selecting an Appropriate Backend¶
It is possible that, when attempting to plot live from a Jupyter environment, matplotlib complains about not having an appropriate backend available or that the plotting runs extremely slow. If that is the case, you can try to force matplotlib to use PyQT5, which you might have to install as well.
1import matplotlib
2
3
4# tell matplotlib to use PyQT5
5matplotlib.use("QT5Agg")
You can install PyQT5 in your Python environment using pip:
$ pip install PyQT5