100万行以上のCSVを開いてグラフで見る無料ビューア「CSV Viewer」
ニンジンです🥕
Excelで大きなCSVを開いたら「ファイル全体を読み込むことができませんでした。」と出て、困ったことはありませんか? Excelで開ける行数には上限があり、それを超えた分は読み込まれません。
そこで、100万行を超えるCSVを分割せずに開いて、グラフで見られるビューアを作りました。Pythonを知らなくても、ダウンロードしてダブルクリックするだけで使えます。
CSV Viewer v1.0.0(Windows 64bit用・無料)
📦 CSVViewer-v1.0.0-win64.zip をダウンロード(約33MB)- SHA256:
A16985AED7B6DAFE38B400AEF39E52B36AA9D0359781027AAEF2A7EB88088557 - ソースコード: https://github.com/kurotyy-svg/csv-viewer
▲ 1000万行のCSVを開いて、ズーム・移動・全体表示に戻すまで(読み込み中の約9秒は4倍速)
この記事の前半はビューアの使い方、後半はPythonでの作り方の話です。Pythonを使わない方は、前半だけ読めば大丈夫です。
確認環境
- Windows 11 25H2
- Excel:Microsoft 365(バージョン 2608)
- (後半)Python 3.13.13 / dearpygui 2.3.1 / pandas 3.0.6 / numpy 2.5.3 / matplotlib 3.11.2
前半:ビューアを使う(Pythonは不要)
1. Excelの行数上限は1,048,576行
Microsoftの仕様では、Excelのワークシートの上限は1,048,576行×16,384列です。この数は増やせません。なお、Excel 2003までは65,536行でした。
上限を超えるCSVを開くと、次のメッセージが出ます。
2. ビューアの使い方
起動する
- ダウンロードした zip を右クリックして「すべて展開」を選ぶ
- 展開してできたフォルダの中の
CSVViewerフォルダを開き、CSVViewer.exeをダブルクリックする
zipの中のまま起動せず、必ず展開してから使ってください。
初めて起動するときの警告
初めて起動するときに、次の画面が出ることがあります。署名(作者を証明する仕組み)の無いソフトをインターネットからダウンロードしたときに表示される、Windowsの警告です。
「詳細情報」をクリックすると「実行」ボタンが出るので、それを押すと起動します。
ウイルス対策ソフトによっては、CSVViewer.exe が「不審なファイル」として隔離されることがあります(作者の環境では、ウイルスバスターの機械学習型検索が、一時フォルダに展開したexeを隔離しました)。PythonのプログラムをPyInstallerでexeにしたソフトは、誤って検出されやすいことが知られています。
不安な方は、ダウンロードしたファイルのSHA256が、上に書いた値と同じか確かめてください。PowerShellで次のように確認できます。
Get-FileHash "$env:USERPROFILE\Downloads\CSVViewer-v1.0.0-win64.zip" -Algorithm SHA256ソースコードもGitHubで公開しているので、Pythonを使える方は、exeを使わずに py csv_viewer.py で直接動かすこともできます(先に py -m pip install -r requirements.txt でライブラリを入れます。手順はGitHubのREADMEにあります)。
CSVを開く
- 「CSVを開く」ボタンを押して、ファイルを選ぶ
- または、CSVファイルを
CSVViewer.exeのアイコンにドラッグ&ドロップする
上には、行数と「Excelの上限の何倍か」が出ます。日時の列は自動で見つけて、横軸を日付の目盛りにします。
グラフの操作
| 操作 | 動き |
|---|---|
| マウスホイール | ズーム |
| 左ドラッグ | 移動 |
| 右ドラッグ | 囲んだ範囲を拡大 |
| ダブルクリック | 全体を表示 |
表示する列を選ぶ
- 左の欄で、縦軸に表示する列を選べます(複数選べます)
- 「横軸」で、横軸にする列を選べます
- 「折れ線」「散布図」を切り替えられます
- 左の欄の下の表に、いま表示している範囲の最小・最大・平均が出ます。ズームすると、その範囲で計算し直します
桁の違う列は「右軸」で
温度(13〜38)と電圧(3前後)のように桁の違う列を同じ目盛りで描くと、電圧はほぼ一直線に張り付いてしまいます。電圧の「右軸」にチェックを入れると、右側の目盛りで表示できます。
3. どれくらいの大きさまで開ける?
作者のPCで、架空のセンサーログ(日時・温度・湿度・電圧の4列)を開いたときの実測です。メモリは、Pythonで実行(py csv_viewer.py)したときのタスクマネージャーの値です。
| 行数 | ファイルの大きさ | 読み込み | メモリ(タスクマネージャー) |
|---|---|---|---|
| 150万行 | 54MB | 1.2〜1.3秒 | 約640MB |
| 1000万行 | 360MB | 8.5〜9.0秒 | 約2.7GB |
読み込みの時間は、何回か開いたときの幅です。
1000万行になると、メモリを2.7GBほど使います。メモリに余裕のないPCでは、ほかのアプリを閉じてから開いてください。
4. できないこと
- CSVの編集や保存はできません(読むだけです)
- 読めるのはCSVだけです(xlsxは開けません)
- 3次元のグラフは描けません
- Windows(64bit)専用です
- 散布図は、点が20万点を超えると等間隔に間引いて表示します(統計はすべての点で計算します)
後半:Pythonでの作り方
5. なぜDearPyGuiなのか
ここからは、Pythonを使う方向けです。ビューアは、PythonのGUIライブラリ「DearPyGui」で作りました。DearPyGuiの基本は、シリーズの第1回をご覧ください。
大量の点を速く描けるからです。Pythonのグラフの定番 matplotlib と、同じデータを1回描くのにかかる時間を比べました。
| 点の数 | 表示 | DearPyGui | matplotlib | 何倍速いか |
|---|---|---|---|---|
| 10万 | 全体 | 1.3ms | 22.5ms | 17.3倍 |
| 10万 | 1%拡大 | 0.4ms | 11.6ms | 29倍 |
| 100万 | 全体 | 15.0ms | 45.2ms | 3.0倍 |
| 100万 | 1%拡大 | 3.1ms | 14.9ms | 4.8倍 |
| 300万 | 全体 | 44.8ms | 89.2ms | 2.0倍 |
| 300万 | 1%拡大 | 9.7ms | 22.4ms | 2.3倍 |
| 1000万 | 全体 | 147.8ms | 229.1ms | 1.6倍 |
| 1000万 | 1%拡大 | 30.9ms | 21.2ms | 0.7倍(matplotlibが速い) |
100万点の全体表示でも1回15ミリ秒(66FPS相当)で、画面の更新に十分間に合います。ただ、点が増えるほど差は縮み、1000万点を拡大したときだけはmatplotlibのほうが速くなりました。
測り方は次のとおりで、完全に同じ条件の比較ではありません。
- DearPyGui:画面の更新に合わせる仕組み(垂直同期)を切り、3秒間描き続けた平均
- matplotlib:画面に出さずに(Agg)同じ大きさの画像を描く時間の、5回の平均。matplotlibは線を間引いて描く機能(path.simplify)が標準で効いています
6. コードのポイントと、作っていて見つかった罠
全体のコードはGitHubにあります。ここでは、ポイントになる部分と、作っていてハマったところを紹介します。
CSVは別のスレッドで読み込む
1000万行の読み込みには9秒ほどかかるので、その間に画面が固まらないよう、読み込みは別のスレッドで行い、終わったら画面のループで受け取っています。文字コードは、UTF-8(BOMあり・なし)とShift_JISの順に試します。
def read_csv(path: str):
t0 = time.perf_counter()
last_error = None
for enc in ("utf-8-sig", "cp932"): # UTF-8 と Shift_JIS(Excel の CSV)に対応
try:
df = pd.read_csv(path, encoding=enc, low_memory=False)
break
except UnicodeDecodeError as e:
last_error = e
else:
raise ValueError(f"文字コードを判定できませんでした(UTF-8 / Shift_JIS 以外): {last_error}")
# 日時らしい列は日時に変換する(先頭1000行で9割以上が日時として読めたら)
for col in df.columns:
# 数値でも日時でもない列(文字の列)だけ調べる。pandas 3 では文字の列が object ではなく str になる
if not (pd.api.types.is_numeric_dtype(df[col]) or pd.api.types.is_datetime64_any_dtype(df[col])):
with warnings.catch_warnings(): # 日時でない列を試したときの警告は出さない
warnings.simplefilter("ignore")
head = pd.to_datetime(df[col].head(1000), errors="coerce")
if head.notna().mean() > 0.9:
df[col] = pd.to_datetime(df[col], errors="coerce")
return df, enc, time.perf_counter() - t0pandas 3で日時が1970年になった
日時の列は、グラフの時刻の目盛りに渡すために「1970年1月1日からの秒数」に変換します。最初はよく見る astype("int64") / 1e9 で変換していたのですが、グラフの日付が1970年1月21日になってしまいました。
pandas 3では、日時の列がナノ秒ではなくマイクロ秒で読み込まれるようになっていて、1e9 で割ると桁がずれていたのが原因です。単位に左右されない書き方に変えました。
def column_values(df, col) -> np.ndarray:
s = df[col]
if pd.api.types.is_datetime64_any_dtype(s):
# 時刻軸には UNIX 時間(1970-01-01 からの秒数)で渡す。
# astype("int64") / 1e9 は使わない: pandas 2 はナノ秒、pandas 3 はマイクロ秒などで持つので桁がずれる
return ((s - pd.Timestamp("1970-01-01")) / pd.Timedelta(seconds=1)).to_numpy(dtype=np.float64)
return pd.to_numeric(s, errors="coerce").to_numpy(dtype=np.float64)pandas 3では、文字の列の型も object から str に変わっていて、dtype == object で文字の列を探すコードも動かなくなっていました。エラーが出ずに結果だけおかしくなるので、気づきにくい変化です。
ファイル選択画面は、Windows標準のものを使う
最初はDearPyGuiのファイル選択画面(file_dialog)を使っていたのですが、Windowsで「マイドライブ」のような日本語のフォルダを開くと、フォルダ名が ?}?C?h???C?u と表示され、中のファイルを選ぶとアプリが何も言わずに終了しました。
「マイドライブ」をShift_JISで表すと 83 7d 83 43 83 68 83 89 83 43 83 75 の12バイトで、英数字以外のバイトを「?」にすると、ちょうど ?}?C?h???C?u になります。日本語のフォルダ名を正しく扱えていないことがわかります。
そこで、Pythonに入っている tkinter で、Windows標準のファイル選択画面を出すようにしました。
def ask_csv_path():
"""Windows 標準のファイル選択画面を出す(tkinter)。
DearPyGui の file_dialog は、Windows で日本語のフォルダ名が「?}?C?h???C?u」のように化け、
日本語を含むフォルダのファイルを選ぶと落ちたので使わない。"""
root = tk.Tk()
root.withdraw()
root.attributes("-topmost", True) # ビューアの後ろに隠れないように
path = filedialog.askopenfilename(
parent=root, title="CSVファイルを選んでください", initialdir=state["last_dir"],
filetypes=[("CSVファイル", "*.csv"), ("すべてのファイル", "*.*")])
root.destroy()
return pathチェックを全部外すと落ちた:コールバックは別スレッドで動く
縦軸のチェックを全部外すと、アプリが落ちました。DearPyGuiは、ボタンやチェックボックスを操作したときの処理(コールバック)を、画面を描く処理とは別のスレッドで動かします。そのため、表を作り直すコールバックと、ループの中で表に数字を書き込む処理がぶつかっていました。
自分でループを回すときは、コールバックもループの中で実行するように設定すると、同時に動くことがなくなります。
# コールバック(チェックボックスなどを操作したときの処理)をメインループの中で動かす。
# 既定では別のスレッドで動くため、統計の更新と表の作り直しがぶつかって落ちた
dpg.configure_app(manual_callback_management=True)while dpg.is_dearpygui_running():
...
dpg.render_dearpygui_frame()
dpg.run_callbacks(dpg.get_callback_queue()) # たまったコールバックをここで実行する桁の違う列は右側の軸に
右側の軸は mvYAxis2 で作れます。opposite=True を付けないと左側に2本並び、最初に隠しておいた軸を表示するときは fit_axis_data() で範囲を合わせ直さないと、0〜1のままになりました。
# 桁の違う列を表示するための右側の軸(「右軸」にチェックした列だけここに描く)
dpg.add_plot_axis(dpg.mvYAxis2, tag="yaxis2", opposite=True, show=False)散布図はメモリを大量に使う
散布図は1点ごとに印を描くので、点が多いとメモリを大量に使い、描く速さも落ちます。Windowsで、同じ30万点を散布図と折れ線で描いて比べました。
測り方は、ビューアではなく、グラフを1つだけ描く測定用のスクリプトです。メモリは、描き続けている間のプロセスの使用量(ワーキングセット)の最大値です。3章のタスクマネージャーの値とは測り方が違うので、表どうしで数字を比べないでください。
| 描き方 | 点の数 | メモリ | 描く速さ |
|---|---|---|---|
| 折れ線 | 30万 | 約200MB | 61FPS |
| 散布図 | 10万 | 約590MB | 46FPS |
| 散布図 | 20万 | 約840MB | 26FPS |
| 散布図 | 30万 | 約940MB | 17.5FPS |
散布図は、30万点で折れ線の4倍以上のメモリを使い、速さは3分の1以下になりました。そこで、20万点を超えたら等間隔に間引いています。
もう1つ、numpyで x[::step] のように飛び飛びに取り出した配列をそのままDearPyGuiに渡すと、エラーも出さずにアプリが落ちました。終了コードは -1073741819(0xC0000005)で、第2回の日本語タイトルのときと同じです。try / except では捕まえられません。np.ascontiguousarray() で詰め直すと渡せます。
scatter = dpg.get_value("style") == "散布図"
step = max(1, -(-len(x) // SCATTER_MAX)) if scatter else 1 # 切り上げの割り算
for name, y in state["cols"]:
axis = "yaxis2" if right_of[name] else "yaxis" # 桁が違う列は右の軸に
if scatter:
# x[::step] は飛び飛びの配列なので、そのままだと DearPyGui が受け取れない。詰め直して渡す
dpg.add_scatter_series(np.ascontiguousarray(x[::step]), np.ascontiguousarray(y[::step]),
label=str(name), parent=axis)
else:
dpg.add_line_series(x, y, label=str(name), parent=axis)7. exeにする
Pythonを使わない人向けのexeは、PyInstallerで作りました。
- リポジトリを、半角英数字だけのパス(例:
C:\dev\csv-viewer)に置く packaging\build_exe.batをダブルクリックするdist\CSVViewer-v1.0.0-win64.zipができる
build_exe.bat は、仮想環境を作ってライブラリのバージョンを固定し、ビルド、ライセンス文の収集、zip化、SHA256の表示までをまとめて行います。
気をつけたことが4つあります。
- 1つのexeにまとめない:起動のたびに中身を展開する形式(
--onefile)は起動が遅くなるので、フォルダの形式(--onedir)をzipで配っています - Googleドライブの同期フォルダでビルドしない:仮想環境とビルドで大量のファイルができ、それが全部同期されてしまいます。日本語を含むパスも避けて、
C:\devのような半角英数字の場所でビルドしています - ライセンス文を同梱する:DearPyGui・numpy・pandasなどのライセンス文を
licensesフォルダに入れています - 警告は、ダウンロードしたときだけ出る:自分のPCで作ったexeを起動しても、SmartScreenの警告は出ませんでした。GitHubからダウンロードし直すと出ました
GitHubのReleasesにアップロードできなかった件
完成したzip(約33MB)をGitHubのReleasesにブラウザから添付しようとすると、「File size too big: 25 MB are allowed」と断られました。Releasesのファイルは本来2GBまで置けるはずで、同じ現象はGitHubのコミュニティでも報告されています。GitHub CLI(gh)を使うとアップロードできました。
gh release create v1.0.0 dist\CSVViewer-v1.0.0-win64.zip --repo kurotyy-svg/csv-viewer --title "CSV Viewer v1.0.0" --notes-file release_notes.md大きなCSVとExcelの行数上限でよくある質問(FAQ)
QExcelの行数の上限は増やせますか?
A増やせません。1,048,576行が上限です(1章)。
QCSVを分割せずに開く方法はありますか?
Aこのビューアなら、1000万行でも分割せずに開けます(3章)。ただし、見るだけで編集はできません。
Qxlsxファイルも開けますか?
A開けるのはCSVだけです。xlsxは、ワークシート自体が1,048,576行までです。
Q3次元のグラフは描けますか?
A描けません。DearPyGui 2.3.1のグラフ(plot)には、3次元のグラフの部品がありません。図形を描く機能(draw系)の行列変換を使えば3次元の絵を自分で描くことはできますが、このビューアでは扱っていません。
Q日本語の見出しが文字化けしませんか?
AUTF-8とShift_JIS(Excelで保存したCSV)に対応しています。
QMacでも使えますか?
A配布しているexeはWindows専用です。Pythonのコードは、Mac・Linuxでは確認していません。
Q安全ですか?
A署名の無いソフトなので、Windowsの警告が出ます。ウイルス対策ソフトによっては、誤って隔離されることもあります(2章)。SHA256でダウンロードしたファイルが同じものか確かめられるようにし、ソースコードもGitHubで公開しています。
まとめ
- Excelで開けるのは1,048,576行まで。超えた分は読み込まれない
- CSV Viewerなら、100万行、1000万行のCSVも分割せずにグラフで見られる
- DearPyGuiは、100万点の全体表示を1回15ミリ秒で描けた。ただし1000万点を拡大すると matplotlib が逆転
- 作っていて、日本語のフォルダ名、コールバックのスレッド、pandas 3の日時、散布図のメモリと飛び飛びの配列でハマった
ぜひ、Excelで開けなかったCSVを、CSV Viewerで開いてみてください。
DearPyGui Series Navigation
DearPyGuiシリーズ:2.3.1で確かめた書き方と落とし穴
DearPyGuiの使い方|pipでのインストールから日本語表示・画面の作り方まで
→ 2DearPyGuiで日本語タイトルにするとエラーも出さずに落ちる原因と回避策|0xC0000005【Windows・2.3.1】
→ 3DearPyGuiのフォント設定と文字サイズの変え方|日本語が「?」になる原因と2.3の変更点
→100万行以上のCSVを開いてグラフ化|Excelの行数上限を超えるデータを見る無料ビューア【Python・DearPyGui】
この記事Follow me on X
本ブログの中の人「ニンジン🥕」はXやってます。新着記事はいち早くポストでお知らせしているので、見逃したくない方は @ninjin_py_vba をフォローしてみてください🥕
@ninjin_py_vba をフォロー



コメント