vẽ màu khác nhau cho các cấp độ phân loại khác nhau bằng cách sử dụng matplotlib


102

Tôi có khung dữ liệu này diamondstrong đó bao gồm các biến như (carat, price, color), và tôi muốn vẽ một biểu đồ phân tán của priceđể caratcho mỗi color, có nghĩa khác nhau colorcó màu sắc khác nhau trong cốt truyện.

Điều này thật dễ dàng Rvới ggplot:

ggplot(aes(x=carat, y=price, color=color),  #by setting color=color, ggplot automatically draw in different colors
       data=diamonds) + geom_point(stat='summary', fun.y=median)

nhập mô tả hình ảnh ở đây

Tôi tự hỏi làm thế nào điều này có thể được thực hiện bằng Python matplotlib?

Tái bút:

Tôi biết về các gói âm mưu phụ trợ, chẳng hạn như seabornggplot for python, và tôi không thích chúng, chỉ muốn tìm hiểu xem liệu có thể thực hiện công việc matplotlibmột mình không,; P


1
Sẽ thực sự tuyệt vời nếu có một thứ như thế này được tích hợp vào matplotlib, nhưng có vẻ như nó sẽ không dễ dàng. Thảo luận ở đây: github.com/matplotlib/matplotlib/issues/6214
naught101

Câu trả lời:


156

Bạn có thể truyền plt.scattermột cđối số cho phép bạn chọn màu. Đoạn mã dưới đây xác định một colorstừ điển để ánh xạ màu kim cương của bạn với màu vẽ.

import matplotlib.pyplot as plt
import pandas as pd

carat = [5, 10, 20, 30, 5, 10, 20, 30, 5, 10, 20, 30]
price = [100, 100, 200, 200, 300, 300, 400, 400, 500, 500, 600, 600]
color =['D', 'D', 'D', 'E', 'E', 'E', 'F', 'F', 'F', 'G', 'G', 'G',]

df = pd.DataFrame(dict(carat=carat, price=price, color=color))

fig, ax = plt.subplots()

colors = {'D':'red', 'E':'blue', 'F':'green', 'G':'black'}

ax.scatter(df['carat'], df['price'], c=df['color'].apply(lambda x: colors[x]))

plt.show()

df['color'].apply(lambda x: colors[x]) ánh xạ hiệu quả các màu từ "kim cương" đến "âm mưu".

(Thứ lỗi cho tôi vì tôi không đưa hình ảnh ví dụ khác lên, tôi nghĩ 2 là đủ: P)

Với seaborn

Bạn có thể sử dụng seabornmột trình bao bọc xung quanh matplotlibđể làm cho nó trông đẹp hơn theo mặc định (tôi biết khá dựa trên ý kiến: P) nhưng cũng có thể thêm một số chức năng vẽ biểu đồ.

Đối với điều này, bạn có thể sử dụng seaborn.lmplotvới fit_reg=False(ngăn nó tự động thực hiện một số hồi quy).

Đoạn mã dưới đây sử dụng một tập dữ liệu mẫu. Bằng cách chọn, hue='color'bạn yêu cầu seaborn phân chia khung dữ liệu của bạn dựa trên màu sắc của bạn và sau đó vẽ biểu đồ cho từng cái.

import matplotlib.pyplot as plt
import seaborn as sns

import pandas as pd

carat = [5, 10, 20, 30, 5, 10, 20, 30, 5, 10, 20, 30]
price = [100, 100, 200, 200, 300, 300, 400, 400, 500, 500, 600, 600]
color =['D', 'D', 'D', 'E', 'E', 'E', 'F', 'F', 'F', 'G', 'G', 'G',]

df = pd.DataFrame(dict(carat=carat, price=price, color=color))

sns.lmplot('carat', 'price', data=df, hue='color', fit_reg=False)

plt.show()

nhập mô tả hình ảnh ở đây

Không seabornsử dụngpandas.groupby

Nếu bạn không muốn sử dụng seaborn thì bạn có thể sử dụng pandas.groupbyđể lấy màu một mình và sau đó vẽ chúng bằng cách chỉ sử dụng matplotlib, nhưng bạn sẽ phải chỉ định màu theo cách thủ công, tôi đã thêm một ví dụ bên dưới:

fig, ax = plt.subplots()

colors = {'D':'red', 'E':'blue', 'F':'green', 'G':'black'}

grouped = df.groupby('color')
for key, group in grouped:
    group.plot(ax=ax, kind='scatter', x='carat', y='price', label=key, color=colors[key])

plt.show()

Mã này giả định DataFrame giống như trên và sau đó nhóm nó dựa trên color. Sau đó, nó lặp lại các nhóm này, vẽ biểu đồ cho từng nhóm. Để chọn màu, tôi đã tạo một colorstừ điển có thể ánh xạ màu kim cương (ví dụ D) sang màu thực (chẳng hạn red).

nhập mô tả hình ảnh ở đây


Cảm ơn, nhưng tôi chỉ muốn tìm hiểu cách thực hiện công việc với matplotlib một mình.

Vâng, thông qua groupbytôi có thể làm điều đó, vì vậy có một tính năng như vậy matplotlibcó thể tự động vẽ cho các cấp độ khác nhau của phân loại bằng cách sử dụng màu sắc khác nhau, phải không?

@loganecolss Ok tôi hiểu rồi :) Tôi đã chỉnh sửa lại và thêm một ví dụ rất đơn giản sử dụng từ điển để ánh xạ màu sắc, tương tự như groupbyví dụ.
Ffisegydd

1
@Ffisegydd Sử dụng phương pháp đầu tiên ax.scatter, bạn sẽ thêm huyền thoại vào nó như thế nào? Tôi đang cố gắng sử dụng label=df['color']và sau đó plt.legend()không thành công.
ahoosh

1
Tốt hơn là nên thay đổi ax.scatter(df['carat'], df['price'], c=df['color'].apply(lambda x: colors[x]))thànhax.scatter(df['carat'], df['price'], c=df['color'].map(colors)
Dawei

33

Đây là một giải pháp ngắn gọn và chung chung để sử dụng bảng màu sơ sinh.

Trước tiên, hãy tìm một bảng màu bạn thích và tùy chọn hình dung nó:

sns.palplot(sns.color_palette("Set2", 8))

Sau đó, bạn có thể sử dụng nó với matplotlibviệc thực hiện điều này:

# Unique category labels: 'D', 'F', 'G', ...
color_labels = df['color'].unique()

# List of RGB triplets
rgb_values = sns.color_palette("Set2", 8)

# Map label to RGB
color_map = dict(zip(color_labels, rgb_values))

# Finally use the mapped values
plt.scatter(df['carat'], df['price'], c=df['color'].map(color_map))

2
Tôi thích cách tiếp cận của bạn. Với ví dụ trên, tất nhiên bạn cũng có thể ánh xạ các giá trị thành các tên màu đơn giản như sau: 1) xác định màu sắc là các màu = {'D': 'red', 'E': 'blue', 'F': 'green ',' G ':' black '} 2) ánh xạ chúng như bạn đã làm: ax.scatter (df [' carat '], df [' price '], c = df [' color ']. Map (Colors))
Stefan

1
Tuy nhiên, bạn sẽ thêm nhãn theo màu như thế nào trong trường hợp này?
François Leblanc

2
Để thêm một số trừu tượng hơn, bạn có thể thay thế 8trong sns.color_palette("Set2", 8)bằng len(color_labels).
Swier

Điều này là tuyệt vời, nhưng nó phải được thực hiện tự động bởi seaborn. Việc phải sử dụng bản đồ cho các biến phân loại mỗi khi bạn muốn vẽ nhanh một thứ gì đó là cực kỳ khó khăn . Chưa kể đến ý tưởng ngu ngốc để loại bỏ khả năng hiển thị số liệu thống kê trên cốt truyện. Thật không may, Seaborn đang giảm giá như một gói hàng vì những lý do này
theo đuổi

8

Tôi đã có cùng một câu hỏi và đã dành cả ngày để thử các gói khác nhau.

Ban đầu tôi đã sử dụng matlibplot: và không hài lòng với một trong hai danh mục ánh xạ tới các màu được xác định trước; hoặc nhóm / tổng hợp sau đó lặp lại qua các nhóm (và vẫn phải ánh xạ màu). Tôi chỉ cảm thấy nó được triển khai gói kém.

Seaborn sẽ không hoạt động trên trường hợp của tôi và Altair CHỈ hoạt động bên trong Máy tính xách tay Jupyter.

Giải pháp tốt nhất cho tôi là PlotNine, "là một triển khai ngữ pháp của đồ họa bằng Python và dựa trên ggplot2".

Dưới đây là mã plotnine để sao chép ví dụ R của bạn bằng Python:

from plotnine import *
from plotnine.data import diamonds

g = ggplot(diamonds, aes(x='carat', y='price', color='color')) + geom_point(stat='summary')
print(g)

ví dụ về kim cương plotnine

Thật sạch sẽ và đơn giản :)


Câu hỏi được đặt ra cho matplotlib
Chuck

6

Sử dụng Altair .

from altair import *
import pandas as pd

df = datasets.load_dataset('iris')
Chart(df).mark_point().encode(x='petalLength',y='sepalLength', color='species')

nhập mô tả hình ảnh ở đây


Câu hỏi được đặt ra cho matplotlib
Chuck

5

Dưới đây là sự kết hợp của các điểm đánh dấu và màu sắc từ một bản đồ màu định tính trong matplotlib:

import itertools
import numpy as np
from matplotlib import markers
import matplotlib.pyplot as plt

m_styles = markers.MarkerStyle.markers
N = 60
colormap = plt.cm.Dark2.colors  # Qualitative colormap
for i, (marker, color) in zip(range(N), itertools.product(m_styles, colormap)):
    plt.scatter(*np.random.random(2), color=color, marker=marker, label=i)
plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0., ncol=4);

nhập mô tả hình ảnh ở đây


In mpl.cm.Dark2.colors- mpldường như không được xác định trong mã của bạn và Dark2không có thuộc tính colors.
Shovalt

@Shovalt Cảm ơn đã đánh giá. Đáng lẽ tôi đã nhập matplotlibdưới dạng mpl, tôi đã sửa mã của mình bằng cách sử dụng mã pltcũng chứa cm. Ít nhất là trong matplotlibphiên bản mà tôi đang sử dụng 2.0.0 Dark2không có thuộc tínhcolors
Pablo Reyes

1
Muộn, nhưng nếu bạn không có thuộc tính màu sắc: iter (plt.cm.Dark2 (np.linspace (0,1, N)))
Geoff Lentsch

3

Với df.plot ()

Thông thường khi vẽ nhanh một DataFrame, tôi sử dụng pd.DataFrame.plot(). Thao tác này nhận chỉ số là giá trị x, giá trị là giá trị y và vẽ từng cột riêng biệt với một màu khác. Một DataFrame ở dạng này có thể đạt được bằng cách sử dụng set_indexunstack.

import matplotlib.pyplot as plt
import pandas as pd

carat = [5, 10, 20, 30, 5, 10, 20, 30, 5, 10, 20, 30]
price = [100, 100, 200, 200, 300, 300, 400, 400, 500, 500, 600, 600]
color =['D', 'D', 'D', 'E', 'E', 'E', 'F', 'F', 'F', 'G', 'G', 'G',]

df = pd.DataFrame(dict(carat=carat, price=price, color=color))

df.set_index(['color', 'carat']).unstack('color')['price'].plot(style='o')
plt.ylabel('price')

âm mưu

Với phương pháp này, bạn không phải chỉ định màu theo cách thủ công.

Thủ tục này có thể có ý nghĩa hơn đối với các chuỗi dữ liệu khác. Trong trường hợp của tôi, tôi có dữ liệu thời gian, vì vậy MultiIndex bao gồm ngày giờ và danh mục. Cũng có thể sử dụng phương pháp này cho nhiều hơn một cột để tô màu, nhưng chú thích đang trở nên lộn xộn.


0

Tôi thường làm điều đó bằng cách sử dụng Seaborn được xây dựng trên matplotlib

import seaborn as sns
iris = sns.load_dataset('iris')
sns.scatterplot(x='sepal_length', y='sepal_width',
              hue='species', data=iris); 
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.