#python #python-3.x #redis #kivy #plotly-dash
#python #python-3.x #redis #kivy #plotly-dash
Вопрос:
Я создал приложение, которое использует приложение kivy для пользовательского интерфейса, python для логики и dash для некоторых графиков. Приложение kivy отправляет цвет (шестнадцатеричный формат) в dash graph через python, и dash должен представлять живой график с использованием цветов kivy. Я попытался использовать эту логику для отправки цветов для dash:
data = [go.Histogram(histfunc='sum', y=y, x=x, marker=dict(color=colors_count.keys()))]
return {'data': data, 'layout': go.Layout(yaxis=dict(range=[0, maxY]))}
Когда colors_count.keys() представляет собой список цветов в шестнадцатеричном формате.
Но я получаю эту ошибку:
[2020-11-17 20:00:41,884] ERROR in app: Exception on /_dash-update-component [POST]
Traceback (most recent call last):
File "C:UsersOwnerAnaconda3libsite-packagesflaskapp.py", line 2446, in wsgi_app
response = self.full_dispatch_request()
File "C:UsersOwnerAnaconda3libsite-packagesflaskapp.py", line 1951, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:UsersOwnerAnaconda3libsite-packagesflaskapp.py", line 1820, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "C:UsersOwnerAnaconda3libsite-packagesflask_compat.py", line 39, in reraise
raise value
File "C:UsersOwnerAnaconda3libsite-packagesflaskapp.py", line 1949, in full_dispatch_request
rv = self.dispatch_request()
File "C:UsersOwnerAnaconda3libsite-packagesflaskapp.py", line 1935, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "C:UsersOwnerAnaconda3libsite-packagesdashdash.py", line 1457, in dispatch
response.set_data(self.callback_map[output]["callback"](*args))
File "C:UsersOwnerAnaconda3libsite-packagesdashdash.py", line 1337, in add_context
output_value = func(*args, **kwargs) # %% callback invoked %%
File "C:/Users/Owner/Desktop/CIM/lab_6/myDash.py", line 112, in idkun
data = [go.Histogram(histfunc='sum', y=y, x=x, marker=dict(color=colors_count.keys()))]
File "C:UsersOwnerAnaconda3libsite-packagesplotlygraph_objs__init__.py", line 60607, in __init__
self["marker"] = marker if marker is not None else _v
File "C:UsersOwnerAnaconda3libsite-packagesplotlybasedatatypes.py", line 3482, in __setitem__
self._set_compound_prop(prop, value)
File "C:UsersOwnerAnaconda3libsite-packagesplotlybasedatatypes.py", line 3836, in _set_compound_prop
val = validator.validate_coerce(val, skip_invalid=self._skip_invalid)
File "C:UsersOwnerAnaconda3libsite-packages_plotly_utilsbasevalidators.py", line 2444, in validate_coerce
v = self.data_class(v, skip_invalid=skip_invalid)
File "C:UsersOwnerAnaconda3libsite-packagesplotlygraph_objshistogram__init__.py", line 1914, in __init__
self["color"] = color if color is not None else _v
File "C:UsersOwnerAnaconda3libsite-packagesplotlybasedatatypes.py", line 3490, in __setitem__
self._set_prop(prop, value)
File "C:UsersOwnerAnaconda3libsite-packagesplotlybasedatatypes.py", line 3777, in _set_prop
raise err
File "C:UsersOwnerAnaconda3libsite-packagesplotlybasedatatypes.py", line 3772, in _set_prop
val = validator.validate_coerce(val)
File "C:UsersOwnerAnaconda3libsite-packages_plotly_utilsbasevalidators.py", line 1359, in validate_coerce
self.raise_invalid_val(v)
File "C:UsersOwnerAnaconda3libsite-packages_plotly_utilsbasevalidators.py", line 283, in raise_invalid_val
valid_clr_desc=self.description(),
ValueError:
Invalid value of type 'builtins.dict_keys' received for the 'color' property of histogram.marker
Received value: dict_keys(['#668cff', '#ef7fff', '#624cff', '#4cff79', '#ffaf7f'])
The 'color' property is a color and may be specified as:
- A hex string (e.g. '#ff0000')
- An rgb/rgba string (e.g. 'rgb(255,0,0)')
- An hsl/hsla string (e.g. 'hsl(0,100%,50%)')
- An hsv/hsva string (e.g. 'hsv(0,100%,100%)')
- A named CSS color:
aliceblue, antiquewhite, aqua, aquamarine, azure,
beige, bisque, black, blanchedalmond, blue,
blueviolet, brown, burlywood, cadetblue,
chartreuse, chocolate, coral, cornflowerblue,
cornsilk, crimson, cyan, darkblue, darkcyan,
darkgoldenrod, darkgray, darkgrey, darkgreen,
lightgoldenrodyellow, lightgray, lightgrey,
yellow, yellowgreen
- A number that will be interpreted as a color
according to histogram.marker.colorscale
- A list or array of any of the above
Мое приложение kivy:
Mimshak:
<Mimshak>:
# Initialization
shem:name
color:tseva
report:report
right:right
left:left
forward:forward
back:back
orientation:'vertical'
BoxLayout:
size_hint_y:0.1
padding:'5dp'
spacing:'5dp'
Label:
text:'Set Name of RoboLego:'
TextInput:
id:name
# start the button after the user insert name to the RoboLego
on_touch_up:if len(self.text)>0:start.disabled=False
ToggleButton:
id:start
text:'Start'
disabled:True
# activating Mimshak.start() funcion
on_press:root.start()
BoxLayout:
size_hint_y:0.1
padding:'5dp'
spacing:'5dp'
Label:
text:'Press to report the color'
Button:
# disable this button until "start" buttom is pressed
disabled:True
id:report
text:'Report Color'
# activating Mimshak.reportColor() funcion
on_press:root.reportColor()
BoxLayout:
ColorPicker:
id:tseva
BoxLayout:
padding:'5dp'
spacing:'10dp'
size_hint_y:0.1
Button:
id:forward
# disable this button until "start" buttom is pressed
disabled:True
text:'Forward'
# activating Mimshak.kadima() funcion
on_press:root.kadima()
Button:
id:right
# disable this button until "start" buttom is pressed
disabled:True
text:'Right'
# activating Mimshak.yamina() funcion
on_press:root.yamina()
Button:
id:left
#disable this button until "start" buttom is pressed
disabled:True
text:'Left'
# activating Mimshak.smola() funcion
on_press:root.smola()
Button:
id:back
# disable this button until "start" buttom is pressed
disabled:True
text:'Back'
# activating Mimshak.backward() funcion
on_press: root.backward()
Button:
text:'Stop'
# activating Mimshak.stop() funcion
on_press:root.stop()
Button:
text:'Exit'
# activating Mimshak.exit() funcion
on_press:root.exit()
мое основное приложение на python:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
import redis, sys
class Mimshak(BoxLayout):
# Object properties
shem = ObjectProperty()
color = ObjectProperty()
left = ObjectProperty()
report = ObjectProperty()
right = ObjectProperty()
forward = ObjectProperty()
back = ObjectProperty()
def start(self):
# the key will be the name entered
self.r = redis.StrictRedis("127.0.0.1", 6379, 0, decode_responses=True, charset="utf-8")
self.brick = self.shem.text
self.r.set("brick:name", self.brick)
# initialize kivun to be stop
self.r.set(self.brick ":kivun", "Stop")
# at first all buttons are disabled
self.left.disabled = False
self.report.disabled = False
self.right.disabled = False
self.forward.disabled = False
self.back.disabled = False
# Setting the direction in the brick to whatever the user picked.
def kadima(self):
self.r.set(self.brick ':kivun', 'Forward')
def stop(self):
self.r.set(self.brick ':kivun', 'Stop')
def yamina(self):
self.r.set(self.brick ':kivun', 'Right')
def smola(self):
self.r.set(self.brick ':kivun', 'Left')
def backward(self):
self.r.set(self.brick ':kivun', 'Back')
def exit(self):
# the "Exit" button will close the window and will set the key's value to be "Exit" as wall
self.r.set(self.brick ':kivun', 'Exit')
sys.exit()
def reportColor(self):
print(self.color.hex_color)
# report the color the use choose in a hexa format
self.r.set(self.brick ':color', str(self.color.hex_color))
class KivyApp(App):
pass
if __name__ == '__main__':
KivyApp().run()
Мой Dash.py сценарий:
#!/usr/bin/env python
import dash
import dash_core_components as dcc
import dash_html_components as html
import redis
import plotly.graph_objs as go
from plotly.subplots import make_subplots
R = [0, 0]
Teta = [0, 0]
Counter = 0; DeltaBack = 0
XMarks = [0]; YMarks = [0]
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
FirstTime = True
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
r = redis.StrictRedis('127.0.0.1', 6379, 0, decode_responses=True, charset='utf-8') # Setting the server to localhost
brik = r.get('brick:name')
# set html layout
app.layout = html.Div([
html.Div([
html.Div([ # movements graph
html.H1('RoboLego Drive'), # set header for the movements graph
dcc.Interval(id='graph-update', interval=1 * 1000, n_intervals=0), # Time stamp that updates the number of intervals every 1000 milliseconds.
dcc.Graph(id='live-graph', animate=False)],className="six columns"), # Live graph that can be updated
html.Div([ #histogram graph
html.H2('Color Useg'), # set for the histogram graph
dcc.Interval( id='histogram-update', interval=1 * 1000, n_intervals=0), # Time stamp that updates the number of intervals every 1000 milliseconds.
dcc.Graph(id='histogram', animate=False)],className="six columns") # Live graph that can be updated
], className="row")
])
def update(val):
# Getting current color in the brick.
color = r.get(brik ':color')
return html.H2('Your color = {}'.format(color), style={'color': '{}'.format(color)})
# Every time the number of intervals is changed activate function "update" and the value returned is sent to Graph: live-graph
@app.callback(
dash.dependencies.Output('live-graph', 'figure'),
[dash.dependencies.Input('graph-update', 'n_intervals')])
# create and update the redotlogo movements graph
def idcun(val):
global Counter, DeltaBack, FirstTime, cnt
# Getting current color and the current direction
colorway = r.get(brik ':color')
kivun = r.get(brik ':kivun')
fig = make_subplots(1, 2) # Figure with 2 plots.
# Changing the direction of the robot according to the direction selected.
if kivun == 'Right':
Counter = 1
R.append(Counter)
dy = manageDy()
dy -= 0.5
Teta.append(Teta[-1] dy)
elif kivun == 'Left':
Counter = 1
R.append(Counter)
dy = manageDy()
dy = 0.5
Teta.append(Teta[-1] dy)
elif kivun == 'Forward':
Counter = 1
R.append(Counter)
dy = manageDy()
Teta.append(Teta[-1] dy)
elif kivun == 'Back':
Counter -= 1
R.append(Counter)
if FirstTime:
DeltaBack = Teta[-1]-Teta[-2]
FirstTime = False
Teta.append(Teta[-1]-DeltaBack)
elif kivun == 'Stop':
XMarks.append(Counter)
YMarks.append(Teta[-1])
# Plots.
data = [go.Scatter(mode='lines', x=list(R), y=list(Teta), name='Trajectory',),
go.Scatter(mode='markers', x=XMarks, y=YMarks, name='Stops', marker=dict(color='rgb(0, 0, 255)',size=12,), ),]
return {'data': data, 'layout': go.Layout(xaxis=dict(range=(0, 100)),
yaxis=dict(range=(-100, 100)),
colorway=[str(colorway)[:-2]]),}
"""create the histogram for the duration usages of the colors"""
# set a new dictionary to save the color as key and the number of usages as the value
colors_count = {}
# Every time the number of intervals is changed activate function "update_graphs" and the value returned is sent to Graph: histogram
@app.callback(
dash.dependencies.Output('histogram', 'figure'),
[dash.dependencies.Input('histogram-update', 'n_intervals')])
# get the current color and create an histogram to show the duration usages of every color
def idkun(val):
# get current color
current_color = str(r.get(brik ':color'))[:-2]
# update the duration usages for the color, if it the first time, create new key fo the color, and set the value to 1
if current_color in colors_count:
colors_count[current_color] = 1
else:
colors_count[current_color] = 1
# get all the colors that was in use as a list - for x- axis
x = colors_count.keys()
# get number of usages fir each colore - for y axis
y = [colors_count[k] for k in colors_count]
maxY = max(y)
# create histogram
data = [go.Histogram(histfunc='sum', y=y, x=x, marker=dict(color=colors_count.keys()))]
return {'data': data, 'layout': go.Layout(yaxis=dict(range=[0, maxY]))}
def manageDy():
global FirstTime
if not FirstTime:
dy = DeltaBack
FirstTime = True
else:
dy = Teta[-1] - Teta[-2]
return dy
if __name__ == '__main__':
app.run_server(debug=False)
Ответ №1:
После некоторого поиска я обнаружил две проблемы в моем Dash.py код:
- параметр
marker=dict(color=python_list)
должен быть :marker_color=python_list
- Этот параметр получает только список, а не
python_dictionary.keys()
то же самое для значений x exis. после того, как я изменил его на:x=list(x), marker_color=list(colors_count.keys())
он работал без каких-либо проблем