简介
有用链接
- Github
- Docs
- Wiki Example
安装
安装很简单,可以直接使用pip install dearpygui安装。
源码编译安装
如果想从源码编译安装,可以使用如下命令
sudoaptinstalllibxrandr-dev libxinerama-dev libxcursor-dev libxi-devgitclone--recursivehttps://github.com/hoffstadt/DearPyGuicdDearPyGui pipinstall.# orpython setup.pyinstall多线程编译安装
将setup.py中的--config Release修改为--config Release -- -j$(nproc)即可实现cmake与make的多线程编译。如下所示:
修改完成后,执行如下代码编译安装
pipinstall.# 或者python setup.pyinstall源码分析
参数传递
set_positional_configuration:输入Python 管道,输出C++结构体,Python顺序传参给C++,位置参数set_configuration:输入Python字典,输出C++配置,Python改配置同步给C++,关键字参数fill_configuration_dict:输入C++配置,输出Python字典,用于导出配置给Python,只读GetEntityParser(mvAppItemType type):入口参数解析
以heat sseries为例,首先看Python的绘制函数add_heat_series
defadd_heat_series(x:Union[List[float],Tuple[float,...]],rows:int,cols:int,*,label:str=None,user_data:Any=None,use_internal_label:bool=True,tag:Union[int,str]=0,parent:Union[int,str]=0,before:Union[int,str]=0,source:Union[int,str]=0,show:bool=True,scale_min:float=0.0,scale_max:float=1.0,bounds_min:Any=(0.0,0.0),bounds_max:Any=(1.0,1.0),format:str='%0.1f',contribute_to_bounds:bool=True,col_major:bool=False,**kwargs)->Union[int,str]:""" Adds a heat series to a plot. Args: x (Any): rows (int): cols (int): label (str, optional): Overrides 'name' as label. user_data (Any, optional): User data for callbacks use_internal_label (bool, optional): Use generated internal label instead of user specified (appends ### uuid). tag (Union[int, str], optional): Unique id used to programmatically refer to the item.If label is unused this will be the label. parent (Union[int, str], optional): Parent to add this item to. (runtime adding) before (Union[int, str], optional): This item will be displayed before the specified item in the parent. source (Union[int, str], optional): Overrides 'id' as value storage key. show (bool, optional): Attempt to render widget. scale_min (float, optional): Sets the color scale min. Typically paired with the color scale widget scale_min. scale_max (float, optional): Sets the color scale max. Typically paired with the color scale widget scale_max. bounds_min (Any, optional): bounds_max (Any, optional): format (str, optional): contribute_to_bounds (bool, optional): col_major (bool, optional): data will be read in column major order id (Union[int, str], optional): (deprecated) Returns: Union[int, str] """if'id'inkwargs.keys():warnings.warn('id keyword renamed to tag',DeprecationWarning,2)tag=kwargs['id']returninternal_dpg.add_heat_series(x,rows,cols,label=label,user_data=user_data,use_internal_label=use_internal_label,tag=tag,parent=parent,before=before,source=source,show=show,scale_min=scale_min,scale_max=scale_max,bounds_min=bounds_min,bounds_max=bounds_max,format=format,contribute_to_bounds=contribute_to_bounds,col_major=col_major,**kwargs)对应C++中实际的绘制函数是draw_heat_series,具体定义在在mvPlotting.h里
structmvHeatSeriesConfig:_mvBasicSeriesConfig{introws=1;intcols=1;doublescale_min=0.0;doublescale_max=1.0;std::string format="%0.1f";ImPlotPoint bounds_min={0.0,0.0};ImPlotPoint bounds_max={1.0,1.0};ImPlotHeatmapFlags flags=ImPlotHeatmapFlags_None;};casemvAppItemType::mvHeatSeries:return"add_heat_series";classmvHeatSeries:publicmvAppItem{public:mvHeatSeriesConfig configData{};explicitmvHeatSeries(mvUUID uuid):mvAppItem(uuid){}voidhandleSpecificPositionalArgs(PyObject*dict)override{DearPyGui::set_positional_configuration(dict,configData);}voiddraw(ImDrawList*drawlist,floatx,floaty)override{DearPyGui::draw_heat_series(drawlist,*this,configData);}voidhandleSpecificKeywordArgs(PyObject*dict)override{DearPyGui::set_configuration(dict,configData);}voidgetSpecificConfiguration(PyObject*dict)override{DearPyGui::fill_configuration_dict(configData,dict);}voidsetDataSource(mvUUID dataSource)override{DearPyGui::set_data_source(*this,dataSource,configData.value);}void*getValue()override{return&configData.value;}PyObject*getPyValue()override{returnToPyList(*configData.value);}voidsetPyValue(PyObject*value)override{*configData.value=ToVectVectDouble(value);}};具体实现在mvPlotting.cpp里
voidDearPyGui::draw_heat_series(ImDrawList*drawlist,mvAppItem&item,constmvHeatSeriesConfig&config)用于参数传递的三个函数如下:
// Python --> C++, 位置参数voidDearPyGui::set_positional_configuration(PyObject*inDict,mvHeatSeriesConfig&outConfig){if(!VerifyRequiredArguments(GetParsers()[GetEntityCommand(mvAppItemType::mvHeatSeries)],inDict))return;(*outConfig.value)[0]=ToDoubleVect(PyTuple_GetItem(inDict,0));outConfig.rows=ToInt(PyTuple_GetItem(inDict,1));outConfig.cols=ToInt(PyTuple_GetItem(inDict,2));(*outConfig.value)[1].push_back(outConfig.bounds_min.y);(*outConfig.value)[1].push_back(outConfig.bounds_max.y);}// Python --> C++, 关键字参数voidDearPyGui::set_configuration(PyObject*inDict,mvHeatSeriesConfig&outConfig){if(inDict==nullptr)return;if(PyObject*item=PyDict_GetItemString(inDict,"format"))outConfig.format=ToString(item);if(PyObject*item=PyDict_GetItemString(inDict,"rows"))outConfig.rows=ToInt(item);if(PyObject*item=PyDict_GetItemString(inDict,"cols"))outConfig.cols=ToInt(item);if(PyObject*item=PyDict_GetItemString(inDict,"bounds_min"))outConfig.bounds_min=ToPoint(item);if(PyObject*item=PyDict_GetItemString(inDict,"bounds_max"))outConfig.bounds_max=ToPoint(item);if(PyObject*item=PyDict_GetItemString(inDict,"scale_min"))outConfig.scale_min=ToDouble(item);if(PyObject*item=PyDict_GetItemString(inDict,"scale_max"))outConfig.scale_max=ToDouble(item);// helper for bit flippingautoflagop=[inDict](constchar*keyword,intflag,int&flags){if(PyObject*item=PyDict_GetItemString(inDict,keyword))ToBool(item)?flags|=flag:flags&=~flag;};// flagsflagop("col_major",ImPlotHeatmapFlags_ColMajor,outConfig.flags);boolvalueChanged=false;if(PyObject*item=PyDict_GetItemString(inDict,"x")){valueChanged=true;(*outConfig.value)[0]=ToDoubleVect(item);}if(valueChanged){(*outConfig.value)[1].push_back(outConfig.bounds_min.y);(*outConfig.value)[1].push_back(outConfig.bounds_max.y);}}// C++ --> Python,关键字参数voidDearPyGui::fill_configuration_dict(constmvHeatSeriesConfig&inConfig,PyObject*outDict){if(outDict==nullptr)return;PyDict_SetItemString(outDict,"format",mvPyObject(ToPyString(inConfig.format)));PyDict_SetItemString(outDict,"rows",mvPyObject(ToPyInt(inConfig.rows)));PyDict_SetItemString(outDict,"cols",mvPyObject(ToPyInt(inConfig.cols)));PyDict_SetItemString(outDict,"bounds_min",mvPyObject(ToPyPair(inConfig.bounds_min.x,inConfig.bounds_min.y)));PyDict_SetItemString(outDict,"bounds_max",mvPyObject(ToPyPair(inConfig.bounds_max.x,inConfig.bounds_max.y)));PyDict_SetItemString(outDict,"scale_min",mvPyObject(ToPyDouble(inConfig.scale_min)));PyDict_SetItemString(outDict,"scale_max",mvPyObject(ToPyDouble(inConfig.scale_max)));// helper to check and set bitautocheckbitset=[outDict](constchar*keyword,intflag,constint&flags){mvPyObject py_result=ToPyBool(flags&flag);PyDict_SetItemString(outDict,keyword,py_result);};// flagscheckbitset("col_major",ImPlotHeatmapFlags_ColMajor,inConfig.flags);}在mvAppItem.cpp文件里有入口参数解析实现
mvPythonParserDearPyGui::GetEntityParser(mvAppItemType type)比如下面是HeatSeries的
casemvAppItemType::mvHeatSeries:{AddCommonArgs(args,(CommonParserArgs)(MV_PARSER_ARG_ID|MV_PARSER_ARG_PARENT|MV_PARSER_ARG_BEFORE|MV_PARSER_ARG_SOURCE|MV_PARSER_ARG_SHOW));args.push_back({mvPyDataType::DoubleList,"x"});args.push_back({mvPyDataType::Integer,"rows"});args.push_back({mvPyDataType::Integer,"cols"});args.push_back({mvPyDataType::Double,"scale_min",mvArgType::KEYWORD_ARG,"0.0","Sets the color scale min. Typically paired with the color scale widget scale_min."});args.push_back({mvPyDataType::Double,"scale_max",mvArgType::KEYWORD_ARG,"1.0","Sets the color scale max. Typically paired with the color scale widget scale_max."});args.push_back({mvPyDataType::DoubleList,"bounds_min",mvArgType::KEYWORD_ARG,"(0.0, 0.0)"});args.push_back({mvPyDataType::DoubleList,"bounds_max",mvArgType::KEYWORD_ARG,"(1.0, 1.0)"});args.push_back({mvPyDataType::String,"format",mvArgType::KEYWORD_ARG,"'%0.1f'"});args.push_back({mvPyDataType::Bool,"contribute_to_bounds",mvArgType::KEYWORD_ARG,"True"});args.push_back({mvPyDataType::Bool,"col_major",mvArgType::KEYWORD_ARG,"False","data will be read in column major order"});setup.about="Adds a heat series to a plot.";setup.category={"Plotting","Containers","Widgets"};break;}绘图
热图
使用热图功能可以得到 类似matlab的imagesc和Matplotlib的imshow的效果。具体函数为add_heat_series,其中format参数用于控制每个矩阵元素的数值显示格式,需设为空字符'',使用bounds_min和bounds_max设置坐标轴刻度范围。其它参数含义,参见文档 heat
3D绘图支持
集成Implot3D
需要注意的是imgui是docking版本 可以在release页面 通过tags来查看各个版本
- imgui主页 https://github.com/ocornut/imgui
- implot3d主页 https://github.com/brenocq/implot3d/
- implot主页 https://github.com/epezent/implot
将implot3d放在thirdparty文件夹下
然后修改DearPyGui/src下的CMakeList.txt文件
添加如下内容设置源文件和头文件
set(MARVEL_SOURCES# implot3d"../thirdparty/implot3d/implot3d.cpp""../thirdparty/implot3d/implot3d_items.cpp""../thirdparty/implot3d/implot3d_meshes.cpp""../thirdparty/implot3d/implot3d_demo.cpp"set(MARVEL_INCLUDE_DIR".""../thirdparty/implot""../thirdparty/implot3d"集成自带demo
然后按如下各图集成implot3d自带的demo
下面两处必须添加,否则会报段错误或直接退出。
修改完代码后,编译安装修改的库,然后运行如下示例代码:
importdearpygui.dearpyguiasdpgimportdearpygui.demoasdemo dpg.create_context()dpg.create_viewport(title='Custom Title',width=600,height=600)demo.show_demo()dpg.show_implot_demo()dpg.show_implot3d_demo()dpg.setup_dearpygui()dpg.show_viewport()dpg.start_dearpygui()dpg.destroy_context()运行后弹出如下窗口,可查看示例效果
疑难杂症
卡顿
发现如果窗口数多于1个,界面操作起来就会卡顿,而如果注释掉dpg.configure_app的代码就不卡顿了。怀疑是参数配置不当,但改了无果。最终发现是dpg.configure_app和create_viewport调用的位置不对。参照官方文档init file更改代码后正常。
importdearpygui.dearpyguiasdpg dpg.create_context()defsave_init():dpg.save_init_file("dpg.ini")dpg.configure_app(init_file="dpg.ini")# default file is 'dpg.ini'withdpg.window(label="about",tag="main window"):dpg.add_button(label="Save Window pos",callback=lambda:save_init)withdpg.window(label="about",tag="side window"):dpg.add_button(label="Press me")dpg.create_viewport(title='Custom Title',width=800,height=600)dpg.setup_dearpygui()dpg.show_viewport()dpg.start_dearpygui()dpg.destroy_context()