使用Matplotlib绘制实时图形(尺寸太小)的Python Kivy

时间:2018-09-06 10:56:27

标签: python matplotlib plot kivy kivy-language

我正在尝试使用Kivy Garden Matplotlib在Kivy内部创建一个测量可视化。目的是绘制字典中的变量及其相关度量。

目前,代码(请参见下文)由3部分组成。在导入部分之后,我定义了在代码内部使用的常量。下一部分是一个字典,我用它以编程方式绘制具有不同设置(线条颜色,线条宽度等)的不同变量。在字典之后,我定义了一个方法slice数组来拼接数组以减少内存使用,并定义了一个Plots类来生成图形。我还发布了similar question,但使用的是基维花园图。

我的代码有两个问题。首先,我无法不显示坐标系。 ax.spines命令无效。第二个问题是,我实际上希望有可能绘制要在单独的子图中显示的任意数量的变量。我希望echt图形在显示器上保持恒定的高度。这应该导致滚动图的可能性。

import time
import psutil
import matplotlib.pyplot as plt

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import Clock
from kivy.uix.scrollview import ScrollView
from kivy.uix.widget import Widget

from kivy.garden.matplotlib.backend_kivyagg import FigureCanvasKivyAgg

# Chart Constants
MAX_MEASUREMENT_ARRAY_LENGTH = 500      # to trim measured values values
X_BASE_INTERVAL_LENGTH = 10             # time axis is displayed for an interval of 50 seconds
BASE_LINE_WIDTH = 0.5                   # line width of lines in plots
BASE_LINE_COLOR = "white"
COLUMNS_OF_PLOTS = 1                    # TODO implement more general layout possibilities, at the moment only 1-column

chart_variables = {
    "cpu_usage": {
        "order_number": 1,
        "title": "CPU Usage",
        "color": BASE_LINE_COLOR,
        "line_width": BASE_LINE_WIDTH,
        "x_interval_length": X_BASE_INTERVAL_LENGTH,
        "y_bottom": 0,
        "y_top": 100,
        "x_label": "Time in epochs",
        "y_label": "CPU usage in %",
        "x_values": [],
        "y_values": [],
        "anti_aliased": False,
    },

    "upc_usage": {
        "order_number": 2,
        "title": "UPC Usage",
        "color": BASE_LINE_COLOR,
        "line_width": BASE_LINE_WIDTH,
        "x_interval_length": X_BASE_INTERVAL_LENGTH,
        "y_bottom": 0,
        "y_top": 100,
        "x_label": "Time in epochs",
        "y_label": "UPC usage in %",
        "x_values": [],
        "y_values": [],
        "anti_aliased": True,
    },

    "test3": {
        "order_number": 3,
        "title": "test",
        "color": BASE_LINE_COLOR,
        "line_width": BASE_LINE_WIDTH,
        "x_interval_length": X_BASE_INTERVAL_LENGTH,
        "y_bottom": 0,
        "y_top": 100,
        "x_label": "Time in epochs",
        "y_label": "UPC usage in %",
        "x_values": [],
        "y_values": [],
        "anti_aliased": True,
    },

    "test4": {
        "order_number": 4,
        "title": "test",
        "color": BASE_LINE_COLOR,
        "line_width": BASE_LINE_WIDTH,
        "x_interval_length": X_BASE_INTERVAL_LENGTH,
        "y_bottom": 0,
        "y_top": 100,
        "x_label": "Time in epochs",
        "y_label": "UPC usage in %",
        "x_values": [],
        "y_values": [],
        "anti_aliased": True,
    },

    "test5": {
        "order_number": 5,
        "title": "test",
        "color": BASE_LINE_COLOR,
        "line_width": BASE_LINE_WIDTH,
        "x_interval_length": X_BASE_INTERVAL_LENGTH,
        "y_bottom": 0,
        "y_top": 100,
        "x_label": "Time in epochs",
        "y_label": "UPC usage in %",
        "x_values": [],
        "y_values": [],
        "anti_aliased": True,
    },

    "test6": {
        "order_number": 6,
        "title": "test",
        "color": BASE_LINE_COLOR,
        "line_width": BASE_LINE_WIDTH,
        "x_interval_length": X_BASE_INTERVAL_LENGTH,
        "y_bottom": 0,
        "y_top": 100,
        "x_label": "Time in epochs",
        "y_label": "UPC usage in %",
        "x_values": [],
        "y_values": [],
        "anti_aliased": True,
    },
}


def slice_arrays(max_array_length):
    if len(chart_variables["cpu_usage"]["x_values"]) > max_array_length:
        for key in chart_variables:
            chart_variables[key]["x_values"] = chart_variables[key]["x_values"][int(max_array_length / 2):]
            chart_variables[key]["y_values"] = chart_variables[key]["y_values"][int(max_array_length / 2):]


class Plots(Widget):
    def __init__(self):
        super(Plots, self).__init__()
        self.number_of_plots = len(chart_variables)
        self.t_start = time.time()
        self.chart, self.axes = plt.subplots(nrows=self.number_of_plots,
                                             ncols=COLUMNS_OF_PLOTS,
                                             facecolor=(0.9, 0.9, 0.9))
        plt.subplots_adjust(hspace=0.01)
        self.chart.patch.set_alpha(0)  # transparent plot background

    def initialize_plots(self):
        for ax, key in zip(self.axes.flat, chart_variables):
            ax.set_title(chart_variables[key]["title"], color=chart_variables[key]["color"])
            ax.tick_params(labelcolor=chart_variables[key]["color"])
            ax.set_xlabel(chart_variables[key]["x_label"], color=chart_variables[key]["color"])
            ax.set_ylabel(chart_variables[key]["y_label"], color=chart_variables[key]["color"])
            ax.set_ylim(bottom=chart_variables[key]["y_bottom"],
                        top=chart_variables[key]["y_top"])
            ax.set_frame_on(False)  # remove white background inside each subplot
            ax.spines['bottom'].set_color('white')
            ax.spines['left'].set_color('white')

    def plot_data(self):
        slice_arrays(MAX_MEASUREMENT_ARRAY_LENGTH)
        for ax, key in zip(self.axes.flat, chart_variables):
            x_axis_interval_length = chart_variables[key]["x_interval_length"]
            elapsed_time = time.time() - self.t_start
            number_of_intervals = elapsed_time // x_axis_interval_length  # index 0 to get div part only
            chart_variables[key]["x_values"].append(elapsed_time)
            chart_variables[key]["y_values"].append(psutil.cpu_percent())
            ax.plot(chart_variables[key]["x_values"],
                    chart_variables[key]["y_values"],
                    color=chart_variables[key]["color"],
                    linewidth=chart_variables[key]["line_width"],
                    antialiased=chart_variables[key]["anti_aliased"])
            self.chart.canvas.draw()
            x_left = x_axis_interval_length * number_of_intervals
            x_right = x_axis_interval_length * (number_of_intervals + 1)
            ax.set_xlim(left=x_left, right=x_right)

    def update_plots(self, _):
        self.plot_data()


class MyApp(App):

    def build(self):
        plot = Plots()
        plot.initialize_plots()
        Clock.schedule_interval(plot.update_plots, 0.2)
        scroll_view = ScrollView()
        box = BoxLayout()
        box.spacing = 24
        scroll_view.add_widget(box)
        box.add_widget(FigureCanvasKivyAgg(plt.gcf()))
        return scroll_view


if __name__ == "__main__":
    MyApp().run()

0 个答案:

没有答案