Use CSS to size plots instead of absolute position

This will make things a lot easier to resize and track.  Absolute
positions are tough on other elements.  Have the plot fill the whole
containing element.

Change-Id: I9463c86a723e257bf8c9b083b1a8dcc31a544604
Signed-off-by: Austin Schuh <austin.linux@gmail.com>
Signed-off-by: James Kuszmaul <jabukuszmaul@gmail.com>
diff --git a/aos/network/www/aos_plotter.ts b/aos/network/www/aos_plotter.ts
index 270c0d9..0145c07 100644
--- a/aos/network/www/aos_plotter.ts
+++ b/aos/network/www/aos_plotter.ts
@@ -190,7 +190,6 @@
 
   private plots: AosPlot[] = [];
   private messages = new Set<MessageHandler>();
-  private lowestHeight = 0;
   constructor(private readonly connection: Connection) {
     // Set up to redraw at some regular interval. The exact rate is unimportant.
     setInterval(() => {
@@ -223,24 +222,19 @@
   // Add a new figure at the provided position with the provided size within
   // parentElement.
   addPlot(
-      parentElement: Element, topLeft: number[]|null = null,
+      parentElement: Element,
       size: number[] = [AosPlotter.DEFAULT_WIDTH, AosPlotter.DEFAULT_HEIGHT]):
       AosPlot {
-    if (topLeft === null) {
-      topLeft = [0, this.lowestHeight];
-    }
     const div = document.createElement("div");
-    div.style.top = topLeft[1].toString();
-    div.style.left = topLeft[0].toString();
-    div.style.position = 'absolute';
+    div.style.position = 'relative';
+    div.style.width = size[0].toString() + "px";
+    div.style.height = size[1].toString() + "px";
     parentElement.appendChild(div);
-    const newPlot = new Plot(div, size[0], size[1]);
+    const newPlot = new Plot(div);
     for (let plot of this.plots.values()) {
       newPlot.linkXAxis(plot.plot);
     }
     this.plots.push(new AosPlot(this, newPlot));
-    // Height goes up as you go down.
-    this.lowestHeight = Math.max(topLeft[1] + size[1], this.lowestHeight);
     return this.plots[this.plots.length - 1];
   }
   private draw(): void {
diff --git a/aos/network/www/colors.ts b/aos/network/www/colors.ts
index b173e13..5c5dd86 100644
--- a/aos/network/www/colors.ts
+++ b/aos/network/www/colors.ts
@@ -1,4 +1,6 @@
 export const RED: number[] = [1, 0, 0];
+export const ORANGE: number[] = [1, 0.65, 0];
+export const YELLOW: number[] = [1, 1, 0];
 export const GREEN: number[] = [0, 1, 0];
 export const BLUE: number[] = [0, 0, 1];
 export const BROWN: number[] = [0.6, 0.3, 0];
diff --git a/aos/network/www/demo_plot.ts b/aos/network/www/demo_plot.ts
index cbd133a..ecd4da6 100644
--- a/aos/network/www/demo_plot.ts
+++ b/aos/network/www/demo_plot.ts
@@ -23,12 +23,12 @@
   const height = AosPlotter.DEFAULT_HEIGHT;
 
   const benchmarkDiv = document.createElement('div');
-  benchmarkDiv.style.top = (height * 2).toString();
-  benchmarkDiv.style.left = '0';
-  benchmarkDiv.style.position = 'absolute';
+  benchmarkDiv.style.width = width.toString() + "px";
+  benchmarkDiv.style.height = height.toString() + "px";
+  benchmarkDiv.style.position = 'relative';
   parentDiv.appendChild(benchmarkDiv);
 
-  const benchmarkPlot = new Plot(benchmarkDiv, width, height);
+  const benchmarkPlot = new Plot(benchmarkDiv);
 
   const aosPlotter = new AosPlotter(conn);
 
diff --git a/aos/network/www/plotter.ts b/aos/network/www/plotter.ts
index e56a808..842f1b7 100644
--- a/aos/network/www/plotter.ts
+++ b/aos/network/www/plotter.ts
@@ -409,7 +409,7 @@
 
   public static readonly COLOR_CYCLE = [
     Colors.RED, Colors.GREEN, Colors.BLUE, Colors.BROWN, Colors.PINK,
-    Colors.CYAN, Colors.WHITE
+    Colors.CYAN, Colors.WHITE, Colors.ORANGE, Colors.YELLOW
   ];
   private colorCycleIndex = 0;
 
@@ -850,6 +850,7 @@
 export class Plot {
   private canvas = document.createElement('canvas');
   private textCanvas = document.createElement('canvas');
+  private lineDrawerContext: WebGLRenderingContext;
   private drawer: LineDrawer;
   private static keysPressed:
       object = {'x': false, 'y': false, 'Escape': false};
@@ -869,25 +870,26 @@
   private defaultYRange: number[]|null = null;
   private zoomRectangle: Line;
 
-  constructor(wrapperDiv: HTMLDivElement, width: number, height: number) {
+  constructor(wrapperDiv: HTMLDivElement) {
     wrapperDiv.appendChild(this.canvas);
     wrapperDiv.appendChild(this.textCanvas);
     this.lastTimeMs = (new Date()).getTime();
 
-    this.canvas.width =
-        width - this.axisLabelBuffer.left - this.axisLabelBuffer.right;
-    this.canvas.height =
-        height - this.axisLabelBuffer.top - this.axisLabelBuffer.bottom;
-    this.canvas.style.left = this.axisLabelBuffer.left.toString();
-    this.canvas.style.top = this.axisLabelBuffer.top.toString();
-    this.canvas.style.position = 'absolute';
-    this.drawer = new LineDrawer(this.canvas.getContext('webgl'));
+    this.canvas.style.paddingLeft = this.axisLabelBuffer.left.toString() + "px";
+    this.canvas.style.paddingRight = this.axisLabelBuffer.right.toString() + "px";
+    this.canvas.style.paddingTop = this.axisLabelBuffer.top.toString() + "px";
+    this.canvas.style.paddingBottom = this.axisLabelBuffer.bottom.toString() + "px";
+    this.canvas.style.width = "100%";
+    this.canvas.style.height = "100%";
+    this.canvas.style.boxSizing = "border-box";
 
-    this.textCanvas.width = width;
-    this.textCanvas.height = height;
-    this.textCanvas.style.left = '0';
-    this.textCanvas.style.top = '0';
+    this.canvas.style.position = 'absolute';
+    this.lineDrawerContext = this.canvas.getContext('webgl');
+    this.drawer = new LineDrawer(this.lineDrawerContext);
+
     this.textCanvas.style.position = 'absolute';
+    this.textCanvas.style.width = "100%";
+    this.textCanvas.style.height = "100%";
     this.textCanvas.style.pointerEvents = 'none';
 
     this.canvas.addEventListener('dblclick', (e) => {
@@ -934,9 +936,22 @@
   }
 
   mouseCanvasLocation(event: MouseEvent): number[] {
+    const computedStyle = window.getComputedStyle(this.canvas);
+    const paddingLeftStr = computedStyle.getPropertyValue('padding-left');
+    const paddingTopStr = computedStyle.getPropertyValue('padding-top');
+    if (paddingLeftStr.substring(paddingLeftStr.length - 2) != "px") {
+      throw new Error("Left padding should be specified in pixels.");
+    }
+    if (paddingTopStr.substring(paddingTopStr.length - 2) != "px") {
+      throw new Error("Left padding should be specified in pixels.");
+    }
+    // Javascript will just ignore the extra "px".
+    const paddingLeft = Number.parseInt(paddingLeftStr);
+    const paddingTop = Number.parseInt(paddingTopStr);
+
     return [
-      event.offsetX * 2.0 / this.canvas.width - 1.0,
-      -event.offsetY * 2.0 / this.canvas.height + 1.0
+      (event.offsetX - paddingLeft) * 2.0 / this.canvas.width - 1.0,
+      -(event.offsetY - paddingTop) * 2.0 / this.canvas.height + 1.0
     ];
   }
 
@@ -1154,6 +1169,17 @@
     const curTime = (new Date()).getTime();
     const frameRate = 1000.0 / (curTime - this.lastTimeMs);
     this.lastTimeMs = curTime;
+    const parentWidth = this.textCanvas.parentElement.offsetWidth;
+    const parentHeight = this.textCanvas.parentElement.offsetHeight;
+    this.textCanvas.width = parentWidth;
+    this.textCanvas.height = parentHeight;
+    this.canvas.width =
+        parentWidth - this.axisLabelBuffer.left - this.axisLabelBuffer.right;
+    this.canvas.height =
+        parentHeight - this.axisLabelBuffer.top - this.axisLabelBuffer.bottom;
+    this.lineDrawerContext.viewport(
+        0, 0, this.lineDrawerContext.drawingBufferWidth,
+        this.lineDrawerContext.drawingBufferHeight);
 
     // Clear the overlay.
     const textCtx = this.textCanvas.getContext("2d");
diff --git a/frc971/analysis/in_process_plotter.cc b/frc971/analysis/in_process_plotter.cc
index c7a715a..0eaf719 100644
--- a/frc971/analysis/in_process_plotter.cc
+++ b/frc971/analysis/in_process_plotter.cc
@@ -25,6 +25,9 @@
   color_wheel_.push_back(Color(1, 1, 0));
   color_wheel_.push_back(Color(0, 1, 1));
   color_wheel_.push_back(Color(1, 0, 1));
+  color_wheel_.push_back(Color(1, 0.6, 0));
+  color_wheel_.push_back(Color(0.6, 0.3, 0));
+  color_wheel_.push_back(Color(1, 1, 1));
 }
 
 void Plotter::Spin() { event_loop_factory_.Run(); }
diff --git a/frc971/analysis/plot_data_utils.ts b/frc971/analysis/plot_data_utils.ts
index def34ed..5d1f4a0 100644
--- a/frc971/analysis/plot_data_utils.ts
+++ b/frc971/analysis/plot_data_utils.ts
@@ -29,9 +29,6 @@
   plotSelect.add(new Option('Select Plot', invalidSelectValue));
 
   const plotDiv = document.createElement('div');
-  plotDiv.style.position = 'absolute';
-  plotDiv.style.top = '30';
-  plotDiv.style.left = '0';
   parentDiv.appendChild(plotDiv);
 
   conn.addReliableHandler(
@@ -50,12 +47,11 @@
         for (let ii = 0; ii < plotFb.figuresLength(); ++ii) {
           const figure = plotFb.figures(ii);
           const figureDiv = document.createElement('div');
-          figureDiv.style.top = figure.position().top().toString();
-          figureDiv.style.left = figure.position().left().toString();
-          figureDiv.style.position = 'absolute';
+          figureDiv.style.width = figure.position().width().toString() + "px";
+          figureDiv.style.height = figure.position().height().toString() + "px";
+          figureDiv.style.position = 'relative';
           div.appendChild(figureDiv);
-          const plot = new Plot(
-              figureDiv, figure.position().width(), figure.position().height());
+          const plot = new Plot(figureDiv);
 
           if (figure.title()) {
             plot.getAxisLabels().setTitle(figure.title());
diff --git a/frc971/control_loops/drivetrain/down_estimator_plotter.ts b/frc971/control_loops/drivetrain/down_estimator_plotter.ts
index c6e414c..7f5bd58 100644
--- a/frc971/control_loops/drivetrain/down_estimator_plotter.ts
+++ b/frc971/control_loops/drivetrain/down_estimator_plotter.ts
@@ -18,7 +18,7 @@
       '/drivetrain', 'frc971.IMUValuesBatch',
       new ImuMessageHandler(conn.getSchema('frc971.IMUValuesBatch')));
 
-  const accelPlot = aosPlotter.addPlot(element, [0, 0], [width, height]);
+  const accelPlot = aosPlotter.addPlot(element, [width, height]);
   accelPlot.plot.getAxisLabels().setTitle(
       'Estimated Accelerations (x = forward, y = lateral, z = vertical)');
   accelPlot.plot.getAxisLabels().setYLabel('Acceleration (m/s/s)');
@@ -31,7 +31,7 @@
   const accelZ = accelPlot.addMessageLine(status, ['down_estimator', 'accel_z']);
   accelZ.setColor(BLUE);
 
-  const velPlot = aosPlotter.addPlot(element, [0, height], [width, height]);
+  const velPlot = aosPlotter.addPlot(element, [width, height]);
   velPlot.plot.getAxisLabels().setTitle('Raw IMU Integrated Velocity');
   velPlot.plot.getAxisLabels().setYLabel('Velocity (m/s)');
   velPlot.plot.getAxisLabels().setXLabel('Monotonic Reading Time (sec)');
@@ -43,7 +43,7 @@
   const velZ = velPlot.addMessageLine(status, ['down_estimator', 'velocity_z']);
   velZ.setColor(BLUE);
 
-  const gravityPlot = aosPlotter.addPlot(element, [0, height * 2], [width, height]);
+  const gravityPlot = aosPlotter.addPlot(element, [width, height]);
   gravityPlot.plot.getAxisLabels().setTitle('Accelerometer Magnitudes');
   gravityPlot.plot.getAxisLabels().setXLabel('Monotonic Sent Time (sec)');
   gravityPlot.plot.setDefaultYRange([0.95, 1.05]);
@@ -58,7 +58,7 @@
   accelMagnitudeLine.setDrawLine(false);
 
   const orientationPlot =
-      aosPlotter.addPlot(element, [0, height * 3], [width, height]);
+      aosPlotter.addPlot(element, [width, height]);
   orientationPlot.plot.getAxisLabels().setTitle('Orientation');
   orientationPlot.plot.getAxisLabels().setYLabel('Angle (rad)');
 
@@ -75,7 +75,7 @@
   yaw.setColor(BLUE);
   yaw.setLabel('yaw');
 
-  const imuAccelPlot = aosPlotter.addPlot(element, [0, height * 4], [width, height]);
+  const imuAccelPlot = aosPlotter.addPlot(element, [width, height]);
   imuAccelPlot.plot.getAxisLabels().setTitle('Filtered Accelerometer Readings');
   imuAccelPlot.plot.getAxisLabels().setYLabel('Acceleration (g)');
   imuAccelPlot.plot.getAxisLabels().setXLabel('Monotonic Reading Time (sec)');
@@ -113,7 +113,7 @@
   expectedAccelZ.setColor(BLUE);
   expectedAccelZ.setPointSize(0);
 
-  const gyroPlot = aosPlotter.addPlot(element, [0, height * 5], [width, height]);
+  const gyroPlot = aosPlotter.addPlot(element, [width, height]);
   gyroPlot.plot.getAxisLabels().setTitle('Gyro Readings');
   gyroPlot.plot.getAxisLabels().setYLabel('Angular Velocity (rad / sec)');
   gyroPlot.plot.getAxisLabels().setXLabel('Monotonic Reading Time (sec)');
@@ -141,7 +141,7 @@
   const gyroZ = gyroPlot.addMessageLine(imu, ['gyro_z']);
   gyroZ.setColor(BLUE);
 
-  const statePlot = aosPlotter.addPlot(element, [0, height * 6], [width, height / 2]);
+  const statePlot = aosPlotter.addPlot(element, [width, height / 2]);
   statePlot.plot.getAxisLabels().setTitle('IMU State');
   statePlot.plot.getAxisLabels().setXLabel('Monotonic Sent Time (sec)');
 
diff --git a/frc971/control_loops/drivetrain/drivetrain_plotter.ts b/frc971/control_loops/drivetrain/drivetrain_plotter.ts
index f55f965..deb300f 100644
--- a/frc971/control_loops/drivetrain/drivetrain_plotter.ts
+++ b/frc971/control_loops/drivetrain/drivetrain_plotter.ts
@@ -24,12 +24,9 @@
       '/drivetrain', 'frc971.IMUValuesBatch',
       new ImuMessageHandler(conn.getSchema('frc971.IMUValuesBatch')));
 
-  let currentTop = 0;
-
   // Polydrivetrain (teleop control) plots
   const teleopPlot =
-      aosPlotter.addPlot(element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
-  currentTop += DEFAULT_HEIGHT / 2;
+      aosPlotter.addPlot(element, [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
   teleopPlot.plot.getAxisLabels().setTitle('Drivetrain Teleop Goals');
   teleopPlot.plot.getAxisLabels().setXLabel(TIME);
   teleopPlot.plot.getAxisLabels().setYLabel('bool, throttle/wheel values');
@@ -44,8 +41,7 @@
 
   // Drivetrain Control Mode
   const modePlot =
-      aosPlotter.addPlot(element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
-  currentTop += DEFAULT_HEIGHT / 2;
+      aosPlotter.addPlot(element, [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
   // TODO(james): Actually add enum support.
   modePlot.plot.getAxisLabels().setTitle(
       'Drivetrain Mode [POLYDRIVE, MOTION_PROFILE, ' +
@@ -58,9 +54,7 @@
   controllerType.setDrawLine(false);
 
   // Drivetrain Status estimated relative position
-  const positionPlot = aosPlotter.addPlot(element, [0, currentTop],
-                                         [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
-  currentTop += DEFAULT_HEIGHT;
+  const positionPlot = aosPlotter.addPlot(element);
   positionPlot.plot.getAxisLabels().setTitle("Estimated Relative Position " +
                                              "of the Drivetrain");
   positionPlot.plot.getAxisLabels().setXLabel(TIME);
@@ -83,9 +77,7 @@
   rightEncoder.setColor(CYAN);
 
   // Drivetrain Output Voltage
-  const outputPlot =
-      aosPlotter.addPlot(element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
-  currentTop += DEFAULT_HEIGHT;
+  const outputPlot = aosPlotter.addPlot(element);
   outputPlot.plot.getAxisLabels().setTitle('Drivetrain Output');
   outputPlot.plot.getAxisLabels().setXLabel(TIME);
   outputPlot.plot.getAxisLabels().setYLabel('Voltage (V)');
@@ -96,9 +88,7 @@
   rightVoltage.setColor(GREEN);
 
   // Voltage Errors
-  const voltageErrors =
-      aosPlotter.addPlot(element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
-  currentTop += DEFAULT_HEIGHT;
+  const voltageErrors = aosPlotter.addPlot(element);
   voltageErrors.plot.getAxisLabels().setTitle('Voltage Errors');
   voltageErrors.plot.getAxisLabels().setXLabel(TIME);
   voltageErrors.plot.getAxisLabels().setYLabel('Voltage (V)');
@@ -118,9 +108,7 @@
   ekfRightVoltageError.setColor(CYAN);
 
   // Sundry components of the output voltages
-  const otherVoltages =
-      aosPlotter.addPlot(element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
-  currentTop += DEFAULT_HEIGHT;
+  const otherVoltages = aosPlotter.addPlot(element);
   otherVoltages.plot.getAxisLabels().setTitle('Other Voltage Components');
   otherVoltages.plot.getAxisLabels().setXLabel(TIME);
   otherVoltages.plot.getAxisLabels().setYLabel('Voltage (V)');
@@ -144,9 +132,7 @@
   uncappedRightVoltage.setDrawLine(false);
 
   // Drivetrain Velocities
-  const velocityPlot =
-      aosPlotter.addPlot(element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
-  currentTop += DEFAULT_HEIGHT;
+  const velocityPlot = aosPlotter.addPlot(element);
   velocityPlot.plot.getAxisLabels().setTitle('Velocity Plots');
   velocityPlot.plot.getAxisLabels().setXLabel(TIME);
   velocityPlot.plot.getAxisLabels().setYLabel('Wheel Velocity (m/s)');
@@ -183,9 +169,7 @@
   rightSpeed.setColor(BROWN);
 
   // Drivetrain trajectory and localizer velocities
-  const velocityPlot2 = aosPlotter.addPlot(element, [0, currentTop],
-                                          [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
-  currentTop += DEFAULT_HEIGHT;
+  const velocityPlot2 = aosPlotter.addPlot(element);
   velocityPlot2.plot.getAxisLabels().setTitle(
       "Trajectory and Localizer Velocity Plots");
   velocityPlot2.plot.getAxisLabels().setXLabel(TIME);
@@ -221,8 +205,7 @@
   splineLateralVelocity.setPointSize(0.0);
 
   // Heading
-  const yawPlot = aosPlotter.addPlot(element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
-  currentTop += DEFAULT_HEIGHT;
+  const yawPlot = aosPlotter.addPlot(element);
   yawPlot.plot.getAxisLabels().setTitle('Robot Yaw');
   yawPlot.plot.getAxisLabels().setXLabel(TIME);
   yawPlot.plot.getAxisLabels().setYLabel('Yaw (rad)');
@@ -240,9 +223,7 @@
   downEstimatorYaw.setColor(BLUE);
 
   // Pitch/Roll
-  const orientationPlot =
-      aosPlotter.addPlot(element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
-  currentTop += DEFAULT_HEIGHT;
+  const orientationPlot = aosPlotter.addPlot(element);
   orientationPlot.plot.getAxisLabels().setTitle('Orientation');
   orientationPlot.plot.getAxisLabels().setXLabel(TIME);
   orientationPlot.plot.getAxisLabels().setYLabel('Angle (rad)');
@@ -257,9 +238,7 @@
   pitch.setLabel('pitch');
 
   // Accelerometer/Gravity
-  const accelPlot =
-      aosPlotter.addPlot(element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
-  currentTop += DEFAULT_HEIGHT;
+  const accelPlot = aosPlotter.addPlot(element);
   accelPlot.plot.getAxisLabels().setTitle('Accelerometer Readings');
   accelPlot.plot.getAxisLabels().setYLabel('Acceleration (g)');
   accelPlot.plot.getAxisLabels().setXLabel('Monotonic Reading Time (sec)');
@@ -293,9 +272,7 @@
   accelZ.setDrawLine(false);
 
   // Absolute X Position
-  const xPositionPlot =
-      aosPlotter.addPlot(element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
-  currentTop += DEFAULT_HEIGHT;
+  const xPositionPlot = aosPlotter.addPlot(element);
   xPositionPlot.plot.getAxisLabels().setTitle('X Position');
   xPositionPlot.plot.getAxisLabels().setXLabel(TIME);
   xPositionPlot.plot.getAxisLabels().setYLabel('X Position (m)');
@@ -307,9 +284,7 @@
   splineX.setColor(GREEN);
 
   // Absolute Y Position
-  const yPositionPlot =
-      aosPlotter.addPlot(element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
-  currentTop += DEFAULT_HEIGHT;
+  const yPositionPlot = aosPlotter.addPlot(element);
   yPositionPlot.plot.getAxisLabels().setTitle('Y Position');
   yPositionPlot.plot.getAxisLabels().setXLabel(TIME);
   yPositionPlot.plot.getAxisLabels().setYLabel('Y Position (m)');
@@ -321,9 +296,7 @@
   splineY.setColor(GREEN);
 
   // Gyro
-  const gyroPlot =
-      aosPlotter.addPlot(element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
-  currentTop += DEFAULT_HEIGHT;
+  const gyroPlot = aosPlotter.addPlot(element);
   gyroPlot.plot.getAxisLabels().setTitle('Gyro Readings');
   gyroPlot.plot.getAxisLabels().setYLabel('Angular Velocity (rad / sec)');
   gyroPlot.plot.getAxisLabels().setXLabel('Monotonic Reading Time (sec)');
@@ -353,8 +326,7 @@
 
   // IMU States
   const imuStatePlot =
-      aosPlotter.addPlot(element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
-  currentTop += DEFAULT_HEIGHT / 2;
+      aosPlotter.addPlot(element, [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
   imuStatePlot.plot.getAxisLabels().setTitle('IMU State');
   imuStatePlot.plot.getAxisLabels().setXLabel(TIME);
   imuStatePlot.plot.setDefaultYRange([-0.1, 1.1]);
diff --git a/frc971/control_loops/drivetrain/robot_state_plotter.ts b/frc971/control_loops/drivetrain/robot_state_plotter.ts
index 829df25..2ce8001 100644
--- a/frc971/control_loops/drivetrain/robot_state_plotter.ts
+++ b/frc971/control_loops/drivetrain/robot_state_plotter.ts
@@ -18,8 +18,7 @@
 
   // Robot Enabled/Disabled and Mode
   const robotStatePlot =
-      aosPlotter.addPlot(element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
-  currentTop += DEFAULT_HEIGHT / 2;
+      aosPlotter.addPlot(element, [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
   robotStatePlot.plot.getAxisLabels().setTitle('Robot State');
   robotStatePlot.plot.getAxisLabels().setXLabel(TIME);
   robotStatePlot.plot.getAxisLabels().setYLabel('bool');
@@ -41,7 +40,7 @@
 
   // Battery Voltage
   const batteryPlot =
-      aosPlotter.addPlot(element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
+      aosPlotter.addPlot(element, [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
   currentTop += DEFAULT_HEIGHT / 2;
   batteryPlot.plot.getAxisLabels().setTitle('Battery Voltage');
   batteryPlot.plot.getAxisLabels().setXLabel(TIME);
@@ -51,7 +50,7 @@
 
   // PID of process reading sensors
   const readerPidPlot =
-      aosPlotter.addPlot(element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
+      aosPlotter.addPlot(element, [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
   currentTop += DEFAULT_HEIGHT / 2;
   readerPidPlot.plot.getAxisLabels().setTitle("PID of Process Reading Sensors");
   readerPidPlot.plot.getAxisLabels().setXLabel(TIME);
diff --git a/frc971/control_loops/drivetrain/spline_plotter.ts b/frc971/control_loops/drivetrain/spline_plotter.ts
index 028a3fc..c39afd5 100644
--- a/frc971/control_loops/drivetrain/spline_plotter.ts
+++ b/frc971/control_loops/drivetrain/spline_plotter.ts
@@ -25,7 +25,7 @@
 
   // Polydrivetrain (teleop control) plots
   const longitudinalPlot = aosPlotter.addPlot(
-      element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
+      element, [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
   currentTop += DEFAULT_HEIGHT / 2;
   longitudinalPlot.plot.getAxisLabels().setTitle('Longitudinal Distance');
   longitudinalPlot.plot.getAxisLabels().setXLabel(TIME);
@@ -35,7 +35,7 @@
       status, ['trajectory_logging', 'distance_remaining']);
 
   const boolPlot = aosPlotter.addPlot(
-      element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
+      element, [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
   currentTop += DEFAULT_HEIGHT / 2;
   boolPlot.plot.getAxisLabels().setTitle('Bool Flags');
   boolPlot.plot.getAxisLabels().setXLabel(TIME);
@@ -46,8 +46,7 @@
   boolPlot.addMessageLine(status, ['trajectory_logging', 'is_executed'])
       .setColor(BLUE);
 
-  const handlePlot = aosPlotter.addPlot(
-      element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
+  const handlePlot = aosPlotter.addPlot(element);
   currentTop += DEFAULT_HEIGHT;
   handlePlot.plot.getAxisLabels().setTitle('Spline Handles');
   handlePlot.plot.getAxisLabels().setXLabel(TIME);
diff --git a/frc971/wpilib/imu_plotter.ts b/frc971/wpilib/imu_plotter.ts
index af23ed9..0c735eb 100644
--- a/frc971/wpilib/imu_plotter.ts
+++ b/frc971/wpilib/imu_plotter.ts
@@ -10,7 +10,7 @@
   const height = 400;
   const aosPlotter = new AosPlotter(conn);
 
-  const accelPlot = aosPlotter.addPlot(element, [0, 0], [width, height]);
+  const accelPlot = aosPlotter.addPlot(element, [width, height]);
   accelPlot.plot.getAxisLabels().setTitle('Accelerometer Readings');
   accelPlot.plot.getAxisLabels().setYLabel('Acceleration (g)');
   accelPlot.plot.getAxisLabels().setXLabel('Monotonic Reading Time (sec)');
@@ -29,7 +29,7 @@
   const accelZ = accelPlot.addMessageLine(imu, ['accelerometer_z']);
   accelZ.setColor([0, 0, 1]);
 
-  const gyroPlot = aosPlotter.addPlot(element, [0, height], [width, height]);
+  const gyroPlot = aosPlotter.addPlot(element, [width, height]);
   gyroPlot.plot.getAxisLabels().setTitle('Gyro Readings');
   gyroPlot.plot.getAxisLabels().setYLabel('Angular Velocity (rad / sec)');
   gyroPlot.plot.getAxisLabels().setXLabel('Monotonic Reading Time (sec)');
@@ -57,14 +57,14 @@
   const gyroZ = gyroPlot.addMessageLine(imu, ['gyro_z']);
   gyroZ.setColor([0, 0, 1]);
 
-  const tempPlot = aosPlotter.addPlot(element, [0, height * 2], [width, height / 2]);
+  const tempPlot = aosPlotter.addPlot(element, [width, height / 2]);
   tempPlot.plot.getAxisLabels().setTitle('IMU Temperature');
   tempPlot.plot.getAxisLabels().setYLabel('Temperature (deg C)');
   tempPlot.plot.getAxisLabels().setXLabel('Monotonic Reading Time (sec)');
 
   tempPlot.addMessageLine(imu, ['temperature']);
 
-  const statePlot = aosPlotter.addPlot(element, [0, height * 2.5], [width, height / 2]);
+  const statePlot = aosPlotter.addPlot(element, [width, height / 2]);
   statePlot.plot.getAxisLabels().setTitle('IMU State');
   statePlot.plot.getAxisLabels().setXLabel('Monotonic Sent Time (sec)');
   statePlot.plot.setDefaultYRange([-0.1, 1.1]);
diff --git a/y2020/control_loops/drivetrain/localizer_plotter.ts b/y2020/control_loops/drivetrain/localizer_plotter.ts
index e6729dd..86465a5 100644
--- a/y2020/control_loops/drivetrain/localizer_plotter.ts
+++ b/y2020/control_loops/drivetrain/localizer_plotter.ts
@@ -12,8 +12,6 @@
 import Schema = configuration.reflection.Schema;
 
 const TIME = AosPlotter.TIME;
-const DEFAULT_WIDTH = AosPlotter.DEFAULT_WIDTH;
-const DEFAULT_HEIGHT = AosPlotter.DEFAULT_HEIGHT;
 
 
 export function plotLocalizer(conn: Connection, element: Element) : void {
@@ -27,11 +25,7 @@
   const superstructureStatus = aosPlotter.addMessageSource(
       '/superstructure', 'y2020.control_loops.superstructure.Status');
 
-  var currentTop = 0;
-
-  const imageAcceptedPlot = aosPlotter.addPlot(
-      element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
-  currentTop += DEFAULT_HEIGHT;
+  const imageAcceptedPlot = aosPlotter.addPlot(element);
   imageAcceptedPlot.plot.getAxisLabels().setTitle('Image Acceptance');
   imageAcceptedPlot.plot.getAxisLabels().setXLabel(TIME);
   imageAcceptedPlot.plot.getAxisLabels().setYLabel('[bool]');
@@ -41,9 +35,7 @@
       .setColor(RED)
       .setDrawLine(false);
 
-  const impliedXPlot = aosPlotter.addPlot(
-      element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
-  currentTop += DEFAULT_HEIGHT;
+  const impliedXPlot = aosPlotter.addPlot(element);
   impliedXPlot.plot.getAxisLabels().setTitle('Implied Robot X');
   impliedXPlot.plot.getAxisLabels().setXLabel(TIME);
   impliedXPlot.plot.getAxisLabels().setYLabel('[m]');
@@ -58,9 +50,7 @@
       .setColor(GREEN)
       .setLabel('Localizer X');
 
-  const impliedYPlot = aosPlotter.addPlot(
-      element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
-  currentTop += DEFAULT_HEIGHT;
+  const impliedYPlot = aosPlotter.addPlot(element);
   impliedYPlot.plot.getAxisLabels().setTitle('Implied Robot Y');
   impliedYPlot.plot.getAxisLabels().setXLabel(TIME);
   impliedYPlot.plot.getAxisLabels().setYLabel('[m]');
@@ -75,9 +65,7 @@
       .setColor(GREEN)
       .setLabel('Localizer Y');
 
-  const impliedHeadingPlot = aosPlotter.addPlot(
-      element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
-  currentTop += DEFAULT_HEIGHT;
+  const impliedHeadingPlot = aosPlotter.addPlot(element);
   impliedHeadingPlot.plot.getAxisLabels().setTitle('Implied Robot Theta');
   impliedHeadingPlot.plot.getAxisLabels().setXLabel(TIME);
   impliedHeadingPlot.plot.getAxisLabels().setYLabel('[rad]');
@@ -89,9 +77,7 @@
       .setColor(GREEN)
       .setLabel('Localizer Theta');
 
-  const impliedTurretGoalPlot = aosPlotter.addPlot(
-      element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
-  currentTop += DEFAULT_HEIGHT;
+  const impliedTurretGoalPlot = aosPlotter.addPlot(element);
   impliedTurretGoalPlot.plot.getAxisLabels().setTitle('Implied Turret Goal');
   impliedTurretGoalPlot.plot.getAxisLabels().setXLabel(TIME);
   impliedTurretGoalPlot.plot.getAxisLabels().setYLabel('[rad]');
@@ -102,9 +88,7 @@
   impliedTurretGoalPlot.addMessageLine(superstructureStatus, ['aimer', 'turret_position'])
       .setColor(GREEN);
 
-  const imageTimingPlot = aosPlotter.addPlot(
-      element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
-  currentTop += DEFAULT_HEIGHT;
+  const imageTimingPlot = aosPlotter.addPlot(element);
   imageTimingPlot.plot.getAxisLabels().setTitle('Timing Plot');
   imageTimingPlot.plot.getAxisLabels().setXLabel(TIME);
   imageTimingPlot.plot.getAxisLabels().setYLabel('[ns]');
diff --git a/y2020/control_loops/superstructure/accelerator_plotter.ts b/y2020/control_loops/superstructure/accelerator_plotter.ts
index b625a1c..e1bc5bc 100644
--- a/y2020/control_loops/superstructure/accelerator_plotter.ts
+++ b/y2020/control_loops/superstructure/accelerator_plotter.ts
@@ -21,8 +21,7 @@
 
   // Robot Enabled/Disabled and Mode
   const velocityPlot =
-      aosPlotter.addPlot(element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
-  currentTop += DEFAULT_HEIGHT / 2;
+      aosPlotter.addPlot(element, [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
   velocityPlot.plot.getAxisLabels().setTitle('Velocity');
   velocityPlot.plot.getAxisLabels().setXLabel(TIME);
   velocityPlot.plot.getAxisLabels().setYLabel('rad/s');
@@ -38,8 +37,7 @@
   velocityPlot.addMessageLine(status, ['shooter', 'accelerator_right', 'dt_angular_velocity']).setColor(BLUE).setPointSize(0.0);
 
   const voltagePlot =
-      aosPlotter.addPlot(element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
-  currentTop += DEFAULT_HEIGHT / 2;
+      aosPlotter.addPlot(element, [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
   voltagePlot.plot.getAxisLabels().setTitle('Voltage');
   voltagePlot.plot.getAxisLabels().setXLabel(TIME);
   voltagePlot.plot.getAxisLabels().setYLabel('Volts');
@@ -53,8 +51,7 @@
 
 
   const currentPlot =
-      aosPlotter.addPlot(element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
-  currentTop += DEFAULT_HEIGHT / 2;
+      aosPlotter.addPlot(element, [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
   currentPlot.plot.getAxisLabels().setTitle('Current');
   currentPlot.plot.getAxisLabels().setXLabel(TIME);
   currentPlot.plot.getAxisLabels().setYLabel('Amps');
diff --git a/y2020/control_loops/superstructure/finisher_plotter.ts b/y2020/control_loops/superstructure/finisher_plotter.ts
index c9420ae..474c8a4 100644
--- a/y2020/control_loops/superstructure/finisher_plotter.ts
+++ b/y2020/control_loops/superstructure/finisher_plotter.ts
@@ -17,12 +17,9 @@
   const pdpValues = aosPlotter.addMessageSource('/roborio/aos', 'frc971.PDPValues');
   const robotState = aosPlotter.addMessageSource('/aos', 'aos.RobotState');
 
-  var currentTop = 0;
-
   // Robot Enabled/Disabled and Mode
   const velocityPlot =
-      aosPlotter.addPlot(element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
-  currentTop += DEFAULT_HEIGHT / 2;
+      aosPlotter.addPlot(element, [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
   velocityPlot.plot.getAxisLabels().setTitle('Velocity');
   velocityPlot.plot.getAxisLabels().setXLabel(TIME);
   velocityPlot.plot.getAxisLabels().setYLabel('rad/s');
@@ -35,8 +32,7 @@
   velocityPlot.addMessageLine(status, ['shooter', 'finisher', 'dt_angular_velocity']).setColor(PINK).setPointSize(0.0);
 
   const ballsShotPlot =
-      aosPlotter.addPlot(element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
-  currentTop += DEFAULT_HEIGHT / 2;
+      aosPlotter.addPlot(element, [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
   ballsShotPlot.plot.getAxisLabels().setTitle('Balls Shot');
   ballsShotPlot.plot.getAxisLabels().setXLabel(TIME);
   ballsShotPlot.plot.getAxisLabels().setYLabel('Balls');
@@ -45,8 +41,7 @@
 
 
   const voltagePlot =
-      aosPlotter.addPlot(element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
-  currentTop += DEFAULT_HEIGHT / 2;
+      aosPlotter.addPlot(element, [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
   voltagePlot.plot.getAxisLabels().setTitle('Voltage');
   voltagePlot.plot.getAxisLabels().setXLabel(TIME);
   voltagePlot.plot.getAxisLabels().setYLabel('Volts');
@@ -58,8 +53,7 @@
 
 
   const currentPlot =
-      aosPlotter.addPlot(element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
-  currentTop += DEFAULT_HEIGHT / 2;
+      aosPlotter.addPlot(element, [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
   currentPlot.plot.getAxisLabels().setTitle('Current');
   currentPlot.plot.getAxisLabels().setXLabel(TIME);
   currentPlot.plot.getAxisLabels().setYLabel('Amps');
diff --git a/y2020/control_loops/superstructure/hood_plotter.ts b/y2020/control_loops/superstructure/hood_plotter.ts
index 6c8025d..55b1ba8 100644
--- a/y2020/control_loops/superstructure/hood_plotter.ts
+++ b/y2020/control_loops/superstructure/hood_plotter.ts
@@ -20,7 +20,7 @@
 
   // Robot Enabled/Disabled and Mode
   const positionPlot =
-      aosPlotter.addPlot(element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
+      aosPlotter.addPlot(element, [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
   currentTop += DEFAULT_HEIGHT / 2;
   positionPlot.plot.getAxisLabels().setTitle('Position');
   positionPlot.plot.getAxisLabels().setXLabel(TIME);
@@ -35,7 +35,7 @@
   positionPlot.addMessageLine(status, ['hood', 'estimator_state', 'position']).setColor(CYAN).setPointSize(0.0);
 
   const voltagePlot =
-      aosPlotter.addPlot(element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
+      aosPlotter.addPlot(element, [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
   currentTop += DEFAULT_HEIGHT / 2;
   voltagePlot.plot.getAxisLabels().setTitle('Voltage');
   voltagePlot.plot.getAxisLabels().setXLabel(TIME);
diff --git a/y2020/control_loops/superstructure/turret_plotter.ts b/y2020/control_loops/superstructure/turret_plotter.ts
index 948ca97..34279ba 100644
--- a/y2020/control_loops/superstructure/turret_plotter.ts
+++ b/y2020/control_loops/superstructure/turret_plotter.ts
@@ -12,8 +12,6 @@
 import Schema = configuration.reflection.Schema;
 
 const TIME = AosPlotter.TIME;
-const DEFAULT_WIDTH = AosPlotter.DEFAULT_WIDTH;
-const DEFAULT_HEIGHT = AosPlotter.DEFAULT_HEIGHT;
 
 class DerivativeMessageHandler extends MessageHandler {
   // Calculated magnitude of the measured acceleration from the IMU.
@@ -71,11 +69,7 @@
   const localizerDebug =
       aosPlotter.addMessageSource('/drivetrain', 'y2020.control_loops.drivetrain.LocalizerDebug');
 
-  var currentTop = 0;
-
-  const turretPosPlot = aosPlotter.addPlot(
-      element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
-  currentTop += DEFAULT_HEIGHT;
+  const turretPosPlot = aosPlotter.addPlot(element);
   turretPosPlot.plot.getAxisLabels().setTitle('Turret Position');
   turretPosPlot.plot.getAxisLabels().setXLabel(TIME);
   turretPosPlot.plot.getAxisLabels().setYLabel('rad');
@@ -93,9 +87,7 @@
       .setColor(BLUE)
       .setDrawLine(false);
 
-  const turretVelPlot = aosPlotter.addPlot(
-      element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
-  currentTop += DEFAULT_HEIGHT;
+  const turretVelPlot = aosPlotter.addPlot(element);
   turretVelPlot.plot.getAxisLabels().setTitle('Turret Velocity');
   turretVelPlot.plot.getAxisLabels().setXLabel(TIME);
   turretVelPlot.plot.getAxisLabels().setYLabel('rad / sec');
@@ -110,9 +102,7 @@
       .setColor(BLUE)
       .setDrawLine(false);
 
-  const turretAccelPlot = aosPlotter.addPlot(
-      element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
-  currentTop += DEFAULT_HEIGHT;
+  const turretAccelPlot = aosPlotter.addPlot(element);
   turretAccelPlot.plot.getAxisLabels().setTitle('Turret Acceleration');
   turretAccelPlot.plot.getAxisLabels().setXLabel(TIME);
   turretAccelPlot.plot.getAxisLabels().setYLabel('rad / sec / sec');
@@ -121,9 +111,7 @@
       .setColor(RED)
       .setPointSize(0.0);
 
-  const turretVoltagePlot = aosPlotter.addPlot(
-      element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
-  currentTop += DEFAULT_HEIGHT;
+  const turretVoltagePlot = aosPlotter.addPlot(element);
   turretVoltagePlot.plot.getAxisLabels().setTitle('Turret Voltage');
   turretVoltagePlot.plot.getAxisLabels().setXLabel(TIME);
   turretVoltagePlot.plot.getAxisLabels().setYLabel('V');
@@ -141,9 +129,7 @@
       .setColor(RED)
       .setPointSize(0.0);
 
-  const currentPlot = aosPlotter.addPlot(
-      element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
-  currentTop += DEFAULT_HEIGHT;
+  const currentPlot = aosPlotter.addPlot(element);
   currentPlot.plot.getAxisLabels().setTitle('Current');
   currentPlot.plot.getAxisLabels().setXLabel(TIME);
   currentPlot.plot.getAxisLabels().setYLabel('Amps');
@@ -154,9 +140,7 @@
       .setPointSize(0.0);
 
 
-  const targetDistancePlot = aosPlotter.addPlot(
-      element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
-  currentTop += DEFAULT_HEIGHT;
+  const targetDistancePlot = aosPlotter.addPlot(element);
   targetDistancePlot.plot.getAxisLabels().setTitle('Target distance');
   targetDistancePlot.plot.getAxisLabels().setXLabel(TIME);
   targetDistancePlot.plot.getAxisLabels().setYLabel('m');
@@ -165,9 +149,7 @@
       .setColor(RED)
       .setPointSize(0.0);
 
-  const targetChoicePlot = aosPlotter.addPlot(
-      element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
-  currentTop += DEFAULT_HEIGHT;
+  const targetChoicePlot = aosPlotter.addPlot(element);
   targetChoicePlot.plot.getAxisLabels().setTitle('Target choice');
   targetChoicePlot.plot.getAxisLabels().setXLabel(TIME);
   targetChoicePlot.plot.getAxisLabels().setYLabel('[bool]');
@@ -177,9 +159,7 @@
       .setColor(RED)
       .setPointSize(0.0);
 
-  const imageAcceptedPlot = aosPlotter.addPlot(
-      element, [0, currentTop], [DEFAULT_WIDTH, DEFAULT_HEIGHT]);
-  currentTop += DEFAULT_HEIGHT;
+  const imageAcceptedPlot = aosPlotter.addPlot(element);
   imageAcceptedPlot.plot.getAxisLabels().setTitle('Image Acceptance');
   imageAcceptedPlot.plot.getAxisLabels().setXLabel(TIME);
   imageAcceptedPlot.plot.getAxisLabels().setYLabel('[bool]');