I often draw graphs from ** Python ** using ** matplotlib **. Data is generated by ** Python ** application, formatted, and graph output by ** matplotlib **.
At that time, I had the following issues.
The code you write to ** visualize the data ** and the code you write to ** manage the design ** I thought it was because it was written in one application.
I tried to separate the code for ** managing the design ** as a ** configuration file **.
Of the three issues listed, the graph design is not unified
is
It means that the ** label size **, ** legend **, ** plotted points **, etc. assigned to the vertical and horizontal axes are not unified.
This is also related to the second task, because I made a ** similar description ** in another Python file.
The problem was that it wasn't ** unified **, and I was doing ** copy and paste ** by referring to past Python files on the spot.
The reason why I repeat ** copy ** is that the ** design ** and ** code ** I'm looking for I think it's because it's not tied, at least not intuitive. This leads to a third challenge.
I thought the reason for these three challenges was that the ** data ** and ** design ** were not ** separated **.
If so, the story is simple: separate the ** design ** into a ** config file **.
I tried to correspond the design and the word as shown in the table below.
The meaning of each item is
--Design classification --Configuration file parameters --Meaning of parameters --Corresponding matplotlib code
is.
-** Size (set the size) ** - figure_x --Horizontal size of the figure - pyplot.figure(figsize=(figure_x, figure_y)) - figure_y --The vertical size of the figure --Same as figure_x - font_title --Title font size - pyplot.title(fontsize=font_title) - font_x_label --X-axis font size - pyplot.figure.add_subplot().ax.set_xlabel(fontsize=font_x_label) - font_y_label --Y-axis font size - pyplot.figure.add_subplot().ax.set_ylabel(fontsize=font_y_label) - font_tick --Axis memory font size - pyplot.tick_params(labelsize=font_tick) - font_legend --Legend font size - pyplot.legend(fontsize=font_legend) - marker --Marker size when plotting data - pyplot.figure.add_subplot().ax.plot(markersize=marker)
-** Position ** - subplot --Where to place the graph - pyplot.figure.add_subplot(subplot) - legend_location --Location in the graph to place the legend - pyplot.legend(loc=legend_location)
For the configuration file, I considered several expression methods, such as json and yaml.
As a result, I decided to use the standard ** [configparser] 1 ** for Python.
I think json and yaml are fine, but I thought it would be better to ** intuitively use ** than to express it hierarchically.
The configuration file is represented by ** configparser ** as follows.
config.ini
[Size]
figure_x=8
figure_y=8
font_title=20
font_x_label=18
font_y_label=18
font_tick=10
font_legend=15
marker=10
[Position]
subplot=111
legend_location=upper right
[Markers]
0=D
1=>
2=.
3=+
4=|
[Color]
0=red
1=blue
2=green
3=black
4=yellow
Items that correspond to ** design classification ** are enclosed in ** square brackets **, such as ** [Size] **. This is called the ** section **. Below that, write ** parameter = value ** of the configuration file. This is called the ** key **.
In addition to ** Size ** and ** Position **, the above configuration files also include ** Markers (types of markers to plot) ** and ** Color (colors of markers and lines to be plotted) **. It is expressed.
To access the parameters in the configuration file, write the code as follows:
import configparser
rule_file = configparser.ConfigParser()
rule_file.read("config file path", "UTF-8")
hogehoge = rule_file["Section name"]["Key name"]
Note that the read value will be a ** string **.
The code below creates a line chart based on the ** passed data ** and ** design configuration file **.
make_line_graph.py
"""Line graph creation function
Draw a line graph using the passed data and save it as image data.
"""
import configparser
import matplotlib.pyplot as plt
def make_line_graph(data, config="config.ini"):
"""Line graph drawing
Create a line graph using the passed data.
Read the design from another config file.
Args:
data(dict):Contains data to plot
config(str):The name of the config file
Returns:
bool:If True, creation is complete, if False, creation fails
Note:
The key and value that should be included in the argument data are described below.
key : value
------------------------
title(str):Graph title name
label(list):Legend description
x_data(list):x-axis data
y_data(list):y-axis data
x_ticks(list):Value to display in x-axis memory
y_ticks(list):Value to display in y-axis memory
x_label(str):x-axis name
y_label(str):y-axis name
save_dir(str):Save file path
save_name(str):Save file name
file_type(str):Save file format
"""
rule_file = configparser.ConfigParser()
rule_file.read("./conf/{0}".format(config), "UTF-8")
fig = plt.figure(figsize=(int(rule_file["Size"]["figure_x"]), int(rule_file["Size"]["figure_y"])))
ax = fig.add_subplot(int(rule_file["Position"]["subplot"]))
ax.set_xlabel(data["x_label"], fontsize=int(rule_file["Size"]["font_x_label"]))
ax.set_ylabel(data["y_label"], fontsize=int(rule_file["Size"]["font_y_label"]))
for index in range(len(data["x_data"])):
ax.plot(data["x_data"][index],
data["y_data"][index],
label=data["label"][index],
color=rule_file["Color"][str(index)],
marker=rule_file["Markers"][str(index)],
markersize=int(rule_file["Size"]["marker"]))
plt.title(data["title"], fontsize=int(rule_file["Size"]["font_title"]))
if "x_ticks" in data.keys():
plt.xticks(data["x_ticks"][0], data["x_ticks"][1])
if "y_ticks" in data.keys():
plt.yticks(data["y_ticks"][0], data["y_ticks"][1])
plt.tick_params(labelsize=int(rule_file["Size"]["font_tick"]))
plt.legend(fontsize=rule_file["Size"]["font_legend"], loc=rule_file["Position"]["legend_location"])
plt.savefig("".join([data["save_dir"], "/", data["save_name"], ".", data["file_type"]]))
The Python file that passes the data looks like this:
main.py
from make_line_graph import make_line_graph
data = {
"title": "hogehoge",
"label": ["A", "B"],
"x_data": [x_data1, x_data2],
"y_data": [y_data1, y_data2],
"x_ticks": [x_ticks1, x_ticks2],
"y_ticks": [y_ticks1, y_ticks2],
"x_label": "hogehoge",
"y_label": "hogehoge",
"save_dir": "Path of the folder you want to save",
"save_name": "File name you want to save",
"file_type": "extension",
}
make_line_graph(data, config="config.ini")
The design is easier to change. In particular, various font sizes vary depending on the data to be plotted and the number of characters to be included in the label.
Also, by duplicating and customizing the configuration file, the amount of Python file changes when you want to change the graph design has been reduced. You only have to change the name of the configuration file to be read.
Since the graph design and the configuration file are tied together, it's okay to forget which design corresponds to which code.
It is difficult to make it versatile.
The ** make_line_graph.py ** I made is a line graph creation function, but I don't want to see more similar Python files, so I made it as versatile as possible. However, this does not draw the graph well, and if another line graph creation function is crowded to correspond to it, it seems that it will return to the drawing.
I'm wondering if there is no end to it considering its versatility.
Recommended Posts