【问题标题】:Kivy garden graph: axes are drawn but plot is missingKivy 花园图:绘制了轴但缺少情节
【发布时间】:2018-03-26 09:46:08
【问题描述】:

关于以下代码,它是我的计算游戏应用程序的子集,我有两个问题:

1) 为什么dummy_series 没有绘制,虽然坐标轴(带有刻度和标签已绘制)

2) 如何获得退出按钮以正确退出应用程序(它是否必须从根小部件中删除所有小部件?是否有与 AppObject.run() 相反的,停止应用程序? - 已解决:App.get_running_app ().stop()

对于第一个问题,代码的相关部分在StatisticScreenPlotScreen 类中找到。第一个创建dummy_series,初始化图形小部件的创建并将屏幕更改为PlotScreen。在PlotScreen类中,有showPlot的方法,基本上是从github README复制过来的。

到目前为止,我尝试将整体背景颜色更改为白色。既是通过“画布之前”一个白色矩形,又是通过真正改变窗口的背景颜色。两者都没有效果(除了轴和标签被隐藏,因为它们也是白色的)。然后我尝试在每次创建图表时对图表进行不同的着色(取自同一个 github 存储库,if __name__ == '__main__': 中有一个 TestApp)。但仍然没有图表。

对于第二个问题,请考虑CalculationRootchangeScreen 方法。如果以quit 作为参数调用它,当前它只是清空screen_list 并返回False。这个想法是调用“返回”按钮的回调(key=27,1000)。由于使用“后退”按钮关闭应用程序实际上可以工作,鉴于screen_list 是空的,我想我可以使用这个现有的过程。同样调度app对象CalculationAppkeyHandler-方法也没有想要的关闭app的效果。

# Python build-in Modules
import os
import operator                 # better handling of +, #, *, etc.
import webbrowser               # access homepages via the about section
import random                   # create random math questions
import datetime                 # for the timer
import itertools                # eg for cycling colors
from functools import partial   # schedule callback functions that take arguments different from 'dt'

# Kivy
from kivy.lang.builder import Builder
from kivy.app import App
from kivy.core.window import Window
from kivy.utils import platform
from kivy.uix.screenmanager import Screen
from kivy.properties import ObjectProperty, NumericProperty, StringProperty
from kivy.storage.dictstore import DictStore
from kivy.utils import get_color_from_hex as rgb

from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView

from kivy.clock import Clock
from kivy.uix.label import Label
from kivy.logger import Logger

from kivy.garden.graph import Graph, MeshLinePlot, SmoothLinePlot

# Non-standard python
import numpy as np







###############################################################################
# Constants
###############################################################################

BACKGROUND_COLOR = [0,0,0,0]
TEXT_COLOR = [1,1,1,1]

kv_string = """

#:import Factory kivy.factory.Factory

#:set color_button (0.784, 0.4, 0.216, 1)  # brown
#:set color_button_pressed (0.659, 0.3, 0.431, 1)  # darker brown
#:set color_background_down '(0.4, 0.4, 0.4, 1)'  # purple

<WrappedLabel@Label>:
    size_hint_y: None
    height: self.texture_size[1] + self.texture_size[1]/2
    markup: True

<GridLabel@Label>:
    font_size: min(root.width, root.height) * .3

<StatisticsSpinner@Spinner>:
    background_color: color_button if self.state == 'normal' else color_button_pressed  
    background_down: color_background_down
    option_cls: Factory.get("SpinnerLabel")

<SpinnerLabel@SpinnerOption>:
    background_color: color_button if self.state == 'down' else color_button_pressed
    background_down: color_background_down

<CalculationRoot>:
    orientation: 'vertical'
    cg_screen_manager: cg_screen_manager
    statistic_screen: statistic_screen
    plot_screen: plot_screen

    ScreenManager:
        id: cg_screen_manager
        StartScreen:
            name: 'StartScreen'
        StatisticScreen:
            id: statistic_screen
            name: 'StatisticScreen'
        PlotScreen:
            id: plot_screen
            name: 'PlotScreen'

<StartScreen@Screen>:
    BoxLayout:
        orientation: 'vertical'
        padding: root.width * .02, root.height * .02
        spacing: min(root.width, root.height) * .02

        WrappedLabel:
            text: '[b] Calculation Game [/b]'
            font_size: min(root.width, root.height) * .1

        Button:
            text: 'Statistic'
            on_release: app.root.changeScreen(self.text.lower())

        Button:
            text: 'Quit'           

<StatisticScreen@Screen>:
    stats_operation_spinner: stats_operation_spinner
    stats_difficulty_spinner: stats_difficulty_spinner
    stats_num_questions_button: stats_num_questions_button
    BoxLayout:
        orientation: 'vertical'
        padding: root.width * .02, root.height * .02
        spacing: min(root.width, root.height) * .02

        WrappedLabel:
            text: '[b] Statistics [/b]'
            halign: 'center'
            font_size: min(root.width, root.height) * .1

        GridLayout:
            size_hint: .9,.4
            cols: 2
            pos_hint: {'center_x': .5}
            GridLabel:
                text: 'Operation Type'
            StatisticsSpinner:
                id: stats_operation_spinner
                text: '+'
                values: ['+', '-', '*', ':', '%']
            GridLabel:
                text: 'Difficulty'
            StatisticsSpinner:
                id: stats_difficulty_spinner
                text: '1'
                values: ['1','2','3','4']
            GridLabel:
                text: 'Number of Questions'
            Button:
                id: stats_num_questions_button
                text: '8'
                on_release: app.root.statistic_screen.switchNumQuestions(self, self.text)
                # on_release: self.text = '16' if self.text == '8' else self.text = '8'
                background_color: color_button if self.state == 'normal' else color_button_pressed
        Button:
            size_hint: 1, .2
            text: 'Plot'
            on_release: app.root.statistic_screen.showPlot()
            font_size: min(root.width, root.height) * .1


<PlotScreen@Screen>:

"""



###############################################################################
# Widgets
###############################################################################



class StatisticScreen(Screen):
    """ Selection screen, where you can fix the parameters for 
        a pot of your statistics. 
    """
    def __init__(self, *args, **kwargs):
        super(StatisticScreen, self).__init__(*args, **kwargs)       


    def showPlot(self):
        """ 'onPlotButtonPress'
            callback for the 'plot'-Button on the bottom of StatisticScreen 
        """

        dummy_series = np.random.randint(1, 10, (12,))        
        App.get_running_app().root.ids.plot_screen.createKivyPlot(dummy_series)
        App.get_running_app().root.changeScreen('plot')


    def switchNumQuestions(self, instance, text):
        """ 'onNumQuestionsButtonPress'
            callback for the 'choose number of questions'-button. 
        """
        if int(text) == 16:
            instance.text = '8'
        else:
            instance.text = '16'



class PlotScreen(Screen):
    def __init__(self, *args, **kwargs):        
        super(PlotScreen, self).__init__(*args, **kwargs)  
        self.series = None     
        self.graph_figure = None        # error if uncommented... why? (referred to former name self.canvas)
        self.colors = itertools.cycle([rgb('7dac9f'), rgb('dc7062'), rgb('66a8d4'), rgb('e5b060')])


    def createKivyPlot(self, series=np.array(range(12))):
        graph_theme = {
                'label_options': {
                    'color': rgb('444444'),  # color of tick labels and titles
                    'bold': True},
                'background_color': rgb('f8f8f2'),  # back ground color of canvas
                'tick_color': rgb('808080'),  # ticks and grid
                'border_color': rgb('808080')}  # border drawn around each graph

        self.graph_figure = Graph(xlabel='Last 12 games', ylabel='Average Response Time', x_ticks_minor=1,
        x_ticks_major=5, y_ticks_major=1,
        y_grid_label=True, x_grid_label=True, padding=10,
        x_grid=True, y_grid=True, xmin=0, xmax=len(series), ymin=0, ymax=int(1.5*max(series)), **graph_theme)
        plot = SmoothLinePlot(mode='line_strip', color=next(self.colors))
        plot.points = [(x, series[x]) for x in range(0, len(series))]
        self.graph_figure.add_plot(plot)

        self.add_widget(self.graph_figure)

    def destroy(self): 

        self.remove_widget(self.graph_figure)
        self.graph_figure = None


###############################################################################
# Root Widget
###############################################################################

class CalculationRoot(BoxLayout):
    """ Root of all widgets
    """
    calculation_screen = ObjectProperty(None)
    def __init__(self, *args, **kwargs):
        super(CalculationRoot, self).__init__(*args, **kwargs)
        self.screen_list = [] # previously visited screens


    def changeScreen(self, next_screen):
        if self.screen_list == [] or self.ids.cg_screen_manager.current != self.screen_list[-1]:
            self.screen_list.append(self.ids.cg_screen_manager.current)

        if next_screen == 'start':
            self.ids.cg_screen_manager.current = 'StartScreen'
        elif next_screen == 'statistic':
            self.ids.cg_screen_manager.current = 'StatisticScreen'          
        elif next_screen == 'plot':
            self.ids.cg_screen_manager.current = 'PlotScreen'       
        elif next_screen == 'quit':
            self.screen_list == []
            #self.onBackBtnPress()    # not working
            #Clock.schedule_once(partial(App.get_running_app().keyHandler(27)), 0)    # not working
            return False

    def onBackBtnPress(self):
        if self.screen_list:
            self.ids.cg_screen_manager.current = self.screen_list.pop()
            return True
        return False



###############################################################################
# App Object
###############################################################################

class CalculationApp(App):
    """ App object
    """
    def __init__(self, *args, **kwargs):
        super(CalculationApp, self).__init__(*args, **kwargs)
        self.use_kivy_settings = False


    def keyHandler(self, *args):
        key = args[1]
        print(key)

        if key in (1000, 27):
            return self.root.onBackBtnPress()

    def post_build_init(self, ev):
        if platform == 'android':
            pass

        win = self._app_window
        win.bind(on_keyboard = self.keyHandler)

    def build(self):
        Builder.load_string(kv_string)
        self.bind(on_start=self.post_build_init)
        return CalculationRoot()


if __name__ in ('__main__', '__android__'):
    CalculationApp().run()

【问题讨论】:

  • 关闭应用可以使用App.get_running_app().stop()

标签: python plot graph kivy


【解决方案1】:

显然,在 ScreenManager 中使用 kivy.garden.graph 已经有一段时间了。根据this issue report 的说法,它已在 kivy 版本 v1.10.1.dev0 中修复。但是,我认为您可以通过在对 Graph() 的调用中添加 _with_stencilbuffer=False 来解决此问题。

要停止应用,您可以在StartScreen 部分修改您的kv_string 以包括:

    Button:
        text: 'Quit'
        on_release: app.stop() 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-19
    • 2020-02-28
    • 1970-01-01
    • 2022-09-17
    • 1970-01-01
    相关资源
    最近更新 更多