Same than trace3D, used when ran from Jupyther notebooks

def trace3D_notebook(self):
        """Same than trace3D, used when ran from Jupyther notebooks"""
        trace = self.get_trace()
        import vpython

        class IPsphere(vpython.sphere):
            def __init__(self, ip, **kargs):
                vpython.sphere.__init__(self, **kargs)
                self.ip = ip
                self.label = None
                self.setlabel(self.ip)
                self.last_clicked = None
                self.full = False
                self.savcolor = vpython.vec(*self.color.value)

            def fullinfos(self):
                self.full = True
                self.color = vpython.vec(1, 0, 0)
                a, b = sr(IP(dst=self.ip) / TCP(dport=[21, 22, 23, 25, 80, 443], flags="S"), timeout=2, verbose=0)  # noqa: E501
                if len(a) == 0:
                    txt = "%s:\nno results" % self.ip
                else:
                    txt = "%s:\n" % self.ip
                    for s, r in a:
                        txt += r.sprintf("{TCP:%IP.src%:%TCP.sport% %TCP.flags%}{TCPerror:%IPerror.dst%:%TCPerror.dport% %IP.src% %ir,ICMP.type%}\n")  # noqa: E501
                self.setlabel(txt, visible=1)

            def unfull(self):
                self.color = self.savcolor
                self.full = False
                self.setlabel(self.ip)

            def setlabel(self, txt, visible=None):
                if self.label is not None:
                    if visible is None:
                        visible = self.label.visible
                    self.label.visible = 0
                elif visible is None:
                    visible = 0
                self.label = vpython.label(text=txt, pos=self.pos, space=self.radius, xoffset=10, yoffset=20, visible=visible)  # noqa: E501

            def check_double_click(self):
                try:
                    if self.full or not self.label.visible:
                        return False
                    if self.last_clicked is not None:
                        return (time.time() - self.last_clicked) < 0.5
                    return False
                finally:
                    self.last_clicked = time.time()

            def action(self):
                self.label.visible ^= 1
                if self.full:
                    self.unfull()

        vpython.scene = vpython.canvas()
        vpython.scene.title = "<center><u><b>%s</b></u></center>" % self.listname  # noqa: E501
        vpython.scene.append_to_caption(
            re.sub(
                r'\%(.*)\%',
                r'<span style="color: red">\1</span>',
                re.sub(
                    r'\`(.*)\`',
                    r'<span style="color: #3399ff">\1</span>',
                    """<u><b>Commands:</b></u>
%Click% to toggle information about a node.
%Double click% to perform a quick web scan on this node.
<u><b>Camera usage:</b></u>
`Right button drag or Ctrl-drag` to rotate "camera" to view scene.
`Shift-drag` to move the object around.
`Middle button or Alt-drag` to drag up or down to zoom in or out.
  On a two-button mouse, `middle is wheel or left + right`.
Touch screen: pinch/extend to zoom, swipe or two-finger rotate."""
                )
            )
        )
        vpython.scene.exit = True
        start = vpython.box()
        rings = {}
        tr3d = {}
        for i in trace:
            tr = trace[i]
            tr3d[i] = []
            for t in range(1, max(tr) + 1):
                if t not in rings:
                    rings[t] = []
                if t in tr:
                    if tr[t] not in rings[t]:
                        rings[t].append(tr[t])
                    tr3d[i].append(rings[t].index(tr[t]))
                else:
                    rings[t].append(("unk", -1))
                    tr3d[i].append(len(rings[t]) - 1)

        for t in rings:
            r = rings[t]
            tmp_len = len(r)
            for i in range(tmp_len):
                if r[i][1] == -1:
                    col = vpython.vec(0.75, 0.75, 0.75)
                elif r[i][1]:
                    col = vpython.color.green
                else:
                    col = vpython.color.blue

                s = IPsphere(pos=vpython.vec((tmp_len - 1) * vpython.cos(2 * i * vpython.pi / tmp_len), (tmp_len - 1) * vpython.sin(2 * i * vpython.pi / tmp_len), 2 * t),  # noqa: E501
                             ip=r[i][0],
                             color=col)
                for trlst in six.itervalues(tr3d):
                    if t <= len(trlst):
                        if trlst[t - 1] == i:
                            trlst[t - 1] = s
        forecol = colgen(0.625, 0.4375, 0.25, 0.125)
        for trlst in six.itervalues(tr3d):
            col = vpython.vec(*next(forecol))
            start = vpython.vec(0, 0, 0)
            for ip in trlst:
                vpython.cylinder(pos=start, axis=ip.pos - start, color=col, radius=0.2)  # noqa: E501
                start = ip.pos

        vpython.rate(50)

        # Keys handling
        # TODO: there is currently no way of closing vpython correctly
        # https://github.com/BruceSherwood/vpython-jupyter/issues/36
        # def keyboard_press(ev):
        #     k = ev.key
        #     if k == "esc" or k == "q":
        #         pass  # TODO: close
        #
        # vpython.scene.bind('keydown', keyboard_press)

        # Mouse handling
        def mouse_click(ev):
            if ev.press == "left":
                o = vpython.scene.mouse.pick
                if o and isinstance(o, IPsphere):
                    if o.check_double_click():
                        if o.ip == "unk":
                            return
                        o.fullinfos()
                    else:
                        o.action()

        vpython.scene.bind('mousedown', mouse_click)