2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Matplotlibで縦横比は合ってるのに目盛りがズレて見える?美しく整えるための簡単Tips

Last updated at Posted at 2025-06-08

はじめに

Matplotlibで画像やヒートマップを描いたとき、
縦横比は aspect='equal' で揃えているのに、なぜかtick(目盛り)の間隔がズレて見えること、ありませんか?

たとえば、下の図のようなケースです。

image.png

左側が「よくある問題のグラフ」、右側が今回めざす理想のグラフ(=この変換を自動で実現したい!)です。

今回は、こうした「tickのズレ問題」を縦横で美しく揃えるコツを紹介します。

※本記事では、ヒートマップなど「縦横比が同じ」プロットを扱うことを前提としています。

本記事のコードはGoogle Colabでも動かせます
すぐ試したい方はこちら

なぜtickがズレるのか?

Matplotlibは、tickラベルが重ならないように自動で間引いて配置してくれます。
この処理自体はとても便利ですが、ラベルの方向や長さの違いによって、以下のような非対称性が生まれます。

横軸のラベルは横向きに並ぶため、縦軸よりも重なりやすく、tickが間引かれやすいといった現象が起きます。

その結果、同じスケール感であっても、tickの“数”や“表示密度”がズレてしまうのです。

グラフ全体の印象に微妙な違和感を与える原因になります。

解決策:tickを“片方に合わせて”整える

tickが自動調整されるなら、一方のtickにもう一方を合わせてあげればいい。
特に、ラベルが間引かれやすい横軸に合わせると、グラフの見た目は一気に整います。

最終的に行き着いたコードを紹介します。
なぜこのコードに行き着いたかは少し長くなるのですが、興味がある方は補足をご覧ください。

サンプルコード

import numpy as np
import matplotlib.pyplot as plt

data = np.random.rand(305, 305)
fig, ax = plt.subplots(figsize=(3, 3))

# ヒートマップ表示(正方形アスペクト)
im = ax.imshow(data, origin='lower', cmap='viridis')
ax.set_aspect('equal')
ax.tick_params(labelsize=20)

# ticksを確定し、x軸とy軸で揃える(ここが重要)
fig.canvas.draw()
ticks = ax.get_xticks()
ax.set_xticks(ticks)
ax.set_yticks(ticks)
ax.set_xlim(-0.5, data.shape[1] - 0.5)
ax.set_ylim(-0.5, data.shape[0] - 0.5)

plt.show()

出力結果(自動で設定された目盛りが縦横で揃う)
image.png

これを加えるだけ
fig.canvas.draw()
ticks = ax.get_xticks()
ax.set_xticks(ticks)
ax.set_yticks(ticks)
ax.set_xlim(-0.5, data.shape[1] - 0.5)
ax.set_ylim(-0.5, data.shape[0] - 0.5)

これを加えるだで、tickの間隔が縦横で一致し、グリッドや枠線も美しく見えるようになります。

補足

ここからは先のコードの深掘りになります。
サンプルコードの重要な箇所は以下になります。

重要なコード
fig.canvas.draw()
ticks = ax.get_xticks()
ax.set_xticks(ticks)
ax.set_yticks(ticks)
ax.set_xlim(-0.5, data.shape[1] - 0.5)
ax.set_ylim(-0.5, data.shape[0] - 0.5)

このコードが必要な理由について説明します。

ここがややこしい!tickの世界

Matplotlibでは、tick(目盛り)の位置や数は「描画の直前」に自動調整されます。
そのため、get_xticks() を使っても、その時点で取得できるのは「仮のtickリスト」であり、実際に画面に描かれるtickかどうかは分かりません。

そこで、

  1. fig.canvas.draw() で一度“仮描画”させてtick配置を確定させる
  2. そのタイミングで get_xticks() を呼び出して、「実際に使われるtickリスト」を取得する
  3. そのtickリストを set_xticks, set_yticks で両軸の目盛りとして指定する
  4. さらに、見せたくない範囲まで出てしまうtickをシャットアウトするため、set_xlim, set_ylim で表示範囲を指定する

4番は不要では?と思う方も多いと思います。
実はここがややこしいポイントなので、以下に補足します。

なぜ4番が必要なの?

get_xticks()で得られるtickリストは、Matplotlibが「データ全体をカバーする間隔」で自動配置してしまうため、実際のデータ範囲(たとえば0〜304)より外側(たとえば−50や350など)にまでtickが付く場合があります。

そのため、そのまま set_xticks, set_yticks を使うと、「本当は見せたくない範囲」までtickが表示されてしまいます。

そこで重要なのがこの2行です。

ax.set_xlim(-0.5, data.shape[1] - 0.5)
ax.set_ylim(-0.5, data.shape[0] - 0.5)

これを加えるだけで、余分なtickや外側の目盛りをきれいにシャットアウトできます。

おわりに

グラフって、一見脇役に見える存在に、どれだけ真摯に向き合えるかにかかっていると思います。
その中でもtickは、グラフのスケール感を支える大切なパーツです。
ただ、tick配置の内部で起こるせめぎ合いが、ときにグラフ全体の雰囲気を微妙に揺らしてしまうんですよね。

こうした、個々のパーツの葛藤に目を向けることが、最終的に「伝えたいこと」の輪郭を、より確実に届けてくれるのだと思います。

Matplotlibは、デフォルトだけでは届かない壁がある。
でも手を加えすぎれば、それは“独りよがり”になってしまう。
そのあいだにある、絶妙なバランスこそが、世界観を“量産可能なかたち”に昇華させてくれるのだと思います。

……と、つい語ってしまいましたが、Matplotlibに込められた思想は、きっともっともっと深くて。
この文章もまた、“グラフのためのグラフ”を描いているに過ぎません。

でも、結局「きれいなグラフ」って、何なんでしょうか。
Matplotlib自身も、きっとまだその答えを探し続けていて。
世に出ることのなかった“グラフのためのグラフ”たちの中に、まだ誰も知らない黄金比が、静かに眠っているのかもしれません。
いつかそれに気づける日が来ると思うと、今から楽しみで仕方ありません。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?