22

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?

3
  • Are input data Python lists or numpy vectors? Commented May 24, 2016 at 13:31
  • They're lists. Sorry, I should have said that. Commented May 24, 2016 at 13:35
  • Instead of plotting a line, you can use - as a first step - a scatter plot (to have unlinked points on your graph) Commented Feb 13, 2019 at 9:41

6 Answers 6

27

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

Sign up to request clarification or add additional context in comments.

Comments

17

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

6 Comments

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).
@akinn, I just undated my answer, including an example.
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.
@akinn, zip needs to fetch all items immediately. izip only advances the underlying iterators.
@akinn, refer to itertools — Functions creating iterators for efficient looping for the detailed description.
|
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

4 Comments

You could still improve performance by using sort(x) only once.
@ThomasKühn: I added it in my answer as an alternative
I edited the answer to make it a bit clearer. If you disagree you may just revert the change.
@Sheldore I think you're still using sort twice: first, when you do np.sort(x) and then when you do f[np.argsort(x)]. I'd instead do indices = np.argsort(x) and then plot by doing: plt.plot(x[indices], f[indices])
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

1 Comment

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.)
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.

Comments

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.

1 Comment

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.