How to make your own widget
Guide explains how to create and add your own widget to Supervisely SDK
In this tutorial you will learn how to create your own widget, add it to Supervisely SDK and make small demo.
How to create your own widget
Clone SDK repo:
git clone https://github.com/supervisely/superviselyClone repo with widgets samples:
git clone https://github.com/supervisely-ecosystem/ui-widgets-demosCreate SDK folder symlink in ui-widgets-demos
ln -s ./supervisely/supervisely ./ui-widgets-demos/superviselyCreate folder in
supervisely/app/widgets/<your_widget_folder>like thatyour_widget_folder |____ __init__.py |____ template.html |____ script.js # optional: you can add javascript file |____ your_widget.pyDeclare a new class with inheritance from Widget in
your_widget.pyfrom supervisely.app.widgets import Widget from supervisely.app.content import StateJson, DataJson class YourWidget(Widget): # ------ Required methods ------ def __init__( self, data_1: list data_2: dict ): self._data_1 = data_1 self._data_2 = data_2 self._some_state_attribute_1 = True self._some_state_attribute_2 = 42 super(YourWidget, self).__init__(widget_id=widget_id, file_path=__file__) # ------ Optional | Add your javascript file ------ # script_path = "./sly/css/app/widgets/your_widget_folder/script.js" # change <your_widget_folder> # JinjaWidgets().context["__widget_scripts__"][self.__class__.__name__] = script_path def get_json_data(self): """ This method will be used in template.html to get widget data """ return { "data_1": self._data_1, "data_2": self._data_2, } def get_json_state(self): """ This method will be used in template.html to get widget state """ return { "some_state_attribute_1": self._some_state_attribute_1, "some_state_attribute_2": self._some_state_attribute_2, } # ------ Optional methods | Just for example ------ def your_method_for_change_data(self): # make changes in widget data self._data_1 = self._data_1 + [1, 2, 3, 4, 5] self._data_2 = {'a': 11} # save this changes of widget data in local storage(RAM) DataJson()[self.widget_id]['data_1'] = self._data_1 DataJson()[self.widget_id]['data_2'] = self._data_2 # sync this changes to remote server DataJson().send_changes() def your_method_for_change_state(self): # change state attribute self._some_state_attribute_1 = False self._some_state_attribute_2 = 0.1 # save this changes of widget data in local storage(RAM) StateJson()[self.widget_id]["some_state_attribute_1"] = self._some_state_attribute_1 StateJson()[self.widget_id]["some_state_attribute_2"] = self._some_state_attribute_2 # sync this changes to remote server StateJson().send_changes()Construct
template.htmlfor your widget using other widgets from SDK or any HTML elements<div> <!-- Elements from SDK had the "sly" prefix --> <sly-field :title="data.{{{widget.widget_id}}}.data_1" :description="state.{{{widget.widget_id}}}.some_state_attribute_1"> <div> {{data.{{{widget.widget_id}}}.data_2}} </div> <div> {{state.{{{widget.widget_id}}}.some_state_attribute_2}} </div> </sly-field> <!-- Just simple HTML element with Javascript function from your scipt.js --> <button :value="data.{{{widget.widget_id}}}.data_1" @click="myFunction()" ></button> <!-- Also simple HTML element, but from UI library of HTML elements - https://element.eleme.io --> <el-button :value="data.{{{widget.widget_id}}}.data_1"></el-button> <div>(Optional) Prepare file
script.jsfor your widget if you need to implement your own Vue JS component. 📗 See this example for more details.const myFunction = function (name) { console.log('Hello world') }Import new widget as part of
widgetsmodule. Just add import insupervisely/app/widgets/__init__.py# imports for other widgets as example from supervisely.app.widgets.radio_tabs.radio_tabs import RadioTabs from supervisely.app.widgets.train_val_splits.train_val_splits import TrainValSplits from supervisely.app.widgets.editor.editor import Editor # import for your widget from supervisely.app.widgets.your_widget_folder.your_widget_py_file import YourWidgetClassCreate folder with example of your widget in
ui-widgets-demos/NEW widgets/<your_widget_example_folder>like thatyour_widget_folder |____src |____main.pyExample of
main.pyimport os import supervisely as sly from dotenv import load_dotenv from supervisely.app.widgets import ( Card, YourWidget # <-- import your widget ) load_dotenv("local.env") load_dotenv(os.path.expanduser("~/supervisely.env")) api = sly.Api() your_widget = YourWidget(data_1=[...], data_2={'c': 0.3355}) card = Card(title="My card", content=your_widget) app = sly.Application(layout=card)To see the demo of your widget, you need to run the server. You got 2 options for that:
a) Just run the server from command line
python -m uvicorn "NEW widgets.grid_plot.src.main:app" --host 0.0.0.0 --port 8000 --ws websockets --reloadb) If you are VSCode user, then just edit
ui-widgets-demos/.vscode/launch.jsonas showed below and run the server from "run & debug" menu{ "version": "0.2.0", "configurations": [ { "name": "Uvicorn", "type": "python", "request": "launch", "module": "uvicorn", "args": [ <!-- change "your_widget_example_folder" to the name of the folder with your widget --> "NEW widgets.your_widget_example_folder.src.main:app", "--host", "0.0.0.0", "--port", "8000", "--ws", "websockets", "--reload" ], "jinja": true, "justMyCode": true, "env": { "PYTHONPATH": "${workspaceFolder}:${PYTHONPATH}", "LOG_LEVEL": "DEBUG", } } ] }After all steps, test your widget in browser http://0.0.0.0:8000 and if it ok make a commit & push & create the pull request in both repo(SDK and ui-widget-demos).
Send the link to pull-request to Maxim Kolomeychenko(@Max) in Slack. He will run a new SDK build.
Success!
Simple widget example
supervisely/app/widgets/textarea/textarea.py
supervisely/app/widgets/textarea/template.html
supervisely/app/widgets/__init__.py
NEW widgets/textarea/src/main.py
Last updated
Was this helpful?