Question

I have a strange issue with the order of labels in a legend. I'm making a scatter plot where I pre-order the lists of data so that smaller points will be plotted on top (the way to accomplish that was proposed to me in this question: Plot larger points on bottom and smaller on top)

The issue I'm having is that the order of the labels in the legend is apparently scattered. Here's a MWE to show what I mean:

import matplotlib.pyplot as plt
import numpy as np

def rand_data():
    return np.random.uniform(low=0., high=1., size=(100,))

# Generate data.
x, y, x2, x3 = [rand_data() for i in range(4)]
# This data defines the markes and labels used.
x1 = np.random.random_integers(7, 9, size=(100,))

# Order all lists so smaller points are on top.
order = np.argsort(-np.array(x2))
# Order x and y.
x_o, y_o = np.take(x, order), np.take(y, order)
# Order list related to markers and labels.
z1 = np.take(x1, order)
# Order list related to sizes.
z2 = np.take(x2, order)
# Order list related to colors.
z3 = np.take(x3, order)

plt.figure()
cm = plt.cm.get_cmap('RdYlBu')

# Scatter plot where each value in z1 has a different marker and label
# assigned.
mrk = {7: ('o', '7'), 8: ('s', '8'), 9: ('D', '9')}
for key, value in mrk.items():

    s1 = (z1 == key)
    plt.scatter(x_o[s1], y_o[s1], marker=value[0], label=value[1],
        s=z2[s1] * 100., c=z3[s1], cmap=cm, lw=0.2)

# Plot colorbar
plt.colorbar()

# Plot legend.
plt.legend(loc="lower left", markerscale=0.7, scatterpoints=1, fontsize=10)

plt.show()

The image produced looks like this:

enter image description here

as can be seen the legend displays the labels like 8, 9, 7 when it should be 7, 8, 9.

Oddly enough, if I instead set the lines that define the x1 list and the mrk dictionary which holds the markers and the labels like so:

x1 = np.random.random_integers(1, 3, size=(100,))
mrk = {1: ('o', '1'), 2: ('s', '2'), 3: ('D', '3')}

the resulting legend is ordered as 1, 2, 3.

So, what is happening here and how could I force the legend to be ordered no matter what numbers I use in x1 to define the markers and labels?

Was it helpful?

Solution

Well, that's because dict .items() method returns unsorted list. But you can do:

for key, value in sorted(mrk.items()):
    <..>

It will get (key, value) tuple pairs in required order: 7 8 9

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top