pythonの複数行の出力を上書きで書き換えたい
解決したいこと
jupyterlabもしくはjupyternotebook上でのpythonでキャリッジリターン(\r)を使うと同じ行を上書きするように出力できますが、行をさかのぼって上書きするにはどうしたらよいのでしょうか? "\033[nA"でできるという記事もあるのですが、jupyterでは思うとうりにはいかないようです。
よろしくお願いいたします
jupyterlabもしくはjupyternotebook上でのpythonでキャリッジリターン(\r)を使うと同じ行を上書きするように出力できますが、行をさかのぼって上書きするにはどうしたらよいのでしょうか? "\033[nA"でできるという記事もあるのですが、jupyterでは思うとうりにはいかないようです。
よろしくお願いいたします
以前の行に遡って編集するには表示されているターミナル画面全体を制御する必要があります。Cursesを使う実装が多いと思いますが、かなりの前準備と後片付けが必要なので、今のスクリプトにちょっと付け足す感じにはなりません。
出力順をうまく工夫して、遡らないやり方を考える方が簡単だと思います。
ちなみに、\r
はエスケープシーケンスと呼ばれる特殊文字です。\r
は行頭に戻るので、そこから同じ行を上書きすることで書き換えているように見えます。
@morisita
Questioner
お返事ありがとうございます。pythonで出来ないこともあるんですね。
処理中のコードの出力をまっさらにすることはできます.
数行だけ遡るのはちょっと無理そうかも.
まあそれが必要なら普通のShellでいいですしまあ.
@morisita
Questioner
お返事ありがとうございます。これは
IPython.displayのclear_outputとは別物ですかね?
"\033[nA"でできるという記事もあるのですが、
ANSIエスケープシーケンス とも言いますが、VT100 などのターミナルへの出力なら可能です。
ほぼ どの Unix系 OS でも使えるはずですが、Windows OS のコマンドプロンプトでは使えないと思います。
元々、Cursesという、C言語ライブラリがあって、それをPythonから使えるようにしたライブラリもあるようですが、これが Jupyter で機能するかどうかは、自分は知りません。やってみるしか無いです。
↓ この Jupyterlab の Terminal なら使えそうな気がしますが、
pip install jupyter-console
をどこで実行するのか、分かりません。
例えばUnix系の端末上から(一応手元のWindowsのコマンドプロンプトでも同種の操作で同様の結果)こんな感じかと…
$ python3 -m venv env
$ . env/bin/activate
(env) $ pip install jupyter-console
...
(env) $ jupyter console
Jupyter console 6.6.3
Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.25.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: print('ほげ');print('\033[1Aふが')
ふが
In [2]:
この使い方でnotebookやlabを使ってると言えるのかは知りません。terminal自体はnotebookやlabのweb画面でもメニューからfile>new>terminal
するなどすれば使えるので、そこからjupyter console
すればできたことになるのかもしれません(やりたいこと次第)。
なお、file>new>console
では\033[1A
のエスケープシーケンスが効きません。あくまでterminal上で使う必要があります。
セル上のエスケープシーケンスについては、色とかなら対応してるけど位置とかは対応する気がないように見えます(古いけど https://github.com/jupyter/notebook/issues/4315 )。
@morisita
Questioner
お返事ありがとうございます。jupyterlab on ubuntuでも駄目でした。
jupyterlab on ubuntuでも駄目でした
というのは
notebookやlabのweb画面でもメニューからfile>new>terminal
とかしても駄目だったということですか?
@morisita
Questioner
notebookやlabのweb画面でもメニューからfile>new>terminalというのはあるのですが、私が使っているのはfile>new>Notebookで、ipynbファイル上での話です。
notebookでないとやりたいことが出来ないということなんですね
だとするとセル側で必要なエスケープシーケンスに対応しない限り無理だと思います
自分でjupyter側をいじる苦労をするくらいなら、\rで何とかする方が楽だと思います
In [1]: for i in range(10):
...: print(i)
...:
0
1
2
3
4
5
6
7
8
9
In [2]: for i in range(10):
...: print(f"\r{i}", end="")
...:
9
In [3]:
@morisita
Questioner
terminalでpython使ってる人は結構多いのですか?僕は初めからjupyterlabだったので****.pyみたいなプログラムは私的ライブラリー用に作るくらいで。。。
一行で済めば'\r'でいいのですが、表示したい情報が多く、一行にいろんな情報が更新されていくと分かりにくいので、行を変えて出力したかった次第です。
表示したい情報が多く、一行にいろんな情報が更新されていくと分かりにくいので、行を変えて出力したかった次第です。
'\r'とか使わずに普通にprint()
すればいい気がします。
例えば、3行でひと塊り(3行さかのぼって上書き出力したかった)とすると、
4行目に空白行を出力すれば、大量に出力されても、かたまりごとに見やすと思います。
もしくは、
n行さかのぼって上書きするということは、結局は、途中経過は消えて残らず、最後に出力したものだけが最終的に残るわけなので(途中の情報は最終的には不要ということで)、
'\r'を使って途中経過の情報は1行だけ出力するようにして、最後に最終結果を必要な行数だけ出力するのはどうですか。
@morisita
Questioner
お返事ありがとうございます。説明が足らずすいません。
作っているプログラムは何台かある計測器のデータを取得しつつ表示するプログラムで、出力の一番上にはグラフのパネルが6枚ほど表示されていて、その下に文字情報で数行の計測器のステータスなどが表示されるようになっています。なので、グラフの下に何行も情報が流れて行かれるとこれはこれで視認性が悪いなと思った次第です。
terminalでpython使ってる人は結構多いのですか?
多いでしょうね。目的によりますがjupyterやipythonを使う方が少数だと思います。
一行で済めば'\r'でいいのですが、表示したい情報が多く、一行にいろんな情報が更新されていくと分かりにくいので、行を変えて出力したかった次第です。
他の文面も全部そうなんですが、言葉が足らずで意味が分かりません。更新したい行が複数行に渡るということでしょうか?
例えばterminal上で実行するならこんな…
from time import sleep
print("\n")
for i in range(5):
print(f"\033[2A{i}\n{2*i}")
sleep(0.5)
こういうケースだと\r
はお手上げですね
なお@Vercleneさんのコメントにある全消去を使う方法だとnotebookのセル上でも出来ます。逆に標準のpythonでは動かなくなりますが。
from time import sleep
from IPython.display import clear_output
for i in range(5):
clear_output(True)
print(f"{i}\n{2*i}")
sleep(0.5)
pipでipywidgetsをインストールすると
from time import sleep
import ipywidgets as widgets
out = widgets.HTML()
display(out)
for i in range(5):
out.value=f"<pre>{i}\n{2*i}</pre>"
sleep(0.5)
でも行けそう。グラフがあるならこれで行けるとは思う。notebookでしか使えないけど。
@morisita
Questioner
terminalでプログラムを実行すると言うことが全くなかったので、食い違ってしまいましたすいません。ちなみにterminalで実行すれば、windowsでもubuntuでも"\033[nA"は有効でした。ただ、matplotlibのplotは表示できないようで、私の希望には沿わないようでした。@dameyodamedameさんの最後の方法はうまく行くようです。out.valueの書き方がよくわかりませんが、これから調べてみます
ありがとうございました