<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 HyperNetX + Graphistry = 💪💪💪
You can quickly explore HyperNetX graphs using Graphistry through the below sample class.
PNNL's HyperNetX is a new Python library for manipulating hypergraphs
Step1:  Lib
Step2:  Demo
Init
Step3:  hypernetx_to_graphistry_bipartite
Flatten to Pandas Dataframes / Graphistry and inspect
Step4:  hypernetx_to_graphistry_nodes
<ASSISTANT_TASK:>
Python Code:
# ! pip install hypernetx -q
# ! pip install graphistry -q
Explanation: HyperNetX + Graphistry = 💪💪💪
You can quickly explore HyperNetX graphs using Graphistry through the below sample class.
PNNL's HyperNetX is a new Python library for manipulating hypergraphs: graphs where an edge may connect any number of nodes. The below helper class converts HyperNetX graphs into 2-edge graphs (node/edge property tables as Panda dataframes ) in two different modes:
hypernetx_to_graphistry_bipartite(hnx_graph): 
Turn every hyperedge and hypernode into nodes. They form a bipartite graph: whenever a hyperedge includes a hypernode, create an edge from the hyperedge's node to the hypernode's node.
ex: Hyperedge 0: ['a', 'b', 'c'] => edge (0, 'a'), edge (0, 'b'), edge (0, 'c')
hypernetx_to_graphistry_nodes(hnx_graph):
Turn every hypernode into a node, and whenever two hypernodes share the same hyperedge, create an edge between their corresponding nodes
To emphasize that edges are undirect, the library sets the edge curvature to 0 (straight)
ex: Hyperedge 0: ['a', 'b', 'c'] => edge ('a', 'b'), edge ('a', 'c'), edge ('b', 'c')
Install
Dependencies already preinstalled in Graphistry Core distributions
End of explanation
import pandas as pd
class HyperNetXG:
  
    def __init__(self, graphistry):
        self.graphistry = graphistry      
    def normalize_id(self, id):
        t = type(id)
        if t == float or t == int:
            return '__id__' + str(id)
        return str(id)
    def hypernetx_to_graphistry_bipartite(self, h):
        nodes_df = pd.concat(
            [pd.DataFrame({
                'node': [self.normalize_id(x) for x in list(H.nodes)], 
                'type': 'hypernode'}),
             pd.DataFrame({
                 'node': [self.normalize_id(x) for x in H.edges], 
                 'type': 'hyperedge'})],
            ignore_index=True,
            sort=False)
        edges_df = pd.concat(
            [ pd.DataFrame({'src': [], 'dst': []}) ] + 
            [
                pd.DataFrame({
                    'src': self.normalize_id(k),
                    'dst': [self.normalize_id(x) for x in list(es)]
                })
                for k, es in H.incidence_dict.items()
            ], ignore_index=True, sort=False)
        return self.graphistry.bind(
              source='src', 
              destination='dst', 
              node='node').nodes(nodes_df).edges(edges_df)
    def __hyperedge_to_graph(self, k, es):
        lst = list(es)
        edges_df = pd.concat([
              pd.DataFrame({'src': [], 'dst': [], 'hyperedge': []})] + [
              pd.DataFrame({
                  'src': self.normalize_id(lst[i]), 
                  'dst': [self.normalize_id(x) for x in lst[i+1:]], 
                  'hyperedge': self.normalize_id(k)})
              for i in range(0, len(lst))
          ], ignore_index=True, sort=False)     
        return edges_df
    def hypernetx_to_graphistry_nodes(self, h):
        hg = self.hypernetx_to_graphistry_bipartite(h)
        nodes_df = pd.DataFrame({
              'node': [self.normalize_id(x) for x in list(h.nodes)], 
              'type': 'hypernode'})
        edges_df = pd.concat(
              [pd.DataFrame({'src': [], 'dst': [], 'hyperedge': []})] +
              [
                  self.__hyperedge_to_graph(k, es) 
                  for (k, es) in h.incidence_dict.items() 
              ])
        return self.graphistry.bind(
              source='src', 
              destination='dst', 
              node='node').settings(url_params={'edgeCurvature': 0}).nodes(nodes_df).edges(edges_df)
Explanation: Lib
End of explanation
import hypernetx as hnx
import graphistry
# To specify Graphistry account & server, use:
# graphistry.register(api=3, username='...', password='...', protocol='https', server='hub.graphistry.com')
# For more options, see https://github.com/graphistry/pygraphistry#configure
scenes = [
    ('FN', 'TH'),
    ('TH', 'JV'),
    ('BM', 'FN', 'JA'),
    ('JV', 'JU', 'CH', 'BM'),
    ('JU', 'CH', 'BR', 'CN', 'CC', 'JV', 'BM'),
    ('TH', 'GP'),
    ('GP', 'MP'),
    ('MA', 'GP')
]
H = hnx.Hypergraph(dict(enumerate(scenes)))
hg = HyperNetXG(graphistry)
Explanation: Demo
Init
End of explanation
g = hg.hypernetx_to_graphistry_bipartite(H)
g._nodes.sample(3)
g._edges.sample(3)
g.plot()
hg.hypernetx_to_graphistry_bipartite(H.dual())._edges.sample(3)
hg.hypernetx_to_graphistry_bipartite(H.dual()).plot()
Explanation: hypernetx_to_graphistry_bipartite
Flatten to Pandas Dataframes / Graphistry and inspect:
End of explanation
g = hg.hypernetx_to_graphistry_nodes(H)
g._edges.sample(3)
hg.hypernetx_to_graphistry_nodes(H).plot()
hg.hypernetx_to_graphistry_nodes(H.dual()).plot()
Explanation: hypernetx_to_graphistry_nodes
End of explanation
<END_TASK>