質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
openpyxl

openpyxlは、Excel2007以降のファイル(xlsx/xlsm/xltx/xltm)を読み書きするためのPythonライブラリです。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

2回答

2247閲覧

openpyxlで、グラフ生成を行うときに、パラメータを一括でファイル(jsonなど)から設定したい。

H.K2

総合スコア88

openpyxl

openpyxlは、Excel2007以降のファイル(xlsx/xlsm/xltx/xltm)を読み書きするためのPythonライブラリです。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

1クリップ

投稿2021/06/27 06:14

編集2021/06/27 11:58

前提・実現したいこと

pythonで、pandasなどで成形したdataframeを、excelに出力し、
excelのグラフを作ろうとしています。(下記のようなイメージ)

イメージ説明

下記のようなコードを書いた(excel出力した後からの処理)のですが、これらのようなコードでは
拡張性がなく、またコードが再利用できないため、非常に保守性が悪いと感じます。
そのため、jsonなどのパラメータファイルにパラメータ部分を外出ししようと
しているのですが、よい方法をご教示いただけないでしょうか。
追記:ファイル形式はjsonにこだわらないので、ファイルから読み込んだデータに対して
長々と代入文を書くのではなく、読み込んだデータをもとに、短い行数でパラメータを
設定するような工夫ができないかをご質問したいという意図でした。文章が分かりにくく申し訳ありません。

~~追記:なお、パラメータをjsonに持たせようと思い、下記jsonファイルを作って、
d = json.loads("graph_param.json")のように辞書で読み込もうとしたのですが、
JSONDecodeError: Expecting value: line 1 column 1 (char 0)となってしまいます。
参考:
https://sasuwo.org/python_reading_json_error/
~~
すみません。この件はご指摘いただき,下記で解決しました。(基礎的な文法ミスでした)
import json
with open('graph_param.json', encoding='utf-8') as f:
dct = json.load(f)

該当のソースコード

json(graph_param.json)

1{ 2 "chart_setting":{ 3 "style_val":2, 4 "height":12, 5 "width":12, 6 "title":"test_散布図", 7 "x_axis_title":"x座標", 8 "y_axis_title":"y座標" 9 }, 10 "marker1_setting":{ 11 "read_x_col":5, 12 "read_y_col":6, 13 "mark_symbol":"circle", 14 "mark_size":12, 15 "solidFill":"FF0000", 16 "line_solidFill":"0000FF" 17 }, 18 "marker2_setting":{ 19 "read_x_col":5, 20 "read_y_col":9, 21 "mark_symbol":"regtangle", 22 "mark_size":10, 23 "solidFill":"FFFF00", 24 "line_solidFill":"00FFFF" 25 }, 26 "marker3_setting":{ 27 "read_x_col":5, 28 "read_y_col":10, 29 "mark_symbol":"circle", 30 "mark_size":8, 31 "solidFill":"FF00FF", 32 "line_solidFill":"FF00FF" 33 }, 34 "marker4_setting":{ 35 "read_x_col":5, 36 "read_y_col":11, 37 "mark_symbol":"regtangle", 38 "mark_size":6, 39 "solidFill":"FFF0FF", 40 "line_solidFill":"FFF0FF" 41 } 42}

Python

1# 関数化したい。 2wb = load_workbook("test_reg_sample.xlsx") 3 4dt_s = s_row + 1 + 1 5list_xy = [[5,6], [5, 9], [5,10], [5,11]] 6list_mark = 7# グラフサイズ 8chart = ScatterChart() 9chart.style = style_val 10chart.height = 12 11chart.width = 12 12 13# ラベル 14chart.title = "sample 散布図" # タイトル 15chart.x_axis.title = 'x座標' # チャートのx軸ラベル 16chart.y_axis.title = 'y座標' # y軸ラベル 17 18# 軸の表示範囲と目盛り間隔 19chart.x_axis.scaling.min = 0 20chart.x_axis.scaling.max = 10 21chart.y_axis.scaling.min = 0 22chart.y_axis.scaling.max = 20 23chart.x_axis.majorUnit = 5 24chart.y_axis.majorUnit = 5 25 26#y,xデータの範囲を選択 27# todo:series, chartのパラメータは外だししたい。 28for i, (c_x, c_y) in enumerate(list_xy): 29 print(i, c_x, c_y) 30 y = Reference(wb["aaa"] ,min_col=c_y, max_col=c_y, min_row=dt_s-1, max_row=s_row+1+data_len) 31 x = Reference(wb["aaa"] ,min_col=c_x, max_col=c_x, min_row=dt_s, max_row=s_row+1+data_len) 32 33 #系列変数seriesをy,xを指定して定義する。yのみラベルを含むときは、title_from_data=Trueにする 34 series = Series(y, x, title_from_data=True) 35 #プロットをつなぐ線を消す 36 series.graphicalProperties.line.noFill = True 37 38 #散布図として定義したchartへデータを指定したseries変数を渡す 39 chart.series.append(series) 40 41 #マーカーを表示する(todo:ここもパラメータ化予定) 42 series.marker.symbol = "circle" 43 chart.series[i].marker.symbol = "circle" 44 chart.series[i].marker.size = 12 45 chart.series[i].marker.graphicalProperties.solidFill = "FF0000" 46 chart.series[i].marker.graphicalProperties.line.solidFill = "0000FF" 47 48#A6セルにグラフを表示 49wb["aaa"].add_chart(chart,"L10") 50wb.save("test2.xlsx")

試したこと

openpyxlのマニュアルなどを確認し、設定可能なパラメータを調査した。
jsonのパラメータについて検索して、パラメータを読み込もうとしてみた。
エラーコードから検索したサイトを調べ、ファイルの文字コードなどを変更してみた。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

meg_

2021/06/27 06:42

> そのため、jsonなどのパラメータファイルにパラメータ部分を外出ししようと しているのですが、よい方法をご教示いただけないでしょうか。 > openpyxlのマニュアルなどを確認し、設定可能なパラメータを調査した。 「やりたいこと」と「試したこと」が一致していないように見受けられますがいかがでしょうか? jsonファイルの扱い方を調べられた方が良いかと思いますが。(それともそちらについては既にご存知ということでしょうか?)
H.K2

2021/06/27 07:42

ご指摘ありがとうございます。恥ずかしながら、質問をした後、自分でもjsonにパラメータを書いて実施してみたのですが、エラーで詰まってしまいました。そちらについても追記します。
meg_

2021/06/27 09:27 編集

追記されたjsonファイルの構文は問題ないようです。文字コードは何ですか? > 下記jsonファイルを作って、load_jsonしたのですが、 そのコードを追記いただくと原因が分かるかもしれません。
H.K2

2021/06/27 11:22

文字コードはUTF8でした。追記しておきます。 (VSCODEでshift-jisやらeuc-jpに変えても読み込めませんでした。)
meg_

2021/06/27 11:58

jsonファイルからの読み込みに成功したのであれば、後は出来そうな気がするのですが。未だ課題が残っているのでしょうか?
H.K2

2021/06/27 12:09 編集

もともとお聞きしたかったのは、代入文をずらずらと書くのではなく、ファイル内に設定したパラメータをそのままオブジェクトに代入できる工夫ができないかということでした。 コード部分に代入を入れてしまうと、パラメータ部分が増えたりしたときに(例えば図の系列が4つ→5つに増えたときなど)、コードが対応できないため、それらをできるだけパラメータ側の情報だけで 何とかしたいという意図があります。 例えば、調べた感じだと、マーカーなどは、下記のようにまとめて設定できるので、 jsonから読んだパラメータをそのままここに流し込むような書きかたの工夫ができないかと思った次第です。※pyinstallerなどでフリージングして配布する関係上、系列を増やすとかのパラメータの設定変更だけでは、できるだけexe部分を変えたくないと思っています。 (例) series.marker = Marker(symbol="circle", size=5, spPr=GraphicalProperties(solidFill="ff0000", ln = LineProperties(solidFill="000000", w = 1 * 12700))) 参考URL: https://hogelog.com/python/openpyxl-excel-chart-1.html#toc13
meg_

2021/06/27 12:38

質問者さんのやりたいこと全てがjsonファイルからの読み込みで実現できるかは分かりませんが、質問のコード中で文字列で指定しているパラメーターは置換可能でしょう。 > jsonから読んだパラメータをそのままここに流し込むような書きかたの工夫 上記はどういう意味か分かりませんが、まずはベタ書きでパラメーター設定するのを止めてjsonファイルから読み込んだ値を使ってみてはどうでしょうか?
meg_

2021/06/27 12:40

外部ファイルを読み込んで使用する場合、エラー処理も必要になるでしょう。※ユーザーが予期せぬ値を書き込む可能性があるため  改良を重ねる必要があるかもしれません。頑張ってください。
H.K2

2021/06/27 12:48

承知しました。まずはjsonファイルから読み込んだ値をそのままひたすら代入文を書いて設定するようにします。そこからいろいろ改造できるところは改造してみます。 たしかにエラー処理なども必要とはおもいますし。ありがとうございます。
guest

回答2

0

ベストアンサー

辞書のデータを使って一括設定を行いたいということですね。

以下の例を参考にしてください。

python

1>>> print(dict_input) 2{'style': 2, 'height': 12, 'width': 12, 'title': 'test_散布図', 'x_axis': {'title': 'x座標'}, 'y_axis': {'title': 'y座標'}} 3>>> 4>>> def set_attrs(inst, dct): 5... for key in dct: 6... if type(dct[key]) == dict: 7... set_attrs(inst.__getattribute__(key), dct[key]) 8... else: 9... inst.__setattr__(key, dct[key]) 10... 11>>> set_attrs(chart, dict_input) 12>>> 13>>> print(chart.style) 142 15>>> print(chart.height) 1612 17>>> print(chart.width) 1812 19>>> print(chart.title) 20test_散布図 21>>> print(chart.x_axis.title) 22x座標 23>>> print(chart.y_axis.title) 24y座標

以下は解決積みになったようですね。
読めないのはencodingが原因のようなのですが、まだ特定できていません。

python

1json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

も出たのですが、そのあといろいろといじったので今再現できません。

ファイルをUTF-8Nで保存して以下で読み込む。

python

1import json 2with open('test.json', encoding='utf-8') as f: 3 dct = json.load(f)

というのと、
ファイルをSJISで保存して以下で読み込む。

python

1import json 2with open('test.json', encoding='cp932') as f: 3 dct = json.load(f)

をやってみてください。どちらかで読み込めるかもしれません。

投稿2021/06/27 09:15

編集2021/06/28 14:08
ppaul

総合スコア24666

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

H.K2

2021/06/27 11:36

ありがとうございます。 with open('test.json', encoding='utf-8') as f: dct = json.load(f) こちらで読み込めました…。先にopenでファイルを開いてから開いたものに対して json.loadしないとダメなんですね…。勘違いしておりました。 ちなみに、長々と書いたパラメータをファイルから直接読んで渡すような書き方ってできるのでしょうか。代入文だけでソースコードが肥大化するのがちょっと嫌だったのが質問の本題だったので。
H.K2

2021/06/28 03:07

ご回答ありがとうございます!仕事が終わったら確認してみます!
H.K2

2021/06/28 23:45 編集

できました!ありがとうございます。set_attrsで、中身が辞書かどうかを 分けて、辞書の場合はinst.__getattribute__(key)をすることで階層構造に対応するのですね。 勉強になりました! あとはプロットの系列が4カラム固定じゃなくてもできるように対応するのは 自分で少し考えてみます。ありがとうございました!
guest

0

提示されているjsonファイルを読み込んでみたところ、問題無く読み込めました。

python

1import json 2 3with open('test.json', 'r') as j: 4 x = json.load(j)

ただし、質問にある「load_json」はjsonモジュールには無いので使っていませんが。 それが原因では?

パラメータを外出しにするのはいい案だと思います。
ただ、それで本当に作業が効率化するかどうかは、作業の内容によるので、なんとも言えません。 いろいろやってみて最善を探すしかないでしょうね。

投稿2021/06/27 08:41

TakaiY

総合スコア12745

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

H.K2

2021/06/27 11:41 編集

すみません。追記しました。 d = json.loads("graph_param.json")のように読み込もうとしてしまって居てました…。文法ミスですね…。 たしかに作業内容によるのかもしれないですが、ツール化した後、フリージングしてほかの人に渡そうとしているため、できるだけソース本体を変更したくないというのがあります。 (そのため、jsonのフォーマットも含め、何かできるだけスクリプト本体を変えずに 汎用化したい(グラフの系列が増えたとき、グラフの枚数、はりつけ場所が増えた時くらいは対応できたら…)と思っています。自分だけなら最悪jupyterにベタっと書いてパラメータ随時書き換えればよいのですけどね…)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問