20

Basically I have two arrays, one containing the values of the x-axis and the second containing the values of the y-axis. The problem is, when I do

plt.semilogy(out_samp,error_mc)

I get this

enter image description here

Which doesn't make any sense. That is because the plot functions plots everything as it encounters in the x array, not caring whether it's sorted in ascending order or not. How can I sort these two arrays so that the x array is sorted by increasing value and the y axis sorted in the same way so that the points are the same but the plot is connected so that it doesn't make this mess?

Thank you in advance!

Łukasz Rogalski
  • 20,566
  • 8
  • 54
  • 89

6 Answers6

20

It is easier to zip, sort and unzip the two lists of data.

Example:

xs = [...]
ys = [...]

xs, ys = zip(*sorted(zip(xs, ys)))

plot(xs, ys)

See the zip documentation here: https://docs.python.org/3.5/library/functions.html#zip

Hidde
  • 10,623
  • 7
  • 40
  • 65
15

Sort by the value of x-axis before plotting. Here is an MWE.

import itertools

x = [3, 5, 6, 1, 2]
y = [6, 7, 8, 9, 10]

lists = sorted(itertools.izip(*[x, y]))
new_x, new_y = list(itertools.izip(*lists))

# import operator
# new_x = map(operator.itemgetter(0), lists)        # [1, 2, 3, 5, 6]
# new_y = map(operator.itemgetter(1), lists)        # [9, 10, 6, 7, 8]

# Plot
import matplotlib.pylab as plt
plt.plot(new_x, new_y)
plt.show()

For small data, zip (as mentioned by other answerers) is enough.

new_x, new_y = zip(*sorted(zip(x, y)))

The result,

enter image description here

SparkAndShine
  • 15,667
  • 17
  • 84
  • 129
  • I get a "ValueError: too many values to unpack". Trying to figure out what it means. The vectors only contain 50 values. (The error is for the sorted(...) line). –  May 24 '16 at 13:39
  • @akinn, I just undated my answer, including an example. – SparkAndShine May 24 '16 at 13:41
  • 1
    Ok, it's working now, thank you. Though, I'm wondering, is it more efficient like this? Using itertools and operator, I mean. The other solution offered by other seem to be working as well. –  May 24 '16 at 13:57
  • @akinn, `zip` needs to fetch all items immediately. `izip` only advances the underlying iterators. – SparkAndShine May 24 '16 at 14:01
  • @akinn, refer to [itertools — Functions creating iterators for efficient looping](https://docs.python.org/2/library/itertools.html#module-itertools) for the detailed description. – SparkAndShine May 24 '16 at 14:09
  • Good point for the MWE, however @Hidde provided a more "modern" and simpler answer for python 3.5 – Tobbey Jun 06 '17 at 11:50
6

An alternative to sort the lists would be to use NumPy arrays and use np.sort() for sorting. The advantage with using arrays would be a vectorized operation while computing a function like y=f(x). Following is an example of plotting a normal distribution:

Without using sorted data

mu, sigma = 0, 0.1
x = np.random.normal(mu, sigma, 200)
f = 1/(sigma * np.sqrt(2 * np.pi)) *np.exp( - (x - mu)**2 / (2 * sigma**2) )
plt.plot(x,f, '-bo', ms = 2)

Output 1

enter image description here

With using np.sort() This allows straightforwardly using sorted array x while computing the normal distribution.

mu, sigma = 0, 0.1
x = np.sort(np.random.normal(mu, sigma, 200)) 
# or use x = np.random.normal(mu, sigma, 200).sort()
f = 1/(sigma * np.sqrt(2 * np.pi)) *np.exp( - (x - mu)**2 / (2 * sigma**2) )
plt.plot(x,f, '-bo', ms = 2)

Alternatively if you already have both x and y data unsorted, you may use numpy.argsort to sort them a posteriori

mu, sigma = 0, 0.1
x = np.random.normal(mu, sigma, 200)
f = 1/(sigma * np.sqrt(2 * np.pi)) *np.exp( - (x - mu)**2 / (2 * sigma**2) )
plt.plot(np.sort(x), f[np.argsort(x)], '-bo', ms = 2)

Notice that the code above uses sort() twice: first with np.sort(x) and then with f[np.argsort(x)]. The total sort() invocations can be reduced to one:

# once you have your x and f...
indices = np.argsort(x)
plt.plot(x[indices], f[indices], '-bo', ms = 2)

In both cases the output is

Output 2

enter image description here

pfabri
  • 753
  • 1
  • 7
  • 24
Sheldore
  • 35,129
  • 6
  • 43
  • 58
1

just do this

list=zip(*sorted(zip(*(x,y))))
plt.plot(*list)

sorted function will sort according to the 1st argument i.e x values

Eular
  • 1,475
  • 4
  • 21
  • 45
  • But, in Python 3, from what I am seeing, it is returning a tuple. I upvoted your answer. However, your list variable is actually a tuple. (By the way, using _list_ as a variable is a pretty bad idea as _list_ is a built-in data-structure and _list()_ initialises a list technically.) – Prasad Raghavendra Feb 11 '20 at 03:53
0

You can convert your arrays to numpy arrays, then use argsort on the first array, take the the array and sort both arrays with the argsort array.

lint
  • 100
  • 8
  • I plotted a scatter plot but it's not easy to interpret. Essentially my x vector is the number of iterations, and y is the error. –  May 24 '16 at 13:38
0

I think you need to sort one array and the other array should also get sorted based on the first array. I got this solution from some other stack overflow question. Most probably this should be your solution.

out_samp,error_mc=zip(*sorted(zip(out_samp,error_mc)))

Now plot those two values, you get a correct graph.