Jean-Pierre Schnyder
Jean-Pierre Schnyder

Reputation: 1934

How to print a Pandas Dataframe to a Kivy ScrollView Label conserving the Pandas columns format

Part of the Pandas DataFrame print out:

DataFrame.to_string()

Same part printed out in the Kivy ScrollView Label. We see that the columns formatting has been lost:

DataFrame.to_string() in the Kivy Label

Here's the Kivy code:

import pandas as pd 

from kivy.app import App
from kivy.config import Config
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.popup import Popup

OWNER = 'OWNER'
CAPITAL_USD = 'CAPITAL USD'
YIELD_USD = 'YIELD USD'
CAPITAL_CHF = 'CAPITAL CHF'
YIELD_CHF = 'YIELD CHF'
CAPITAL_EUR = 'CAPITAL EUR'
YIELD_EUR = 'YIELD EUR'
CAPITAL_DM = 'CAPITAL DM'
YIELD_DM = 'YIELD DM'

class ScrollablePopup(Popup):
    contentBox = ObjectProperty()
    scrollView = ObjectProperty()

    def scrollToTop(self):
        self.scrollView.scroll_y = 1 # force scrolling to top

    def scrollToBottom(self):
        self.scrollView.scroll_y = 0 # force scrolling to bottom

    def initText(self, text):
        self.contentBox.content.text = text


class ScrollPopup(BoxLayout):
    popup = None

    def openPopup(self):
        self.popup = ScrollablePopup(title="Scrollable popup")

        dfstr = self.createDataframe()
        print(dfstr)
        text = dfstr
        self.popup.initText(text)
        self.popup.open()

    def createDataframe(self):
        df = pd.DataFrame({OWNER: ['John', 'John', 'John', 'John', 'John', 'John', 'Rob', 'Rob', 'Rob', 'Rob', 'Rob',
                                   'Rob', 'Rob', 'Rob', 'Tom', 'Tom', 'Tom', 'Tom', 'Tom', 'Tom', 'Bob', 'Bob', 'Bob',
                                   'Bob', 'Bob'] * 3,
                           CAPITAL_USD: [10000, 5000, 20000, 4000, 3000] * 15,
                           YIELD_USD: [1000, 500, 2000, 400, 300] * 15,
                           CAPITAL_CHF: [10000, 5000, 20000, 4000, 3000] * 15,
                           YIELD_CHF: [1000, 500, 2000, 400, 300] * 15,
                           CAPITAL_EUR: [10000, 5000, 20000, 4000, 3000] * 15,
                           YIELD_EUR: [1000, 500, 2000, 400, 300] * 15,
                           CAPITAL_DM: [10000, 5000, 20000, 4000, 3000] * 15,
                           YIELD_DM: [1000, 500, 2000, 400, 300] * 15})

        # adding OWNER total rows

        dfGroupOwnerTotal = df.groupby([OWNER]).agg({CAPITAL_USD: 'sum',
                                                     YIELD_USD: 'sum',
                                                     CAPITAL_CHF: 'sum',
                                                     YIELD_CHF: 'sum',
                                                     CAPITAL_EUR: 'sum',
                                                     YIELD_EUR: 'sum',
                                                     CAPITAL_DM: 'sum',
                                                     YIELD_DM: 'sum'})
        totalDf = pd.DataFrame(columns=[OWNER,
                                        CAPITAL_USD,
                                        YIELD_USD,
                                        CAPITAL_CHF,
                                        YIELD_CHF,
                                        CAPITAL_EUR,
                                        YIELD_EUR,
                                        CAPITAL_DM,
                                        YIELD_DM])
        currentOwner = df.loc[1, OWNER]
        totalDfIndex = 0

        # deactivating SettingWithCopyWarning caueed by totalRow[OWNER] += ' total'
        pd.set_option('mode.chained_assignment', None)

        for index, row in df.iterrows():
            if currentOwner == row[OWNER]:
                totalDf = totalDf.append({OWNER: row[OWNER],
                                          CAPITAL_USD: row[CAPITAL_USD],
                                          YIELD_USD: row[YIELD_USD],
                                          CAPITAL_CHF: row[CAPITAL_CHF],
                                          YIELD_CHF: row[YIELD_CHF],
                                          CAPITAL_EUR: row[CAPITAL_EUR],
                                          YIELD_EUR: row[YIELD_EUR],
                                          CAPITAL_DM: row[CAPITAL_DM],
                                          YIELD_DM: row[YIELD_DM]}, ignore_index=True)
            else:
                totalRow = dfGroupOwnerTotal.loc[currentOwner]
                totalDf = totalDf.append(totalRow, ignore_index=True)
                totalDf.iloc[totalDfIndex][OWNER] = currentOwner + ' total'
                totalDfIndex += 1
                totalDf = totalDf.append({OWNER: row[OWNER],
                                          CAPITAL_USD: row[CAPITAL_USD],
                                          YIELD_USD: row[YIELD_USD],
                                          CAPITAL_CHF: row[CAPITAL_CHF],
                                          YIELD_CHF: row[YIELD_CHF],
                                          CAPITAL_EUR: row[CAPITAL_EUR],
                                          YIELD_EUR: row[YIELD_EUR],
                                          CAPITAL_DM: row[CAPITAL_DM],
                                          YIELD_DM: row[YIELD_DM]}, ignore_index=True)
                currentOwner = row[OWNER]
            totalDfIndex += 1

        totalRow = dfGroupOwnerTotal.loc[currentOwner]
        totalDf = totalDf.append(totalRow, ignore_index=True)
        totalDf.iloc[totalDfIndex][OWNER] = currentOwner + ' total'

        return totalDf.to_string()


class ScrollPopupVertHorzPandasApp(App):
    def build(self): # implicitly looks for a kv file of name kivylistview1111.kv which is
                     # class name without App, in lowercases

        Config.set('graphics', 'width', '400')
        Config.set('graphics', 'height', '500')
        Config.write()

        return ScrollPopup()

    def on_pause(self):
        # Here you can save data if needed
        return True

    def on_resume(self):
        # Here you can check if any data needs replacing (usually nothing)
        pass

if __name__ == '__main__':
    ScrollPopupVertHorzPandasApp().run()

scrollpopupverthorzpandas.kv

<ScrollPopup>:
    orientation: "vertical"
    popupButton: popup_button

    BoxLayout:
        size_hint_y: None
        Button:
            id: popup_button
            text: "Open scrollable popup"
            size_hint_y: None
            height: "40dp"
            on_press: root.openPopup()

<ScrollablePopup>:
    id: scr_popup
    auto_dismiss: False
    contentBox: content_box
    scrollView: scroll_view
    padding:10, 10

    BoxLayout:
        id: content_box
        orientation: "vertical"
        content: content_text

        ScrollView:
            id: scroll_view
            effect_cls: "ScrollEffect" # prevents overscrolling
            do_scroll_x: True # limiting to vertical scrolling
            Label:
                id: content_text
                size_hint_x: None # requnred for horizontal scrolling to work
                size_hint_y: None # requnred for horizontal scrolling to work
                height: self.texture_size[1] # required for vertical scrolling to work
                width: self.texture_size[0]  # Set the Label width to the text width.
                                             # Requnred for horizontal scrolling to work
                line_height: 1
                valign: "top"

        Button:
            text: "Scroll to top"
            size_hint_y: None
            height: "40dp"
            on_press: scr_popup.scrollToTop()

        Button:
            text: "Scroll to bottom"
            size_hint_y: None
            height: "40dp"
            on_press: scr_popup.scrollToBottom()

        Button:
            text: "Close"
            size_hint_y: None
            height: "40dp"
            on_press: root.dismiss()

My question is: how can we keep the Pandas DataFrame columns formatting in the Kivy ScrollView Label ?

Upvotes: 0

Views: 513

Answers (1)

Jean-Pierre Schnyder
Jean-Pierre Schnyder

Reputation: 1934

Here's the solution. To implement it, I did download the JetBrainsMono open source font and stored the JetBrainsMono-Regular.ttf file in the same directory as the kv file.

Here's the solution for the Label version:

Label:
    font_name: 'JetBrainsMono-Regular'
    font_size: '12' # ok on Windows but much too smallon Android

and for a TextInput version:

TextInput:
    font_name: 'JetBrainsMono-Regular'
    font_size: '12' # ok on Windows but much too smallon Android
    background_color: 43, 43, 43, 0.18
    cursor_color: 1, 1, 1, 1
    foreground_color: 1, 1, 1, 1

Result of the label version

Upvotes: 1

Related Questions