<commit_before>from __future__ import print_function
from __future__ import absolute_import
from builtins import str
from builtins import range
from builtins import object
import random
import string
import copy
import types
import pandas

from . import pygraphistry
from . import util


class Plotter(object):
    _defaultNodeId = '__nodeid__'

    def __init__(self):
        # Bindings
        self._edges = None
        self._nodes = None
        self._source = None
        self._destination = None
        self._node = None
        self._edge_title = None
        self._edge_label = None
        self._edge_color = None
        self._edge_weight = None
        self._point_title = None
        self._point_label = None
        self._point_color = None
        self._point_size = None
        # Settings
        self._height = 500
        self._url_params = {'info': 'true'}

    def __repr__(self):
        bnds = ['edges', 'nodes', 'source', 'destination', 'node', 'edge_title',
                'edge_label', 'edge_color', 'edge_weight', 'point_title',
                'point_label', 'point_color', 'point_size']
        stgs = ['height', 'url_params']

        rep = {'bindings': dict([(f, getattr(self, '_' + f)) for f in bnds]),
               'settings': dict([(f, getattr(self, '_' + f)) for f in stgs])}
        if util.in_ipython():
            from IPython.lib.pretty import pretty
            return pretty(rep)
        else:
            return str(rep)

    def bind(self, source=None, destination=None, node=None,
             edge_title=None, edge_label=None, edge_color=None, edge_weight=None,
             point_title=None, point_label=None, point_color=None, point_size=None):
        res = copy.copy(self)
        res._source = source or self._source
        res._destination = destination or self._destination
        res._node = node or self._node

        res._edge_title = edge_title or self._edge_title
        res._edge_label = edge_label or self._edge_label
        res._edge_color = edge_color or self._edge_color
        res._edge_weight = edge_weight or self._edge_weight

        res._point_title = point_title or self._point_title
        res._point_label = point_label or self._point_label
        res._point_color = point_color or self._point_color
        res._point_size = point_size or self._point_size
        return res

    def nodes(self, nodes):
        res = copy.copy(self)
        res._nodes = nodes
        return res

    def edges(self, edges):
        res = copy.copy(self)
        res._edges = edges
        return res

    def graph(self, ig):
        res = copy.copy(self)
        res._edges = ig
        res._nodes = None
        return res

    def settings(self, height=None, url_params={}):
        res = copy.copy(self)
        res._height = height or self._height
        res._url_params = dict(self._url_params, **url_params)
        return res

    def plot(self, graph=None, nodes=None):
        if graph is None:
            if self._edges is None:
                util.error('Graph/edges must be specified.')
            g = self._edges
        else:
            g = graph
        n = self._nodes if nodes is None else nodes

        self._check_mandatory_bindings(not isinstance(n, type(None)))
        dataset = self._plot_dispatch(g, n)
        if dataset is None:
            util.error('Expected Pandas dataframe(s) or Igraph/NetworkX graph.')

        dataset_name = pygraphistry.PyGraphistry._etl(dataset)
        viz_url = pygraphistry.PyGraphistry._viz_url(dataset_name, self._url_params)

        if util.in_ipython() is True:
            from IPython.core.display import HTML
            return HTML(self._iframe(viz_url))
        else:
            print('Url: ', viz_url)
            import webbrowser
            webbrowser.open(viz_url)
            return self

    def pandas2igraph(self, edges, directed=True):
        import igraph
        self._check_mandatory_bindings(False)
        self._check_bound_attribs(edges, ['source', 'destination'], 'Edge')
        if self._node is None:
            util.warn('"node" is unbound, automatically binding it to "%s".' % Plotter._defaultNodeId)

        self._node = self._node or Plotter._defaultNodeId
        eattribs = edges.columns.values.tolist()
        eattribs.remove(self._source)
        eattribs.remove(self._destination)
        cols = [self._source, self._destination] + eattribs
        etuples = [tuple(x) for x in edges[cols].values]
        return igraph.Graph.TupleList(etuples, directed=directed, edge_attrs=eattribs,
                                      vertex_name_attr=self._node)

    def igraph2pandas(self, ig):
        def get_edgelist(ig):
            idmap = dict(enumerate(ig.vs[self._node]))
            for e in ig.es:
                t = e.tuple
                yield dict({self._source: idmap[t[0]], self._destination: idmap[t[1]]},
                            **e.attributes())

        self._check_mandatory_bindings(False)
        if self._node is None:
            util.warn('"node" is unbound, automatically binding it to "%s".' % Plotter._defaultNodeId)
            ig.vs[Plotter._defaultNodeId] = [v.index for v in ig.vs]
            self._node = Plotter._defaultNodeId
        elif self._node not in ig.vs.attributes():
            util.error('Vertex attribute "%s" bound to "node" does not exist.' % self._node)

        edata = get_edgelist(ig)
        ndata = [v.attributes() for v in ig.vs]
        nodes = pandas.DataFrame(ndata, columns=ig.vs.attributes())
        cols = [self._source, self._destination] + ig.es.attributes()
        edges = pandas.DataFrame(edata, columns=cols)
        return (edges, nodes)

    def networkx2pandas(self, g):
        def get_nodelist(g):
            for n in g.nodes(data=True):
                yield dict({self._node: n[0]}, **n[1])
        def get_edgelist(g):
            for e in g.edges(data=True):
                yield dict({self._source: e[0], self._destination: e[1]}, **e[2])

        self._check_mandatory_bindings(False)
        vattribs = g.nodes(data=True)[0][1] if g.number_of_nodes() > 0 else []
        if self._node is None:
            util.warn('"node" is unbound, automatically binding it to "%s".' % Plotter._defaultNodeId)
            self._node = Plotter._defaultNodeId
        elif self._node not in vattribs:
            util.error('Vertex attribute "%s" bound to "node" does not exist.' % self._node)

        nodes = pandas.DataFrame(get_nodelist(g))
        edges = pandas.DataFrame(get_edgelist(g))<commit_msg>Fix networkx2pandas node bug:<commit_after>from __future__ import print_function
from __future__ import absolute_import
from builtins import str
from builtins import range
from builtins import object
import random
import string
import copy
import types
import pandas

from . import pygraphistry
from . import util


class Plotter(object):
    _defaultNodeId = '__nodeid__'

    def __init__(self):
        # Bindings
        self._edges = None
        self._nodes = None
        self._source = None
        self._destination = None
        self._node = None
        self._edge_title = None
        self._edge_label = None
        self._edge_color = None
        self._edge_weight = None
        self._point_title = None
        self._point_label = None
        self._point_color = None
        self._point_size = None
        # Settings
        self._height = 500
        self._url_params = {'info': 'true'}

    def __repr__(self):
        bnds = ['edges', 'nodes', 'source', 'destination', 'node', 'edge_title',
                'edge_label', 'edge_color', 'edge_weight', 'point_title',
                'point_label', 'point_color', 'point_size']
        stgs = ['height', 'url_params']

        rep = {'bindings': dict([(f, getattr(self, '_' + f)) for f in bnds]),
               'settings': dict([(f, getattr(self, '_' + f)) for f in stgs])}
        if util.in_ipython():
            from IPython.lib.pretty import pretty
            return pretty(rep)
        else:
            return str(rep)

    def bind(self, source=None, destination=None, node=None,
             edge_title=None, edge_label=None, edge_color=None, edge_weight=None,
             point_title=None, point_label=None, point_color=None, point_size=None):
        res = copy.copy(self)
        res._source = source or self._source
        res._destination = destination or self._destination
        res._node = node or self._node

        res._edge_title = edge_title or self._edge_title
        res._edge_label = edge_label or self._edge_label
        res._edge_color = edge_color or self._edge_color
        res._edge_weight = edge_weight or self._edge_weight

        res._point_title = point_title or self._point_title
        res._point_label = point_label or self._point_label
        res._point_color = point_color or self._point_color
        res._point_size = point_size or self._point_size
        return res

    def nodes(self, nodes):
        res = copy.copy(self)
        res._nodes = nodes
        return res

    def edges(self, edges):
        res = copy.copy(self)
        res._edges = edges
        return res

    def graph(self, ig):
        res = copy.copy(self)
        res._edges = ig
        res._nodes = None
        return res

    def settings(self, height=None, url_params={}):
        res = copy.copy(self)
        res._height = height or self._height
        res._url_params = dict(self._url_params, **url_params)
        return res

    def plot(self, graph=None, nodes=None):
        if graph is None:
            if self._edges is None:
                util.error('Graph/edges must be specified.')
            g = self._edges
        else:
            g = graph
        n = self._nodes if nodes is None else nodes

        self._check_mandatory_bindings(not isinstance(n, type(None)))
        dataset = self._plot_dispatch(g, n)
        if dataset is None:
            util.error('Expected Pandas dataframe(s) or Igraph/NetworkX graph.')

        dataset_name = pygraphistry.PyGraphistry._etl(dataset)
        viz_url = pygraphistry.PyGraphistry._viz_url(dataset_name, self._url_params)

        if util.in_ipython() is True:
            from IPython.core.display import HTML
            return HTML(self._iframe(viz_url))
        else:
            print('Url: ', viz_url)
            import webbrowser
            webbrowser.open(viz_url)
            return self

    def pandas2igraph(self, edges, directed=True):
        import igraph
        self._check_mandatory_bindings(False)
        self._check_bound_attribs(edges, ['source', 'destination'], 'Edge')
        if self._node is None:
            util.warn('"node" is unbound, automatically binding it to "%s".' % Plotter._defaultNodeId)

        self._node = self._node or Plotter._defaultNodeId
        eattribs = edges.columns.values.tolist()
        eattribs.remove(self._source)
        eattribs.remove(self._destination)
        cols = [self._source, self._destination] + eattribs
        etuples = [tuple(x) for x in edges[cols].values]
        return igraph.Graph.TupleList(etuples, directed=directed, edge_attrs=eattribs,
                                      vertex_name_attr=self._node)

    def igraph2pandas(self, ig):
        def get_edgelist(ig):
            idmap = dict(enumerate(ig.vs[self._node]))
            for e in ig.es:
                t = e.tuple
                yield dict({self._source: idmap[t[0]], self._destination: idmap[t[1]]},
                            **e.attributes())

        self._check_mandatory_bindings(False)
        if self._node is None:
            util.warn('"node" is unbound, automatically binding it to "%s".' % Plotter._defaultNodeId)
            ig.vs[Plotter._defaultNodeId] = [v.index for v in ig.vs]
            self._node = Plotter._defaultNodeId
        elif self._node not in ig.vs.attributes():
            util.error('Vertex attribute "%s" bound to "node" does not exist.' % self._node)

        edata = get_edgelist(ig)
        ndata = [v.attributes() for v in ig.vs]
        nodes = pandas.DataFrame(ndata, columns=ig.vs.attributes())
        cols = [self._source, self._destination] + ig.es.attributes()
        edges = pandas.DataFrame(edata, columns=cols)
        return (edges, nodes)

    def networkx2pandas(self, g):
        def get_nodelist(g):
            for n in g.nodes(data=True):
                yield dict({self._node: n[0]}, **n[1])
        def get_edgelist(g):
            for e in g.edges(data=True):
                yield dict({self._source: e[0], self._destination: e[1]}, **e[2])

        self._check_mandatory_bindings(False)
        vattribs = g.nodes(data=True)[0][1] if g.number_of_nodes() > 0 else []
        if self._node is None:
            util.warn('"node" is unbound, automatically binding it to "%s".' % Plotter._defaultNodeId)
        elif self._node in vattribs:
            util.error('Vertex attribute "%s" already exists.' % self._node)

        self._node = self._node or Plotter._defaultNodeId
        nodes = pandas.DataFrame(get_nodelist(g))
        edges = pandas.DataFrame(get_edgelist(g))
{'fraction_non_alphanumeric': 0.10373760488176964, 'fraction_numerical': 0.002517162471395881, 'mean_word_length': 2.256582215598609, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '314509', 'n_tokens_mistral': 3959, 'n_tokens_neox': 3854, 'n_words': 969}