epezent / implot使用说明和常见问题解答

1,831 阅读7分钟

ImPlot

ImPlot是Dear ImGui的一个即时模式、GPU加速的绘图库。它的目的是提供一个一流的API,ImGui的粉丝会喜欢。ImPlot非常适用于实时可视化程序数据或创建交互式绘图,并且需要最小的代码来集成。就像ImGui一样,它不会给终端用户带来GUI状态管理的负担,避免了STL容器和C++头文件,除了ImGui本身,没有任何外部依赖性。

特点

  • GPU加速渲染
  • 多种绘图类型。
    • 线状图
    • 阴影图
    • 散点图
    • 垂直/水平/叠加条形图
    • 垂直/水平误差条
    • 茎状图
    • 阶梯图
    • 饼状图
    • 热图图
    • 一维/二维直方图
    • 图像
    • 以及更多可能出现的
  • 在一个图上混合/匹配多个图项
  • 可配置的坐标轴范围和比例(线性/对数)。
  • 子图
  • 时间格式化的X轴(美国格式化或ISO 8601)。
  • 可逆的和可锁定的轴
  • 多个X轴和Y轴
  • 缩放、平移、框选和自动拟合数据的控件
  • 用于创建持久性查询范围的控件(见演示)
  • 多个绘图样式选项。10种标记类型,可调整的标记尺寸、线重、轮廓颜色、填充颜色等。
  • 16个内置的颜色图,支持用户添加的颜色图
  • 可选的绘图标题、轴标签和网格标签
  • 可选的、可配置的图例,带有切换按钮,可快速显示/隐藏绘图项目
  • 基于当前ImGui主题的默认样式,或完全自定义的绘图样式
  • 可定制的数据获取器和数据串联(就像ImGui:PlotLine)。
  • 接受浮点、双倍、以及8、16、32和64位有符号/无符号积分类型的数据
  • 还有更多!(见公告2020/2021)

使用方法

该API的使用与其他ImGuiBeginX/EndX 对一样。首先,用ImPlot::BeginPlot() 开始一个新的绘图。接下来,用所提供的PlotX 函数绘制你想要的项目(例如:PlotLine(),PlotBars(),PlotScatter(), 等等)。最后,通过调用ImPlot::EndPlot() 来结束工作。就这样!

int   bar_data[11] = ...;
float x_data[1000] = ...;
float y_data[1000] = ...;

ImGui::Begin("My Window");
if (ImPlot::BeginPlot("My Plot")) {
    ImPlot::PlotBars("My Bar Plot", bar_data, 11);
    ImPlot::PlotLine("My Line Plot", x_data, y_data, 1000);
    ...
    ImPlot::EndPlot();
}
ImGui::End();

当然,你还可以用ImPlot做更多的事情...

演示

ImPlot功能的一个综合例子可以在implot_demo.cpp 中找到。将此文件添加到你的源代码中,并在你的更新循环中调用ImPlot::ShowDemoWindow() 。我们鼓励你在需要实现各种绘图类型时使用该文件作为参考。该演示一直在更新,以显示新的绘图类型和功能,所以请在每次发布时回来查看

该演示的在线版本存放在这里。你可以查看这些图和生成这些图的源代码。请注意,这个演示可能并不总是最新的,也不像桌面实现那样高性能,但它应该让你大致了解ImPlot的可能性。特别感谢pthom创建和主持这个演示!

更复杂的演示需要更长的代码和/或第三方库,可以在一个单独的仓库找到:Implot_demos。在这里,你会发现先进的信号处理和ImPlot的实际应用。如果你有新演示的想法,请阅读该资料库的Contributing

集成

  1. 如果你还没有一个ImGui环境,请建立一个ImGui环境。
  2. 添加implot.h,implot_internal.h,implot.cpp,implot_items.cpp 和可选的implot_demo.cpp 到你的源代码。或者,你可以使用vcpkg获得ImPlot。
  3. 在任何地方为你的ImGuiContext ,创建并销毁一个ImPlotContext
ImGui::CreateContext

你应该可以开始了!

如果你想快速测试ImPlot,可以考虑试试mahi-gui,它为你捆绑了ImGui、ImPlot和其他一些软件包。

极其重要的说明

亲爱的ImGui默认使用16位索引,所以高密度的ImPlot部件,如ImPlot::PlotHeatmap() ,可能会产生太多的顶点到ImDrawList ,这将导致断言失败,并将导致数据截断和/或视觉故障。因此,强烈建议你采用以下方法。

  • 选项1: 在你的ImGui文件中取消注释#define ImDrawIdx unsigned int ,启用32位指数。 imconfig.h文件中的32位指数。
  • 选项2: 如果你必须使用16位索引,在你的渲染器中处理ImGuiBackendFlags_RendererHasVtxOffset 标志。许多默认的 ImGui 渲染后端已经支持ImGuiBackendFlags_RendererHasVtxOffset 。更多信息请参考这个问题

常见问题

问:为什么?

答:ImGui是一个非常强大的快速原型设计和开发工具,但只提供有限的数据可视化机制。二维图是无处不在的,对几乎所有的应用都很有用。能够实时可视化你的数据将使你对你的应用程序有深入的了解和更好的认识。

问:ImPlot是适合我的绘图库吗?

答:如果你想生成出版物质量的图和/或将图导出到文件,ImPlot不适合你!ImPlot的目标是以实时速度绘制应用程序的数据,并具有高度的互动性。ImPlot尽力创建漂亮的图(事实上,有相当多的风格选项),但它总是偏向于功能而不是形式。

问:文档在哪里?

答:API在implot.h 中有详细的注释,implot_demo.cpp 中的演示应该足以让你开始使用。也可以看一下implot_demos仓库。

问:ImPlot是否适用于绘制大型数据集?

答:是的,在合理范围内。你可以毫无问题地绘制几万到几十万个点,但不要指望几百万个点会是一个非常流畅的体验。也就是说,如果需要的话,你可以通过告诉ImPlot以更大的间隔对数据进行缩减采样。也可以试试实验性的backends 分支,其目的是提供GPU加速支持。

问:我可以绘制哪些数据类型?

答:ImPlot的绘图功能接受大多数标量类型。float,double,int8,uint8,int16,uint16,int32,uint32,int64,uint64 。自定义结构或类的数组(例如:Vector2f 或类似的)很容易使用内置的striding功能传递给ImPlot函数(文档见implot.h ),许多绘图仪提供一个 "getter "重载,接受数据生成的回调。

问:绘图样式可以修改吗?

答:可以。数据彩图和各种样式的颜色和变量可以在启动时被推送/弹出或永久修改。有三种默认风格,以及一种自动风格,试图与你的ImGui风格相匹配。

问:ImPlot是否支持对数缩放或时间格式化?

答:是的!对数刻度和时间刻度都支持。

问:ImPlot是否支持多个Y轴和X轴?

答:是的。最多可以启用三个X轴和三个Y轴。

问:ImPlot是否支持[插入绘图类型]?

答:可能。检查演示,画廊,或公告(2020/2021),看看你想要的绘图类型是否显示。如果没有,考虑提交一个问题或更好的是,一个PR

问:ImPlot是否支持3D绘图?

答:不,可能永远不会,因为ImGui只处理2D渲染。

问:我的绘图线看起来像垃圾!?

答:默认情况下,为了提高性能,在线条图上不做抗锯齿处理。如果你使用至少4倍的MSAA,那么你甚至可能不会注意到。然而,你可以用ImPlotFlags_AntiAliased 标志在每个图上启用软件AA,或者用ImPlot::GetStyle().AntiAliasedLines = true;

问:ImPlot是否提供分析工具?

答:不完全是,但它确实给你提供了查询绘图子范围的能力,你可以用它来处理你喜欢的数据。

问:能否将图画导出/保存为图像?

答:目前不能。如果你需要捕捉一个情节,请使用你的操作系统的屏幕捕捉机制。ImPlot不适合渲染出版质量的图;它只打算作为一个可视化工具使用。出于这些目的,请用MATLAB或matplotlib对您的数据进行后期处理。

问:我可以把ImPlot编译成一个动态库吗?

答:与ImGui一样,建议将ImPlot作为静态库或直接作为源代码的一部分进行编译和链接。然而,如果你必须把ImPlot和ImGui编译成独立的DLLs,请确保你用ImPlot::SetImGuiContext(ImGuiContext* ctx) 来设置当前的ImGui环境。这可以确保全局的ImGui变量在DLL边界上正确共享。

问:ImPlot可以与其他语言/绑定使用吗?

答:是的,你可以在大多数高级语言中使用生成的C语言绑定,cimplotDearPyGui提供了一个Python包装器,除此之外,imgui-java提供了Java的绑定。一个Rust的绑定,implot-rs,目前正在开发中。一个使用Emscripten的例子可以在这里找到。