2013-11-22 24 views
13

Tôi đang cố tạo đường bao đầy cho tập dữ liệu. Nó phải khá đơn giản:Đã thay đổi thanh màu matplotlib

plt.contourf(x, y, z, label = 'blah', cm = matplotlib.cm.RdBu) 

Tuy nhiên, tôi phải làm gì nếu tập dữ liệu của tôi không đối xứng về 0? Giả sử tôi muốn chuyển từ màu xanh (giá trị âm) thành 0 (màu trắng) thành màu đỏ (giá trị dương). Nếu tập dữ liệu của tôi đi từ -8 đến 3, thì phần màu trắng của thanh màu, phải ở 0, thực ra là hơi âm. Có cách nào để thay đổi thanh màu sắc không?

Trả lời

29

Trước hết, có nhiều cách để thực hiện việc này.

  1. Sử dụng colors kwarg để contourf và tự xác định màu sắc
  2. Sử dụng một lớp tùy chỉnh Normalize và vượt qua một ví dụ trong khi norm kwarg.
  3. Sử dụng bản đồ rời rạc được tạo bằng matplotlib.colors.from_levels_and_colors.

Cách đơn giản nhất là chuyển màu cụ thể bằng colors=sequence_of_colors. Tuy nhiên, nếu bạn không tự thiết lập số lượng đường nét, điều này có thể bất tiện.

Cách linh hoạt nhất là tùy chọn thứ hai: sử dụng số norm kwarg để chỉ định tùy chỉnh chuẩn hóa. Đối với những gì bạn muốn, bạn sẽ cần phải phân lớp Normalize, nhưng điều này không quá khó để làm. Đây là tùy chọn duy nhất cho phép bạn sử dụng bản đồ màu liên tục.

Lý do sử dụng tùy chọn thứ hai hoặc thứ ba là chúng sẽ hoạt động với bất kỳ loại âm mưu matplotlib nào sử dụng bản đồ màu (ví dụ: imshow, scatter, v.v ...).

Tùy chọn thứ ba xây dựng một đối tượng chuẩn hóa và đối tượng chuẩn hóa rời rạc từ các màu cụ thể. Về cơ bản nó giống với tùy chọn đầu tiên, nhưng nó sẽ a) làm việc với các loại ô khác so với các ô đường viền, và b) tránh phải chỉ định số lượng đường bao theo cách thủ công.

Như một ví dụ về sự lựa chọn thứ hai (Tôi sẽ sử dụng imshow ở đây vì nó có ý nghĩa hơn contourf cho dữ liệu ngẫu nhiên, nhưng contourf sẽ phải sử dụng giống hệt nhau khác hơn là tùy chọn interpolation.):

import numpy as np 
import matplotlib.pyplot as plt 
from matplotlib.colors import Normalize 

class MidpointNormalize(Normalize): 
    def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False): 
     self.midpoint = midpoint 
     Normalize.__init__(self, vmin, vmax, clip) 

    def __call__(self, value, clip=None): 
     # I'm ignoring masked values and all kinds of edge cases to make a 
     # simple example... 
     x, y = [self.vmin, self.midpoint, self.vmax], [0, 0.5, 1] 
     return np.ma.masked_array(np.interp(value, x, y)) 

data = np.random.random((10,10)) 
data = 10 * (data - 0.8) 

fig, ax = plt.subplots() 
norm = MidpointNormalize(midpoint=0) 
im = ax.imshow(data, norm=norm, cmap=plt.cm.seismic, interpolation='none') 
fig.colorbar(im) 
plt.show() 

enter image description here

Như một ví dụ về sự lựa chọn thứ ba (lưu ý rằng điều này mang lại một bản đồ màu rời rạc thay vì một bản đồ màu liên tục):

import numpy as np 
import matplotlib.pyplot as plt 
from matplotlib.colors import from_levels_and_colors 

data = np.random.random((10,10)) 
data = 10 * (data - 0.8) 

num_levels = 20 
vmin, vmax = data.min(), data.max() 
midpoint = 0 
levels = np.linspace(vmin, vmax, num_levels) 
midp = np.mean(np.c_[levels[:-1], levels[1:]], axis=1) 
vals = np.interp(midp, [vmin, midpoint, vmax], [0, 0.5, 1]) 
colors = plt.cm.seismic(vals) 
cmap, norm = from_levels_and_colors(levels, colors) 

fig, ax = plt.subplots() 
im = ax.imshow(data, cmap=cmap, norm=norm, interpolation='none') 
fig.colorbar(im) 
plt.show() 

enter image description here

+0

Tuyệt vời, đây chỉ là những gì tôi đang tìm kiếm, cảm ơn! – pgierz

+2

Nên được thêm vào Matplotlib – Moritz

+0

@Joe Kington, điều đó thực sự tuyệt vời! Tôi đang sao chép định nghĩa lớp học của bạn cho một dự án nguồn mở và đặt tên của bạn là tác giả. Hy vọng bạn sẽ ổn với nó. –

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