WhitakerLab / scona

Code to analyse structural covariance brain networks using python.
https://whitakerlab.github.io/scona/
MIT License
68 stars 33 forks source link

calculate_nodal_measures doesn't work on graph bundles #127

Open KirstieJane opened 5 years ago

KirstieJane commented 5 years ago

I though that graph bundles had all the same attributes as graphs....but I get the following error when I try to run calculate_nodal_measures() on bundleGraphs (setup as described in the collapsed section below).

bundleGraphs.calculate_nodal_measures()

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-3-5972c4b80e32> in <module>
----> 1 bundleGraphs.calculate_nodal_measures()

AttributeError: 'GraphBundle' object has no attribute 'calculate_nodal_measures'

I also get the error for calculate_global_measures():

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-18-8a0f9f100859> in <module>
      1 # Calculate the global measures
----> 2 bundleGraphs.calculate_global_measures()
      3 #bundleGraphs_measures = bundleGraphs.report_global_measures()

AttributeError: 'GraphBundle' object has no attribute 'calculate_global_measures'

In contrast bundleGraphs.report_global_measures() gives the expected output 😄, but bundleGraphs.report_nodal_measures() doesn't 😢 (same error as above).

And to be clear bundleGraphs['real_graph'].calculate_nodal_measures() works as expected too 😸

So is this a feature or a bug? Which attributes are supposed to be passed from graphs to the bundles?


Click the arrow below to see the MWE I ran to get the errors above.

Click here to expand

``` import scona as scn import scona.datasets as datasets import numpy as np import networkx as nx import pandas as pd import matplotlib.pyplot as plt import seaborn as sns %matplotlib inline # Read in sample data from the NSPN WhitakerVertes PNAS 2016 paper. df, names, covars, centroids = datasets.NSPN_WhitakerVertes_PNAS2016.import_data() # calculate residuals of the matrix df for the columns of names df_res = scn.create_residuals_df(df, names, covars) # create a correlation matrix over the columns of df_res M = scn.create_corrmat(df_res, method='pearson') # Initialise a weighted graph G from the correlation matrix M G = scn.BrainNetwork(network=M, parcellation=names, centroids=centroids) # Threshold G at cost 10 to create a binary graph with 10% as many edges as the complete graph G. G10 = G.threshold(10) # Create a GraphBundle object that contains the G10 graph called "real_graph" bundleGraphs = scn.GraphBundle([G10], ["real_graph"]) ```

wingedRuslan commented 5 years ago

@KirstieJane, this is the GraphBundle's behavior we have right now and I hope @Islast will confirm my below-mentioned explanations.

So, in general, it is a feature :smiley: GraphBundle is a dictionary, where value - is the BrainNetwork Graph and key - is the name of the graph. Right now methods like calculate_nodal_measures && report_nodal_measures for this class GraphBundle are not implemented. That's why there are errors saying that these operations (methods) on GraphBundle do not exist.

And to be clear bundleGraphs['real_graph'].calculate_nodal_measures() works as expected too

This works as expected because we take one BrainNetwork Graph (keyed by the name - real_graph]) from a bunch of Graphs (GraphBundle) and perform nodal measures calculation only on this one Graph. bundleGraphs['real_graph'] returns the BrainNetwork Graph, as this is a single BrainNetwork object we can calculate_nodal_measures(). In your case these 2 lines calculate nodal measures on the same object G10 :

bundleGraphs['real_graph'].calculate_nodal_measures()  
G10.calculate_nodal_measures()

Speaking about calculate_global_measures(), we have report_global_measures that will calculate global measures (if not already calculated) and report the results as a pandas dataframe.

PS. adding the support of calculate_nodal_measures for GraphBundle is pretty straightforward (pseudocode):

for each graph in GraphBundle:
    measures = graph.calculate_nodal_measures()
    store the reported nodal measures of each graph in a dataframe

return dataframe

We can discuss this in details during the next week's meeting if you want to have this functionality ;)