2012-01-31 31 views
33

Tôi có một tập hợp dữ liệu mà tôi muốn hiển thị dưới dạng ô phân tán. Tôi muốn mỗi điểm được vẽ thành một hình vuông có kích thước dx.Âm mưu phân tán Python. Kích thước và kiểu của điểm đánh dấu

  x = [0.5,0.1,0.3] 
      y = [0.2,0.7,0.8] 
      z = [10.,15.,12.] 
      dx = [0.05,0.2,0.1] 

      scatter(x,y,c=z,s=dx,marker='s') 

Vấn đề là kích thước s mà chức năng phân tán đọc là điểm^2. Những gì tôi muốn là có mỗi điểm đại diện bởi một hình vuông diện tích dx^2, nơi mà khu vực này là trong các đơn vị 'thực', các đơn vị cốt truyện. Tôi hy vọng bạn có thể nhận được điểm này.

Tôi cũng có một câu hỏi khác. Chức năng phân tán vẽ các điểm đánh dấu bằng đường viền màu đen, làm cách nào tôi có thể thả tùy chọn này và không có đường viền nào?

Trả lời

37

Dịch từ dữ liệu người dùng hệ tọa độ thành hiển thị hệ tọa độ.

và sử dụng edgecolors = 'none' để vẽ các khuôn mặt không có đường viền.

import numpy as np 

fig = figure() 
ax = fig.add_subplot(111) 
dx_in_points = np.diff(ax.transData.transform(zip([0]*len(dx), dx))) 
scatter(x,y,c=z,s=dx_in_points**2,marker='s', edgecolors='none') 
+7

Điều này không vẽ các ô vuông trong * đơn vị lô * dưới dạng ô được yêu cầu nhưng kích thước cố định không thay đổi kích thước (ví dụ bằng cách thay đổi kích thước khung hình theo cách thủ công. – joaquin

+1

Có thể là một câu hỏi ngu ngốc. ở trên nếu dx không phải là một mảng nhưng nó giống nhau cho mọi điểm (x, y, z) .Vì vậy, những gì tôi thực sự cần phải sử dụng add_subplot? – Brian

+1

Làm thế nào bạn tìm thấy đối số 'edgecolors'? – Dror

20

Nếu bạn muốn đánh dấu rằng thay đổi kích thước với kích thước hình, bạn có thể sử dụng các bản vá lỗi:

from matplotlib import pyplot as plt 
from matplotlib.patches import Rectangle 

x = [0.5, 0.1, 0.3] 
y = [0.2 ,0.7, 0.8] 
z = [10, 15, 12] 
dx = [0.05, 0.2, 0.1] 

cmap = plt.cm.hot 
fig = plt.figure() 
ax = fig.add_subplot(111, aspect='equal') 

for x, y, c, h in zip(x, y, z, dx): 
    ax.add_artist(Rectangle(xy=(x, y), 
        color=cmap(c**2),  # I did c**2 to get nice colors from your numbers 
        width=h, height=h))  # Gives a square of area h*h 

plt.show() 

enter image description here

Lưu ý rằng:

  1. Các hình vuông không tập trung ở (x,y). x, y thực sự là coords của hình vuông phía dưới bên trái. Tôi cho nó theo cách này để đơn giản hóa mã của tôi. Bạn nên sử dụng (x + dx/2, y + dx/2).
  2. Màu sắc lấy từ bản đồ màu nóng. Tôi đã sử dụng z ** 2 để cho màu sắc. bạn cũng nên điều chỉnh này yêu cầu của bạn

Cuối cùng cho câu hỏi thứ hai của bạn. Bạn có thể nhận được đường viền của các dấu phân tán bằng cách sử dụng đối số từ khóa edgecolor hoặc edgecolors. Đây là một đối số màu matplotlib hoặc một chuỗi các rgba tuple, tương ứng. Nếu bạn đặt tham số thành 'Không', các đường viền sẽ không được vẽ.

17

Tôi nghĩ chúng tôi có thể làm tốt hơn với một bộ sưu tập các bản vá lỗi. Theo tài liệu:

này (PatchCollection) làm cho nó dễ dàng hơn để gán một bản đồ màu đến một bộ sưu tập không đồng nhất của các bản vá lỗi.

Điều này cũng có thể cải thiện tốc độ âm mưu, vì PatchCollection sẽ vẽ nhanh hơn một số lượng lớn các bản vá.

Giả sử bạn muốn vẽ một phân tán của vòng tròn với bán kính được đưa ra trong đơn vị dữ liệu:

def circles(x, y, s, c='b', vmin=None, vmax=None, **kwargs): 
    """ 
    Make a scatter of circles plot of x vs y, where x and y are sequence 
    like objects of the same lengths. The size of circles are in data scale. 

    Parameters 
    ---------- 
    x,y : scalar or array_like, shape (n,) 
     Input data 
    s : scalar or array_like, shape (n,) 
     Radius of circle in data unit. 
    c : color or sequence of color, optional, default : 'b' 
     `c` can be a single color format string, or a sequence of color 
     specifications of length `N`, or a sequence of `N` numbers to be 
     mapped to colors using the `cmap` and `norm` specified via kwargs. 
     Note that `c` should not be a single numeric RGB or RGBA sequence 
     because that is indistinguishable from an array of values 
     to be colormapped. (If you insist, use `color` instead.) 
     `c` can be a 2-D array in which the rows are RGB or RGBA, however. 
    vmin, vmax : scalar, optional, default: None 
     `vmin` and `vmax` are used in conjunction with `norm` to normalize 
     luminance data. If either are `None`, the min and max of the 
     color array is used. 
    kwargs : `~matplotlib.collections.Collection` properties 
     Eg. alpha, edgecolor(ec), facecolor(fc), linewidth(lw), linestyle(ls), 
     norm, cmap, transform, etc. 

    Returns 
    ------- 
    paths : `~matplotlib.collections.PathCollection` 

    Examples 
    -------- 
    a = np.arange(11) 
    circles(a, a, a*0.2, c=a, alpha=0.5, edgecolor='none') 
    plt.colorbar() 

    License 
    -------- 
    This code is under [The BSD 3-Clause License] 
    (http://opensource.org/licenses/BSD-3-Clause) 
    """ 
    import numpy as np 
    import matplotlib.pyplot as plt 
    from matplotlib.patches import Circle 
    from matplotlib.collections import PatchCollection 

    if np.isscalar(c): 
     kwargs.setdefault('color', c) 
     c = None 
    if 'fc' in kwargs: kwargs.setdefault('facecolor', kwargs.pop('fc')) 
    if 'ec' in kwargs: kwargs.setdefault('edgecolor', kwargs.pop('ec')) 
    if 'ls' in kwargs: kwargs.setdefault('linestyle', kwargs.pop('ls')) 
    if 'lw' in kwargs: kwargs.setdefault('linewidth', kwargs.pop('lw')) 

    patches = [Circle((x_, y_), s_) for x_, y_, s_ in np.broadcast(x, y, s)] 
    collection = PatchCollection(patches, **kwargs) 
    if c is not None: 
     collection.set_array(np.asarray(c)) 
     collection.set_clim(vmin, vmax) 

    ax = plt.gca() 
    ax.add_collection(collection) 
    ax.autoscale_view() 
    if c is not None: 
     plt.sci(collection) 
    return collection 

Tất cả những lập luận và từ khóa (trừ) của scatter chức năng sẽ làm việc theo cách tương tự. Tôi đã viết một gist bao gồm vòng tròn, elipvuông/hình chữ nhật. Nếu bạn muốn có một bộ sưu tập hình dạng khác, bạn có thể tự sửa đổi nó.

Nếu bạn muốn vẽ một thanh màu chỉ cần chạy colorbar() hoặc chuyển đối tượng bộ sưu tập đã trả về tới chức năng colorbar.

Một ví dụ:

from pylab import * 
figure(figsize=(6,4)) 
ax = subplot(aspect='equal') 

#plot a set of circle 
a = arange(11) 
out = circles(a, a, a*0.2, c=a, alpha=0.5, ec='none') 
colorbar() 

#plot one circle (the lower-right one) 
circles(1, 0, 0.4, 'r', ls='--', lw=5, fc='none', transform=ax.transAxes) 

xlim(0,10) 
ylim(0,10) 

Output:

Example Figure

+1

Tôi muốn sử dụng chức năng của bạn trong một dự án mã nguồn mở nhưng không thể làm điều đó bởi vì theo mặc định tất cả các mã SO dưới [giấy phép CC BY-SA] (https://meta.stackexchange.com/a/12539/155787). giấy phép mã của bạn, tốt nhất là một cái gì đó giống như BSD? – letmaik

+1

@neo Vui mừng khi biết điều đó. Tôi không có giấy phép với giấy phép, tôi nghĩ nó nên giữ nguyên với [matplotlib] (http://matplotlib.org/users/ li cense.html), vì tôi vừa viết mã này dựa trên hàm 'scatter'. Vậy nó phải là PSF hay gì đó? –

+0

Đoạn mã của bạn không phải là tác phẩm phái sinh của matplotlib, do đó bạn có thể cấp phép mã của mình theo bất kỳ giấy phép nào. Tôi sẽ chỉ sử dụng [BSD 3-khoản] (http://opensource.org/licenses/BSD-3-Clause), nó rất phổ biến trong thế giới Python. – letmaik

0

Để làm Python này 3 tương thích, tôi đã thêm đoạn mã sau đây

try: 
    basestring 
except NameError: 
    basestring = str 

từ

How to check if variable is string with python 2 and 3 compatibility

này là cần thiết vì basestring không có sẵn trong Python 3. Trong Python 2, mục đích của basestring là bao gồm cả strunicode. Trong Python 3 không có sự phân biệt giữa strunicode và chỉ là str.

Các vấn đề liên quan