0

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?

Mr. T
  • 11,960
  • 10
  • 32
  • 54
Jim Wang
  • 421
  • 6
  • 17
  • 1
    If you have more of these graphs, you may want to consider using [seaborn](https://seaborn.pydata.org/examples/horizontal_boxplot.html) - its jitter parameter takes care of this automatically. – Mr. T Oct 28 '20 at 22:57

1 Answers1

1

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()
Simon Notley
  • 2,070
  • 3
  • 12
  • 18
  • Thanks for the response. But I always got the following errors with plt.xticks(xx,x) when running the above codes: TypeError: 'int' object is not iterable. – Jim Wang Oct 28 '20 at 22:26
  • 1
    `from numpy import *` [meh](https://stackoverflow.com/q/2386714/8881141) – Mr. T Oct 28 '20 at 22:32
  • 1
    @JimWang You're not using Python 2.7 are you? This runs fine for me in 3.8. – Simon Notley Oct 28 '20 at 22:46
  • @SimonN Yes, it turns out to be the python version issue. I add the python3 for jupyter notebook, and it works now. Thanks! – Jim Wang Oct 29 '20 at 00:10