2017-04-05 12 views
2

matplotlibを使用して、Pandas Dataframeに保存されているデータをプロットします。私はx軸のティックに特定のラベルを貼りたい。だから、私はそれらを設定します。うまく動作しますが、それはプロットが読めなくなって、各データポイントの目盛りラベルを設定しますmatplotlibプロットのラベルのテキストと周波数を

ax.xaxis.set_ticklabels(data_frame['labels']) 

ので、私が試した:の数を減らすことができ

ax.locator_params(axis='x', nbins=3) 

(ラベルがa、b、c、d、e ...、x、y、zの場合、ラベルはa、m、 zなど)。私の次のアイデアは、目盛りラベルの位置を設定することでした:

ax.xaxis.set_ticks(data_frame.index.values) 

しかし、動作しません。どのような作品

は次のとおりです。

ax.xaxis.set_ticklabels(data_frame['labels'][::step]) 
ax.xaxis.set_ticks(data_frame.index.values[::step]) 

任意のlocator_paramsを設定せずに。

これはほぼ完璧です。それはティックとラベルを修正しますが、(matplotlibインタラクティブウィンドウを使って)プロットをズームすると、新しいラベルは明らかに表示されません。そして私が必要とするのは、プロットのズームに応じて調整可能な読み取り可能なティックです(これはax.locator_params(axis='x', nbins=3)がカスタムラベルなしで正しく機能するものです)。

つまり、データポイントごとに固有のラベルを設定する必要がありますが、プロットの軸の目盛りには、正しい割り当てを失うことなく、それらのラベルのみを表示する必要があります。

+0

私はあなたが望むものを理解する問題を抱えています。なぜ実際にデータポイントの位置にラベルを付けるだけのときに新しいラベルを表示したいのですか?それは私と矛盾しているようです。 – ImportanceOfBeingErnest

+0

@ michal-2am私の答えはあなたの質問に答えましたか? – mhoff

答えて

1

Locatorを使用すると、生成されるダニの数と配置場所を定義できます。 MaxNLocator(これは本質的にデフォルトのロケータ)をサブクラス化することで、機能を再利用して、望ましくないティック(例えば、ラベル範囲外のティック)を単に除外することができます。スパースまたは非等距離のx範囲データが簡単なフィルタリングソリューションを破るため、私のアプローチは間違いなく改善される可能性があります。フロート値も問題になるかもしれませんが、上記の条件が当てはまらない場合、そのようなデータ範囲は常に便利な整数範囲にマップできます。しかし、これはこの質問の範囲外です。

Formatterでは、ラベルリスト内の対応するラベルを検索して、正しい目盛りラベルを作成できるようになりました。最も近い値を見つけるために、bisectモジュール(related question)を効率的に利用できます。静的プロットでは、Locatorがリストアクセスに直接使用できるインデックスを既に生成していることを前提としています(不必要な2等分演算を避ける)。しかし、ダイナミックビュー(スクリーンショットの左下隅を参照)は、フォーマッタを使用してティック以外の位置ラベルをフォーマットします。したがって、bisectの使用は、より一般的で安定したアプローチです。

Unzoomed

Zoomed

import matplotlib.pyplot as plt 
import numpy as np 
import bisect 
from matplotlib.ticker import Formatter 
from matplotlib.ticker import MaxNLocator 

x = np.arange(0, 100, 1) 

y = np.sin(x) 

# custom labels, could by anything 
l = ["!{}!".format(v) for v in x] 

plt.plot(x, y) 
ax = plt.gca() 

class LookupLocator(MaxNLocator): 
    def __init__(self, valid_ticks, nbins='auto', min_n_ticks=0, integer=True): 
     MaxNLocator.__init__(self, integer=integer, nbins=nbins, min_n_ticks=min_n_ticks) 
     self._valid_ticks = valid_ticks 
     self._integer = integer 

    def is_tick_valid(self, t): 
     if self._integer: 
      return t.is_integer() and int(t) in self._valid_ticks 
     return t in self._valid_ticks 

    def tick_values(self, vmin, vmax): 
     return filter(self.is_tick_valid, MaxNLocator.tick_values(self, vmin, vmax)) 


class LookupFormatter(Formatter): 
    def __init__(self, tick_values, tick_labels): 
     Formatter.__init__(self) 
     self._tick_values = tick_values 
     self._tick_labels = tick_labels 

    def _find_closest(self, x): 
     # https://stackoverflow.com/questions/12141150/from-list-of-integers-get-number-closest-to-a-given-value 
     i = bisect.bisect_left(self._tick_values, x) 
     if i == 0: 
      return i 
     if i == len(self._tick_values): 
      return i - 1 
     l, r = self._tick_values[i - 1], self._tick_values[i] 
     if l - x < x - r: 
      return i 
     return i - 1 

    def __call__(self, x, pos=None): 
     return self._tick_labels[self._find_closest(x)] 

ax.xaxis.set_major_locator(LookupLocator(x)) 
ax.xaxis.set_major_formatter(LookupFormatter(x, l)) 

plt.show() 
関連する問題