как отправить словарь цветов в dash graph, используя go.Гистограмма, для создания графиков разных цветов

#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 код:

  1. параметр marker=dict(color=python_list) должен быть : marker_color=python_list
  2. Этот параметр получает только список, а не python_dictionary.keys() то же самое для значений x exis. после того, как я изменил его на: x=list(x), marker_color=list(colors_count.keys()) он работал без каких-либо проблем