1

I have the following code for a scatterplot, and the corresponding plot is shown below:

x = ['C9-U2', 'C10-U5', 'C10-U5', 'C11-U1', 'C11-U1']
y = ['J',     'C',      'H',      'J',     'H']
plt.scatter(x,y)

enter image description here

In the plot, I would like to see both axes sorted, ie the x-axis should be [C9, C10, C11] (which is what it is, because I have entered the data in that sequence), and the y-axis should be [C, H, J] (which it is not).

How do I make sure that both axes are sorted?

R71
  • 4,283
  • 7
  • 32
  • 60
  • Are you asking [how to sort a list](https://stackoverflow.com/questions/36139/how-to-sort-a-list-of-strings) or [how to sort a list based on values from another list](https://stackoverflow.com/questions/6618515/sorting-list-based-on-values-from-another-list)? – ImportanceOfBeingErnest Nov 07 '18 at 14:33
  • I am asking, how to plot keeping BOTH axes sorted. I can keep any one axis sorted by rearranging the data set, but how to sort both axes together? – R71 Nov 08 '18 at 14:24
  • Can you write that clearly in the question. At the moment it reads that you do not care about the x axis. Best describe in detail what exactly the desired outcome would be. – ImportanceOfBeingErnest Nov 08 '18 at 14:28
  • I have corrected the error in the code, and made the question more explicit. – R71 Nov 08 '18 at 14:38

3 Answers3

3

This is actually a problem for which there is no good solution at the moment. The axis units are determined as they come from the input. So a solution is to predetermine the categorical order manually by plotting something in the correct order first and then remove it again.

import matplotlib.pyplot as plt

x = ['C9-U2', 'C10-U5', 'C10-U5', 'C11-U1', 'C11-U1']
y = ['J',     'C',      'H',      'J',     'H']

def unitsetter(xunits, yunits, ax=None, sort=True):
    ax = ax or plt.gca()
    if sort:
        xunits = sorted(xunits)
        yunits = sorted(yunits)
    us = plt.plot(xunits, [yunits[0]]*len(xunits),
                  [xunits[0]]*len(yunits), yunits)
    for u in us:
        u.remove()

unitsetter(x,y)
plt.scatter(x,y)

plt.show()

enter image description here

Here, sort is set to True, hence you get alphabetically sorted categories in both axes.

If you have a custom order you want the axis to obey, as is the case here (at least for the x axis) you would need to supply that order to the above function.

unitsetter(x, sorted(y), sort=False)
plt.scatter(x,y)

enter image description here

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • Thanks. But Michael's solution is simpler. – R71 Nov 12 '18 at 10:37
  • Sorry, looks like Michael's solution is not working. – R71 Nov 12 '18 at 10:39
  • Your solution works, but I am still trying to figure out what it is doing. Meanwhile, looking for a better solution. – R71 Nov 12 '18 at 10:46
  • As said, there is currently no better solution, because the axis units are determined at creation time. An alternative would be not to plot strings, but numbers and then set the ticklabels accordingly. – ImportanceOfBeingErnest Nov 12 '18 at 13:48
0

Following 'ImportanceOfBeingErnest ', the code could be shorten to

# initial plot to set sorted axis label
us = plt.plot(sorted(x),sorted(y))
[u.remove() for u in us]

# now plot the real thing, sorting not required
plt.scatter(x,y)
Dr. Duke
  • 51
  • 5
-1

I changed how your scatterplot is created quite a bit.

Here is my code:

import matplotlib.pyplot as plt

# This is your original code.
# x = ['C9-U2', 'C10-U5', 'C10-U5', 'C3-U1', 'C3-U1']
# y = ['J',     'C',      'H',      'J',     'H']
# plt.scatter(x,y)
# plt.show()

ordered_pairs = set([
     ('C9-U2', 'J'),
     ('C10-U5', 'C'),
     ('C10-U5', 'H'),
     ('C3-U1', 'J'),
     ('C3-U1', 'H')
])

x,y = zip(*ordered_pairs)
plt.scatter(x, y)
plt.show()

I turned your data points into a set of ordered pairs. This lets us zip the set, which is used to pack and unpack arrays with each argument passed. We use the * operator to inverse the process. You can read more about zip here.

When the code is ran, the image shown is the following, which I hope is what you were looking for:

result_of_shown_code

Michael Bonnet
  • 111
  • 2
  • 11
  • While you have sorted the y axis, you have unsorted the x-axis. How to keep both axes sorted? (One error in my code: replace C3 with C11). – R71 Nov 08 '18 at 14:29
  • try adding `plt.yticks(ticks=np.arange(0, 3, 1), labels=['J', 'H', 'C'])` right after `plt.scatter(x, y)` (and of course, `import numpy as np`) – Michael Bonnet Nov 08 '18 at 15:25
  • labels=sorted(set(y)) is better. Can you post this as a solution, so that I can accept. – R71 Nov 12 '18 at 10:36
  • 1
    No, in your solution the labels are now showing as sorted, but the points still remain the same. So this solution is wrong. – R71 Nov 12 '18 at 10:39