I have a graph where some edges are directed and some are undirected, but I cannot get Gephi to acknowledge both edge types in the same graph.
I am currently using R to manipulate the graph, and then using the 'rgexf' package to encode the graph into a Gephi-readable .gexf file as follows:
write.gexf(nodes = nodes_df, edges = edges_df, edgesWeight = E(gD)$weight,
nodesAtt = nodes_att, edgesAtt = edges_att, nodesVizAtt = nodes_att_viz,
edgesVizAtt = edges_att_viz,output = "plag_c_d3.gexf")
Here, edgesAtt contains a Type column of strings ('Directed' and 'Undirected'). edgesAtt looks like:
Type weight sourcedate targetdate repost_date_diff
Directed 100 1361424992 1361426157 0.0134838
Undirected 100 1362140722 1362140722 0.0000000
Directed 54 1365403984 1365465600 0.7131481
However, when I open Gephi and open the gexf file, Gephi does not read this 'Type' column as the edge type. Instead, it just treats the 'Type' column like any other arbitrary edge attribute, and it adds a new column called 'Type' filled with the default edge type I choose when opening the dataset. Selecting 'mixed' when I import the data does not change this. Gephi does successfully read the 'weight' column as edge weights, however.
How do I make Gephi see both edge types?
Edit changing the defaultedgetype attribute to 'mixed' or to 'mutual' also does not work, nor does making each undirected edge into two directional edges that face opposite ways.
Based on Yannis P.'s notes on how .gexf files store 'type' in mixed types, I built a quick Python 3 script that solves the problem. The script is below. It assumes you have a .gexf file, and that you've stored 'type' in an edgesAtt column named 'type' that contains strings 'Directed' and 'Undirected'. The script reads these and writes them in to the correct place in 'edges' so that Gephi will recognize them. When you open the new script-generated .gexf file in Gephi, just set the type to 'mixed' when importing.
note: it's a quick script that eschews error handling and any testing of what it's operating on...use at your own risk and/or add your own catches...but if you're stuck on this as I was, then this should get you started.
#Call script like:
# python this_script.py foo.gexf
#Assumes that in foo.gexf, Type ('Directed' or 'Undirected') is stored as a string column in edgesAtt
#Script outputs a file foo_mixed.gexf that is identical except that mixed Directed and Undirected edge types will be specified in edge elements so that Gephi can read them
import sys
import argparse
def work (args):
linecount = 0
notinnodes = False # nodes att comes first in gexf file
# Read the whole .gexf input file into memory as a list
with open (args.fname, 'r') as infile:
gexf = infile.readlines()
infile.close()
# Create output gexf file
outfname = args.fname.split('.')[0]+'_mixed'+'.'+args.fname.split('.')[1]
with open (outfname, 'w') as outgexf:
for line in gexf:
# First, ignore the node attributes that come before edge atts in .gexf files
if '<attributes class=\"edge\"' in line:
notinnodes = True
# Get the edge attribute number that contains 'Type' or 'type'
if notinnodes and 'title=\"type\"' in line.lower():
Type_attnumber = int(line.split('id=\"att')[1].split('\"')[0])
break
# Edit every line that contains an edge element and add the 'type' to it from the attributes listed below it
for line in gexf:
if not '<edge id=' in line:
outgexf.writelines(line)
else:
edgeLine = line.split('\"')
Type = gexf[linecount + 1 + Type_attnumber].split('value=')[1].split('/')[0]
outgexf.writelines( '\"'.join(edgeLine[0:6])+'\" '+'type='+Type +'\"'.join(edgeLine[6:]) )
linecount = linecount+1
def main():
# Parser to grab name of file we're currently working on
parser = argparse.ArgumentParser()
parser.add_argument("fname")
args = parser.parse_args()
work(args)
if __name__ == "__main__":
main()