diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index d4b175dff9580fdcd333be7975f2f20f280f312f..97c4171e758525dd01bf407e312eaf184e569308 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -22,10 +22,6 @@ before_script:
           coverage_format: cobertura
           path: cov.xml
 
-run-test-3.7:
-  image: python:3.7
-  extends: ".run-test"
-
 run-test-3.8:
   image: python:3.8
   extends: ".run-test"
@@ -38,9 +34,13 @@ run-test-3.10:
   image: python:3.10
   extends: ".run-test"
 
+run-test-3.11:
+  image: python:3.11
+  extends: ".run-test"
+
 pages:
   stage: deploy
-  image: python:3.10
+  image: python:3.11
   script:
     - sphinx-build -b html docs_sphinx public
   artifacts:
diff --git a/b_asic/schedule.py b/b_asic/schedule.py
index 1a01d7453c9694d17782bbcc8cab3c0df1ad1616..3e8d7201f64bd9d3dc637bc04f0af66247f1618d 100644
--- a/b_asic/schedule.py
+++ b/b_asic/schedule.py
@@ -11,8 +11,9 @@ from typing import Dict, List, Optional, Tuple
 
 import matplotlib.pyplot as plt
 import numpy as np
+from matplotlib.patches import PathPatch
+from matplotlib.path import Path
 from matplotlib.ticker import MaxNLocator
-from scipy import interpolate
 
 from b_asic import OutputPort, Signal
 from b_asic.graph_component import GraphID
@@ -353,13 +354,13 @@ class Schedule:
                 )
         self._remove_delays()
 
-    def _plot_schedule(self):
+    def _plot_schedule(self, ax):
         def _draw_arrow2(start, end):
             if end[0] < start[0]:  # Wrap around
-                plt.plot([start[0], self._schedule_time], [start[1], start[1]])
-                plt.plot([0, end[0]], [end[1], end[1]])
+                ax.plot([start[0], self._schedule_time], [start[1], start[1]])
+                ax.plot([0, end[0]], [end[1], end[1]])
             elif end[0] == start[0]:
-                plt.plot(
+                ax.plot(
                     [
                         start[0],
                         start[0] + 0.2,
@@ -378,7 +379,7 @@ class Schedule:
                     ],
                 )
             else:
-                plt.plot(
+                ax.plot(
                     [
                         start[0],
                         (start[0] + end[0]) / 2,
@@ -388,31 +389,21 @@ class Schedule:
                     [start[1], start[1], end[1], end[1]],
                 )
 
-        def _draw_spline(x, y):
-            l = len(x)
-            t = np.linspace(0, 1, l - 2, endpoint=True)
-            t = np.append([0, 0, 0], t)
-            t = np.append(t, [1, 1, 1])
-            tck = [t, [x, y], 3]
-            u3 = np.linspace(0, 1, 50, endpoint=True)
-            out = interpolate.splev(u3, tck)
-            plt.plot(out[0], out[1], color="black")
-
         def _draw_arrow(start, end, name="", laps=0):
             if end[0] < start[0] or laps > 0:  # Wrap around
-                plt.plot(
+                ax.plot(
                     [start[0], self._schedule_time + 0.2],
                     [start[1], start[1]],
                     color="black",
                 )
-                plt.plot([-0.2, end[0]], [end[1], end[1]], color="black")
-                plt.text(
+                ax.plot([-0.2, end[0]], [end[1], end[1]], color="black")
+                ax.text(
                     self._schedule_time + 0.2,
                     start[1],
                     name,
                     verticalalignment="center",
                 )
-                plt.text(
+                ax.text(
                     -0.2,
                     end[1],
                     "{}: {}".format(name, laps),
@@ -421,34 +412,33 @@ class Schedule:
                 )
 
             elif end[0] == start[0]:
-                _draw_spline(
+                p = Path(
                     [
-                        start[0],
-                        start[0] + 0.2,
-                        start[0] + 0.2,
-                        start[0] - 0.2,
-                        start[0] - 0.2,
-                        start[0],
-                    ],
-                    [
-                        start[1],
-                        start[1],
-                        (start[1] + end[1]) / 2,
-                        (start[1] + end[1]) / 2,
-                        end[1],
-                        end[1],
+                        start,
+                        [start[0] + 0.2, start[1]],
+                        [start[0] + 0.2, (start[1] + end[1]) / 2],
+                        [start[0], (start[1] + end[1]) / 2],
+                        [start[0] - 0.2, (start[1] + end[1]) / 2],
+                        [start[0] - 0.2, end[1]],
+                        end
                     ],
+                    [Path.MOVETO, Path.CURVE4, Path.CURVE4, Path.CURVE4, Path.CURVE4, Path.CURVE4, Path.CURVE4]
                 )
+                pp = PathPatch(p, fc='none')
+                ax.add_patch(pp)
             else:
-                _draw_spline(
+                p = Path(
                     [
-                        start[0],
-                        (start[0] + end[0]) / 2,
-                        (start[0] + end[0]) / 2,
-                        end[0],
+                        start,
+                        [(start[0] + end[0]) / 2, start[1]],
+                        [(start[0] + end[0]) / 2, end[1]],
+                        end,
                     ],
-                    [start[1], start[1], end[1], end[1]],
-                )
+                    [Path.MOVETO, Path.CURVE4, Path.CURVE4, Path.CURVE4]
+                    )
+                pp = PathPatch(p, fc='none')
+                ax.add_patch(pp)
+
 
         def _draw_offset_arrow(
             start, end, start_offset, end_offset, name="", laps=0
@@ -463,7 +453,7 @@ class Schedule:
         ypos = 0.5
         ytickpositions = []
         yticklabels = []
-        plt.grid(zorder=0.5)
+        ax.grid(zorder=0.5)
         ypositions = {}
         for op_id, op_start_time in self._start_times.items():
             op = self._sfg.find_by_id(op_id)
@@ -471,12 +461,12 @@ class Schedule:
             _x, _y = zip(*latency_coords)
             x = np.array(_x)
             y = np.array(_y)
-            plt.fill(x + op_start_time, y + ypos)
+            ax.fill(x + op_start_time, y + ypos)
             if execution_time_coords:
                 _x, _y = zip(*execution_time_coords)
                 x = np.array(_x)
                 y = np.array(_y)
-                plt.plot(
+                ax.plot(
                     x + op_start_time,
                     y + ypos,
                     color="black",
@@ -512,11 +502,12 @@ class Schedule:
                         laps=self._laps[output_signal.graph_id],
                     )
 
-        plt.yticks(ytickpositions, yticklabels)
-        plt.axis([-1, self._schedule_time + 1, 0, ypos])
-        plt.gca().xaxis.set_major_locator(MaxNLocator(integer=True))
-        plt.plot([0, 0], [0, ypos], linestyle="--", color="black")
-        plt.plot(
+        ax.set_yticks(ytickpositions)
+        ax.set_yticklabels(yticklabels)
+        ax.axis([-1, self._schedule_time + 1, 0, ypos])
+        ax.xaxis.set_major_locator(MaxNLocator(integer=True))
+        ax.plot([0, 0], [0, ypos], linestyle="--", color="black")
+        ax.plot(
             [self._schedule_time, self._schedule_time],
             [0, ypos],
             linestyle="--",
@@ -524,14 +515,14 @@ class Schedule:
         )
 
     def plot_schedule(self) -> None:
-        plt.figure()
-        self._plot_schedule()
-        plt.show()
+        fig, ax = plt.subplots()
+        self._plot_schedule(ax)
+        fig.show()
 
     def _repr_svg_(self):
-        plt.figure()
-        self._plot_schedule()
+        fig, ax = plt.subplots()
+        self._plot_schedule(ax)
         f = io.StringIO()
-        plt.savefig(f, format="svg")
+        fig.savefig(f, format="svg")
 
         return f.getvalue()
diff --git a/pyproject.toml b/pyproject.toml
index ccf43fe6a27ece1144830e504fdd30e71350d5c6..2b0d2e6968c122721057e691183095ed26a80810 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -6,24 +6,23 @@ maintainers = [
     { name = "Oscar Gustafsson", email = "oscar.gustafsson@gmail.com" },
 ]
 license = { file = "LICENSE" }
-requires-python = ">=3.7"
+requires-python = ">=3.8"
 dependencies = [
     "numpy",
     "pybind11>=2.3.0",
     "pyside2",
     "qtpy",
-    "graphviz<=0.17",
+    "graphviz",
     "matplotlib",
-    "scipy",
 ]
 classifiers = [
     "Intended Audience :: Education",
     "Intended Audience :: Science/Research",
     "Programming Language :: Python :: 3",
-    "Programming Language :: Python :: 3.7",
     "Programming Language :: Python :: 3.8",
     "Programming Language :: Python :: 3.9",
     "Programming Language :: Python :: 3.10",
+    "Programming Language :: Python :: 3.11",
     "Programming Language :: C++",
     "License :: OSI Approved :: MIT License",
     "Operating System :: OS Independent",