Problems plotting multiple data sets on same graph in python

Viewed 38

I have a dataset which consists of data gathered from experiments from various participants done over 3 days.

I managed to plot the data for each participant on a seperate plot for each experiment succefully using the following code:

by_part = p1.groupby('participant_id')
for name, group in by_part:
    byexp_num = p1.groupby('exp_num')
    fig, axs = plt.subplots(figsize=(len(byexp_num), 5), nrows=2, ncols=(len(byexp_num)//2)+ (len(byexp_num) % 2 > 0)) #as there are 2 rows, the column is by the length of the experiments divided by 2 plus the modulo of the same operation to account for odd numbers
    plt.subplots_adjust(left=0.1, bottom=0.1, right=0.9,  top=0.8,  wspace=0.4,  hspace=0.4)
    fig.suptitle('Participant {}'.format(name), fontsize=20)
    subplot_targets = zip(byexp_num.groups.keys(), axs.flatten())
    for key, ax in subplot_targets:
        ax.plot(byexp_num.get_group(key).rn_norm, byexp_num.get_group(key).scale_data)
        ax.set_ylabel('Scale Data')
        ax.set_title('Experiment {}'.format(key+1))

But when I try to group the data in days and plot multiple experiments on the same graph for each day there is a problem with how the graphs are displayed. The data is grouped succesffuly, but it joins the all the experiments together. i.e the line continues from the last datapoint of the experiment to the next so instead of showing n seperate lines in each plot, it shows 1 continuous one. I am not sure about what im doing wrong.

by_part = p1.groupby('participant_id')
p1 = df_all[(df_all['participant_id']== 1)]
by_part = p1.groupby('participant_id')
for name, group in by_part:
    by_day = p1.groupby('day')
    fig, axs = plt.subplots(figsize=(30, 5), nrows=1, ncols=(len(by_day)))
    fig.suptitle('Participant {}'.format(name), fontsize=20)
    subplot_targets = zip(by_day.groups.keys(), axs.flatten())
    for key, ax in subplot_targets:
        ax.plot(by_day.get_group(key).rn, by_day.get_group(key).scale_data)
        ax.set_ylabel('Scale Data')
        ax.set_title('Day {}'.format(key))
        ax.legend(p1['exp_num'])

Here is the graph it displays. Plots

EDIT Adding dataframe as requested by GalacticPonderer

DataFrame for Participant 1

1 Answers

I suspect you need to sort your data, per invocation of plot, by X value (rn). To do this, we'll convert it into a numpy array, find out what indexes will sort the X axis, then apply these indices to both the X and Y axis, creating a new numpy array we can plot.

First let's look at a simple example:

import matplotlib.pyplot as plt
import numpy as np

y=[list(range(0,10)), list(range(0,20,2))]
# Randomly chosen out-of-order values
x=[[7,3,8,5,2,1,9,6,4,0],[8,2,4,0,1,6,3,7,9,5]]
fig,axs=plt.subplots()
for i in range(0,2):
    axs.plot(x[i], y[i])

plt.show()

Yields:

Unsorted X-axis

Now let's sort by X axis:

for i in range(0,2):
    xy=np.array([x[i],y[i]])
    ind=np.argsort(xy,axis=-1)[0]
    axs.plot(np.take_along_axis(xy[0,:], ind, axis=0), np.take_along_axis(xy[1,:], ind, axis=0))

The xy=np.array([x[i],y[i]]) line converts the data to a numpy array, because numpy has the requisite sorting operations. ind=np.argsort(xy,axis=-1) returns a numpy array of indices that will sort the X-axis, which we will apply to both the X and Y axes. Since we are only interested in the X-axis sort results, we discard the second row ([0]). take_along_axis is a companion to argsort and allows us to apply the indices to the array. Result: Sorted by X values

Applying to your code:

import numpy as np
# [...]
    for key, ax in subplot_targets:
        xy=np.array([by_day.get_group(key).rn, by_day.get_group(key).scale_data])
        ind=np.argsort(xy,axis=-1)[0]
        ax.plot(np.take_along_axis(xy[0,:], ind, axis=0), np.take_along_axis(xy[1,:], ind, axis=0)))
        ax.set_ylabel('Scale Data')
        ax.set_title('Day {}'.format(key))
        ax.legend(p1['exp_num'])
Related