Plotly

【plotlyチュートリアル】<<第10回>>平行座標プロット作成

本記事ではPythonのグラフライブラリとして使えるplotlyによる「平行座標プロット」の作成について紹介します。

2021年現在も流行している機械学習コンテストなど、データサイエンスという分野で用いられることがある平行座標プロット。

特徴として変数間やカテゴリ間の相関関係を可視化できる点が挙げられます。

どの関係性に目をつけるべきか知れるツールとして使えます。

今回もplotlyチュートリアルの平行カテゴリ図平行座標プロットから例題を抜粋しながら解説していきます。

①px.parallel_categoriesを使用した平行カテゴリ図

②色で区分する平行カテゴリ図

go.Parcatsを使用した平行カテゴリ図

go.Parcats+色区別を使用した平行カテゴリ図

⑤go.FigureWidgetを使用した散布図+平行カテゴリ図

⑥px.parallel_coordinatesを使用した平行座標プロット

⑦go.Parcoordsを使用した平行座標プロット

今回紹介する例題ではグラフの元データを容易する必要がなく、下記プログラムを完コピすればグラフを作成することができます。

まずは実際に手を動かしてコードを書いて見てください。

AnacondaのインストールとJupyter notebookの準備

Anacondaのインストールがまだの方はこちらの記事を参考に準備してください。

Jupyter notebookの起動と使い方まで紹介しています。

【2020年版、Python3をはじめよう!(Mac&Win対応)】AnacondaとJupyter notebookの始め方 はじめに Jupyter notebookとは Jupyter notebook(ジュピター・ノートブック)はブラウザ上で...

plotlyとplotly_expressのインストール

導入から基本的な使い方まで紹介しています。

Pythonをグラフ作成で学ぶ【plotly_expressで1行プログラミング】 【本記事の目標】 たった1行で動くグラフを作成し、体感する! これからPythonを学びたい人向けに朗報です。 今から紹介...

それでは平行座標プロットについて解説していきます。

px.parallel_categoriesを使用した平行カテゴリ図

plotly_express、plotly_graph_objectsを使用するので、まずはインポートします。

import plotly.express as px
import plotly.graph_objects as go

元データはplotly_expressで用意されているdata.tipsを使用します。

tipsの中には合計消費量(totall_bill)(チップを除く)、チップ量(tip)、顧客の性別(sex)、消費した曜日(day)、消費期間(time)、食事回数(size)を含む7つのフィールドが含まれています。

fig=px.parallel_categories()の一文で平行カテゴリ図が書けます。

df = px.data.tips()
fig = px.parallel_categories(df)

fig.show()

②色で区分する平行カテゴリ図

①に加えてcolor=”size”とすることでサイズによって色が区別されるようになります。

df = px.data.tips()
fig = px.parallel_categories(df, dimensions=['sex', 'smoker', 'day'],
                color="size", color_continuous_scale=px.colors.sequential.Inferno,
                labels={'sex':'Payer sex', 'smoker':'Smokers at the table', 'day':'Day of week'})
fig.show()

go.Parcatsを使用した平行カテゴリ図

go.Parcatsを使用しても書くことができます。

fig = go.Figure(go.Parcats(
    dimensions=[
        {'label': 'Hair',
         'values': ['Black', 'Brown', 'Brown', 'Brown', 'Red']},
        {'label': 'Eye',
         'values': ['Brown', 'Brown', 'Brown', 'Blue', 'Blue']},
        {'label': 'Sex',
         'values': ['Female', 'Male', 'Female', 'Male', 'Male']}],
    counts=[6, 10, 40, 23, 7]
))


fig.show()

go.Parcats+色区別を使用した平行カテゴリ図

色の他にもhoveron、hoverinfo、labelfont、tickfont、arrangementなどの引数が使えます。

titanic_df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/titanic.csv")

# Create dimensions
class_dim = go.parcats.Dimension(
    values=titanic_df.Pclass,
    categoryorder='category ascending', label="Class"
)

gender_dim = go.parcats.Dimension(values=titanic_df.Sex, label="Gender")

survival_dim = go.parcats.Dimension(
    values=titanic_df.Survived, label="Outcome", categoryarray=[0, 1],
    ticktext=['perished', 'survived']
)

# Create parcats trace
color = titanic_df.Survived;
colorscale = [[0, 'lightsteelblue'], [1, 'mediumseagreen']];

fig = go.Figure(data = [go.Parcats(dimensions=[class_dim, gender_dim, survival_dim],
        line={'color': color, 'colorscale': colorscale},
        hoveron='color', hoverinfo='count+probability',
        labelfont={'size': 18, 'family': 'Times'},
        tickfont={'size': 16, 'family': 'Times'},
        arrangement='freeform')])

fig.show()

⑤go.FigureWidgetを使用した散布図+平行カテゴリ図

複雑なので説明は省略します。

使えそうな部分をピックアップして活用しましょう。

import ipywidgets as widgets
import pandas as pd
import numpy as np

cars_df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/imports-85.csv')

# Build parcats dimensions
categorical_dimensions = ['body-style', 'drive-wheels', 'fuel-type']

dimensions = [dict(values=cars_df[label], label=label) for label in categorical_dimensions]

# Build colorscale
color = np.zeros(len(cars_df), dtype='uint8')
colorscale = [[0, 'gray'], [0.33, 'gray'],
              [0.33, 'firebrick'], [0.66, 'firebrick'],
              [0.66, 'blue'], [1.0, 'blue']]
cmin = -0.5
cmax = 2.5

# Build figure as FigureWidget
fig = go.FigureWidget(
    data=[go.Scatter(x=cars_df.horsepower, y=cars_df['highway-mpg'],
                marker={'color': color, 'cmin': cmin, 'cmax': cmax,
                        'colorscale': colorscale, 'showscale': True,
                        'colorbar': {'tickvals': [0, 1, 2], 'ticktext': ['None', 'Red', 'Blue']}},
                     mode='markers'),

      go.Parcats(domain={'y': [0, 0.4]}, dimensions=dimensions,
                   line={'colorscale': colorscale, 'cmin': cmin,
                   'cmax': cmax, 'color': color, 'shape': 'hspline'})]
)

fig.update_layout(height=800, xaxis={'title': 'Horsepower'},
                  yaxis={'title': 'MPG', 'domain': [0.6, 1]},
                  dragmode='lasso', hovermode='closest')

# Build color selection widget
color_toggle = widgets.ToggleButtons(
    options=['None', 'Red', 'Blue'],
    index=1, description='Brush Color:', disabled=False)

# Update color callback
def update_color(trace, points, state):
    # Compute new color array
    new_color = np.array(fig.data[0].marker.color)
    new_color[points.point_inds] = color_toggle.index

    with fig.batch_update():
        # Update scatter color
        fig.data[0].marker.color = new_color

        # Update parcats colors
        fig.data[1].line.color = new_color

# Register callback on scatter selection...
fig.data[0].on_selection(update_color)
# and parcats click
fig.data[1].on_click(update_color)

# Display figure
widgets.VBox([color_toggle, fig])

⑥px.parallel_coordinatesを使用した平行座標プロット

px.parallel_coordinates()で作成することができます。

color=で色による区別もできます。

import plotly.express as px
df = px.data.iris()
fig = px.parallel_coordinates(df, color="species_id",
                              dimensions=['sepal_width', 'sepal_length', 'petal_width',
                                          'petal_length'],
                              color_continuous_scale=px.colors.diverging.Tealrose,
                              color_continuous_midpoint=2)
fig.show()

⑦go.Parcoordsを使用した平行座標プロット

最後も応用例です。

使えそうな部分をピックアップして活用しましょう。

import plotly.graph_objects as go

import pandas as pd

df = pd.read_csv("https://raw.githubusercontent.com/bcdunbar/datasets/master/parcoords_data.csv")

fig = go.Figure(data=
    go.Parcoords(
        line = dict(color = df['colorVal'],
                   colorscale = 'Electric',
                   showscale = True,
                   cmin = -4000,
                   cmax = -100),
        dimensions = list([
            dict(range = [32000,227900],
                 constraintrange = [100000,150000],
                 label = "Block Height", values = df['blockHeight']),
            dict(range = [0,700000],
                 label = 'Block Width', values = df['blockWidth']),
            dict(tickvals = [0,0.5,1,2,3],
                 ticktext = ['A','AB','B','Y','Z'],
                 label = 'Cyclinder Material', values = df['cycMaterial']),
            dict(range = [-1,4],
                 tickvals = [0,1,2,3],
                 label = 'Block Material', values = df['blockMaterial']),
            dict(range = [134,3154],
                 visible = True,
                 label = 'Total Weight', values = df['totalWeight']),
            dict(range = [9,19984],
                 label = 'Assembly Penalty Wt', values = df['assemblyPW']),
            dict(range = [49000,568000],
                 label = 'Height st Width', values = df['HstW'])])
    )
)
fig.show()

ABOUT ME
Mickey@コーヒー好きエンジニア
【製造業×プログラミング×AI】Python/VBAを活用した業務改善、Streamlit/Plotlyを活用したWebアプリ開発について初心者向けに発信中|Wordpressブログを運営しながらHTML/CSSの勉強中|趣味は自家焙煎コーヒー作り|noteでは焙煎理論を発信