Search code examples
pythonwindowsplotly-dashnidaqmx

Plotly-Dash with nidaqmx, name 'task' is not defined error


I am using python through windows, and I am trying to read data from a NI 9234 using an accelerometer. I want this data to be remotely read and for that I am using Dash. While for the NI part, I was trying to use nidaqmx, using this example.

My dash program is easy right now and it was working without the nidaqmx part (doing something reaaaally easy), while the nidaqmx program was succesfully reading data from the sensor. If I try to merge them together, I get the following error: error message

Here is my script:

import dash
import dash_daq as daq
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.graph_objects as go
from dash.exceptions import PreventUpdate
import nidaqmx
from nidaqmx.constants import AcquisitionType
import numpy as np

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

# some color to this
colors = {
    'background': '#111111',
    'text': '#7FDBFF'
}

#Initial conditions to have something in the graph
trace_1 = go.Scatter(
    x = [],
    y = []
)

layout = go.Layout(title = 'Título de gráfica')
fig = go.Figure(data = [trace_1], layout = layout)

app.layout = html.Div(style = {'backgroundColor': colors['background']},
    children = [

# H3 es para marcar el título, es el mediano que los demás, H1 es súper grande.
    html.H3(
        children = 'Ejemplo fácil para chequear botones-gráficas-menus', 
            style = {
            'textAlign': 'center',
            'color': colors['text']
        }
    ),

# Div parece que divide éste párrafo abajo de lo anterior
    html.Div(
        id= 'respuesta',
        children= 'Clickea el botón',
          style = {
            'textAlign': 'center',
            'color': colors['text']
        }
    ),
# Se define el botón:
    daq.BooleanSwitch(
        id = 'Swtc_1',
        label = 'Capturar',
        on = False
    ),
    
    html.Div(
        [
        html.Br(),
        html.Br(),
        html.Label(
            ['Elija algo'],
            style = {
                'font-weight': 'bold',
                'text-align': 'center',
                'color': colors['text']
            }
        ),
        dcc.Dropdown(
            id = 'f_muestreo',
                options = [
                    {'label' : '2048', 'value':'2048'},
                    {'label' : '2560', 'value':'2560'},
                    {'label' : '3200', 'value':'3200'},
                    {'label' : '5120', 'value':'5120'},
                    {'label' : '6400', 'value':'6400'},
                    {'label' : '10240', 'value':'10240'},
                    {'label' : '12800', 'value':'12800'},
                    {'label' : '25600', 'value':'25600'}
            ],
            value = '2048',
            multi = False,
            disabled = False,
            persistence = 'string',
            persistence_type = 'session'
        ),
        html.Br(),
        dcc.Dropdown(
            id = 'muestras',
                options = [
                    {'label' : '2048', 'value':'2048'},
                    {'label' : '4096', 'value':'4096'},
                    {'label' : '8192', 'value':'8192'},
                    {'label' : '16384', 'value':'16384'},
                    {'label' : '32768', 'value':'32768'},
                    {'label' : '65536', 'value':'65536'},
                    {'label' : '131072', 'value':'131072'}
            ],
            value = '2048',
            multi = False,
            disabled = False,
            persistence = 'string',
            persistence_type = 'session'
        )
        ],className = 'three columns'
    ),
        
# graph
    html.Div(
        [
        dcc.Graph(id = 'plot_id', figure = fig)
        ],className = 'eight columns'
    )
    ]
)

# interaction
@app.callback(
    Output('plot_id', 'figure'),
    [Input('Swtc_1', 'on'),
    Input('f_muestreo', 'value'),
    Input('muestras', 'value')]
    
)

def update_output(on, value_1, value_2):
    
    if on is True:
        sample_rate = float(value_1)
        samples_to_acq = float(value_2)
        wait_time = samples_to_acq/sample_rate
        #Name and channel of my NI 9234
        channel_name = 'cDAQBAYO1Mod1/ai0'
        #Not using the trig yet
        #trig_name = 'cDAQBAYO1Mod1/ai1'
        cont_mode = AcquisitionType.CONTINUOUS
        units_g = nidaqmx.constants.AccelUnits.G
        
        # Create accelerometer channel and configure sample clock and trigger specs
        task.ai_channels.add_ai_accel_chan(channel_name, units = units_g)
        task.timing.cfg_samp_clk_timing(sample_rate, sample_mode = cont_mode, samps_per_chan=samples_to_acq)
        #task.triggers.start_trigger.cfg_dig_edge_start_trig(trigger_source = trig_name)
    
        # Reading data from sensor and generating time data with numpy
        ydata = task.read(number_of_samples_per_channel=samples_to_acq)
        xdata = np.linspace(0, wait_time,samples_to_acq)
        
        trace_1 = go.Scatter(
            x = list(xdata),
            y = list(ydata)
        )
        layout = go.Layout(title = 'Oscilograma')
        fig = go.Figure(data = [trace_1], layout = layout)
        return (fig)
    else:
        raise PreventUpdate    
   

if __name__ == '__main__':
    app.run_server(port=3040, debug=True)

I was thinking that maybe dash is not supporting nidaqmx, and if that's the case a possible solution would be using the two scripts: one for doing the sensor reading, and the main one in dash to display the info to the user... However, I was trying to have everything in one script for clarification purposes.

Searched everywhere, but can't find nidaqmx being implemented into dash. Any help is greatly appreciated.


Solution

  • Thanks, dm2! Like you said, I was not declaring the task, I also ran into a ctypes problem that I need to research further, but for now I will declare my values as int. I am posting the solution because I guess that the world is full of newbs as myself:

    import dash
    import dash_daq as daq
    import dash_core_components as dcc
    import dash_html_components as html
    from dash.dependencies import Input, Output
    import plotly.graph_objects as go
    from dash.exceptions import PreventUpdate
    import nidaqmx
    from nidaqmx.constants import AcquisitionType
    import numpy as np
    
    
    
    external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
    
    app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
    
    # some color to this
    colors = {
        'background': '#111111',
        'text': '#7FDBFF'
    }
    
    #Initial conditions to have something in the graph
    trace_1 = go.Scatter(
        x = [],
        y = []
    )
    
    layout = go.Layout(title = 'Título de gráfica')
    fig = go.Figure(data = [trace_1], layout = layout)
    
    app.layout = html.Div(style = {'backgroundColor': colors['background']},
        children = [
    
    # H3 es para marcar el título, es el mediano que los demás, H1 es súper grande.
        html.H3(
            children = 'Ejemplo fácil para chequear botones-gráficas-menus', 
                style = {
                'textAlign': 'center',
                'color': colors['text']
            }
        ),
    
    # Div parece que divide éste párrafo abajo de lo anterior
        html.Div(
            id= 'respuesta',
            children= 'Clickea el botón',
              style = {
                'textAlign': 'center',
                'color': colors['text']
            }
        ),
    # Se define el botón:
        daq.BooleanSwitch(
            id = 'Swtc_1',
            label = 'Capturar',
            on = False
        ),
        
        html.Div(
            [
            html.Br(),
            html.Br(),
            html.Label(
                ['Elija algo'],
                style = {
                    'font-weight': 'bold',
                    'text-align': 'center',
                    'color': colors['text']
                }
            ),
            dcc.Dropdown(
                id = 'f_muestreo',
                    options = [
                        {'label' : '2048', 'value':'2048'},
                        {'label' : '2560', 'value':'2560'},
                        {'label' : '3200', 'value':'3200'},
                        {'label' : '5120', 'value':'5120'},
                        {'label' : '6400', 'value':'6400'},
                        {'label' : '10240', 'value':'10240'},
                        {'label' : '12800', 'value':'12800'},
                        {'label' : '25600', 'value':'25600'}
                ],
                value = '2048',
                multi = False,
                disabled = False,
                persistence = 'string',
                persistence_type = 'session'
            ),
            html.Br(),
            dcc.Dropdown(
                id = 'muestras',
                    options = [
                        {'label' : '2048', 'value':'2048'},
                        {'label' : '4096', 'value':'4096'},
                        {'label' : '8192', 'value':'8192'},
                        {'label' : '16384', 'value':'16384'},
                        {'label' : '32768', 'value':'32768'},
                        {'label' : '65536', 'value':'65536'},
                        {'label' : '131072', 'value':'131072'}
                ],
                value = '2048',
                multi = False,
                disabled = False,
                persistence = 'string',
                persistence_type = 'session'
            )
            ],className = 'three columns'
        ),
            
    # graph
        html.Div(
            [
            dcc.Graph(id = 'plot_id', figure = fig)
            ],className = 'eight columns'
        )
        ]
    )
    
    # interaction
    @app.callback(
        Output('plot_id', 'figure'),
        [Input('Swtc_1', 'on'),
        Input('f_muestreo', 'value'),
        Input('muestras', 'value')]
        
    )
    
    def update_output(on, value_1, value_2):
        
        if on is True:
            sample_rate = int(value_1)
            samples_to_acq = int(value_2)
            wait_time = samples_to_acq/sample_rate
            #Name and channel of my NI 9234
            channel_name = 'cDAQBAYO1Mod1/ai0'
            #Not using the trig yet
            #trig_name = 'cDAQBAYO1Mod1/ai1'
            cont_mode = AcquisitionType.CONTINUOUS
            units_g = nidaqmx.constants.AccelUnits.G
            with nidaqmx.Task() as task:
            # Create accelerometer channel and configure sample clock and trigger specs
                task.ai_channels.add_ai_accel_chan(channel_name, units = units_g)
                task.timing.cfg_samp_clk_timing(sample_rate, sample_mode = cont_mode, samps_per_chan=samples_to_acq)
                #task.triggers.start_trigger.cfg_dig_edge_start_trig(trigger_source = trig_name)
        
                # Reading data from sensor and generating time data with numpy
                ydata = task.read(number_of_samples_per_channel=samples_to_acq)
                xdata = np.linspace(0, wait_time,samples_to_acq)
            
                trace_1 = go.Scatter(
                    x = list(xdata),
                    y = list(ydata)
                )
                layout = go.Layout(title = 'Oscilograma')
                fig = go.Figure(data = [trace_1], layout = layout)
            return (fig)
        else:
            raise PreventUpdate    
       
    
    if __name__ == '__main__':
        app.run_server(port=3040, debug=True)
    

    The sensor is reading the data!!

    yay!!