カテゴリー

Plotly全般

【plotly&色の自動調節】入力したRGBをrgba(R, G, B, a)に自動変換する

2021年8月1日

こんな人にオススメ

RGB形式で書かれたmatplotlib.pyplotpltの色をplotlyに入れると黒になるんだけどなんで?どうしたら他の色に変えられるの?

ということで、今回はplotlyでRGB形式の色を指定する際に自動で必要な計算とか言葉づけとかをしてくれるコードについて紹介する。

pltを使い始めて2年ほどが経過した時plotlyに出会った。書き方やグラフなどの全てが全然異なって困惑したがさらに追い討ちをかけるのが色問題。pltのノリでコードを書くと全てのプロットが黒になる。

今回は色を色々イジくる回。python環境は以下。

  • Python 3.9.4
  • plotly-orca 3.4.2
  • plotly 4.14.3
  • matplotlib 3.4.2
  • numpy 1.20.3

運営者のメガネです。YouTubeTwitterInstagram、自己紹介はこちら、お問い合わせはこちらから。

運営者メガネ

下準備

import numpy as np
import matplotlib
import plotly.colors
import plotly.graph_objects as go
import plotly.io as pio

x = np.array([1, 2, 3])
y = np.array([30, 50, 40])

まずは下準備としてのimport関連とデータの作成。今回はデータがどうこうって話じゃないから簡単なものを使用。ただし、今回は色を中心に話すので色関連の配列を定義。

colors = (
    (1, 0.5, 0), (255, 125, 0),  # (R, G, B)形式
    (1, 0.5, 0, 1), (255, 125, 0, 0.5),  # (R, G, B, a)形式
    '(1, 0.5, 0)', '(255, 125, 0)',  # 文字列の(R, G, B)形式
    '(1, 0.5, 0, 1)', '(255, 125, 0, 0.5)',  # 文字列の(R, G, B, a)形式
    'rgb(1, 0.5, 0)', 'rgb(255, 255, 255)',  # rgb(R, G, B)形式
    'rgba(1, 0.5, 0.1, 1)', 'rgba(255, 125, 0.1, 0.5)',  # rgba(R, G, B, a)形式
    'black', 'white', 'mediumvioletred',  # 色名
    '#ffffff', '#000000', '#fff', '#000',  # 16進数形式の黒と白(後ろ2つは短縮系)
    '#c71585', '#dcdcdc',  # 数字まじりと全英語の16進数形式
)

今回はGRB形式を中心に解説するのでhslなどは考えない。執筆者がまだ学習していない範囲だ。RGBというのはRed, Green, Blueを表していて、これら3色の組み合わせてあらゆる色を表現しようってこと。

全部が最小値なら黒で全部が最大値なら白になる。pltの場合は最小値が0で最大値が1。で、今回のplotlyは最小値が0で最大値が255。この値の違いが面倒なことを引き起こす。

ちなみにGRBaのaはalphaの略で、透明度を表す。alphaはplt, plotlyともに0から1の範囲で書き、0が薄く1が濃い。

plotlyで受け付ける色の書き方と色の範囲

今回はRGB形式に絞ってplotlyと色についての解説を行うが、実はRGB形式の中でも受け付けられる書き方と受け付けられない書き方がある。

まずはこれについて解説。その後、指定した色と実際のグラフを見てみて何が起きているのかを知る。

plotlyで受け付ける色の書き方・受け付けない書き方

# 大半の指定方法だと動くのは動く
# しかし、pltでは色の範囲は0-1なので、そのままだとほぼ黒
plot = []
for num, color in enumerate(colors):
    try:
        d = go.Scatter(
            x=x, y=y - num, name=color,
            line=dict(color=color),
        )
        plot.append(d)
        print(f"{color}: OK")
    except ValueError:
        print(f"{color}: error")

下準備で書いたcolors変数を次々とgo.Scatterに入れ、plotlyで受け付ける色と受け付けない色を判別した。すると以下のような結果となる。

# (1, 0.5, 0): error
# (255, 125, 0): error
# (1, 0.5, 0, 1): error
# (255, 125, 0, 0.5): error
# (1, 0.5, 0): error
# (255, 125, 0): error
# (1, 0.5, 0, 1): error
# (255, 125, 0, 0.5): error
# rgb(1, 0.5, 0): OK
# rgb(255, 255, 255): OK
# rgba(1, 0.5, 0.1, 1): OK
# rgba(255, 125, 0.1, 0.5): OK
# black: OK
# white: OK
# mediumvioletred: OK
# #ffffff: OK
# #000000: OK
# #fff: OK
# #000: OK
# #c71585: OK
# #dcdcdc: OK

要するに通常のtuple形式で書くのがダメそうだ。なのでtupleに焦点を絞って解決する必要があるんだけど、一応他の書き方も見る。詳細は後ほど。

plotlyでは色は0から255


で、今回のお悩みがpltと同じようにグラフを書いたらプロットが全て黒くなるというもの。それもそのはず、pltは0から1の範囲内で色を指定するかたわら、plotlyは0から255。そりゃ黒くなる。

実際にグラフを描くと上のようになり、rgb(1, 0.5, 0)のプロットがオレンジになるはずが黒になる。0から1の範囲内の1と0から255の範囲内の1では意味合いが全く異なる。

# 大半の指定方法だと動くのは動く
# しかし、pltでは色の範囲は0-1なので、そのままだとほぼ黒
plot = []
for num, color in enumerate(colors):
    try:
        d = go.Scatter(
            x=x, y=y - num, name=color,
            line=dict(color=color),
        )
        plot.append(d)
        print(f"{color}: OK")
    except ValueError:
        print(f"{color}: error")

fig = go.Figure(data=plot)
fig.show()

name = 'plot'
pio.write_html(fig, f"{name}.html", auto_open=False,)
pio.write_image(fig, f"{name}.png")

今回の記事はRGB中心

# 使用できる色
# A hex string (e.g. '#ff0000')
# An rgb/rgba string (e.g. 'rgb(255,0,0)')
# An hsl/hsla string (e.g. 'hsl(0,100%,50%)')
# An hsv/hsva string (e.g. 'hsv(0,100%,100%)')
# A named CSS color (e.g. 'red')

じゃあ面倒なRGBをやめて他の色にしたらいいじゃんっていうのはアリ。hex、すなわち16進数だとぱっと見わからないし、CSS colorの場合は透明度が指定できないし、hslとhsvも馴染みがない。

どれもわかりにくいけど、個人的に一番使いやすく、かつ、有名なのがRGB。なのでRGBを使うことにする。自分が慣れにいくスタイル。

色をrgba(R, G, B, a)に自動変換する

def check_rgb_print(color: str or tuple, alpha: float):
    """入力した色のstrやtupleをplotlyで使われる色の書式形式rgba(R, G, B, a)に変換

    Parameters
    ----------
    color : str or tuple
        書式を変換したい色
    alpha : float
        透明度

    Returns
    -------
    str
        書式を設定した色と透明度の文字列
    """
    try:  # rgb(R, G, B)、rgba(R, G, B, a)の場合
        ans = plotly.colors.unlabel_rgb(color)
        print('\\trgb(R, G, B)、rgba(R, G, B, a)に該当')
        print(f"halfway: {ans}")
    except TypeError:  # (R, G, B)の場合
        ans = color
        print('\\t(R, G, B)に該当')
        print(f"halfway: {ans}")
    except ValueError:  # 色名のstr、全英語の16進数の場合
        ans = matplotlib.colors.ColorConverter.to_rgb(color)
        print('\\t色のstr、全英語の16進数に該当')
        print(f"halfway: {ans}")
    except IndexError:  # 数字まじりの16進数の場合
        ans = plotly.colors.hex_to_rgb(color)
        print('\\t数字まじりの16進数に該当')
        print(f"halfway: {ans}")

    if max(ans) <= 1:  # 最大値が1以下の場合は0-1になっているはずだから0-255にする
        ans = plotly.colors.convert_to_RGB_255(ans)

    if len(ans) == 3:  # 要素数が3だと透明度の指定がないはずだから透明度を指定
        ans += (alpha,)

    ans = f"rgba{ans}"  # rgbaという文字を追加

    return ans

ということでplotlyに色を入れて適切な処理をしてくれるコードを作成した。結構複雑に見えるのはprintを大量にしているから。色の処理わけは以下。16進数っていうのは#ffffffとかのこと。

  1. rgb(R, G, B)rgba(R, G, B, a): plotly.colors.unlabel_rgb(color)
  2. (R, G, B): そのまま
  3. 色名のstr、全英語の16進数の場合: matplotlib.colors.ColorConverter.to_rgb(color)
  4. 数字まじりの16進数の場合: plotly.colors.hex_to_rgb(color)

上記の処理で入力された色を(r, g, b)の形式に変換できる。さらにmax(ans) <= 1で最大値が1以下の場合はplotly.colors.convert_to_RGB_255で全要素を0-255に変換。これでplt表記のrgbをplotly用に変換できる。

あとは長さがピッタリ3なら透明度alphaを追加し、rgbaの文字を追加して完成。初めに見たように、tupleの状態だとエラーが吐かれるがrgbaをつけると吐かれない。

自動変換を使用してグラフ化


最後に作成したcheck_rgb_print関数からprintを除いたcheck_rgb関数使用してcolorsに入っていた色を全て変換してグラフ化。圧倒的オレンジだが仕方ない。

def check_rgb(color: str or tuple, alpha: float):
    """入力した色のstrやtupleをplotlyで使われる色の書式形式rgba(R, G, B, a)に変換

    Parameters
    ----------
    color : str or tuple
        書式を変換したい色
    alpha : float
        透明度

    Returns
    -------
    str
        書式を設定した色と透明度の文字列
    """
    try:  # rgb(R, G, B)、rgba(R, G, B, a)
        ans = plotly.colors.unlabel_rgb(color)
    except TypeError:  # (R, G, B)の場合
        ans = color
    except ValueError:  # 色のstr、全英語の16進数の場合
        ans = matplotlib.colors.ColorConverter.to_rgb(color)
    except IndexError:  # 数字まじりの16進数の場合
        ans = plotly.colors.hex_to_rgb(color)

    if max(ans) <= 1:  # 最大値が1以下の場合は0-1になっているはずだから0-255にする
        ans = plotly.colors.convert_to_RGB_255(ans)

    if len(ans) == 3:  # 要素数が3だと透明度の指定がないはずだから透明度を指定
        ans += (alpha,)

    ans = f"rgba{ans}"  # rgbaという文字を追加

    return ans

check_rgb関数の残念なところは元の配列を変更してしまうので凡例が変わるところ。ここはlistとかを使って変換前後を残しておくことで回避できそう。面倒だから今回はしない。

def plot_color():
    plot = []

    for num, color in enumerate(colors):

        color = check_rgb(color, 0.8)
        d = go.Scatter(
            x=x, y=y - num, name=color,
            line=dict(color=color, width=3),
        )
        plot.append(d)

    fig = go.Figure(data=plot)
    fig.show()

    name = 'plot_color'
    pio.write_html(fig, f"{name}.html", auto_open=False,)
    pio.write_image(fig, f"{name}.png")

plot_color()

統一してくれたらいいのにな

今回はplotlypltにおける色の認識の違いをなくすための関数を作成した。この関数を使用すると大体の色の入力はまかなえる気がする。でも、そもそもこんな仕様じゃなかったら困ることはない。

なんで0-255にしたのかは知らないけど、メジャーどころと変なところで差別化されると対応する側も大変。幸いあっさり解決する内容だったから良かったけど、これかも何かしら引っかかりそうで怖い。

関連記事

自作したplotlyのマーカーのシンボル一覧
【plotly&マーカー】plotlyのマーカーのシンボル

続きを見る

【plt vs plotly】matplotlibとgoでグラフの比較

続きを見る

(9 < x y2)の条件に合った塗りつぶし
【plt&fill_between】matplotlibで領域を塗りつぶし

続きを見る

bubblechart2017_pop
【plotly&バブルチャート】plotlyで各国の収入と平均寿命をバブルチャートで描く

続きを見る

ガジェット

2023/9/18

【デスクツアー2022下半期】モノは少なく、でも効率的に Desk Updating #0

今回はガジェットブロガーなのにデスク環境を構築していない執筆者の ...

ライフハック

2023/9/16

【Audible vs YouTube Premium】耳で聴く音声学習コンテンツを比較

ワイヤレスイヤホンが普及し耳で学習することへのハードルが格段に下 ...

完全ワイヤレスイヤホン(TWS)

2023/9/18

【SENNHEISER MOMENTUM True Wireless 3レビュー】全てが整ったイヤホン

今回は高音質・高機能なSENNHEISERのフラグシップ完全ワイヤレスイヤホン「SENNH ...

ライフハック

2023/3/11

【YouTube Premiumとは】メリットしかないから全員入れ

今回はYouTube Premiumを実際に使ってみてどうなのか、どんなメリット/デメリット ...

マウス

2023/8/17

【Logicool MX ERGOレビュー】疲れない作業効率重視トラックボールマウス

こんな人におすすめ トラックボールマウスの王道Logicool MX ERGOが気になるけどऩ ...

ベストバイ

2023/9/18

【ベストバイ2022】今年買って良かったモノのトップ10

2022年ベストバイ この1年を振り返って執筆者は何を買ったのか。ガジェッ& ...

スマホ

2023/1/15

【楽天モバイル×povo2.0の併用】月1,000円の保険付きデュアルSIM運用

こんな人におすすめ 楽天モバイルとpovo2.0のデュアルSIM運用って実際のとこ ...

マウス

2023/9/16

【Logicool MX ERGO vs MX Master 3】ERGOをメインにした決定的な理由

こんな疑問・お悩みを持っている人におすすめ 執筆者はLogicoolのハイエンӠ ...

macOSアプリケーション

2022/9/30

【Chrome拡張機能】便利で効率的に作業できるおすすめの拡張機能を18個紹介する

こんな人におすすめ Chromeの拡張機能を入れたいけど、調べても同じような ...

macOSアプリケーション

2023/5/3

【Automator活用術】Macで生産性を上げる作業の自動化術

今回はMacに標準でインストールされているアプリ「Automator」を使ってできる ...

Pythonを学びたいけど独学できる時間なんてない人へのすゝめ

執筆者は大学の研究室・大学院にて独学でPythonを習得した。

でも社会人になったら独学で行うには時間も体力もなくて大変だ。

時間がない社会人だからこそプロの教えを乞うのが効率的。

ここでは色んなタイプに合ったプログラミングスクールの紹介をする。

  • この記事を書いた人

メガネ

Webエンジニア駆け出し。独学のPythonで天文学系の大学院を修了。常時金欠のガジェット好きでM2 Pro MacBook Pro(30万円) x Galaxy S22 Ultra(17万円)使いの狂人。自己紹介と半生→変わって楽しいの繰り返しレビュー依頼など→お問い合わせ運営者情報、TwitterX@m_ten_pa、 YouTube@megatenpa、 Threads@megatenpa

-Plotly全般
-, ,