简体   繁体   中英

Matplotlib: 3D Scatter plots not recognizing labels

I believe a similar question to this was asked before, but it didn't really clarify things for me.

Basically, I have a list of tuples, each of which functions as a point (so (x, y, z) for example).

I want to plot them in either 2D or 3D after I run a clustering algorithm (that color codes the points).

clusters = []
def plotPoints(self):
    fig = plt.figure()
    if self.clusters[0].dimensions == 2:
        ax = fig.add_subplot(111)
        for i in range(0, len(self.clusters)):
            ax.scatter(*zip(*self.clusters[i].points), c=self.clusters[i].color, marker="o", label=("Cluster " + str(i + 1)))
        plt.legend(loc='upper left')
        plt.show()
    elif self.clusters[0].dimensions == 3:
        ax = fig.add_subplot(111, projection='3d')
        for i in range(0, len(self.clusters)):
            ax.scatter(*zip(*self.clusters[i].points), c=self.clusters[i].color, marker="o", label=("Cluster " + str(i + 1)))
        plt.legend(loc='upper left')
        plt.show()
    else:
        print "Cannot plot in dimensions lower than 2 or higher than 3"

Cluster class:

class Cluster(object):
centroid = ()
dimensions = 0
color = 'k'

def __init__(self, init_pt, color):
    self.points = []
    self.points.append(init_pt)
    self.dimensions = len(init_pt)
    self.centroid = init_pt
    self.color = color

def addPoint(self, pt):
    try:
        if len(pt) != self.dimensions:
            raise ArithmeticError("Wrong number of dimensions on new point, ignoring")
        else:
            centroid_dim_list = []
            for dim in range(0, self.dimensions):
                centroid_dim_list.append((self.centroid[dim] * len(self.points) + pt[dim]) / float(len(self.points) + 1))
            self.centroid = tuple(centroid_dim_list)
            self.points.append(pt)
    except ArithmeticError as ae:
        print ae.message
        pass

2D plots work just fine (and look really nice), but 3D plots give me a warning:

UserWarning: No labeled objects found. Use label='...' kwarg on individual plots.
  warnings.warn("No labeled objects found. "

And no legend appears. But I am labeling the points, and the code I am using is almost identical, so I am confused as to what the problem is. I heard something about a proxy object, but I have no clue how to use that for this case.

I partially solved my problem by adding the following code:

ax.plot([], [], 'o', c=self.clusters[i].color, label="Cluster " + str(i + 1))

to each iteration of the loop, giving the following figure.

在此处输入图片说明

The marker is doubled for some reason, but at least it mostly works. If someone can comment on why it is doubled that would be great.

Edit Per jedwards comment, I fixed it by changing my legend() call to:

plt.legend(numpoints=1 , loc='upper left')

I'm not sure what the format of your self.clusters is, but with something I came up with that I think closely resembles it, I was able to produce the following:

1个

With the code

for i,c in enumerate(self.clusters):
    x,y,z = c.points
    ax.text(x,y,z, "Cluster %d" % (i+1), None)

Based off text3d demo .

I'm using matplotlib 1.4.3

Note , you won't be able to "drag and drop" this code, since my cluster instances are simple 3-tuples, yours seem more complicated.

I may not fully understood your question, but here is an example you may tweak it to your case. Hope it helps:

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from random import randint

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

# dataset
def data():
    return [randint(0,100) for _ in range(10)]

c1 = (data(), data(), data())
c2 = (data(), data(), data())
c3 = (data(), data(), data())
clusters = [c1, c2, c3]

# plot 
colors = ['r', 'b', 'y', 'c']
for i, c in enumerate(clusters):
    ax.scatter(c[0], c[1], c[2], c=colors[i], label='cluster {}'.format(i))

ax.legend(bbox_to_anchor = (1.5, 1))
plt.show()

It produces this: 在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM