4. スケール、軸、凡例#
視覚的エンコーディング – データを位置、サイズ、形状、色などの視覚的変数にマッピングすること – はデータ可視化の中心的な要素です。このマッピングを実際に行う主役がスケールです。スケールは、データ値(スケールのドメイン)を入力として受け取り、ピクセル位置やRGB色などの視覚的な値(スケールのレンジ)を出力する関数です。もちろん、可視化は内容が伝わらなければ意味がありません!グラフィカルマークに加え、チャートには読者がグラフィックを解読するための参照要素、つまりガイドが必要です。軸(空間的な範囲でスケールを可視化する)や凡例(色、サイズ、形状の範囲でスケールを可視化する)といったガイドは、効果的なデータ可視化の縁の下の力持ちです。
このノートブックでは、スケールマッピング、軸、凡例のカスタマイズ設計をサポートするAltairのオプションを、抗生物質の効果に関する例を使って探っていきます。
このノートブックは、データ可視化カリキュラム の一部です。
import pandas as pd
import altair as alt
4.1. 抗生物質データ#
第二次世界大戦後、抗生物質は「奇跡の薬」と見なされ、それまで治療が困難だった病気に対する簡単な治療法として広まりました。どの抗生物質がどの細菌感染症に最も効果的かを調べるため、16種類の細菌に対する3つの最も人気のある抗生物質の効果が収集されました。
vega-datasetsコレクションから抗生物質データセットを使用します。以下の例では、このデータセットのURLをAltairに直接渡します。
antibiotics = 'https://cdn.jsdelivr.net/npm/vega-datasets@1/data/burtin.json'
まず、Pandasを使用してデータを読み込み、データセット全体を表示し、利用可能なフィールドに慣れ親しみましょう:
pd.read_json(antibiotics)
Bacteria | Penicillin | Streptomycin | Neomycin | Gram_Staining | Genus | |
---|---|---|---|---|---|---|
0 | Aerobacter aerogenes | 870.000 | 1.00 | 1.600 | negative | other |
1 | Bacillus anthracis | 0.001 | 0.01 | 0.007 | positive | other |
2 | Brucella abortus | 1.000 | 2.00 | 0.020 | negative | other |
3 | Diplococcus pneumoniae | 0.005 | 11.00 | 10.000 | positive | other |
4 | Escherichia coli | 100.000 | 0.40 | 0.100 | negative | other |
5 | Klebsiella pneumoniae | 850.000 | 1.20 | 1.000 | negative | other |
6 | Mycobacterium tuberculosis | 800.000 | 5.00 | 2.000 | negative | other |
7 | Proteus vulgaris | 3.000 | 0.10 | 0.100 | negative | other |
8 | Pseudomonas aeruginosa | 850.000 | 2.00 | 0.400 | negative | other |
9 | Salmonella (Eberthella) typhosa | 1.000 | 0.40 | 0.008 | negative | Salmonella |
10 | Salmonella schottmuelleri | 10.000 | 0.80 | 0.090 | negative | Salmonella |
11 | Staphylococcus albus | 0.007 | 0.10 | 0.001 | positive | Staphylococcus |
12 | Staphylococcus aureus | 0.030 | 0.03 | 0.001 | positive | Staphylococcus |
13 | Streptococcus fecalis | 1.000 | 1.00 | 0.100 | positive | Streptococcus |
14 | Streptococcus hemolyticus | 0.001 | 14.00 | 10.000 | positive | Streptococcus |
15 | Streptococcus viridans | 0.005 | 10.00 | 40.000 | positive | Streptococcus |
表中の数値は、抗生物質の効果を測定する指標である最小発育阻止濃度 (MIC)を示しています。これは、in vitro(試験管内)での細菌の成長を防ぐために必要な抗生物質の濃度(マイクログラム/ミリリットル)を表します。また、細菌の反応を示す名義型フィールドGram_Staining
は、グラム染色と呼ばれる手法によって記録されています。濃青色または紫色に変色する細菌はグラム陽性(Gram-positive)です。それ以外はグラム陰性(Gram-negative)と分類されます。
このデータセットのさまざまな可視化を検討しながら、自問してみてください:
抗生物質の相対的な効果について何を学べるでしょうか?
細菌種の抗生物質反応に基づいて、細菌について何を理解できるでしょうか?
4.2. スケールと軸の設定#
4.2.1. 抗生物質耐性のプロット:スケールタイプの調整#
まず、NeomycinのMICを示すシンプルなドットプロットを見てみましょう。
alt.Chart(antibiotics).mark_circle().encode(
alt.X('Neomycin:Q')
)
MIC値が桁違いの範囲にわたることがわかります。ほとんどのポイントは左側に集中し、右側にはいくつかの大きな外れ値があります。
デフォルトでは、Altairはドメイン値(MIC)とレンジ値(ピクセル)の間にlinear
マッピングを使用します。データの全体像をよりよく把握するために、別のスケール変換を適用してみましょう。
スケールタイプを変更するには、scale
属性を設定し、alt.Scale
メソッドとtype
パラメータを使用します。
以下は平方根(sqrt
)スケールタイプを使用した結果です。ピクセル範囲の距離がデータドメインの距離の平方根に対応するようになります。
alt.Chart(antibiotics).mark_circle().encode(
alt.X('Neomycin:Q',
scale=alt.Scale(type='sqrt'))
)
左側のポイントは以前よりも区別しやすくなりましたが、依然として強い偏りが見られます。
次に、対数スケール(log
)を使用してみましょう:
alt.Chart(antibiotics).mark_circle().encode(
alt.X('Neomycin:Q',
scale=alt.Scale(type='log'))
)
この結果、データはより均等に分布し、異なる細菌に対して必要な濃度の非常に大きな違いが明確に見えるようになりました。
標準的な線形スケールでは、視覚的な距離(ピクセル単位)10がデータドメインでの加算10に対応することがあります。一方、対数変換では、乗算と加算の間でマッピングが行われ、log(u) + log(v) = log(u*v)
が成り立ちます。その結果、対数スケールでは、視覚的な距離10がデータドメインでの乗算10に対応します(対数の底が10の場合)。上記のlog
スケールはデフォルトで底10の対数を使用しますが、base
パラメータをスケールに指定することでこの値を調整できます。
4.2.2. 軸のスタイリング#
低い投与量はより高い効果を示します。しかし、一部の人々は「良い」値がチャート内で「右上」に位置することを期待するかもしれません。この慣習に合わせる場合、「効果」を逆方向のMICスケールとしてエンコードするために軸を反転させることができます。
これを実現するには、エンコーディングのsort
プロパティを'descending'
に設定します。
alt.Chart(antibiotics).mark_circle().encode(
alt.X('Neomycin:Q',
sort='descending',
scale=alt.Scale(type='log'))
)
残念ながら、この軸は少し混乱を招き始めています。データを対数スケールでプロットし、逆方向に表示し、単位が明確に示されていないからです!
より情報豊かな軸タイトルを追加してみましょう。エンコーディングのtitle
プロパティを使用して、目的のタイトルテキストを設定します。
alt.Chart(antibiotics).mark_circle().encode(
alt.X('Neomycin:Q',
sort='descending',
scale=alt.Scale(type='log'),
title='Neomycin MIC (μg/ml, reverse log scale)')
)
ずっと良くなりましたね!
デフォルトでは、Altairはx軸をチャートの下部に配置します。このデフォルトを変更するには、axis
属性を追加し、orient='top'
を指定します。
alt.Chart(antibiotics).mark_circle().encode(
alt.X('Neomycin:Q',
sort='descending',
scale=alt.Scale(type='log'),
axis=alt.Axis(orient='top'),
title='Neomycin MIC (μg/ml, reverse log scale)')
)
同様に、y軸はデフォルトで'left'
(左側)に配置されますが、'right'
(右側)に設定することもできます。
4.2.3. 抗生物質の比較:グリッドライン、目盛りの数、およびサイズの調整#
Neomycinは、streptomycinやpenicillinのような他の抗生物質とどのように比較されるのでしょうか?
この質問に答え始めるために、散布図を作成し、y軸に別の抗生物質のエンコーディングを追加します。これは、x軸に設定したneomycinのデザインを反映させたものです。
alt.Chart(antibiotics).mark_circle().encode(
alt.X('Neomycin:Q',
sort='descending',
scale=alt.Scale(type='log'),
title='Neomycin MIC (μg/ml, reverse log scale)'),
alt.Y('Streptomycin:Q',
sort='descending',
scale=alt.Scale(type='log'),
title='Streptomycin MIC (μg/ml, reverse log scale)')
)
Neomycinとstreptomycinは高い相関があるようで、細菌株が両方の抗生物質に対して類似した反応を示していることがわかります。
次に、neomycinとpenicillinを比較してみましょう:
alt.Chart(antibiotics).mark_circle().encode(
alt.X('Neomycin:Q',
sort='descending',
scale=alt.Scale(type='log'),
title='Neomycin MIC (μg/ml, reverse log scale)'),
alt.Y('Penicillin:Q',
sort='descending',
scale=alt.Scale(type='log'),
title='Penicillin MIC (μg/ml, reverse log scale)')
)
ここでは、より区別された反応が見られます。一部の細菌はneomycinにはよく反応するがpenicillinには反応せず、その逆も見られます!
このプロットは有用ですが、さらに改善できます。x軸とy軸は同じ単位を使用していますが、範囲(幅が高さより大きい)やドメイン(x軸は0.001から100、y軸は0.001から1,000)が異なります。
軸を統一してみましょう。チャートに明示的なwidth
とheight
の設定を追加し、スケールのdomain
プロパティを使用して一致するドメインを指定します。
alt.Chart(antibiotics).mark_circle().encode(
alt.X('Neomycin:Q',
sort='descending',
scale=alt.Scale(type='log', domain=[0.001, 1000]),
title='Neomycin MIC (μg/ml, reverse log scale)'),
alt.Y('Penicillin:Q',
sort='descending',
scale=alt.Scale(type='log', domain=[0.001, 1000]),
title='Penicillin MIC (μg/ml, reverse log scale)')
).properties(width=250, height=250)
このプロットはよりバランスが取れており、微妙な誤解を招きにくくなりました!
しかし、現在のグリッドラインはやや密集しています。グリッドラインを完全に削除したい場合は、axis
属性にgrid=False
を追加できます。しかし、代わりに目盛り線の数を減らし、例えば桁ごとにグリッドラインを含めたい場合はどうすればよいでしょうか?
目盛りの数を変更するには、Axis
オブジェクトのtickCount
プロパティで目標とする目盛り数を指定できます。tickCount
はAltairにとって提案として扱われ、人間に優しい間隔など他の要素と一緒に考慮されます。正確に指定した目盛りの数を得られるわけではありませんが、近いものが得られるはずです。
alt.Chart(antibiotics).mark_circle().encode(
alt.X('Neomycin:Q',
sort='descending',
scale=alt.Scale(type='log', domain=[0.001, 1000]),
axis=alt.Axis(tickCount=5),
title='Neomycin MIC (μg/ml, reverse log scale)'),
alt.Y('Penicillin:Q',
sort='descending',
scale=alt.Scale(type='log', domain=[0.001, 1000]),
axis=alt.Axis(tickCount=5),
title='Penicillin MIC (μg/ml, reverse log scale)')
).properties(width=250, height=250)
tickCount
を5に設定することで、目的の効果が得られました。
散布図のポイントが少し小さく感じられます。デフォルトのサイズを変更するには、サークルマークのsize
プロパティを設定します。このサイズ値は、マークの面積をピクセル単位で指定します。
alt.Chart(antibiotics).mark_circle(size=80).encode(
alt.X('Neomycin:Q',
sort='descending',
scale=alt.Scale(type='log', domain=[0.001, 1000]),
axis=alt.Axis(tickCount=5),
title='Neomycin MIC (μg/ml, reverse log scale)'),
alt.Y('Penicillin:Q',
sort='descending',
scale=alt.Scale(type='log', domain=[0.001, 1000]),
axis=alt.Axis(tickCount=5),
title='Penicillin MIC (μg/ml, reverse log scale)'),
).properties(width=250, height=250)
ここでは、サークルマークの面積を80ピクセルに設定しました。必要に応じて値をさらに調整してください!
4.3. 色凡例の設定#
4.3.1. グラム染色による色分け#
上記では、neomycinが一部の細菌に対してより効果的であり、penicillinが他の細菌に対してより効果的であることがわかりました。しかし、特定の細菌種がわからない場合、どの抗生物質を使用すればよいかをどうやって判断すれば良いのでしょうか?グラム染色は、細菌の分類を区別する診断手法として役立ちます!
Gram_Staining
を名義型データとしてcolor
チャネルにエンコードしてみましょう:
alt.Chart(antibiotics).mark_circle(size=80).encode(
alt.X('Neomycin:Q',
sort='descending',
scale=alt.Scale(type='log', domain=[0.001, 1000]),
axis=alt.Axis(tickCount=5),
title='Neomycin MIC (μg/ml, reverse log scale)'),
alt.Y('Penicillin:Q',
sort='descending',
scale=alt.Scale(type='log', domain=[0.001, 1000]),
axis=alt.Axis(tickCount=5),
title='Penicillin MIC (μg/ml, reverse log scale)'),
alt.Color('Gram_Staining:N')
).properties(width=250, height=250)
グラム陽性細菌はペニシリンに最も感受性が高く、グラム陰性細菌にはネオマイシンの方が効果的であるようです!
上記のカラースキームは、名義型データ(等しいか等しくないかの比較)のために知覚的に区別しやすい色を自動的に選択しています。しかし、使用する色をカスタマイズしたい場合があります。この場合、グラム染色の結果は物理的に特徴的な色分け:グラム陰性はピンク、グラム陽性は紫となります。
データのdomain
(ドメイン)から色のrange
(レンジ)への明示的なスケールマッピングを指定して、それらの色を使用してみましょう:
alt.Chart(antibiotics).mark_circle(size=80).encode(
alt.X('Neomycin:Q',
sort='descending',
scale=alt.Scale(type='log', domain=[0.001, 1000]),
axis=alt.Axis(tickCount=5),
title='Neomycin MIC (μg/ml, reverse log scale)'),
alt.Y('Penicillin:Q',
sort='descending',
scale=alt.Scale(type='log', domain=[0.001, 1000]),
axis=alt.Axis(tickCount=5),
title='Penicillin MIC (μg/ml, reverse log scale)'),
alt.Color('Gram_Staining:N',
scale=alt.Scale(domain=['negative', 'positive'], range=['hotpink', 'purple'])
)
).properties(width=250, height=250)
デフォルトでは、凡例はチャートの右側に配置されます。軸と同様に、orient
パラメータを使用して凡例の配置を変更できます。
alt.Chart(antibiotics).mark_circle(size=80).encode(
alt.X('Neomycin:Q',
sort='descending',
scale=alt.Scale(type='log', domain=[0.001, 1000]),
axis=alt.Axis(tickCount=5),
title='Neomycin MIC (μg/ml, reverse log scale)'),
alt.Y('Penicillin:Q',
sort='descending',
scale=alt.Scale(type='log', domain=[0.001, 1000]),
axis=alt.Axis(tickCount=5),
title='Penicillin MIC (μg/ml, reverse log scale)'),
alt.Color('Gram_Staining:N',
scale=alt.Scale(domain=['negative', 'positive'], range=['hotpink', 'purple']),
legend=alt.Legend(orient='left')
)
).properties(width=250, height=250)
凡例を完全に削除するには、legend=None
を指定します。
alt.Chart(antibiotics).mark_circle(size=80).encode(
alt.X('Neomycin:Q',
sort='descending',
scale=alt.Scale(type='log', domain=[0.001, 1000]),
axis=alt.Axis(tickCount=5),
title='Neomycin MIC (μg/ml, reverse log scale)'),
alt.Y('Penicillin:Q',
sort='descending',
scale=alt.Scale(type='log', domain=[0.001, 1000]),
axis=alt.Axis(tickCount=5),
title='Penicillin MIC (μg/ml, reverse log scale)'),
alt.Color('Gram_Staining:N',
scale=alt.Scale(domain=['negative', 'positive'], range=['hotpink', 'purple']),
legend=None
)
).properties(width=250, height=250)
4.3.2. 種ごとの色分け#
これまで、抗生物質の有効性について考えてきました。次に視点を変えて、抗生物質の反応が異なる細菌種について私たちに何を教えてくれるかを考えてみましょう。
まず、名義型データフィールドであるBacteria
をcolor
チャネルでエンコードしてみましょう:
alt.Chart(antibiotics).mark_circle(size=80).encode(
alt.X('Neomycin:Q',
sort='descending',
scale=alt.Scale(type='log', domain=[0.001, 1000]),
axis=alt.Axis(tickCount=5),
title='Neomycin MIC (μg/ml, reverse log scale)'),
alt.Y('Penicillin:Q',
sort='descending',
scale=alt.Scale(type='log', domain=[0.001, 1000]),
axis=alt.Axis(tickCount=5),
title='Penicillin MIC (μg/ml, reverse log scale)'),
alt.Color('Bacteria:N')
).properties(width=250, height=250)
結果は少し混乱しています! 細菌の種類が十分に多いため、Altairは名義値のデフォルト10色パレットを繰り返し使用しています。
カスタムカラーを使用するには、色のエンコーディングのscale
プロパティを更新できます。一つの方法は、上記のグラム染色の例と同様に、スケールのdomain
(ドメイン)とrange
(レンジ)の値を明示的に指定し、それぞれの値に対する正確な色のマッピングを示すことです。もう一つの方法は、代替のカラースキームを使用することです。Altairには、さまざまな組み込みのカラースキームが含まれています。完全なリストについては、Vegaのカラースキームドキュメントを参照してください。
組み込みの20色スキームであるtableau20
に切り替え、スケールのscheme
プロパティを使用して設定してみましょう。
alt.Chart(antibiotics).mark_circle(size=80).encode(
alt.X('Neomycin:Q',
sort='descending',
scale=alt.Scale(type='log', domain=[0.001, 1000]),
axis=alt.Axis(tickCount=5),
title='Neomycin MIC (μg/ml, reverse log scale)'),
alt.Y('Penicillin:Q',
sort='descending',
scale=alt.Scale(type='log', domain=[0.001, 1000]),
axis=alt.Axis(tickCount=5),
title='Penicillin MIC (μg/ml, reverse log scale)'),
alt.Color('Bacteria:N',
scale=alt.Scale(scheme='tableau20'))
).properties(width=250, height=250)
これで各細菌にユニークな色が割り当てられましたが、チャートはまだ混乱しています。特に問題なのは、エンコーディングが同じ属(genus)に属する細菌を考慮していない点です。例えば、上記のチャートでは、2つの異なるサルモネラ(Salmonella)株が非常に異なる色相(ティールとピンク)で表されていますが、生物学的には近い親戚です。
別のスキームを試すには、データ型を名義型(nominal)から順序型(ordinal)に変更することもできます。デフォルトの順序型スキームは、青の階調を使用し、薄い青から濃い青へと変化します:
alt.Chart(antibiotics).mark_circle(size=80).encode(
alt.X('Neomycin:Q',
sort='descending',
scale=alt.Scale(type='log', domain=[0.001, 1000]),
axis=alt.Axis(tickCount=5),
title='Neomycin MIC (μg/ml, reverse log scale)'),
alt.Y('Penicillin:Q',
sort='descending',
scale=alt.Scale(type='log', domain=[0.001, 1000]),
axis=alt.Axis(tickCount=5),
title='Penicillin MIC (μg/ml, reverse log scale)'),
alt.Color('Bacteria:O')
).properties(width=250, height=250)
Some of those blue shades may be hard to distinguish.
For more differentiated colors, we can experiment with alternatives to the default blues
color scheme. The viridis
scheme ramps through both hue and luminance:
alt.Chart(antibiotics).mark_circle(size=80).encode(
alt.X('Neomycin:Q',
sort='descending',
scale=alt.Scale(type='log', domain=[0.001, 1000]),
axis=alt.Axis(tickCount=5),
title='Neomycin MIC (μg/ml, reverse log scale)'),
alt.Y('Penicillin:Q',
sort='descending',
scale=alt.Scale(type='log', domain=[0.001, 1000]),
axis=alt.Axis(tickCount=5),
title='Penicillin MIC (μg/ml, reverse log scale)'),
alt.Color('Bacteria:O',
scale=alt.Scale(scheme='viridis'))
).properties(width=250, height=250)
Bacteria from the same genus now have more similar colors than before, but the chart still remains confusing. There are many colors, they are hard to look up in the legend accurately, and two bacteria may have similar colors but different genus.
4.3.3. Color by Genus#
Let’s try to color by genus instead of bacteria. To do so, we will add a calculate
transform that splits up the bacteria name on space characters and takes the first word in the resulting array. We can then encode the resulting Genus
field using the tableau20
color scheme.
(Note that the antibiotics dataset includes a pre-calculated Genus
field, but we will ignore it here in order to further explore Altair’s data transformations.)
alt.Chart(antibiotics).mark_circle(size=80).transform_calculate(
Genus='split(datum.Bacteria, " ")[0]'
).encode(
alt.X('Neomycin:Q',
sort='descending',
scale=alt.Scale(type='log', domain=[0.001, 1000]),
axis=alt.Axis(tickCount=5),
title='Neomycin MIC (μg/ml, reverse log scale)'),
alt.Y('Penicillin:Q',
sort='descending',
scale=alt.Scale(type='log', domain=[0.001, 1000]),
axis=alt.Axis(tickCount=5),
title='Penicillin MIC (μg/ml, reverse log scale)'),
alt.Color('Genus:N',
scale=alt.Scale(scheme='tableau20'))
).properties(width=250, height=250)
Hmm… While the data are better segregated by genus, this cacapohony of colors doesn’t seem particularly useful.
If we look at some of the previous charts carefully, we can see that only a handful of bacteria have a genus shared with another bacteria: Salmonella, Staphylococcus, and Streptococcus. To focus our comparison, we might add colors only for these repeated genus values.
Let’s add another calculate
transform that takes a genus name, keeps it if it is one of the repeated values, and otherwise uses the string "Other"
.
In addition, we can add custom color encodings using explicit domain
and range
arrays for the color encoding scale
.
alt.Chart(antibiotics).mark_circle(size=80).transform_calculate(
Split='split(datum.Bacteria, " ")[0]'
).transform_calculate(
Genus='indexof(["Salmonella", "Staphylococcus", "Streptococcus"], datum.Split) >= 0 ? datum.Split : "Other"'
).encode(
alt.X('Neomycin:Q',
sort='descending',
scale=alt.Scale(type='log', domain=[0.001, 1000]),
axis=alt.Axis(tickCount=5),
title='Neomycin MIC (μg/ml, reverse log scale)'),
alt.Y('Penicillin:Q',
sort='descending',
scale=alt.Scale(type='log', domain=[0.001, 1000]),
axis=alt.Axis(tickCount=5),
title='Penicillin MIC (μg/ml, reverse log scale)'),
alt.Color('Genus:N',
scale=alt.Scale(
domain=['Salmonella', 'Staphylococcus', 'Streptococcus', 'Other'],
range=['rgb(76,120,168)', 'rgb(84,162,75)', 'rgb(228,87,86)', 'rgb(121,112,110)']
))
).properties(width=250, height=250)
We now have a much more revealing plot, made possible by customizations to the axes and legend. Take a moment to examine the plot above. Notice any surprising groupings?
The upper-left region has a cluster of red Streptococcus bacteria, but with a grey Other bacteria alongside them. Meanwhile, towards the middle-right we see another red Streptococcus placed far away from its “cousins”. Might we expect bacteria from the same genus (and thus presumably more genetically similar) to be grouped closer together?
As it so happens, the underlying dataset actually contains errors. The dataset reflects the species designations used in the early 1950s. However, the scientific consensus has since been overturned. That gray point in the upper-left? It’s now considered a Streptococcus! That red point towards the middle-right? It’s no longer considered a Streptococcus!
Of course, on its own, this dataset doesn’t fully justify these reclassifications. Nevertheless, the data contain valuable biological clues that went overlooked for decades! Visualization, when used by an appropriately skilled and inquisitive viewer, can be a powerful tool for discovery.
This example also reinforces an important lesson: always be skeptical of your data!
4.3.4. Color by Antibiotic Response#
We might also use the color
channel to encode quantitative values. Though keep in mind that typically color is not as effective for conveying quantities as position or size encodings!
Here is a basic heatmap of penicillin MIC values for each bacteria. We’ll use a rect
mark and sort the bacteria by descending MIC values (from most to least resistant):
alt.Chart(antibiotics).mark_rect().encode(
alt.Y('Bacteria:N',
sort=alt.EncodingSortField(field='Penicillin', op='max', order='descending')
),
alt.Color('Penicillin:Q')
)
We can further improve this chart by combining features we’ve seen thus far: a log-transformed scale, a change of axis orientation, a custom color scheme (plasma
), tick count adjustment, and custom title text. We’ll also exercise configuration options to adjust the axis title placement and legend title alignment.
alt.Chart(antibiotics).mark_rect().encode(
alt.Y('Bacteria:N',
sort=alt.EncodingSortField(field='Penicillin', op='max', order='descending'),
axis=alt.Axis(
orient='right', # orient axis on right side of chart
titleX=7, # set x-position to 7 pixels right of chart
titleY=-2, # set y-position to 2 pixels above chart
titleAlign='left', # use left-aligned text
titleAngle=0 # undo default title rotation
)
),
alt.Color('Penicillin:Q',
scale=alt.Scale(type='log', scheme='plasma', nice=True),
legend=alt.Legend(titleOrient='right', tickCount=5),
title='Penicillin MIC (μg/ml)'
)
)
Alternatively, we can remove the axis title altogether, and use the top-level title
property to add a title for the entire chart:
alt.Chart(antibiotics, title='Penicillin Resistance of Bacterial Strains').mark_rect().encode(
alt.Y('Bacteria:N',
sort=alt.EncodingSortField(field='Penicillin', op='max', order='descending'),
axis=alt.Axis(orient='right', title=None)
),
alt.Color('Penicillin:Q',
scale=alt.Scale(type='log', scheme='plasma', nice=True),
legend=alt.Legend(titleOrient='right', tickCount=5),
title='Penicillin MIC (μg/ml)'
)
).configure_title(
anchor='start', # anchor and left-align title
offset=5 # set title offset from chart
)
4.4. Summary#
Integrating what we’ve learned across the notebooks so far about encodings, data transforms, and customization, you should now be prepared to make a wide variety of statistical graphics. Now you can put Altair into everyday use for exploring and communicating data!
Interested in learning more about this topic?
Start with the Altair Customizing Visualizations documentation.
For a complementary discussion of scale mappings, see “Introducing d3-scale”.
For a more in-depth exploration of all the ways axes and legends can be styled by the underlying Vega library (which powers Altair and Vega-Lite), see “A Guide to Guides: Axes & Legends in Vega”.
For a fascinating history of the antibiotics dataset, see Wainer & Lysen’s “That’s Funny…” in the American Scientist.