adding arrows between datapoints

Viewed 132

I have the following dataframe:

dataT = [{'Record_ID': 10, 'Timepoint': 1, 'Value1':30,'Value2':15, "Improvement" : 1 }, {'Record_ID': 10, 'Timepoint': 2,  'Value1':30,'Value2':30, "Improvement" : 1 },
        {'Record_ID': 12, 'Timepoint': 1, 'Value1':40,'Value2':10 , "Improvement" : 2 }, {'Record_ID': 12, 'Timepoint': 2,  'Value1':30,'Value2':30, "Improvement" : 2 },
        {'Record_ID': 13, 'Timepoint': 1,  'Value1':70,'Value2':30 , "Improvement" : 3 }, {'Record_ID': 13, 'Timepoint': 2,  'Value1':25,'Value2':40 , "Improvement" : 3},
        {'Record_ID': 11, 'Timepoint': 1,  'Value1':60,'Value2':50 , "Improvement" : 1 }, {'Record_ID': 11, 'Timepoint': 2,  'Value1':35,'Value2':45, "Improvement" : 1   }]  
data = pd.DataFrame(dataT)

#plot:

import matplotlib.pyplot as plt
sns.set_style("darkgrid")
colors = dict({1: "green",
           2:"red",
           3:"orange"})
expVarPC1 = my_pcoa.eigvals.PC1/my_pcoa.eigvals.sum()
fig, ax = plt.subplots(figsize=(24, 16))
sns.scatterplot(x =data['Value1'],  y= data['Value2'],style=data["Timepoint"], hue=data["Improvement"], s=200,
              palette=colors)


plt.legend(title='', title_fontsize=20,  fontsize=20, markerscale=2., scatterpoints=1, )
              
              
plt.xlabel("Val1" , fontsize=22)
plt.ylabel("Val2 ", fontsize=22)
plt.title("samples T1 & T2 ",  fontsize='40')

plt.show()

The resulting plot: dataframe Data

I would like to add arrows between each time point 1 and 2 sample for each record id, so far I haven't found anything that works, any help would be appreciated.

P.s. I would also like to colour the arrows the same as the markers

2 Answers

Have a look at NetworkX .

NetworkX is a Python package for the creation, manipulation, and study of the structure, dynamics, and functions of complex networks.

Creating reproducible example with NetworkX:

import networkx as nx
import matplotlib.pyplot as plt

# create an empty graph
G=nx.Graph()
#Now we will add some nodes to our graph. We can add one node with the method add_node() and a list of nodes with the method add_nodes_from():
G.add_node("a")
G.add_nodes_from(["b","c"])


# If we have a tuple or a list as the edge, we can use the asterisk operator to unpack the tuple or the list:
edge = ("d", "e")
G.add_edge(*edge)
edge = ("a", "b")
G.add_edge(*edge)

# we can print nodes/edges
print("Nodes of graph: ")
print(G.nodes())
print("Edges of graph: ")
print(G.edges())

#We can add a bunch of edges as a list of edges in the form of 2 tuples.
G.add_edges_from([("a","c"),("c","d"), ("a",1), (1,"d"), ("a",2)])

# we can plot the final graph
nx.draw(G, with_labels=True)
plt.show() # display

Output:

enter image description here

matplotlib.pyplot has the function arrow which does exactly what you want. You can specify the color using the color= keyword argument.

Here is a working example, except for coloring:

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

dataT = [{'Record_ID': 10, 'Timepoint': 1, 'Value1':30,'Value2':15, "Improvement" : 1 }, {'Record_ID': 10, 'Timepoint': 2,  'Value1':30,'Value2':30, "Improvement" : 1 },
        {'Record_ID': 12, 'Timepoint': 1, 'Value1':40,'Value2':10 , "Improvement" : 2 }, {'Record_ID': 12, 'Timepoint': 2,  'Value1':30,'Value2':32, "Improvement" : 2 },
        {'Record_ID': 13, 'Timepoint': 1,  'Value1':70,'Value2':30 , "Improvement" : 3 }, {'Record_ID': 13, 'Timepoint': 2,  'Value1':25,'Value2':40 , "Improvement" : 3},
        {'Record_ID': 11, 'Timepoint': 1,  'Value1':60,'Value2':50 , "Improvement" : 1 }, {'Record_ID': 11, 'Timepoint': 2,  'Value1':35,'Value2':45, "Improvement" : 1   }]
data = pd.DataFrame(dataT)

#plot:
sns.set_style("darkgrid")
colors = dict({1: "green",
           2:"red",
           3:"orange"})
#expVarPC1 = my_pcoa.eigvals.PC1/my_pcoa.eigvals.sum()
fig, ax = plt.subplots(figsize=(24, 16))
sns.scatterplot(x =data['Value1'],  y= data['Value2'],style=data["Timepoint"], hue=data["Improvement"], s=200,
              palette=colors)

# for all record IDs
for record_id in data["Record_ID"].unique():
    # get that record IDs datapoints
    record_data = data[data["Record_ID"] == record_id]
    # if you have more than 1 datapoint
    prev = None
    if len(record_data) > 1:
        for ind,row in record_data.iterrows():
            if not prev is None:
                plt.arrow(prev["Value1"],
                          prev["Value2"],
                          row["Value1"]-prev["Value1"],
                          row["Value2"]-prev["Value2"],
                          width=0.1)
            prev = row


plt.legend(title='', title_fontsize=20,  fontsize=20, markerscale=2., scatterpoints=1, )
Related