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?

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158

6 Answers6

24

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
  • 11,493
  • 8
  • 43
  • 68
16

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
  • 17,001
  • 22
  • 90
  • 134
  • 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
  • 885
  • 1
  • 9
  • 25
Sheldore
  • 37,862
  • 7
  • 57
  • 71
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,707
  • 4
  • 26
  • 50
  • 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
  • 98
  • 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.