148 lines
5.3 KiB
Python
148 lines
5.3 KiB
Python
from kivycharts.graph import *
|
|
from kivy.clock import Clock
|
|
import numpy as np
|
|
|
|
if __name__ == '__main__':
|
|
import itertools
|
|
from math import sin, cos, pi
|
|
from random import randrange
|
|
from kivy.utils import get_color_from_hex as rgb
|
|
from kivy.uix.boxlayout import BoxLayout
|
|
from kivy.app import App
|
|
|
|
class TestApp(App):
|
|
|
|
def build(self):
|
|
b = BoxLayout(orientation='vertical')
|
|
# example of a custom theme
|
|
colors = itertools.cycle([
|
|
rgb('0000FF'), rgb('dc7062'), rgb('66a8d4'), rgb('e5b060')])
|
|
graph_theme = {
|
|
'label_options': {
|
|
'color': rgb('444444'), # color of tick labels and titles
|
|
'bold': True},
|
|
'background_color': rgb('f8f8f2'), # canvas background color
|
|
'tick_color': rgb('808080'), # ticks and grid
|
|
'border_color': rgb('808080')} # border drawn around each graph
|
|
|
|
graph = Graph(
|
|
xlabel='Cheese',
|
|
ylabel='Apples',
|
|
# x_ticks_minor=5,
|
|
# x_ticks_major=25,
|
|
x_ticks_major=5,
|
|
y_ticks_major=1,
|
|
y_grid_label=True,
|
|
x_grid_label=True,
|
|
padding=5,
|
|
xlog=False,
|
|
ylog=False,
|
|
x_grid=True,
|
|
y_grid=True,
|
|
xmin=-50,
|
|
xmax=50,
|
|
ymin=-1,
|
|
ymax=1,
|
|
**graph_theme)
|
|
|
|
"""
|
|
c = next(colors)
|
|
print(c)
|
|
plot = SmoothLinePlot(color=c)
|
|
plot.points = [(x / 10., sin(x / 50.)) for x in range(-500, 501)]
|
|
# for efficiency, the x range matches xmin, xmax
|
|
graph.add_plot(plot)
|
|
"""
|
|
|
|
plot = MeshLinePlot(color=next(colors))
|
|
plot.points = [(x / 10., cos(x / 50.)) for x in range(-500, 501)]
|
|
graph.add_plot(plot)
|
|
self.plot = plot # this is the moving graph, so keep a reference
|
|
|
|
"""
|
|
plot = MeshStemPlot(color=next(colors))
|
|
graph.add_plot(plot)
|
|
plot.points = [(x, x / 50.) for x in range(-50, 51)]
|
|
"""
|
|
plot = BarPlot(color=next(colors), bar_spacing=.72)
|
|
graph.add_plot(plot)
|
|
plot.bind_to_graph(graph)
|
|
plot.points = [(x, .1 + randrange(10) / 10.) for x in range(-50, 1)]
|
|
# Test the scatter plot
|
|
plot = ScatterPlot(color=next(colors), point_size=5)
|
|
graph.add_plot(plot)
|
|
plot.points = [(x, .1 + randrange(10) / 10.) for x in range(-50, 1)]
|
|
Clock.schedule_interval(self.update_points, 1 / 60.)
|
|
|
|
graph2 = Graph(
|
|
xlabel='Position (m)',
|
|
ylabel='Time (s)',
|
|
x_ticks_minor=0,
|
|
x_ticks_major=1,
|
|
y_ticks_major=10,
|
|
y_grid_label=True,
|
|
x_grid_label=True,
|
|
padding=5,
|
|
xlog=False,
|
|
ylog=False,
|
|
xmin=0,
|
|
ymin=0,
|
|
**graph_theme)
|
|
b.add_widget(graph)
|
|
|
|
if np is not None:
|
|
(xbounds, ybounds, data) = self.make_contour_data()
|
|
# This is required to fit the graph to the data extents
|
|
graph2.xmin, graph2.xmax = xbounds
|
|
graph2.ymin, graph2.ymax = ybounds
|
|
|
|
plot = ContourPlot()
|
|
plot.data = data
|
|
plot.xrange = xbounds
|
|
plot.yrange = ybounds
|
|
plot.color = [1, 0.7, 0.2, 1]
|
|
graph2.add_plot(plot)
|
|
|
|
b.add_widget(graph2)
|
|
self.contourplot = plot
|
|
|
|
Clock.schedule_interval(self.update_contour, 1 / 60.)
|
|
|
|
return b
|
|
|
|
def make_contour_data(self, ts=0):
|
|
omega = 2 * pi / 30
|
|
k = (2 * pi) / 2.0
|
|
|
|
ts = sin(ts * 2) + 1.5 # emperically determined 'pretty' values
|
|
npoints = 100
|
|
data = np.ones((npoints, npoints))
|
|
|
|
position = [ii * 0.1 for ii in range(npoints)]
|
|
time = [(ii % 100) * 0.6 for ii in range(npoints)]
|
|
|
|
for ii, t in enumerate(time):
|
|
for jj, x in enumerate(position):
|
|
data[ii, jj] = sin(
|
|
k * x + omega * t) + sin(-k * x + omega * t) / ts
|
|
return (0, max(position)), (0, max(time)), data
|
|
|
|
def update_points(self, *args):
|
|
self.plot.points = [
|
|
(x / 10., cos(Clock.get_time() + x / 50.))
|
|
for x in range(-500, 501)]
|
|
|
|
def update_contour(self, *args):
|
|
_, _, self.contourplot.data[:] = self.make_contour_data(
|
|
Clock.get_time())
|
|
# this does not trigger an update, because we replace the
|
|
# values of the arry and do not change the object.
|
|
# However, we cannot do "...data = make_contour_data()" as
|
|
# kivy will try to check for the identity of the new and
|
|
# old values. In numpy, 'nd1 == nd2' leads to an error
|
|
# (you have to use np.all). Ideally, property should be patched
|
|
# for this.
|
|
self.contourplot.ask_draw()
|
|
|
|
TestApp().run()
|