Hi Jelle,
Thanks for this interesting question. I will answer your question based on the functionalities you requested:
-
Create an action button that creates and stores all graphs
For this, you could simply define an ActionButton
and store the Plotly graphs as JSON strings using Storage
. For more info on how to use Storage
, you can refer to this link: Results & visualizations - Storing results | VIKTOR Documentation
But for this, you do not necessarily have to use Storage
to save the graphs. Only in cases where it takes a considerable time to generate the graphs, I would maybe recommend using an ActionButton
to achieve this.
-
Select graph to visualize from DynamicArray
There are different approaches one could take. The easy way would be to simply have an OptionField
with a dynamic list of the dynamic array rows listed. When selecting the option, it takes the index of that row, and visualizes that graph. I made a simple snippet to demonstrate this case:
from viktor import ViktorController, UserError
from viktor.parametrization import ViktorParametrization, NumberField, DynamicArray, Step, TextField, \
OptionField, OptionListElement
from viktor.views import PlotlyView, PlotlyResult
def graph_options(params, **kwargs):
return [OptionListElement(label=row.name, value=idx) for idx, row in enumerate(params.step_1.array)]
class Parametrization(ViktorParametrization):
step_1 = Step('Step 1')
step_1.array = DynamicArray('Array')
step_1.array.name = TextField('Name')
step_1.array.a = NumberField('A', default=1)
step_1.array.b = NumberField('B', default=2)
step_1.array.c = NumberField('C', default=3)
step_1.array.d = NumberField('D', default=4)
step_2 = Step('Step 2', views=['get_plotly_view'])
step_2.select_array = OptionField('Select graph to visualize', options=graph_options)
class Controller(ViktorController):
label = '...'
parametrization = Parametrization
@PlotlyView('Results', duration_guess=10)
def get_plotly_view(self, params, **kwargs):
if params.step_2.select_array is None:
raise UserError('Select a graph to visualize')
row = params.step_1.array[params.step_2.select_array]
fig = {
"data": [{"type": "bar", "x": [1, 2, 3, 4], "y": [row.a, row.b, row.c, row.d]}],
"layout": {"title": {"text": f"Graph that is visualized: {row.name}"}}
}
return PlotlyResult(fig)
- Create a download button that automatically zips all created png figures together.
To achieve this, you will 1) need to convert your Plotly plots to PNGs, 2) bundle these PNGs to be zipped, and 3) add the logic to a DownloadButton
method. Luckily with VIKTOR, zipping files is a functionality that is included in the DownloadResult
. For more info on this, refer to this link.
For converting a Plotly plot to a PNG, you can follow the steps described here. Make sure to add kaleido
to your requirements.
Here is a snippet that combines all these steps.
def download_graphs(self, params, **kwargs):
zipped_files = {}
for row in params.step_1.array:
fig_dict = {
"data": [{"type": "bar", "x": [1, 2, 3, 4], "y": [row.a, row.b, row.c, row.d]}],
"layout": {"title": {"text": f"Graph that is visualized: {row.name}"}}
}
fig = go.Figure(fig_dict) # make sure to add plotly to requirements.txt
img_bytes = fig.to_image(format="png") # make sure to add kaleido to requirements.txt
zipped_files[f'{row.name}.png'] = File.from_data(img_bytes)
return DownloadResult(zipped_files=zipped_files, file_name='my_file.zip')
I hope this helps!
PS take note that kaleido gives some issues with some versions. For my local environment, I used kaleido==v0.1.0post1
in my requirements.