Jim Wang
Jim Wang

Reputation: 461

How can I shift overlapping data points slightly along the x-axis in matplotlib?

I collected some data points for 4 different experimental setups, which are labeled "1", "2", "4" and "8". For each experimental setup, I collected 10 data points.

I am able to successfully plot these data points and draw an additional curve to show the average values for each setup.

However, I changed other settings in my experiments, and I can plot another figure like that. Now I hope to put everything in one single plot (2 sets of data points and two average curves), but everything look too crowded. My script for plotting and the plot are like these:

from numpy import *
import math
import matplotlib.pyplot as plt
import numpy as np

raw_1 = [0.38, 0.49, 0.25, 0.3, 0.4, 0.19, 0.45, 0.93, 0.44, 0.65] 
raw_2 = [0.27, 0.39, 0.09, 0.75, 0.79, 0.77, 0.31, 0.05, 0.73, 0.7]
raw_4 = [0.2, 0.84, 0.83, 0.7, 0.86, 0.2, 0.37, 0.41, 0.72, 0.29]
raw_8 = [0.2, 0.71, 0.31, 0.63, 0.24, 0.07, 0.2, 0.89, 0.34, 0.92]
y = np.array([raw_1, raw_2, raw_4, raw_8])
y = np.transpose(y)
y_mean = [mean(raw_1), mean(raw_2), mean(raw_4), mean(raw_8)]
x = [1,2,4,8]
xx = range(len(x))
plt.plot(xx, y[0], 'rx') 
plt.plot(xx, y[1], 'rx') 
plt.plot(xx, y[2], 'rx') 
plt.plot(xx, y[3], 'rx') 
plt.plot(xx, y[4], 'rx') 
plt.plot(xx, y[5], 'rx') 
plt.plot(xx, y[6], 'rx') 
plt.plot(xx, y[7], 'rx') 
plt.plot(xx, y[8], 'rx') 
plt.plot(xx, y[9], 'rx')

plt.xticks(xx,x)
leg = plt.legend(loc='upper left');

new_raw_1 = [0.217, 0.206, 0.222, 0.271, 0.212, 0.58, 0.333, 0.463, 0.314, 0.59] 
new_raw_2 = [0.511, 0.537, 0.565, 0.597, 0.527, 0.571, 0.505, 0.541, 0.542, 0.517]
new_raw_4 = [0.662, 0.552, 0.772, 0.436, 0.505, 0.577, 0.313, 0.796, 0.582, 0.574]
new_raw_8 = [0.511, 0.587, 0.591, 0.531, 0.522, 0.549, 0.593, 0.544, 0.552, 0.555]
y = np.array([new_raw_1, new_raw_2, new_raw_4, new_raw_8])
y = np.transpose(y)
y_mean_new = [mean(new_raw_1), mean(new_raw_2), mean(new_raw_4), mean(new_raw_8)]
x = [1,2,4,8]
xx = range(len(x))
plt.plot(xx, y[0], 'bo') 
plt.plot(xx, y[1], 'bo') 
plt.plot(xx, y[2], 'bo') 
plt.plot(xx, y[3], 'bo') 
plt.plot(xx, y[4], 'bo') 
plt.plot(xx, y[5], 'bo') 
plt.plot(xx, y[6], 'bo') 
plt.plot(xx, y[7], 'bo') 
plt.plot(xx, y[8], 'bo') 
plt.plot(xx, y[9], 'bo')
plt.plot(xx, y_mean_new, color='C0', marker='D', markersize=10, markerfacecolor='white', label='Avg A')
plt.plot(xx, y_mean, color='C1', marker='H', markersize=10, markerfacecolor='white', label='Avg B')
#plt.xticks(xx,x)
leg = plt.legend();


plt.show()

enter image description here

Currently, the blue circles and the red X markers are blocking each other. How should I modify my script to introduce a small x-axis shift between blue circles and red X markers, while still keeping xticks as "1", "2", "4", "8" with equal distances?

Upvotes: 0

Views: 750

Answers (1)

Simon Notley
Simon Notley

Reputation: 2136

You can add an offset to the x positions simply by defining a different list of x coordinates for each series. This doesn't affect your ticks as you simply keep the original x positions for them. Here's an example:

from numpy import *
import math
import matplotlib.pyplot as plt
import numpy as np

raw_1 = [0.38, 0.49, 0.25, 0.3, 0.4, 0.19, 0.45, 0.93, 0.44, 0.65] 
raw_2 = [0.27, 0.39, 0.09, 0.75, 0.79, 0.77, 0.31, 0.05, 0.73, 0.7]
raw_4 = [0.2, 0.84, 0.83, 0.7, 0.86, 0.2, 0.37, 0.41, 0.72, 0.29]
raw_8 = [0.2, 0.71, 0.31, 0.63, 0.24, 0.07, 0.2, 0.89, 0.34, 0.92]
y = np.array([raw_1, raw_2, raw_4, raw_8])
y = np.transpose(y)
y_mean = [mean(raw_1), mean(raw_2), mean(raw_4), mean(raw_8)]
x = [1,2,4,8]
xx = range(len(x))
xxr = [x - 0.1 for x in xx]
plt.plot(xxr, y[0], 'rx')
plt.plot(xxr, y[1], 'rx')
plt.plot(xxr, y[2], 'rx')
plt.plot(xxr, y[3], 'rx')
plt.plot(xxr, y[4], 'rx')
plt.plot(xxr, y[5], 'rx')
plt.plot(xxr, y[6], 'rx')
plt.plot(xxr, y[7], 'rx')
plt.plot(xxr, y[8], 'rx')
plt.plot(xxr, y[9], 'rx')

plt.xticks(xx,x)
leg = plt.legend(loc='upper left');

new_raw_1 = [0.217, 0.206, 0.222, 0.271, 0.212, 0.58, 0.333, 0.463, 0.314, 0.59] 
new_raw_2 = [0.511, 0.537, 0.565, 0.597, 0.527, 0.571, 0.505, 0.541, 0.542, 0.517]
new_raw_4 = [0.662, 0.552, 0.772, 0.436, 0.505, 0.577, 0.313, 0.796, 0.582, 0.574]
new_raw_8 = [0.511, 0.587, 0.591, 0.531, 0.522, 0.549, 0.593, 0.544, 0.552, 0.555]
y = np.array([new_raw_1, new_raw_2, new_raw_4, new_raw_8])
y = np.transpose(y)
y_mean_new = [mean(new_raw_1), mean(new_raw_2), mean(new_raw_4), mean(new_raw_8)]
x = [1,2,4,8]
xx = range(len(x))
xxb = [x + 0.1 for x in xx]
plt.plot(xxb, y[0], 'bo')
plt.plot(xxb, y[1], 'bo')
plt.plot(xxb, y[2], 'bo')
plt.plot(xxb, y[3], 'bo')
plt.plot(xxb, y[4], 'bo')
plt.plot(xxb, y[5], 'bo')
plt.plot(xxb, y[6], 'bo')
plt.plot(xxb, y[7], 'bo')
plt.plot(xxb, y[8], 'bo')
plt.plot(xxb, y[9], 'bo')
plt.plot(xx, y_mean_new, color='C0', marker='D', markersize=10, markerfacecolor='white', label='Avg A')
plt.plot(xx, y_mean, color='C1', marker='H', markersize=10, markerfacecolor='white', label='Avg B')
#plt.xticks(xx,x)
leg = plt.legend()

You could also improve the code a bit by removing duplications (particularly the duplicated import of numpy) and using loops to save repeating yourself:

I've also used unique variable names inside the comprehensions in this version as I think the reuse of x might cause problems in Python 2.7.

import matplotlib.pyplot as plt
import numpy as np

raw_1 = [0.38, 0.49, 0.25, 0.3, 0.4, 0.19, 0.45, 0.93, 0.44, 0.65] 
raw_2 = [0.27, 0.39, 0.09, 0.75, 0.79, 0.77, 0.31, 0.05, 0.73, 0.7]
raw_4 = [0.2, 0.84, 0.83, 0.7, 0.86, 0.2, 0.37, 0.41, 0.72, 0.29]
raw_8 = [0.2, 0.71, 0.31, 0.63, 0.24, 0.07, 0.2, 0.89, 0.34, 0.92]
y = np.array([raw_1, raw_2, raw_4, raw_8])
y = np.transpose(y)
y_mean = [np.mean(raw_1), np.mean(raw_2), np.mean(raw_4), np.mean(raw_8)]
x = [1,2,4,8]
xx = range(len(x))

xxr = [j - 0.1 for j in xx]
for point in y:
    plt.plot(xxr, point, 'rx')

plt.xticks(xx,x)
leg = plt.legend(loc='upper left');

new_raw_1 = [0.217, 0.206, 0.222, 0.271, 0.212, 0.58, 0.333, 0.463, 0.314, 0.59] 
new_raw_2 = [0.511, 0.537, 0.565, 0.597, 0.527, 0.571, 0.505, 0.541, 0.542, 0.517]
new_raw_4 = [0.662, 0.552, 0.772, 0.436, 0.505, 0.577, 0.313, 0.796, 0.582, 0.574]
new_raw_8 = [0.511, 0.587, 0.591, 0.531, 0.522, 0.549, 0.593, 0.544, 0.552, 0.555]
y = np.array([new_raw_1, new_raw_2, new_raw_4, new_raw_8])
y = np.transpose(y)
y_mean_new = [np.mean(new_raw_1), np.mean(new_raw_2), np.mean(new_raw_4), np.mean(new_raw_8)]

xxb = [k + 0.1 for k in xx]
for point in y:
    plt.plot(xxb, point, 'bo')

plt.plot(xx, y_mean_new, color='C0', marker='D', markersize=10, markerfacecolor='white', label='Avg A')
plt.plot(xx, y_mean, color='C1', marker='H', markersize=10, markerfacecolor='white', label='Avg B')

leg = plt.legend()

Upvotes: 1

Related Questions