2012-04-29 3 views
33

मै मैटलप्लिब का उपयोग करके 3 डी स्कैटर प्लॉट जेनरेट करने की कोशिश कर रहा हूं। मैं यहां 2 डी मामले जैसे व्यक्तिगत बिंदुओं को एनोटेट करना चाहता हूं: Matplotlib: How to put individual tags for a scatter plotमैटलप्लिब: एक 3 डी स्कैटर प्लॉट एनोटेटिंग

मैंने इस फ़ंक्शन का उपयोग करने की कोशिश की है और मैटलप्लिब डॉकॉमेंट से परामर्श किया है लेकिन ऐसा लगता है कि लाइब्रेरी 3 डी एनोटेशन का समर्थन नहीं करती है। क्या किसी को भी यह करना आता है?

धन्यवाद!

+0

खेद है, लेकिन कैसे आप वास्तव में 3 डी साजिश में छोटे हलकों (डेटा बिंदुओं) रख सकता हूं? –

उत्तर

30

बिंदु की 2 डी स्थिति की गणना करें, और इसका उपयोग एनोटेशन बनाएं। यदि आपको आकृति के साथ इंटरैक्टिव की आवश्यकता है, तो माउस जारी होने पर आप स्थान को फिर से समझ सकते हैं।

import pylab 
from mpl_toolkits.mplot3d import Axes3D 
from mpl_toolkits.mplot3d import proj3d 
fig = pylab.figure() 
ax = fig.add_subplot(111, projection = '3d') 
x = y = z = [1, 2, 3] 
sc = ax.scatter(x,y,z) 
# now try to get the display coordinates of the first point 

x2, y2, _ = proj3d.proj_transform(1,1,1, ax.get_proj()) 

label = pylab.annotate(
    "this", 
    xy = (x2, y2), xytext = (-20, 20), 
    textcoords = 'offset points', ha = 'right', va = 'bottom', 
    bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5), 
    arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0')) 

def update_position(e): 
    x2, y2, _ = proj3d.proj_transform(1,1,1, ax.get_proj()) 
    label.xy = x2,y2 
    label.update_positions(fig.canvas.renderer) 
    fig.canvas.draw() 
fig.canvas.mpl_connect('button_release_event', update_position) 
pylab.show() 

enter image description here

+2

मुझे लगता है कि 'button_notify_event '' बटन_release_event ' – zhangxaochen

+0

विस्मयकारी समाधान से कनेक्ट करना बेहतर है। मुझे 'label.update_positions (fig.canvas.renderer) 'to' label.update_positions (fig.canvas.get_renderer())' को बदलना था ताकि इसे TkAgg बैकएंड के साथ काम करने के लिए मिल सके। – jdehesa

+0

खेद है लेकिन आप वास्तव में 3 डी साजिश में छोटे सर्कल (डेटा पॉइंट) कैसे डालते हैं? –

5

यहाँ HYRY उत्तम जवाब का एक थोड़ा अधिक सामान्य रूप है। यह अंक और लेबल की किसी भी सूची के लिए काम करता है।

import numpy as np 
from matplotlib import pyplot as plt 
from mpl_toolkits.mplot3d import Axes3D 
from mpl_toolkits.mplot3d import proj3d 

points = np.array([(1,1,1), (2,2,2)]) 
labels = ['billy', 'bobby'] 

fig = plt.figure() 
ax = fig.add_subplot(111, projection = '3d') 
xs, ys, zs = np.split(points, 3, axis=1) 
sc = ax.scatter(xs,ys,zs) 

# if this code is placed inside a function, then 
# we must use a predefined global variable so that 
# the update function has access to it. I'm not 
# sure why update_positions() doesn't get access 
# to its enclosing scope in this case. 
global labels_and_points 
labels_and_points = [] 

for txt, x, y, z in zip(labels, xs, ys, zs): 
    x2, y2, _ = proj3d.proj_transform(x,y,z, ax.get_proj()) 
    label = plt.annotate(
     txt, xy = (x2, y2), xytext = (-20, 20), 
     textcoords = 'offset points', ha = 'right', va = 'bottom', 
     bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5), 
     arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0')) 
    labels_and_points.append((label, x, y, z)) 


def update_position(e): 
    for label, x, y, z in labels_and_points: 
     x2, y2, _ = proj3d.proj_transform(x, y, z, ax.get_proj()) 
     label.xy = x2,y2 
     label.update_positions(fig.canvas.renderer) 
    fig.canvas.draw() 

fig.canvas.mpl_connect('motion_notify_event', update_position) 

plt.show() 

एक कष्टप्रद नाम अंतरिक्ष समस्या है जिसे मैं केवल वैश्विक चर का उपयोग करके (हैकली) द्वारा ठीक कर सकता हूं। अगर कोई बेहतर समाधान प्रदान कर सकता है या बता रहा है कि क्या हो रहा है, तो कृपया मुझे बताएं!

+0

यह नाम स्कॉइंग है। मैं बिल्कुल समझ नहीं पा रहा हूं कि आप किस समस्या का जिक्र कर रहे हैं, लेकिन मुझे लगता है कि आप 'लेबल' के बारे में बात कर रहे हैं। मैंने नीचे एक उत्तर पोस्ट किया है, इसलिए कृपया मुझे बताएं कि क्या आप यही बात कर रहे थे :) –

3

यह उत्तर उपयोगकर्ता 315582 द्वारा पिछले उत्तर पर आधारित है। मैंने वैश्विक चर का उपयोग किए बिना समाधान प्रदान करने के लिए कुछ संशोधन किए हैं।

import numpy as np 
from matplotlib import pyplot as plt 
from mpl_toolkits.mplot3d import Axes3D 
from mpl_toolkits.mplot3d import proj3d 

def main(): 
    fig = plt.figure() 
    ax = fig.add_subplot(111, projection = '3d') 
    points = np.array([(1,1,1), (2,2,2)]) 
    labels = ['billy', 'bobby'] 
    plotlabels = [] 
    xs, ys, zs = np.split(points, 3, axis=1) 
    sc = ax.scatter(xs,ys,zs) 

    for txt, x, y, z in zip(labels, xs, ys, zs): 
     x2, y2, _ = proj3d.proj_transform(x,y,z, ax.get_proj()) 
     label = plt.annotate(
      txt, xy = (x2, y2), xytext = (-20, 20), 
      textcoords = 'offset points', ha = 'right', va = 'bottom', 
      bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5), 
      arrowprops = dict(arrowstyle = '-', connectionstyle = 'arc3,rad=0')) 
     plotlabels.append(label) 
    fig.canvas.mpl_connect('motion_notify_event', lambda event: update_position(event,fig,ax,zip(plotlabels, xs, ys, zs))) 
    plt.show() 


def update_position(e,fig,ax,labels_and_points): 
    for label, x, y, z in labels_and_points: 
     x2, y2, _ = proj3d.proj_transform(x, y, z, ax.get_proj()) 
     label.xy = x2,y2 
     label.update_positions(fig.canvas.renderer) 
    fig.canvas.draw() 



if __name__ == '__main__': 
    main() 
39
ax.text के माध्यम से

शायद आसान (...):

from matplotlib import pyplot 
from mpl_toolkits.mplot3d import Axes3D 
from numpy.random import rand 
from pylab import figure 


m=rand(3,3) # m is an array of (x,y,z) coordinate triplets 

fig = figure() 
ax = Axes3D(fig) 


for i in range(len(m)): #plot each point + it's index as text above 
ax.scatter(m[i,0],m[i,1],m[i,2],color='b') 
ax.text(m[i,0],m[i,1],m[i,2], '%s' % (str(i)), size=20, zorder=1, 
color='k') 

ax.set_xlabel('x') 
ax.set_ylabel('y') 
ax.set_zlabel('z') 
pyplot.show() 

enter image description here

+8

बहुत आसान। अच्छी तरह से काम। यह स्वीकार्य उत्तर क्यों नहीं है? – b10hazard

7

आप कई डेटा बिंदु हैं तो, चार्ट बहुत अव्यवस्थित प्राप्त कर सकते हैं अगर आप उन सब पर टिप्पणी करें। निम्नलिखित समाधान (HYRY के उत्तर के शीर्ष पर बनाया गया) 3 डी चार्ट में डेटा पॉइंट्स के लिए माउस-ओवर (पॉप-ओवर) समाधान लागू करता है। केवल आपके माउस की स्थिति के बगल में डेटा बिंदु एनोटेट किया जाएगा। प्रत्येक माउस आंदोलन के बाद, माउस पॉइंटर की सभी डेटा बिंदुओं की दूरी की गणना की जाती है, और निकटतम बिंदु एनोटेट किया जाता है।

import matplotlib.pyplot as plt, numpy as np 
from mpl_toolkits.mplot3d import proj3d 

def visualize3DData (X): 
    """Visualize data in 3d plot with popover next to mouse position. 

    Args: 
     X (np.array) - array of points, of shape (numPoints, 3) 
    Returns: 
     None 
    """ 
    fig = plt.figure(figsize = (16,10)) 
    ax = fig.add_subplot(111, projection = '3d') 
    ax.scatter(X[:, 0], X[:, 1], X[:, 2], depthshade = False, picker = True) 


    def distance(point, event): 
     """Return distance between mouse position and given data point 

     Args: 
      point (np.array): np.array of shape (3,), with x,y,z in data coords 
      event (MouseEvent): mouse event (which contains mouse position in .x and .xdata) 
     Returns: 
      distance (np.float64): distance (in screen coords) between mouse pos and data point 
     """ 
     assert point.shape == (3,), "distance: point.shape is wrong: %s, must be (3,)" % point.shape 

     # Project 3d data space to 2d data space 
     x2, y2, _ = proj3d.proj_transform(point[0], point[1], point[2], plt.gca().get_proj()) 
     # Convert 2d data space to 2d screen space 
     x3, y3 = ax.transData.transform((x2, y2)) 

     return np.sqrt ((x3 - event.x)**2 + (y3 - event.y)**2) 


    def calcClosestDatapoint(X, event): 
     """"Calculate which data point is closest to the mouse position. 

     Args: 
      X (np.array) - array of points, of shape (numPoints, 3) 
      event (MouseEvent) - mouse event (containing mouse position) 
     Returns: 
      smallestIndex (int) - the index (into the array of points X) of the element closest to the mouse position 
     """ 
     distances = [distance (X[i, 0:3], event) for i in range(X.shape[0])] 
     return np.argmin(distances) 


    def annotatePlot(X, index): 
     """Create popover label in 3d chart 

     Args: 
      X (np.array) - array of points, of shape (numPoints, 3) 
      index (int) - index (into points array X) of item which should be printed 
     Returns: 
      None 
     """ 
     # If we have previously displayed another label, remove it first 
     if hasattr(annotatePlot, 'label'): 
      annotatePlot.label.remove() 
     # Get data point from array of points X, at position index 
     x2, y2, _ = proj3d.proj_transform(X[index, 0], X[index, 1], X[index, 2], ax.get_proj()) 
     annotatePlot.label = plt.annotate("Value %d" % index, 
      xy = (x2, y2), xytext = (-20, 20), textcoords = 'offset points', ha = 'right', va = 'bottom', 
      bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5), 
      arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0')) 
     fig.canvas.draw() 


    def onMouseMotion(event): 
     """Event that is triggered when mouse is moved. Shows text annotation over data point closest to mouse.""" 
     closestIndex = calcClosestDatapoint(X, event) 
     annotatePlot (X, closestIndex) 

    fig.canvas.mpl_connect('motion_notify_event', onMouseMotion) # on mouse motion 
    plt.show() 


if __name__ == '__main__': 
    X = np.random.random((30,3)) 
    visualize3DData (X) 
11

निम्न पदों [1] में, [2] matplotlib में 3 डी तीर की साजिश चर्चा की है।

इसी Annotation3D वर्ग (एनोटेशन से विरासत में मिली) बनाया जा सकता है: इस समारोह एनोटेशन टैग में जोड़ा जा सकता का उपयोग करना

def annotate3D(ax, s, *args, **kwargs): 
    '''add anotation text s to to Axes3d ax''' 

    tag = Annotation3D(s, *args, **kwargs) 
    ax.add_artist(tag) 

:

from mpl_toolkits.mplot3d.proj3d import proj_transform 
from matplotlib.text import Annotation 

class Annotation3D(Annotation): 
    '''Annotate the point xyz with text s''' 

    def __init__(self, s, xyz, *args, **kwargs): 
     Annotation.__init__(self,s, xy=(0,0), *args, **kwargs) 
     self._verts3d = xyz   

    def draw(self, renderer): 
     xs3d, ys3d, zs3d = self._verts3d 
     xs, ys, zs = proj_transform(xs3d, ys3d, zs3d, renderer.M) 
     self.xy=(xs,ys) 
     Annotation.draw(self, renderer) 

इसके अलावा, हम annotate3D() फ़ंक्शन परिभाषित कर सकते हैं एक्सिस 3 डी उदाहरण के रूप में:

3D graph example

import matplotlib.pyplot as plt  
from mpl_toolkits.mplot3d import axes3d 
from mpl_toolkits.mplot3d.art3d import Line3DCollection 

# data: coordinates of nodes and links 
xn = [1.1, 1.9, 0.1, 0.3, 1.6, 0.8, 2.3, 1.2, 1.7, 1.0, -0.7, 0.1, 0.1, -0.9, 0.1, -0.1, 2.1, 2.7, 2.6, 2.0] 
yn = [-1.2, -2.0, -1.2, -0.7, -0.4, -2.2, -1.0, -1.3, -1.5, -2.1, -0.7, -0.3, 0.7, -0.0, -0.3, 0.7, 0.7, 0.3, 0.8, 1.2] 
zn = [-1.6, -1.5, -1.3, -2.0, -2.4, -2.1, -1.8, -2.8, -0.5, -0.8, -0.4, -1.1, -1.8, -1.5, 0.1, -0.6, 0.2, -0.1, -0.8, -0.4] 
group = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 2, 2, 2, 3, 3, 3, 3] 
edges = [(1, 0), (2, 0), (3, 0), (3, 2), (4, 0), (5, 0), (6, 0), (7, 0), (8, 0), (9, 0), (11, 10), (11, 3), (11, 2), (11, 0), (12, 11), (13, 11), (14, 11), (15, 11), (17, 16), (18, 16), (18, 17), (19, 16), (19, 17), (19, 18)] 
xyzn = zip(xn, yn, zn) 
segments = [(xyzn[s], xyzn[t]) for s, t in edges]     

# create figure   
fig = plt.figure(dpi=60) 
ax = fig.gca(projection='3d') 
ax.set_axis_off() 

# plot vertices 
ax.scatter(xn,yn,zn, marker='o', c = group, s = 64)  
# plot edges 
edge_col = Line3DCollection(segments, lw=0.2) 
ax.add_collection3d(edge_col) 
# add vertices annotation. 
for j, xyz_ in enumerate(xyzn): 
    annotate3D(ax, s=str(j), xyz=xyz_, fontsize=10, xytext=(-3,3), 
       textcoords='offset points', ha='right',va='bottom')  
plt.show() 
+0

इस उत्तर के लिए धन्यवाद! साजिश को एनिमेट करने के लिए आपने क्या उपयोग किया? इस उदाहरण के लिए – morepenguins

+0

मैं 'matplotlib एनीमेशन मॉड्यूल '(http://matplotlib.org/api/animation_api.html) का उपयोग कर रहा था। इसका उपयोग करने में काफी आसान है और अच्छी तरह से प्रलेखित है। यदि आपको ऐसे एनिमेशन बनाने की आवश्यकता होती है तो आपको अक्सर GUI टूल की जांच करने में दिलचस्पी हो सकती है जिसे मैंने matplotlib https://github.com/luchko/mpl_animationmanager के शीर्ष पर बनाया था। आप इसे बड़े पीईक्यूटी परियोजना में भी एकीकृत कर सकते हैं। – Luchko

+0

धन्यवाद @Luchko! मैं आपके जीयूआई और एनीमेशन मॉड्यूल में देखूंगा। – morepenguins

1

आप @ msch के जवाब बनाना चाहते मामले में बारी बारी से:

enter image description here

from mpl_toolkits.mplot3d import axes3d 
import matplotlib.pyplot as plt 
from numpy.random import rand 

m = rand(3,3) # m is an array of (x,y,z) coordinate triplets 

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

for i in range(len(m)): # plot each point + it's index as text above 
    x = m[i,0] 
    y = m[i,1] 
    z = m[i,2] 
    label = i 
    ax.scatter(x, y, z, color='b') 
    ax.text(x, y, z, '%s' % (label), size=20, zorder=1, color='k') 

ax.set_xlabel('x') 
ax.set_ylabel('y') 
ax.set_zlabel('z') 

for angle in range(0, 360): 
    ax.view_init(30, angle) 
    plt.draw() 
    plt.pause(.001) 

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^