Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Imputing "null" values for missing keys? #170

Open
ericmjl opened this issue Nov 6, 2017 · 2 comments
Open

Imputing "null" values for missing keys? #170

ericmjl opened this issue Nov 6, 2017 · 2 comments

Comments

@ericmjl
Copy link
Owner

ericmjl commented Nov 6, 2017

This is a note left for myself or future contributors, and refers to issue #168.

The end-user of networkx might not necessarily have every key represented on every node. I being opinionated think this is a bad idea, but I also recognize that there may be use cases where this is necessary.

There are two routes for this:

  1. Document clearly that every node has to have the same set of attribute keys.
  2. Silently impute a None value for nodes that don't have an attribute key.
@yerraeee
Copy link

yerraeee commented Jan 27, 2018

Hi Eric,

Thank you for this awesome nxviz package.

I have a bipartite graph of "technical-tickets" and "teams" (that work on tickets) as nodes. So "Ticket"s and "Team"s have different attributes. When I tried to Color,Order and Group the ticket-nodes based on attributes that absent in Team-nodes, faced issues due to missing keys in Team-nodes.

I have overwritten the class methods in my code with below 2-functions. you may verify and update the code as appropriate.

Below code helps :

  1. Coloring, grouping and ordering the nodes irrespective of missing keys in few nodes.
  2. Overrides the CMAP dictionary to take unlimited values of categories in any key, original one has a limit of 8-categories for any key.
def new_compute_node_colors(self):
        import logging
        import nxviz as nv
        import matplotlib.patches as patches
        import matplotlib.pyplot as plt
        import networkx as nx
        from matplotlib.cm import get_cmap
        from matplotlib.path import Path
        from nxviz.geometry import circos_radius, get_cartesian, node_theta
        from nxviz.utils import (cmaps, infer_data_type, is_data_diverging, num_discrete_groups)
        """Compute the node colors. Also computes the colorbar."""
        #data = [self.graph.node[n][self.node_color] if self.node_color in self.graph.node[n].keys() else 'no_key' for n in self.nodes]
        data = [self.graph.node[n][self.node_color] if self.node_color in self.graph.node[n].keys() else 'zzz_no_key' for n in self.nodes]
        data_reduced = sorted(list(set(data)))
        dtype = infer_data_type(data)
        n_grps = num_discrete_groups(data)

        if dtype == 'categorical' or dtype == 'ordinal':
            #cmap = get_cmap(cmaps['Accent_{0}'.format(n_grps)].mpl_colormap)
            cmap = get_cmap(cmaps['Paired_12'].mpl_colormap)
        elif dtype == 'continuous' and not is_data_diverging(data):
            cmap = get_cmap(cmaps['continuous'].mpl_colormap)
        elif dtype == 'continuous' and is_data_diverging(data):
            cmap = get_cmap(cmaps['diverging'].mpl_colormap)

        for d in data:
            idx = data_reduced.index(d) / n_grps
            self.node_colors.append(cmap(idx))

        # Add colorbar if required.
        logging.debug('length of data_reduced: {0}'.format(len(data_reduced)))
        logging.debug('dtype: {0}'.format(dtype))
        if len(data_reduced) > 1 and dtype == 'continuous':
            self.sm = plt.cm.ScalarMappable(cmap=cmap,
                                            norm=plt.Normalize(vmin=min(data_reduced),  # noqa
                                                               vmax=max(data_reduced)   # noqa
                                                               )
                                            )
            self.sm._A = []

def new_group_and_sort_nodes(self):
        """
        Groups and then sorts the nodes according to the criteria passed into
        the Plot constructor.
        """
        if self.node_grouping and not self.node_order:
            #self.nodes = [n for n, d in sorted(self.graph.nodes(data=True), key=lambda x: x[1][self.node_grouping])]
            self.nodes = [n for n,d in sorted([(n,self.graph.node[n][self.node_grouping]) if self.node_grouping in self.graph.node[n].keys() else (n,'zzz_no_key') for n in self.graph.nodes],key= lambda x: x[1])]

        elif self.node_order and not self.node_grouping:
            #self.nodes = [n for n, _ in sorted(self.graph.nodes(data=True), key=lambda x: x[1][self.node_order])]
            self.nodes = [n for n, _ in sorted([(n,self.graph.node[n][self.node_order]) if self.node_order in self.graph.node[n].keys() else (n,'zzz_no_key') for n in self.graph.nodes],key= lambda x: x[1])]

        elif self.node_grouping and self.node_order:
            #self.nodes = [n for n, d in sorted(self.graph.nodes(data=True), key=lambda x: (x[1][self.node_grouping], x[1][self.node_order]))]
            nodes = []
            for n in self.nodes:
                if self.node_grouping in self.graph.node[n].keys():
                    grouping = self.graph.node[n][self.node_grouping]
                else:
                    grouping = 'zzz_no_key'
                
                if self.node_order in self.graph.node[n].keys():
                    order = self.graph.node[n][self.node_order]
                else:
                    order = 'zzz_no_key'
                    
                nodes.append((n,grouping,order))
            
            self.nodes = [n for n,group,order in sorted(nodes,key= lambda x: (x[1], x[2]))]
                
                
            

new_cmaps = {
    'Accent_2': qualitative.Accent_3,
    'Accent_3': qualitative.Accent_3,
    'Accent_4': qualitative.Accent_4,
    'Accent_5': qualitative.Accent_5,
    'Accent_6': qualitative.Accent_6,
    'Accent_7': qualitative.Accent_7,
    'Accent_8': qualitative.Accent_8,
    'Paired_12': qualitative.Paired_12, #added colorbrewer set ref:https://jiffyclub.github.io/palettable/colorbrewer/qualitative/#paired_12
    'continuous': sequential.YlGnBu_9,
    'diverging': diverging.RdBu_11,
}
            
nv.plots.BasePlot.compute_node_colors = new_compute_node_colors
nv.plots.BasePlot.group_and_sort_nodes = new_group_and_sort_nodes
nv.utils.cmaps = new_cmaps

@yerraeee
Copy link

Pasting my code again, did not paste properly above.

def new_compute_node_colors(self):
        import logging
        import nxviz as nv
        import matplotlib.patches as patches
        import matplotlib.pyplot as plt
        import networkx as nx
        from matplotlib.cm import get_cmap
        from matplotlib.path import Path
        from nxviz.geometry import circos_radius, get_cartesian, node_theta
        from nxviz.utils import (cmaps, infer_data_type, is_data_diverging, num_discrete_groups)
        """Compute the node colors. Also computes the colorbar."""
        #data = [self.graph.node[n][self.node_color] if self.node_color in self.graph.node[n].keys() else 'no_key' for n in self.nodes]
        data = [self.graph.node[n][self.node_color] if self.node_color in self.graph.node[n].keys() else 'zzz_no_key' for n in self.nodes]
        data_reduced = sorted(list(set(data)))
        dtype = infer_data_type(data)
        n_grps = num_discrete_groups(data)

        if dtype == 'categorical' or dtype == 'ordinal':
            #cmap = get_cmap(cmaps['Accent_{0}'.format(n_grps)].mpl_colormap)
            cmap = get_cmap(cmaps['Paired_12'].mpl_colormap)
        elif dtype == 'continuous' and not is_data_diverging(data):
            cmap = get_cmap(cmaps['continuous'].mpl_colormap)
        elif dtype == 'continuous' and is_data_diverging(data):
            cmap = get_cmap(cmaps['diverging'].mpl_colormap)

        for d in data:
            idx = data_reduced.index(d) / n_grps
            self.node_colors.append(cmap(idx))

        # Add colorbar if required.
        logging.debug('length of data_reduced: {0}'.format(len(data_reduced)))
        logging.debug('dtype: {0}'.format(dtype))
        if len(data_reduced) > 1 and dtype == 'continuous':
            self.sm = plt.cm.ScalarMappable(cmap=cmap,
                                            norm=plt.Normalize(vmin=min(data_reduced),  # noqa
                                                               vmax=max(data_reduced)   # noqa
                                                               )
                                            )
            self.sm._A = []

def new_group_and_sort_nodes(self):
        """
        Groups and then sorts the nodes according to the criteria passed into
        the Plot constructor.
        """
        if self.node_grouping and not self.node_order:
            #self.nodes = [n for n, d in sorted(self.graph.nodes(data=True), key=lambda x: x[1][self.node_grouping])]
            self.nodes = [n for n,d in sorted([(n,self.graph.node[n][self.node_grouping]) if self.node_grouping in self.graph.node[n].keys() else (n,'zzz_no_key') for n in self.graph.nodes],key= lambda x: x[1])]

        elif self.node_order and not self.node_grouping:
            #self.nodes = [n for n, _ in sorted(self.graph.nodes(data=True), key=lambda x: x[1][self.node_order])]
            self.nodes = [n for n, _ in sorted([(n,self.graph.node[n][self.node_order]) if self.node_order in self.graph.node[n].keys() else (n,'zzz_no_key') for n in self.graph.nodes],key= lambda x: x[1])]

        elif self.node_grouping and self.node_order:
            #self.nodes = [n for n, d in sorted(self.graph.nodes(data=True), key=lambda x: (x[1][self.node_grouping], x[1][self.node_order]))]
            nodes = []
            for n in self.nodes:
                if self.node_grouping in self.graph.node[n].keys():
                    grouping = self.graph.node[n][self.node_grouping]
                else:
                    grouping = 'zzz_no_key'
                
                if self.node_order in self.graph.node[n].keys():
                    order = self.graph.node[n][self.node_order]
                else:
                    order = 'zzz_no_key'
                    
                nodes.append((n,grouping,order))
            
            self.nodes = [n for n,group,order in sorted(nodes,key= lambda x: (x[1], x[2]))]
                
                
            

new_cmaps = {
    'Accent_2': qualitative.Accent_3,
    'Accent_3': qualitative.Accent_3,
    'Accent_4': qualitative.Accent_4,
    'Accent_5': qualitative.Accent_5,
    'Accent_6': qualitative.Accent_6,
    'Accent_7': qualitative.Accent_7,
    'Accent_8': qualitative.Accent_8,
    'Paired_12': qualitative.Paired_12, #added colorbrewer set ref:https://jiffyclub.github.io/palettable/colorbrewer/qualitative/#paired_12
    'continuous': sequential.YlGnBu_9,
    'diverging': diverging.RdBu_11,
}
            
nv.plots.BasePlot.compute_node_colors = new_compute_node_colors
nv.plots.BasePlot.group_and_sort_nodes = new_group_and_sort_nodes
nv.utils.cmaps = new_cmaps

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants