I created a Kivy app that is supposed to output the following: Row 1 (Spans across 3 columns): A graph of candlegraph Row 2 (3 columns): 1 graph in each column
The graphs update itself once every few seconds. I have only implemented code for the graph for row 1 and row 2 column 1. The code is shown below:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.clock import Clock
from kivy.properties import ListProperty, NumericProperty
from kivy.garden.matplotlib.backend_kivyagg import FigureCanvasKivyAgg
import matplotlib.pyplot as plt
class TestScreen(Widget):
TestNum = NumericProperty(0)
TestArray = ListProperty()
class Graph_Item(FigureCanvasKivyAgg):
def __init__(self, **kwargs):
super().__init__(plt.gcf(), **kwargs)
class AppLayoutTest(App):
def build(self):
# update graph every 10 seconds
Clock.schedule_interval(lambda dt: self.mainExecutable(), 10)
return TestScreen()
def PlotCandlegraph(self, Data):
plt.clf()
for x in range(len(Data['Close'])):
thickHeight = abs(Data['Close'][x] - Data['Open'][x])
thinHeight = abs(Data['High'][x] - Data['Low'][x])
thinBottom = Data['Low'][x]
if Data['Close'][x] > Data['Open'][x]:
thickBottom = Data['Open'][x]
candleColor = 'green'
else:
thickBottom = Data['Close'][x]
candleColor = 'red'
plt.bar(x=Data.index[x], height=thickHeight, width=0.005, bottom=thickBottom, color=candleColor)
plt.bar(x=Data.index[x], height=thinHeight, width=0.002, bottom=thinBottom, color=candleColor)
plt.grid(True)
plt.title("Candlegraph")
graph = self.root.ids.Candlegraph
graph.figure = plt.gcf()
graph.draw()
def mainExecutable(self):
# input from somewhere else
self.PlotCandlegraph(Data=RawData)
self.TestPlot()
def TestPlot(self):
self.root.TestNum += 1
self.root.TestArray.append(self.root.TestNum)
plt.clf()
plt.plot(self.root.TestArray, color='r')
plt.grid(True)
plt.title("Test Graph")
graph = self.root.ids.LossGraph
graph.figure = plt.gcf()
graph.draw()
if __name__ == '__main__':
AppLayoutTest().run()
The kv file is shown here:
<TestScreen>
GridLayout:
rows: 2
size: root.width, root.height
Graph_Item:
id: Candlegraph
GridLayout:
cols: 3
Graph_Item:
id: LossGraph
Label:
text: "RewardGraph"
Label:
text: "Information"
This is the result on the first cycle of the code: 1
Am I using the libary wrong? Is there a way to keep the graph at a certain size that spans across however many columns?
When I remove the plot from the second row by replacing the graph with a label instead, the following is shown and does not get squished however many cycle it runs: 2
I also tried defining the size of the plots using the matplotlib library's plt.figsize() and still did not work.
Can someone tell me how to get the graph to span across 3 columns on the first row please?
The problem is that methods like plt.clf()
, plt.bar()
, plt.grid()
, and plt.title()
all refer to the current figure. In your app, you have two Graph_Item
instances, but only one figure
. The figure
reacts to the size
of the Graph_Item
, but since there is only one figure, the sizing is confused.
You can fix this by creating a new figure
for each Graph_Item
instance:
class Graph_Item(FigureCanvasKivyAgg):
def __init__(self, **kwargs):
super().__init__(plt.figure(), **kwargs)
Then, in your PlotCandlegraph()
method, you can use the saved plt_num
to activate the correct figure
:
def PlotCandlegraph(self, Data):
plt_num = self.root.ids.Candlegraph.figure.number
plt.figure(num=plt_num)
plt.clf()
The plt.figure()
method activates the figure with the specified num
(or creates a new figure
). See the documentation