✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
🐇 Announcing Dash VTK for 3d simulation graphics. Check out the March webinar.

Make a Dynamic Matrix

Hi, I’ve been working on a personal project using Dash and I’ve run into a bit of a speed bump. I’ve never posted to a coding site asking for help or anything like that so I have no idea how to format code or how to frame my question so apologies in advance.

What I want:
The ability to make a matrix (min:2, max:5) using two dropdowns, representing number of rows and columns. I got to the point where I could make a matrix using the methods below but I couldn’t find a way to actually listen to the user input without hardcoding the matrix size.

This is the method used to make a table. The ids and everything line up with what I want properly. I just call this method inside a html.Table() and it works fine.
def generate_table(row_number, column_number, table_id):
tr_list = []
row_id = 0
for r in range(row_number):
row = []
row_id += 1
col_id = 0
for c in range(column_number):
col_id += 1
id = ‘t’ + str(table_id) + ‘_r’ + str(row_id) + ‘_c’ + str(col_id)
row.append(html.Td(dcc.Input(type=‘text’, id=id, placeholder=id)))
tr_list.append(html.Tr(row))
return tr_list

This is the callback I was using to get the user input.
@app.callback(Output(credentials_2x2.get(‘output_id’), ‘children’),
[Input(credentials_2x2.get(‘submit_id’), ‘n_clicks’)],
[State(‘t{}_r{}_c{}’.format(t, r, c), ‘value’) for t in range(1, 3) for r in
range(1, 3) for c in range(1, 3)])
def answer_matrix_2x2(click, *args):
print(‘Answering matrix 2x2’)
if click is None:
print(‘Dummy call…’)
return

return html.Div([
    html.P('Answer'),
])

If the matrix size is hardcoded like it is above it works - the issue is in making a dynamic matrix.

I’ve tried using global variables to represent the matrix size and then updating the initial value to whatever the dropdowns are set to but that does not work; the states only recognize whatever the initial value was set to. I know that Dash and global variables don’t play well so I wasn’t too surprised about that.

I’ve also tried using the table from dash-table-experiments but I wasn’t even able to get it to show up if it was in a callback or method. If it was directly in the app layout it worked fine.

I’ve tried using a hidden div that is updated with the correct states to use when the matrix is generated and then using that as an input but that also didn’t work. States are not json serializable.

I’ve kind of given up on making a dynamic matrix and I’ve just hardcoded a couple matrixes in my layout. It’s not ideal for what I’m trying to do but its acceptable since its just a personal project. But after banging my head against this for so long I’d like to hear someone else’s opinion and hopefully figure it out. I tried to share as little code as possible to illustrate the core problem but I’m willing to share as much as needed. Thanks!

Figured it out. Here’s the code:
Generate a callback for every possible combination of input.

for value1, value2 in itertools.product(
# For each dropdown (One defining # of rows, the other defining # of columns
[o[‘value’] for o in app.layout[‘row_dropdown’].options],
[o[‘value’] for o in app.layout[‘column_dropdown’].options]):
app.callback(
# Get the output from dictionary depending on what the current row and column number is
Output(answer_options.get(str(value1)).get(str(value2)), ‘children’),
# Input will always be the same - a button
[Input(‘answer_matrix_submit_button’, ‘n_clicks’)],
# Have to generate states representing the dcc.Inputs based on what the current row/col count is. +1 because it’s a list
[State(‘t{}_r{}_c{}’.format(t, r, c), ‘value’) for t in range(1, 3) for r in
range(1, value1 + 1) for c in range(1, value2 + 1)] + [State(‘answer_matrix_radio’, ‘value’)])(
generate_output_callback(value1, value2)
)