340 likes | 350 Views
Fit.Panel is a modern and user-friendly GUI that allows interactive histogram fitting using the powerful tools of ROOT. It runs directly in a browser as a client/server program, with communication handled using WebSocket protocol.
E N D
ROOT7 Fit Panel IlianaBetsouNational Technical University of Athens
ROOT7 version – Fit Panel After Before
Objectives of the new version What we want from the new version to be: • Client/Server program • Web based application • Run directly in a browser • Modern and user friendly • Responsive layout
Fit Panel… …is a GUI, which can use all the power of ROOT Fitting tools and interactively fit histograms. • Predefined or User Function • Draw Options • Libraries • Different Minimization Methods • Range • Print Options
Client Server Model Organizes network traffic Client sends requests to server Server responds by returning results
WebSocket Protocol • Communication Protocol • Duplex communication channels • Compatible with HTTP and almost all browsers
TBufferJSON • void ROOT::Experimental::RFitPanel::SendModel() • { • if(fWindow&&(fConnId>0)){ • TStringjson=TBufferJSON::ToJSON(&model());fWindow->Send(fConnId,"MODEL:"s +json.Data()); • } • } Communication between C++ and JavaScript Converts any streamable object to JSON format ↔ read objects from JSON format ROOT I/O remains on the server side
OpenUI5 OpenUI5 is the new technology we have used to design the new version of the Fit Panel. It is a JavaScript UI library consisting of a really large number of UI controls. Combo BoxesRadio ButtonsCheck Boxes
MVC Architecture • Model Component → Dynamic data structure • View Component → Display of the data (UI) • Controller → Contains control logic
How it’s working Model Component – XMLwith the static values Server side – C++the non-static values Controller - JavaScript View Component HTML file
The Fit Panel Layout (1/3) We need more compact design: Compact Layout: for achieving a compact layout we are using: GridData Compact Class<VBoxclass="sapUiSizeCompact"> Custom CSS
The Fit Panel Layout (2/3) The controls: • ComboBox • RadioButton • Step Inputs • RangeSlider • CheckBox • Text Inputs • Buttons
The Fit Panel Layout (3/3) <CheckBoxtext="Linear Fit"selected="{/fLinearFit}"/> // True or False in fLinearFit <CheckBoxtext="Best errors"selected="{/fBestErrors}"enabled="{= ${/fLinearFit} !== true}"tooltip="'E'-better ..."/> // the checkbox is enabled only if Linear Fit option is not selected(false) Binding: We are using data binding to communicate with the client.
Server Side in C++ (1/3) • /// Generic item for ui5 ComboBox • structRComboBoxItem{ • std::string key; std::string value;RComboBoxItem()=default; • RComboBoxItem(const std::string &_key,const std::string &_value): key(_key), value(_value){} • }; Structures for most complicated controls (ComboBox) for implement the controls to ROOT
Server Side in C++ (2/3) • structRFitPanelModel{ • /// Generic item for ui5 ComboBox • structRComboBoxItem{ ... }; • /// Entry in minimizer algorithm combo • structRMinimezerAlgorithm{ • int lib{0};// to which library belongs • int id{0};// identifier • std::string text;// text shown in comboboxRMinimezerAlgorithm()=default;RMinimezerAlgorithm(int _lib,int _id,const std::string &_text): lib(_lib), id(_id), text(_text){} • }; • std::string fTitle;///< title of the fit panel • }; RFitPanelModel Structure with the definition of all types
Server Side in C++ (3/3) auto&m = model(); m.fDataSet.clear(); for(auto&obj:fObjects)m.fDataSet.emplace_back("Panel","panel::"s + obj->GetName(), Form("%s::%s", obj->ClassName(),obj->GetName())); We give values to the parameters in our model follow the structure we have defined before.
ComboBox – C++ (1/4) structRFitPanelModel { std::vector<RCoomboBoxItem>fItems; std::string fSelected; } RFitPanelModelmodel; model.fItems={{"id0","value0"},{"id1","value1"},{"id2","value2"}}; model.fSelected="id1"; autojson=TBufferJSON::ToJSON(&model); fWindow->Send(fConnId,"MODEL:"s +json.Data()); C++ - Add values to the ComboBox
ComboBox – JSON (2/4) { "_typename":"FitPanelModel", "fItems":[{ "_typename":"RComboBoxItem", "key":"id0", "value":"value0" },{ "_typename":"RComboBoxItem", "key":"id1", "value":"value1“ },{ "_typename":"RComboBoxItem", "key":"id2", "value":"value2" }], "fSelected":"id1" } The produced JSON code:
ComboBoxJavaScript - XML (3/4) obj=JSROOT.parse(str);this.getView().setModel(newJSONModel(obj)); <ComboBoxselectedKey="{/fSelected}" items="{ path: '/fItems'}"> <core:Itemkey="{id}"text="{text}"/></ComboBox> Create a new model in JavaScript: Assign to the XML view:
ComboBoxJavaScript – C++(4/4) varjson=this.getView().getModel().getJSON();this.websocket.Send("MODEL:"+json); auto model =TBufferJSON::FromJSON<RFitPanelModel>(json); Sending the selected from JavaScript side to C++: Create the C++ object:
Fit Function caseRFitPanelModel::kObjectHisto: { TH1 *hist=dynamic_cast<TH1*>(obj); if(hist) res = ROOT::Fit::FitObject(hist, f1.get(),fitOpts,minOption,drawOpts,drange); break; } caseRFitPanelModel::kObjectGraph: { TGraph*gr=dynamic_cast<TGraph*>(obj); if(gr) res = ROOT::Fit::FitObject(gr, f1.get(),fitOpts,minOption,drawOpts,drange); break; }
Draw Function • TF1 *func=FindFunction(m.fSelectedFunc); • if(func){ • // when "Pars" tab is selected, automatically update function parameters • if((m.fSelectedTab.compare("Pars")==0)&&(m.fSelectedFunc== m.fFuncPars.id))m.fFuncPars.SetParameters(func); • func->Draw("same"); • } • pad->Modified(); • pad->Update();
Summary • Web Based Fit Panel Model Component Creation – XML (static values) JavaScript Controller Server side in C++ (non static values) View Component
More Stuff! Dependant Combo Boxes, Layout with code, Controls with code, MVC architecture (SAP)
Future Work • There are a few things that still missing from the new version of Fit Panel and will be completed in the next months. • Picking on Rpad • Provide list of primitives on RPad to fit panel on C++ side • Add functionality to Update Range Button • Create a Back function
The Fit Panel Layout (2/4) The controls: ComboBox <ComboBoxid="DataSet"selectedKey="{/fSelectDataId}"items="{ path: '/fDataSet', sorter: { path: 'fSet' } }"><core:Itemkey="{fId}"text="{fSet}"/></ComboBox> RadioButton <RadioButtonid="RB1-1"text="Nop"/> CheckBox <CheckBoxid="Integral"text="Integral"/> RangeSlider <RangeSliderid="Slider"range="{/fRange}"min="{/fMinRange}"max="{/fMaxRange}"step="{/fStep}"/>
Functions for handling the values The selected function from the ComboBox appears directly on the TextArea. onTypeXYChange:function(){ var data =this.getView().getModel().getData(); var linear =this.getView().getModel().getData().fSelectXYId;data.fFuncChange= linear;this.getView().getModel().refresh(); //updates the text area and text in selected tab, depending on the choice in TypeXYComboBox var function =this.getView().byId("TypeXY").getValue();this.byId("OperationText").setValueLiveUpdate();this.byId("OperationText").setValue(function);this.byId("selectedOpText").setText(function); },
Communication between C++ and JavaScript The communication between the server side and the client side TStringjson=TBufferJSON::ConvertToJSON(&model, gROOT->GetClass("FitPanelModel")); fWindow->Send(fConnId, std::string("MODEL:")+json.Data()); TBufferJSON::ConvertsToJSON()→converts an object to JSON string
Create Window in C++ void Show(const std::string &where =""){ fWindow=ROOT::Experimental::TWebWindowsManager::Instance() ->CreateWindow(false); //defines the OpenUi5 element which will run on client-side fWindow->SetPanelName("localapp.view.SimpleFitPanel"); //receive the model via WebSocket fWindow->SetDataCallBack([this](unsignedconnid,const std::string &arg){ProcessData(connid,arg);}); //configure predefined geometry fWindow->SetGeometry(450,550); fWindow->Show(where); //instead showing of window just generate URL, which can be copied into the browser std::string url=fWindow->GetUrl(true); printf("Example: %s\n",url.c_str());}
Dependent ComboBox (1/2) There are some ComboBoxes which values aredependant from the selection of a previous control. Definition:std::vector<std::vector<ComboBoxItem>>fMethodMinAll;
Dependent ComboBox (2/2) We give the values: // corresponds to library == 0 model.fMethodMinAll.emplace_back(); std::vector<ComboBoxItem>&vect0 = model.fMethodMinAll.back(); vect0.push_back(ComboBoxItem("1","MIGRAD")); vect0.push_back(ComboBoxItem("2","SIMPLEX")); // corresponds to library == 2 model.fMethodMinAll.emplace_back();std::vector<ComboBoxItem>&vect2 =model.fMethodMinAll.back(); vect2.push_back(ComboBoxItem("1","FUMILI"));
Client Side on JavaScript • OnWebsocketMsg:function(handle,msg){if(msg.startsWith("MODEL:")){ • varjson=msg.substr(6); • var data =JSROOT.parse(json); • if(data){ • this.getView().setModel(newJSONModel(data));this._data= data;} • } • else{} • }, Function for the communication with the server, OnWebSocketMessage