2016-10-25 7 views
0

У меня есть 3D-массив (3,10).Интерактивный график рассеяния с легендой цветового бара

У меня есть 2D-график рассеяния, где цвет и размер маркеров зависят от третьего столбца. Я зацикливаюсь на двух вещах: стараюсь, чтобы легенда отображала цвет и/или размер, и пыталась сделать ярлыки интерактивными, чтобы я мог их перемещать (чтобы они не перекрывались). Трудно объяснить; Надеюсь, мой код ниже принесет определенную ясность.

Код

import numpy as np 
import matplotlib.pyplot as plt 
import pandas as pd 

aha = [0.1872, 0.0101, 0.0166, 0.0164, 0.0164, 0.0170, 0.0187, 0.0188, 0.0652, 0.0102] 
ahaa = [0.2872, 0.0301, 0.0466, 0.0364, 0.0564, 0.0670, 0.0287, 0.0888, 0.0852, 0.0502] 
dist = [0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2] 
mod = ['One', 'Another', 'Other', 'That', 'This', 'Two', 'Three', 'Four', 'Five', 'Six'] 
N = 10 
data = np.vstack((aha, ahaa, dist)) 
data = np.transpose(data) 
labels = [mod[i].format(i) for i in range (N)] 
plt.subplots_adjust(bottom = 0.1) 
plt.scatter(
    data[:, 0], data[:, 1], marker = 'o', c = data[:, 0], s = data[:, 2]*1500, 
    cmap = plt.get_cmap('Spectral')) 
for label, x, y in zip(labels, data[:, 0], data[:, 1]): 
    plt.annotate(
     label, 
     xy = (x, y), 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')) 


plt.show() 

Я новичок в Python, и было бы крайне признателен за любую помощь.

С уважением Joel

* EDIT

На основе обратной связи я также этот код сейчас,

import numpy as np 
import matplotlib.pyplot as plt 
from numpy.random import * 

def get_text_positions(x_data, y_data, txt_width, txt_height): 
    a = zip(y_data, x_data) 
    text_positions = y_data.copy() 
    for index, (y, x) in enumerate(a): 
     local_text_positions = [i for i in a if i[0] > (y - txt_height) 
          and (abs(i[1] - x) < txt_width * 2) and i != (y,x)] 
     if local_text_positions: 
      sorted_ltp = sorted(local_text_positions) 
      if abs(sorted_ltp[0][0] - y) < txt_height: #True == collision 
       differ = np.diff(sorted_ltp, axis=0) 
       a[index] = (sorted_ltp[-1][0] + txt_height, a[index][1]) 
       text_positions[index] = sorted_ltp[-1][0] + txt_height 
       for k, (j, m) in enumerate(differ): 
        #j is the vertical distance between words 
        if j > txt_height * 2: #if True then room to fit a word in 
         a[index] = (sorted_ltp[k][0] + txt_height, a[index][1]) 
         text_positions[index] = sorted_ltp[k][0] + txt_height 
         break 
    return text_positions 

def text_plotter(x_data, y_data, text_positions, axis,txt_width,txt_height): 
    for x,y,t in zip(x_data, y_data, text_positions): 
     axis.text(x - txt_width, 1.01*t, '%d'%int(y),rotation=0, color='blue') 
     if y != t: 
      axis.arrow(x, t,0,y-t, color='red',alpha=0.3, width=txt_width*0.1, 
         head_width=txt_width, head_length=txt_height*0.5, 
         zorder=0,length_includes_head=True) 

#test data: 
aha = [0.1872, 0.0101, 0.0166, 0.0164, 0.0164, 0.0170, 0.0187, 0.0188, 0.0652, 0.0102] 
ahaa = [0.2872, 0.0301, 0.0466, 0.0364, 0.0564, 0.0670, 0.0287, 0.0888, 0.0852, 0.0502] 
dist = [0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2] 
mod = ['One', 'Another', 'Other', 'That', 'This', 'Two', 'Three', 'Four', 'Five', 'Six'] 
N = 10 
data = np.vstack((aha, ahaa, dist)) 
data = np.transpose(data) 
x_data = data[:,0] 
y_data = data[:,1] 

#GOOD PLOT: 
fig2 = plt.figure() 
ax2 = fig2.add_subplot(111) 
#ax2.plt.scatter(x_data, y_data) 
labels = [mod[i].format(i) for i in range (N)] 
#ax2 = plt.subplots_adjust(bottom = 0.1) 
################################# 
for i in range (10): 
    plt.scatter(
     data[:, 0], data[:, 1], marker = 'o', c = data[:, 0], s = data[:, 2]*1500, alpha=0.7, 
     cmap = plt.get_cmap('Spectral')) 
#set the bbox for the text. Increase txt_width for wider text. 
txt_height = 0.04*(plt.ylim()[1] - plt.ylim()[0]) 
txt_width = 0.02*(plt.xlim()[1] - plt.xlim()[0]) 
#Get the corrected text positions, then write the text. 
text_positions = get_text_positions(x_data, y_data, txt_width, txt_height) 
text_plotter(x_data, y_data, text_positions, ax2, txt_width, txt_height) 

plt.ylim(0,max(text_positions)+2*txt_height) 
plt.xlim(-0.1,1.1) 


for x,y,z in zip(x_data, y_data, mod): 
    ax2.text(x - txt_width, 1.01*y, '%s'%z,rotation=0) 
plt.ylim(0,max(text_positions)+2*txt_height) 
plt.xlim(-0.1,1.1) 

plt.show() 

Размещение этикетки ограничивающей коробки выглядит хорошо, но вопрос я имея в виду, что сами метки не находятся в ограничивающих коробках. Метка находится над каждой точкой, а стрелка и ограничивающая рамка находятся в другом месте.

Опять же, действительно признателен за любую помощь.

+0

Попробуйте ответить на [этой] (http://stackoverflow.com/questions/8850142/matplotlib-overlapping-annotations) вопрос для перекрытия аннотаций. – DavidG

+0

Спасибо за комментарий! Должен признать, я изо всех сил стараюсь реализовать это решение. Скопировать и вставить работает отлично, но когда я пытаюсь использовать свои метки вместо значений, используемых в этом примере, я застрял. Если бы вы были в состоянии дать совет, я был бы очень признателен! Пример действительно вдохновил меня на достижение _something_. Я применил очень уродливое временное исправление, которое настраивает каждую метку, вызывая два массива со смещениями, которые я определил (1 для смещения x, 1 для смещения y). Еще раз спасибо. Если бы вы были в состоянии дать советы относительно корректировки ответа, с которым вы связались, я был бы очень благодарен. – Minary

ответ

0

Благодаря @DavidG я смог решить эту проблему.

Я отправлю свой код на случай, если он может помочь кому-то в будущем;

import numpy as np 
import matplotlib.pyplot as plt 
import pandas as pd 
from numpy.random import * 
from matplotlib.colors import ListedColormap 

def get_text_positions(x_data, y_data, txt_width, txt_height): 
    a = zip(y_data, x_data) 
    text_positions = y_data.copy() 
    for index, (y, x) in enumerate(a): 
     local_text_positions = [i for i in a if i[0] > (x - txt_height) 
          and (abs(i[1] - x) < txt_width * 2) and i != (y,x)] 
     if local_text_positions: 
      sorted_ltp = sorted(local_text_positions) 
      if abs(sorted_ltp[0][0] - y) < txt_height: #True == collision 
       differ = np.diff(sorted_ltp, axis=0) 
       a[index] = (sorted_ltp[-1][0] + txt_height, a[index][1]) 
       text_positions[index] = sorted_ltp[-1][0] + txt_height 
       for k, (j, m) in enumerate(differ): 
        #j is the vertical distance between words 
        if j > txt_height * 2: #if True then room to fit a word in 
         a[index] = (sorted_ltp[k][0] + txt_height, a[index][1]) 
         text_positions[index] = sorted_ltp[k][0] + txt_height 
         break 
    return text_positions 

def text_plotter(x_data, y_data, z_data, text_positions, axis,txt_width,txt_height): 
    for x,y,z,t in zip(x_data, y_data, z_data, text_positions): 
     axis.text(x - txt_width, 1.03*t, '%s'%z,rotation=0, color='blue') 
     if y != t: 
      axis.arrow(x, t,0,y-t, color='red',alpha=0.5, width=txt_width*0.1, 
         head_width=txt_width, head_length=txt_height*0.5, 
         zorder=0,length_includes_head=True) 




aha = [0.1872, 0.0101, 0.0166, 0.0164, 0.0164, 0.0170, 0.0187, 0.0188, 0.0652, 0.0102] 
ahaa = [0.2872, 0.0301, 0.0466, 0.0364, 0.0564, 0.0670, 0.0287, 0.0888, 0.0852, 0.0502] 
dist = [0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2] 
mod = ['One', 'Another', 'Other', 'That', 'This', 'Two', 'Three', 'Four', 'Five', 'Six'] 
N = 10 
data = np.vstack((aha, ahaa, dist)) 
data = np.transpose(data) 

fig1 = plt.figure() 
ax2 = fig1.add_subplot(111) 
labels = [mod[i].format(i) for i in range (N)] 
plt.subplots_adjust(bottom = 0.1) 
CS = ax2.scatter(
    data[:, 0], data[:, 1], marker = 'o', c = data[:, 0], s = data[:, 2]*1500, alpha = 0.5, 
    cmap = plt.cm.Spectral) 



################################## 
x_data = data[:,0] 
y_data = data[:,1] 
z_data = mod 
#set the bbox for the text. Increase txt_width for wider text. 
txt_height = 0.03*(plt.ylim()[1] - plt.ylim()[0]) 
txt_width = 0.02*(plt.xlim()[1] - plt.xlim()[0]) 
#Get the corrected text positions, then write the text. 
text_positions = get_text_positions(x_data, y_data, txt_width, txt_height) 
text_plotter(x_data, y_data, z_data, text_positions, ax2, txt_width, txt_height) 

print text_positions 

cbar = plt.colorbar(CS) 
cbar.ax.set_ylabel('Legend Label') 


plt.show()