折れ線グラフのAxesからデータを復元したい
状況
matplotlib, plot
関数を使用して折れ線グラフを作成した。
plot
関数の対象となったAxes
オブジェクトから、折れ線グラフの作成に使われた
データを抽出したい。
""" ## Purpose This is a problem related to [matplotlib](https://matplotlib.org/) As you know, you can make a figure of line graph with such as the following functions. > fig, (ax) = plt.subplots(1, 1) > ax.plot([1, 2, 3], [4, 5, 6]) Here, I'd like the function to read the representation of the data from given ``Axes`` class. ### Environment * matplotlib==3.0.3 * pandas==0.24.2 """ import warnings from collections import defaultdict import random import matplotlib import matplotlib.pyplot as plt from matplotlib.axes._axes import Axes import pandas as pd def read_plot(ax, *, fill=None): """ Speculate the data of plotted ``Axes``. Args: ax(Axes): The target ``Axes`` of read. fill(Number): The value for empty ``X``. Return: ``dict`` of ``list`` format of the estimated data. """ assert isinstance(ax, Axes), "Given Object must be ``Axes`` " """ If ``xaxis.label`` is existent, then it is regarded as label. Otherwiser, ``X`` is used. """ x_text = ax.xaxis.label.get_text() if x_text: xlabel = x_text else: warnings.warn("``label`` of ``X`` is not specified. ") xlabel = "X" if len(ax.lines) == 0: raise ValueError("There is no ``Line2D`` given ``Axes``.") # Construct the data dependent on ``X``. x_to_data = defaultdict(dict) """ ### As for the label of ``Y``. * Priority 1. If the ``label`` is set at ``line``, then it is regarded as label of ``Y``. """ labeled_lines = [line for line in ax.lines if line._label] if labeled_lines: for line in labeled_lines: label = line._label for x, y in zip(*line.get_data()): x_to_data[x][label] = y else: if len(ax.lines) == 1: """ ### As for the label of ``Y``. * Priority2. As long as the ``label`` of ``yaxis`` exists. it is regarded as the column of ``Y``. """ label = ax.yaxis.label.get_text() if label: for x, y in zip(*ax.lines[0].get_data()): x_to_data[x][label] = y if not x_to_data: raise ValueError("Cannot read any semantic data.") listmap = [] x_values = x_to_data.keys() columns = {c for x in x_values for c in x_to_data[x].keys()} for x in sorted(x_to_data.keys()): row = dict() row[xlabel] = x for c in columns: row[c] = x_to_data[x].get(c, fill) listmap.append(row) return listmap if __name__ == "__main__": """ Example. 1. Plot an artificial data to ``in_ax``. 2. Using ``read_plot``, the target data is given from ``in_ax``. 3. Read data is plotted to ``out_ax``. """ fig, (in_ax, out_ax) = plt.subplots(1, 2) func = lambda x: 3 * x + 1 + random.random() * 10 x_values = range(10) y_values = tuple(map(func, x_values)) in_ax.plot(x_values, y_values, "-*", color="C0", label="LINE_SAMPLE1") y_values = tuple(map(func, x_values)) in_ax.plot(x_values, y_values, "-*", color="C1", label="LINE_SAMPLE2") in_ax.set_title("This is ``in_ax``. ", fontsize=16) in_ax.set_xlabel("X_LABEL") in_ax.set_ylabel("Y_LABEL") in_ax.legend() in_ax.tick_params(labelsize=12) """ Read the contents of ``in_ax``, and plot to ``out_ax``. """ listmap = read_plot(in_ax) xlabel = in_ax.get_xlabel() df = pd.DataFrame.from_records(listmap) df.plot(ax=out_ax, x=xlabel, style="-o") out_ax.set_title("This is read from ``in_ax``.", fontsize=16) out_ax.tick_params(labelsize=12) fig.tight_layout() plt.show() # Display """ Comment * Return of ``read_plot`` may be preferable if the type is ``Dataframe``. """
ユースケース
見当たらない。
作成動機1
「JSON
, YAML
, CSV
なんでもいいから、テキスト形式でデータをください...
再利用可能な形でデータを提供できないのは、貴方が騙りだからですよ!」
という知人の呟きを聞いたから
作成動機2
逆変換ができることって、大切だと思うんだ。
いつでも恋人同士に戻れる夫婦はいいなーって、学校の先生が言っていたし、 別れた後も友達に戻れたカップルの先輩たちはどっちもいい人だった。
安心できるから、ちょっと怖くても一歩を踏み出せるんだよね!