import numpy as np
import pytest
from matplotlib.collections import LineCollection, PolyCollection

import holoviews as hv
from holoviews.core.options import AbbreviatedException
from holoviews.element import circular_layout
from holoviews.testing import assert_data_equal

from .test_plot import MPL_GE_3_4_0, TestMPLPlot, mpl_renderer


class TestMplGraphPlot(TestMPLPlot):
    def setup_method(self):
        super().setup_method()

        N = 8
        self.nodes = circular_layout(np.arange(N, dtype=np.int32))
        self.source = np.arange(N, dtype=np.int32)
        self.target = np.zeros(N, dtype=np.int32)
        self.weights = np.random.rand(N)
        self.graph = hv.Graph(((self.source, self.target),))
        self.node_info = hv.Dataset(["Output"] + ["Input"] * (N - 1), vdims=["Label"])
        self.node_info2 = hv.Dataset(self.weights, vdims="Weight")
        self.graph2 = hv.Graph(((self.source, self.target), self.node_info))
        self.graph3 = hv.Graph(((self.source, self.target), self.node_info2))
        self.graph4 = hv.Graph(((self.source, self.target, self.weights),), vdims="Weight")

    def test_plot_simple_graph(self):
        plot = mpl_renderer.get_plot(self.graph)
        nodes = plot.handles["nodes"]
        edges = plot.handles["edges"]
        assert_data_equal(np.asarray(nodes.get_offsets()), self.graph.nodes.array([0, 1]))
        assert_data_equal(
            np.array([p.vertices for p in edges.get_paths()]),
            [p.array() for p in self.graph.edgepaths.split()],
        )

    def test_plot_graph_categorical_colored_nodes(self):
        g = self.graph2.opts(color_index="Label", cmap="Set1")
        plot = mpl_renderer.get_plot(g)
        nodes = plot.handles["nodes"]
        facecolors = np.array(
            [
                [0.89411765, 0.10196078, 0.10980392, 1.0],
                [0.6, 0.6, 0.6, 1.0],
                [0.6, 0.6, 0.6, 1.0],
                [0.6, 0.6, 0.6, 1.0],
                [0.6, 0.6, 0.6, 1.0],
                [0.6, 0.6, 0.6, 1.0],
                [0.6, 0.6, 0.6, 1.0],
                [0.6, 0.6, 0.6, 1.0],
            ]
        )
        assert_data_equal(nodes.get_facecolors(), facecolors)

    def test_plot_graph_numerically_colored_nodes(self):
        g = self.graph3.opts(color_index="Weight", cmap="viridis")
        plot = mpl_renderer.get_plot(g)
        nodes = plot.handles["nodes"]
        assert_data_equal(np.asarray(nodes.get_array()), self.weights)
        assert nodes.get_clim() == (self.weights.min(), self.weights.max())

    def test_plot_graph_categorical_colored_edges(self):
        g = self.graph3.opts(edge_color_index="start", edge_cmap=["#FFFFFF", "#000000"])
        plot = mpl_renderer.get_plot(g)
        edges = plot.handles["edges"]
        colors = np.array(
            [
                [1.0, 1.0, 1.0, 1.0],
                [0.0, 0.0, 0.0, 1.0],
                [1.0, 1.0, 1.0, 1.0],
                [0.0, 0.0, 0.0, 1.0],
                [1.0, 1.0, 1.0, 1.0],
                [0.0, 0.0, 0.0, 1.0],
                [1.0, 1.0, 1.0, 1.0],
                [0.0, 0.0, 0.0, 1.0],
            ]
        )
        assert_data_equal(edges.get_colors(), colors)

    def test_plot_graph_numerically_colored_edges(self):
        g = self.graph4.opts(edge_color_index="Weight", edge_cmap=["#FFFFFF", "#000000"])
        plot = mpl_renderer.get_plot(g)
        edges = plot.handles["edges"]
        assert_data_equal(np.asarray(edges.get_array()), self.weights)
        assert edges.get_clim() == (self.weights.min(), self.weights.max())

    ###########################
    #    Styling mapping      #
    ###########################

    def test_graph_op_node_color(self):
        edges = [(0, 1), (0, 2)]
        nodes = hv.Nodes(
            [(0, 0, 0, "#000000"), (0, 1, 1, "#FF0000"), (1, 1, 2, "#00FF00")], vdims="color"
        )
        graph = hv.Graph((edges, nodes)).opts(node_color="color")
        plot = mpl_renderer.get_plot(graph)
        artist = plot.handles["nodes"]
        assert_data_equal(
            artist.get_facecolors(), np.array([[0, 0, 0, 1], [1, 0, 0, 1], [0, 1, 0, 1]])
        )

    def test_graph_op_node_color_update(self):
        edges = [(0, 1), (0, 2)]

        def get_graph(i):
            c1, c2, c3 = {
                0: ("#00FF00", "#0000FF", "#FF0000"),
                1: ("#FF0000", "#00FF00", "#0000FF"),
            }[i]
            nodes = hv.Nodes([(0, 0, 0, c1), (0, 1, 1, c2), (1, 1, 2, c3)], vdims="color")
            return hv.Graph((edges, nodes))

        graph = hv.HoloMap({0: get_graph(0), 1: get_graph(1)}).opts(node_color="color")
        plot = mpl_renderer.get_plot(graph)
        artist = plot.handles["nodes"]
        assert_data_equal(
            artist.get_facecolors(), np.array([[0, 1, 0, 1], [0, 0, 1, 1], [1, 0, 0, 1]])
        )
        plot.update((1,))
        assert_data_equal(
            artist.get_facecolors(), np.array([[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 1]])
        )

    def test_graph_op_node_color_linear(self):
        edges = [(0, 1), (0, 2)]
        nodes = hv.Nodes([(0, 0, 0, 0.5), (0, 1, 1, 1.5), (1, 1, 2, 2.5)], vdims="color")
        graph = hv.Graph((edges, nodes)).opts(node_color="color")
        plot = mpl_renderer.get_plot(graph)
        artist = plot.handles["nodes"]
        assert_data_equal(np.asarray(artist.get_array()), np.array([0.5, 1.5, 2.5]))
        assert artist.get_clim() == (0.5, 2.5)

    def test_graph_op_node_color_linear_update(self):
        edges = [(0, 1), (0, 2)]

        def get_graph(i):
            c1, c2, c3 = {0: (0.5, 1.5, 2.5), 1: (3, 2, 1)}[i]
            nodes = hv.Nodes([(0, 0, 0, c1), (0, 1, 1, c2), (1, 1, 2, c3)], vdims="color")
            return hv.Graph((edges, nodes))

        graph = hv.HoloMap({0: get_graph(0), 1: get_graph(1)}).opts(
            node_color="color", framewise=True
        )
        plot = mpl_renderer.get_plot(graph)
        artist = plot.handles["nodes"]
        assert_data_equal(np.asarray(artist.get_array()), np.array([0.5, 1.5, 2.5]))
        assert artist.get_clim() == (0.5, 2.5)
        plot.update((1,))
        assert_data_equal(np.asarray(artist.get_array()), np.array([3, 2, 1]))
        assert artist.get_clim() == (1, 3)

    def test_graph_op_node_color_categorical(self):
        edges = [(0, 1), (0, 2)]
        nodes = hv.Nodes([(0, 0, 0, "A"), (0, 1, 1, "B"), (1, 1, 2, "A")], vdims="color")
        graph = hv.Graph((edges, nodes)).opts(node_color="color")
        plot = mpl_renderer.get_plot(graph)
        artist = plot.handles["nodes"]
        assert_data_equal(np.asarray(artist.get_array()), np.array([0, 1, 0]))

    def test_graph_op_node_size(self):
        edges = [(0, 1), (0, 2)]
        nodes = hv.Nodes([(0, 0, 0, 2), (0, 1, 1, 4), (1, 1, 2, 6)], vdims="size")
        graph = hv.Graph((edges, nodes)).opts(node_size="size")
        plot = mpl_renderer.get_plot(graph)
        artist = plot.handles["nodes"]
        assert_data_equal(artist.get_sizes(), np.array([4, 16, 36]))

    def test_graph_op_node_size_update(self):
        edges = [(0, 1), (0, 2)]

        def get_graph(i):
            c1, c2, c3 = {0: (2, 4, 6), 1: (12, 3, 5)}[i]
            nodes = hv.Nodes([(0, 0, 0, c1), (0, 1, 1, c2), (1, 1, 2, c3)], vdims="size")
            return hv.Graph((edges, nodes))

        graph = hv.HoloMap({0: get_graph(0), 1: get_graph(1)}).opts(node_size="size")
        plot = mpl_renderer.get_plot(graph)
        artist = plot.handles["nodes"]
        assert_data_equal(artist.get_sizes(), np.array([4, 16, 36]))
        plot.update((1,))
        assert_data_equal(artist.get_sizes(), np.array([144, 9, 25]))

    def test_graph_op_node_linewidth(self):
        edges = [(0, 1), (0, 2)]
        nodes = hv.Nodes([(0, 0, 0, 2), (0, 1, 1, 4), (1, 1, 2, 3.5)], vdims="line_width")
        graph = hv.Graph((edges, nodes)).opts(node_linewidth="line_width")
        plot = mpl_renderer.get_plot(graph)
        artist = plot.handles["nodes"]
        assert artist.get_linewidths() == [2, 4, 3.5]

    def test_graph_op_node_linewidth_update(self):
        edges = [(0, 1), (0, 2)]

        def get_graph(i):
            c1, c2, c3 = {0: (2, 4, 6), 1: (12, 3, 5)}[i]
            nodes = hv.Nodes([(0, 0, 0, c1), (0, 1, 1, c2), (1, 1, 2, c3)], vdims="line_width")
            return hv.Graph((edges, nodes))

        graph = hv.HoloMap({0: get_graph(0), 1: get_graph(1)}).opts(node_linewidth="line_width")
        plot = mpl_renderer.get_plot(graph)
        artist = plot.handles["nodes"]
        assert artist.get_linewidths() == [2, 4, 6]
        plot.update((1,))
        assert artist.get_linewidths() == [12, 3, 5]

    def test_graph_op_node_alpha(self):
        edges = [(0, 1), (0, 2)]
        nodes = hv.Nodes([(0, 0, 0, 0.2), (0, 1, 1, 0.6), (1, 1, 2, 1)], vdims="alpha")
        graph = hv.Graph((edges, nodes)).opts(node_alpha="alpha")

        if MPL_GE_3_4_0:
            plot = mpl_renderer.get_plot(graph)
            artist = plot.handles["nodes"]
            assert_data_equal(artist.get_alpha(), np.array([0.2, 0.6, 1]))
        else:
            # Python 3.6 only support up to matplotlib 3.3
            msg = "TypeError: alpha must be a float or None"
            with pytest.raises(AbbreviatedException, match=msg):
                mpl_renderer.get_plot(graph)

    def test_graph_op_edge_color(self):
        edges = [(0, 1, "red"), (0, 2, "green"), (1, 3, "blue")]
        graph = hv.Graph(edges, vdims="color").opts(edge_color="color")
        plot = mpl_renderer.get_plot(graph)
        edges = plot.handles["edges"]
        assert_data_equal(
            edges.get_edgecolors(),
            np.array([[1.0, 0.0, 0.0, 1.0], [0.0, 0.50196078, 0.0, 1.0], [0.0, 0.0, 1.0, 1.0]]),
        )

    def test_graph_op_edge_color_update(self):
        graph = hv.HoloMap(
            {
                0: hv.Graph([(0, 1, "red"), (0, 2, "green"), (1, 3, "blue")], vdims="color"),
                1: hv.Graph([(0, 1, "green"), (0, 2, "blue"), (1, 3, "red")], vdims="color"),
            }
        ).opts(edge_color="color")
        plot = mpl_renderer.get_plot(graph)
        edges = plot.handles["edges"]
        assert_data_equal(
            edges.get_edgecolors(),
            np.array([[1.0, 0.0, 0.0, 1.0], [0.0, 0.50196078, 0.0, 1.0], [0.0, 0.0, 1.0, 1.0]]),
        )
        plot.update((1,))
        assert_data_equal(
            edges.get_edgecolors(),
            np.array([[0.0, 0.50196078, 0.0, 1.0], [0.0, 0.0, 1.0, 1.0], [1.0, 0.0, 0.0, 1.0]]),
        )

    def test_graph_op_edge_color_linear(self):
        edges = [(0, 1, 2), (0, 2, 0.5), (1, 3, 3)]
        graph = hv.Graph(edges, vdims="color").opts(edge_color="color")
        plot = mpl_renderer.get_plot(graph)
        edges = plot.handles["edges"]
        assert_data_equal(np.asarray(edges.get_array()), np.array([2, 0.5, 3]))
        assert edges.get_clim() == (0.5, 3)

    def test_graph_op_edge_color_linear_update(self):
        graph = hv.HoloMap(
            {
                0: hv.Graph([(0, 1, 2), (0, 2, 0.5), (1, 3, 3)], vdims="color"),
                1: hv.Graph([(0, 1, 4.3), (0, 2, 1.4), (1, 3, 2.6)], vdims="color"),
            }
        ).opts(edge_color="color", framewise=True)
        plot = mpl_renderer.get_plot(graph)
        edges = plot.handles["edges"]
        assert_data_equal(np.asarray(edges.get_array()), np.array([2, 0.5, 3]))
        assert edges.get_clim() == (0.5, 3)
        plot.update((1,))
        assert_data_equal(np.asarray(edges.get_array()), np.array([4.3, 1.4, 2.6]))
        assert edges.get_clim() == (1.4, 4.3)

    def test_graph_op_edge_color_categorical(self):
        edges = [(0, 1, "C"), (0, 2, "B"), (1, 3, "A")]
        graph = hv.Graph(edges, vdims="color").opts(edge_color="color")
        plot = mpl_renderer.get_plot(graph)
        edges = plot.handles["edges"]
        assert_data_equal(np.asarray(edges.get_array()), np.array([0, 1, 2]))
        assert edges.get_clim() == (0, 2)

    def test_graph_op_edge_alpha(self):
        edges = [(0, 1, 0.1), (0, 2, 0.5), (1, 3, 0.3)]
        graph = hv.Graph(edges, vdims="alpha").opts(edge_alpha="alpha")
        msg = 'ValueError: Mapping a dimension to the "edge_alpha" style'
        with pytest.raises(AbbreviatedException, match=msg):
            mpl_renderer.get_plot(graph)

    def test_graph_op_edge_linewidth(self):
        edges = [(0, 1, 2), (0, 2, 10), (1, 3, 6)]
        graph = hv.Graph(edges, vdims="line_width").opts(edge_linewidth="line_width")
        plot = mpl_renderer.get_plot(graph)
        edges = plot.handles["edges"]
        assert edges.get_linewidths() == [2, 10, 6]

    def test_graph_op_edge_line_width_update(self):
        graph = hv.HoloMap(
            {
                0: hv.Graph([(0, 1, 2), (0, 2, 0.5), (1, 3, 3)], vdims="line_width"),
                1: hv.Graph([(0, 1, 4.3), (0, 2, 1.4), (1, 3, 2.6)], vdims="line_width"),
            }
        ).opts(edge_linewidth="line_width")
        plot = mpl_renderer.get_plot(graph)
        edges = plot.handles["edges"]
        assert edges.get_linewidths() == [2, 0.5, 3]
        plot.update((1,))
        assert edges.get_linewidths() == [4.3, 1.4, 2.6]


class TestMplTriMeshPlot(TestMPLPlot):
    def setup_method(self):
        super().setup_method()

        self.nodes = [(0, 0, 0), (0.5, 1, 1), (1.0, 0, 2), (1.5, 1, 3)]
        self.simplices = [(0, 1, 2, 0), (1, 2, 3, 1)]
        self.trimesh = hv.TriMesh((self.simplices, self.nodes))
        self.trimesh_weighted = hv.TriMesh((self.simplices, self.nodes), vdims="weight")

    def test_plot_simple_trimesh(self):
        plot = mpl_renderer.get_plot(self.trimesh)
        nodes = plot.handles["nodes"]
        edges = plot.handles["edges"]
        assert isinstance(edges, LineCollection)
        assert_data_equal(np.asarray(nodes.get_offsets()), self.trimesh.nodes.array([0, 1]))
        assert_data_equal(
            np.asarray([p.vertices for p in edges.get_paths()]),
            [p.array() for p in self.trimesh._split_edgepaths.split()],
        )

    def test_plot_simple_trimesh_filled(self):
        plot = mpl_renderer.get_plot(self.trimesh.opts(filled=True))
        nodes = plot.handles["nodes"]
        edges = plot.handles["edges"]
        assert isinstance(edges, PolyCollection)
        assert_data_equal(np.asarray(nodes.get_offsets()), self.trimesh.nodes.array([0, 1]))
        paths = np.asarray(self.trimesh._split_edgepaths.split(datatype="array"))
        assert_data_equal([p.vertices[:4] for p in edges.get_paths()], paths)

    def test_plot_trimesh_colored_edges(self):
        opts = dict(edge_color_index="weight", edge_cmap="Greys")
        plot = mpl_renderer.get_plot(self.trimesh_weighted.opts(**opts))
        edges = plot.handles["edges"]
        colors = np.array([[1.0, 1.0, 1.0, 1.0], [0.0, 0.0, 0.0, 1.0]])
        assert_data_equal(edges.get_edgecolors(), colors)

    def test_plot_trimesh_categorically_colored_edges(self):
        opts = dict(edge_color_index="node1", edge_color=hv.Cycle("Set1"))
        plot = mpl_renderer.get_plot(self.trimesh_weighted.opts(**opts))
        edges = plot.handles["edges"]
        colors = np.array(
            [[0.894118, 0.101961, 0.109804, 1.0], [0.215686, 0.494118, 0.721569, 1.0]]
        )
        assert_data_equal(edges.get_edgecolors(), colors)

    def test_plot_trimesh_categorically_colored_edges_filled(self):
        opts = dict(edge_color_index="node1", filled=True, edge_color=hv.Cycle("Set1"))
        plot = mpl_renderer.get_plot(self.trimesh_weighted.opts(**opts))
        edges = plot.handles["edges"]
        colors = np.array(
            [[0.894118, 0.101961, 0.109804, 1.0], [0.215686, 0.494118, 0.721569, 1.0]]
        )
        assert_data_equal(edges.get_facecolors(), colors)

    ###########################
    #    Styling mapping      #
    ###########################

    def test_trimesh_op_node_color(self):
        edges = [(0, 1, 2), (1, 2, 3)]
        nodes = [(-1, -1, 0, "red"), (0, 0, 1, "green"), (0, 1, 2, "blue"), (1, 0, 3, "black")]
        trimesh = hv.TriMesh((edges, hv.Nodes(nodes, vdims="color"))).opts(node_color="color")
        plot = mpl_renderer.get_plot(trimesh)
        artist = plot.handles["nodes"]
        assert_data_equal(
            artist.get_facecolors(),
            np.array([[1, 0, 0, 1], [0, 0.501961, 0, 1], [0, 0, 1, 1], [0, 0, 0, 1]]),
        )

    def test_trimesh_op_node_color_linear(self):
        edges = [(0, 1, 2), (1, 2, 3)]
        nodes = [(-1, -1, 0, 2), (0, 0, 1, 1), (0, 1, 2, 3), (1, 0, 3, 4)]
        trimesh = hv.TriMesh((edges, hv.Nodes(nodes, vdims="color"))).opts(node_color="color")
        plot = mpl_renderer.get_plot(trimesh)
        artist = plot.handles["nodes"]
        assert_data_equal(np.asarray(artist.get_array()), np.array([2, 1, 3, 4]))
        assert artist.get_clim() == (1, 4)

    def test_trimesh_op_node_color_categorical(self):
        edges = [(0, 1, 2), (1, 2, 3)]
        nodes = [(-1, -1, 0, "B"), (0, 0, 1, "C"), (0, 1, 2, "A"), (1, 0, 3, "B")]
        trimesh = hv.TriMesh((edges, hv.Nodes(nodes, vdims="color"))).opts(node_color="color")
        plot = mpl_renderer.get_plot(trimesh)
        artist = plot.handles["nodes"]
        assert_data_equal(np.asarray(artist.get_array()), np.array([0, 1, 2, 0]))
        assert artist.get_clim() == (0, 2)

    def test_trimesh_op_node_size(self):
        edges = [(0, 1, 2), (1, 2, 3)]
        nodes = [(-1, -1, 0, 3), (0, 0, 1, 2), (0, 1, 2, 8), (1, 0, 3, 4)]
        trimesh = hv.TriMesh((edges, hv.Nodes(nodes, vdims="size"))).opts(node_size="size")
        plot = mpl_renderer.get_plot(trimesh)
        artist = plot.handles["nodes"]
        assert_data_equal(artist.get_sizes(), np.array([9, 4, 64, 16]))

    def test_trimesh_op_node_alpha(self):
        edges = [(0, 1, 2), (1, 2, 3)]
        nodes = [(-1, -1, 0, 0.2), (0, 0, 1, 0.6), (0, 1, 2, 1), (1, 0, 3, 0.3)]
        trimesh = hv.TriMesh((edges, hv.Nodes(nodes, vdims="alpha"))).opts(node_alpha="alpha")

        if MPL_GE_3_4_0:
            plot = mpl_renderer.get_plot(trimesh)
            artist = plot.handles["nodes"]
            assert_data_equal(artist.get_alpha(), np.array([0.2, 0.6, 1, 0.3]))
        else:
            # Python 3.6 only support up to matplotlib 3.3
            msg = "TypeError: alpha must be a float or None"
            with pytest.raises(AbbreviatedException, match=msg):
                mpl_renderer.get_plot(trimesh)

    def test_trimesh_op_node_line_width(self):
        edges = [(0, 1, 2), (1, 2, 3)]
        nodes = [(-1, -1, 0, 0.2), (0, 0, 1, 0.6), (0, 1, 2, 1), (1, 0, 3, 0.3)]
        trimesh = hv.TriMesh((edges, hv.Nodes(nodes, vdims="line_width"))).opts(
            node_linewidth="line_width"
        )
        plot = mpl_renderer.get_plot(trimesh)
        artist = plot.handles["nodes"]
        assert artist.get_linewidths() == [0.2, 0.6, 1, 0.3]

    def test_trimesh_op_edge_color_linear_mean_node(self):
        edges = [(0, 1, 2), (1, 2, 3)]
        nodes = [(-1, -1, 0, 2), (0, 0, 1, 1), (0, 1, 2, 3), (1, 0, 3, 4)]
        trimesh = hv.TriMesh((edges, hv.Nodes(nodes, vdims="color"))).opts(edge_color="color")
        plot = mpl_renderer.get_plot(trimesh)
        artist = plot.handles["edges"]
        assert_data_equal(np.asarray(artist.get_array()), np.array([2, 8 / 3.0]))
        assert artist.get_clim() == (1, 4)

    def test_trimesh_op_edge_color(self):
        edges = [(0, 1, 2, "red"), (1, 2, 3, "blue")]
        nodes = [(-1, -1, 0), (0, 0, 1), (0, 1, 2), (1, 0, 3)]
        trimesh = hv.TriMesh((edges, nodes), vdims="color").opts(edge_color="color")
        plot = mpl_renderer.get_plot(trimesh)
        artist = plot.handles["edges"]
        assert_data_equal(artist.get_edgecolors(), np.array([[1, 0, 0, 1], [0, 0, 1, 1]]))

    def test_trimesh_op_edge_color_linear(self):
        edges = [(0, 1, 2, 2.4), (1, 2, 3, 3.6)]
        nodes = [(-1, -1, 0), (0, 0, 1), (0, 1, 2), (1, 0, 3)]
        trimesh = hv.TriMesh((edges, nodes), vdims="color").opts(edge_color="color")
        plot = mpl_renderer.get_plot(trimesh)
        artist = plot.handles["edges"]
        assert_data_equal(np.asarray(artist.get_array()), np.array([2.4, 3.6]))
        assert artist.get_clim() == (2.4, 3.6)

    def test_trimesh_op_edge_color_categorical(self):
        edges = [(0, 1, 2, "A"), (1, 2, 3, "B")]
        nodes = [(-1, -1, 0), (0, 0, 1), (0, 1, 2), (1, 0, 3)]
        trimesh = hv.TriMesh((edges, nodes), vdims="color").opts(edge_color="color")
        plot = mpl_renderer.get_plot(trimesh)
        artist = plot.handles["edges"]
        assert_data_equal(np.asarray(artist.get_array()), np.array([0, 1]))
        assert artist.get_clim() == (0, 1)

    def test_trimesh_op_edge_alpha(self):
        edges = [(0, 1, 2, 0.7), (1, 2, 3, 0.3)]
        nodes = [(-1, -1, 0), (0, 0, 1), (0, 1, 2), (1, 0, 3)]
        trimesh = hv.TriMesh((edges, nodes), vdims="alpha").opts(edge_alpha="alpha")
        msg = 'ValueError: Mapping a dimension to the "edge_alpha" style'
        with pytest.raises(AbbreviatedException, match=msg):
            mpl_renderer.get_plot(trimesh)

    def test_trimesh_op_edge_line_width(self):
        edges = [(0, 1, 2, 7), (1, 2, 3, 3)]
        nodes = [(-1, -1, 0), (0, 0, 1), (0, 1, 2), (1, 0, 3)]
        trimesh = hv.TriMesh((edges, nodes), vdims="line_width").opts(edge_linewidth="line_width")
        plot = mpl_renderer.get_plot(trimesh)
        artist = plot.handles["edges"]
        assert artist.get_linewidths() == [7, 3]


class TestMplChordPlot(TestMPLPlot):
    def setup_method(self):
        super().setup_method()
        self.edges = [(0, 1, 1), (0, 2, 2), (1, 2, 3)]
        self.nodes = hv.Dataset([(0, "A"), (1, "B"), (2, "C")], "index", "Label")
        self.chord = hv.Chord((self.edges, self.nodes))

    def make_chord(self, i):
        edges = [(0, 1, 1 + i), (0, 2, 2 + i), (1, 2, 3 + i)]
        nodes = hv.Dataset([(0, 0 + i), (1, 1 + i), (2, 2 + i)], "index", "Label")
        return hv.Chord((edges, nodes), vdims="weight")

    def test_chord_nodes_label_text(self):
        g = self.chord.opts(label_index="Label")
        plot = mpl_renderer.get_plot(g)
        labels = plot.handles["labels"]
        assert [l.get_text() for l in labels] == ["A", "B", "C"]

    def test_chord_nodes_labels_mapping(self):
        g = self.chord.opts(labels="Label")
        plot = mpl_renderer.get_plot(g)
        labels = plot.handles["labels"]
        assert [l.get_text() for l in labels] == ["A", "B", "C"]

    def test_chord_nodes_categorically_colormapped(self):
        g = self.chord.opts(color_index="Label", cmap=["#FFFFFF", "#CCCCCC", "#000000"])
        plot = mpl_renderer.get_plot(g)
        arcs = plot.handles["arcs"]
        nodes = plot.handles["nodes"]
        colors = np.array([[1.0, 1.0, 1.0, 1.0], [0.8, 0.8, 0.8, 1.0], [0.0, 0.0, 0.0, 1.0]])
        assert_data_equal(arcs.get_colors(), colors)
        assert_data_equal(nodes.get_facecolors(), colors)

    def test_chord_node_color_style_mapping(self):
        g = self.chord.opts(node_color="Label", cmap=["#FFFFFF", "#CCCCCC", "#000000"])
        plot = mpl_renderer.get_plot(g)
        arcs = plot.handles["arcs"]
        nodes = plot.handles["nodes"]
        assert_data_equal(np.asarray(nodes.get_array()), np.array([0, 1, 2]))
        assert_data_equal(np.asarray(arcs.get_array()), np.array([0, 1, 2]))
        assert nodes.get_clim() == (0, 2)
        assert arcs.get_clim() == (0, 2)

    def test_chord_edges_categorically_colormapped(self):
        g = self.chord.opts(edge_color_index="start", edge_cmap=["#FFFFFF", "#000000"])
        plot = mpl_renderer.get_plot(g)
        edges = plot.handles["edges"]
        colors = np.array([[1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0], [0.0, 0.0, 0.0, 1.0]])
        assert_data_equal(edges.get_edgecolors(), colors)

    def test_chord_edge_color_style_mapping(self):
        g = self.chord.opts(
            edge_color=hv.dim("start").astype(str), edge_cmap=["#FFFFFF", "#000000"]
        )
        plot = mpl_renderer.get_plot(g)
        edges = plot.handles["edges"]
        assert_data_equal(np.asarray(edges.get_array()), np.array([0, 0, 1]))
        assert edges.get_clim() == (0, 2)

    def test_chord_edge_color_linear_style_mapping_update(self):
        hmap = hv.HoloMap({0: self.make_chord(0), 1: self.make_chord(1)}).opts(
            edge_color="weight", framewise=True
        )
        plot = mpl_renderer.get_plot(hmap)
        edges = plot.handles["edges"]
        assert_data_equal(np.asarray(edges.get_array()), np.array([1, 2, 3]))
        assert edges.get_clim() == (1, 3)
        plot.update((1,))
        assert_data_equal(np.asarray(edges.get_array()), np.array([2, 3, 4]))
        assert edges.get_clim() == (2, 4)

    def test_chord_node_color_linear_style_mapping_update(self):
        hmap = hv.HoloMap({0: self.make_chord(0), 1: self.make_chord(1)}).opts(
            node_color="Label", framewise=True
        )
        plot = mpl_renderer.get_plot(hmap)
        arcs = plot.handles["arcs"]
        nodes = plot.handles["nodes"]
        assert_data_equal(np.asarray(nodes.get_array()), np.array([0, 1, 2]))
        assert_data_equal(np.asarray(arcs.get_array()), np.array([0, 1, 2]))
        assert nodes.get_clim() == (0, 2)
        assert arcs.get_clim() == (0, 2)
        plot.update((1,))
        assert_data_equal(np.asarray(nodes.get_array()), np.array([1, 2, 3]))
        assert_data_equal(np.asarray(arcs.get_array()), np.array([1, 2, 3]))
        assert nodes.get_clim() == (1, 3)
        assert arcs.get_clim() == (1, 3)

    def test_chord_edge_color_style_mapping_update(self):
        hmap = hv.HoloMap({0: self.make_chord(0), 1: self.make_chord(1)}).opts(
            edge_color=hv.dim("weight").categorize({1: "red", 2: "green", 3: "blue", 4: "black"})
        )
        plot = mpl_renderer.get_plot(hmap)
        edges = plot.handles["edges"]
        assert_data_equal(
            edges.get_edgecolors(), np.array([[1, 0, 0, 1], [0, 0.501961, 0, 1], [0, 0, 1, 1]])
        )
        plot.update((1,))
        assert_data_equal(
            edges.get_edgecolors(), np.array([[0, 0.501961, 0, 1], [0, 0, 1, 1], [0, 0, 0, 1]])
        )

    def test_chord_node_color_style_mapping_update(self):
        hmap = hv.HoloMap({0: self.make_chord(0), 1: self.make_chord(1)}).opts(
            node_color=hv.dim("Label").categorize({0: "red", 1: "green", 2: "blue", 3: "black"})
        )
        plot = mpl_renderer.get_plot(hmap)
        arcs = plot.handles["arcs"]
        nodes = plot.handles["nodes"]
        colors = np.array([[1, 0, 0, 1], [0, 0.501961, 0, 1], [0, 0, 1, 1]])
        assert_data_equal(arcs.get_edgecolors(), colors)
        assert_data_equal(nodes.get_facecolors(), colors)
        plot.update((1,))
        colors = np.array([[0, 0.501961, 0, 1], [0, 0, 1, 1], [0, 0, 0, 1]])
        assert_data_equal(arcs.get_edgecolors(), colors)
        assert_data_equal(nodes.get_facecolors(), colors)
