1
0
Fork 0
mirror of https://github.com/gwm17/Specter.git synced 2024-11-26 12:18:51 -05:00

Editor now can display plots, list available spectra with info. Made HistogramMap fully thread safe, and minimized amount of cross-thread calls.

This commit is contained in:
Gordon McCann 2022-01-12 21:37:20 -05:00
parent 530d0bf8e3
commit f91a3dce69
5 changed files with 274 additions and 59 deletions

View File

@ -1,5 +1,6 @@
#include "EditorLayer.h" #include "EditorLayer.h"
#include "imgui.h" #include "imgui.h"
#include "implot.h"
namespace Navigator { namespace Navigator {
@ -28,7 +29,55 @@ namespace Navigator {
void EditorLayer::OnImGuiRender() void EditorLayer::OnImGuiRender()
{ {
ImGui::Begin("MyTestSpace"); static bool dockspaceOpen = true;
static bool opt_fullscreen_persistant = true;
bool opt_fullscreen = opt_fullscreen_persistant;
static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_None;
// We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into,
// because it would be confusing to have two docking targets within each others.
ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
if (opt_fullscreen)
{
ImGuiViewport* viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(viewport->Pos);
ImGui::SetNextWindowSize(viewport->Size);
ImGui::SetNextWindowViewport(viewport->ID);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
}
// When using ImGuiDockNodeFlags_PassthruCentralNode, DockSpace() will render our background and handle the pass-thru hole, so we ask Begin() to not render a background.
if (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode)
window_flags |= ImGuiWindowFlags_NoBackground;
// Important: note that we proceed even if Begin() returns false (aka window is collapsed).
// This is because we want to keep our DockSpace() active. If a DockSpace() is inactive,
// all active windows docked into it will lose their parent and become undocked.
// We cannot preserve the docking relationship between an active window and an inactive docking, otherwise
// any change of dockspace/settings would lead to windows being stuck in limbo and never being visible.
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
ImGui::Begin("MyTestSpace", &dockspaceOpen, window_flags);
ImGui::PopStyleVar();
if (opt_fullscreen)
ImGui::PopStyleVar(2);
// DockSpace
ImGuiIO& io = ImGui::GetIO();
ImGuiStyle& style = ImGui::GetStyle();
float minWinSizeX = style.WindowMinSize.x;
style.WindowMinSize.x = 370.0f;
if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
{
ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
}
style.WindowMinSize.x = minWinSizeX;
if(ImGui::BeginMenuBar()) if(ImGui::BeginMenuBar())
{ {
if(ImGui::BeginMenu("File")) if(ImGui::BeginMenu("File"))
@ -44,10 +93,122 @@ namespace Navigator {
} }
ImGui::EndMenu(); ImGui::EndMenu();
} }
if (ImGui::BeginMenu("Data Source"))
{
if (ImGui::MenuItem("Attach Source"))
{
}
if (ImGui::MenuItem("Detach Source"))
{
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Add"))
{
if (ImGui::MenuItem("Spectrum"))
{
}
if (ImGui::MenuItem("Cut"))
{
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Remove"))
{
if (ImGui::MenuItem("Spectrum"))
{
}
if (ImGui::MenuItem("Cut"))
{
}
ImGui::EndMenu();
}
ImGui::EndMenuBar(); ImGui::EndMenuBar();
} }
static std::vector<HistogramParameters> paramList = m_histMap->GetListOfHistogramParams();
if (ImGui::Begin("Active View"))
{
if (paramList.size() > 0)
{
static std::vector<std::string> s_selectedGrams;
static int sizes[2] = { 1,1 };
static int total = 1;
ImGui::SliderInt2("Rows, Columns", sizes, 1, 3);
total = sizes[0] * sizes[1];
s_selectedGrams.resize(total);
for (auto& gram : s_selectedGrams)
gram = paramList[0].name;
if (ImGui::BeginTable("Select Histograms", sizes[1]))
{
std::string label;
int this_gram;
for (int i = 0; i < sizes[0]; i++)
{
ImGui::TableNextRow();
for (int j = 0; j < sizes[1]; j++)
{
ImGui::TableNextColumn();
this_gram = i * sizes[1] + j;
label = "Histogram" + std::to_string(this_gram);
if (ImGui::BeginCombo(label.c_str(), paramList[0].name.c_str()))
{
for (auto& params : paramList)
if (ImGui::Selectable(params.name.c_str(), params.name == s_selectedGrams[this_gram]))
s_selectedGrams[this_gram] = params.name;
ImGui::EndCombo();
}
}
}
ImGui::EndTable();
}
if (ImPlot::BeginSubplots("Histograms", sizes[0], sizes[1], ImVec2(-1, -1)))
{
int i = 0;
for (auto& spec : s_selectedGrams)
{
if (ImPlot::BeginPlot(spec.c_str()))
{
m_histMap->DrawHistogram(spec);
if (ImPlot::IsPlotHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
NAV_INFO("We got'em boys, they're in plot {0}", i);
ImPlot::EndPlot();
}
i++;
}
ImPlot::EndSubplots();
}
}
ImGui::End();
}
if (ImGui::Begin("Spectra"))
{
for (auto& params : paramList)
{
if (ImGui::TreeNode(params.name.c_str()))
{
ImGui::BulletText("X Parameter: %s", params.x_par.c_str());
ImGui::BulletText("X Bins: %d X Min: %d X Max: %d", params.nbins_x, params.min_x, params.max_x);
if (params.y_par != "None")
{
ImGui::BulletText("Y Parameter: %s", params.y_par.c_str());
ImGui::BulletText("Y Bins: %d Y Min: %d Y Max: %d", params.nbins_y, params.min_y, params.max_y);
}
ImGui::TreePop();
}
}
ImGui::End();
}
ImGui::End(); ImGui::End();
} }
} }

View File

@ -12,30 +12,33 @@ namespace Navigator {
1D Histogram class 1D Histogram class
*/ */
Histogram1D::Histogram1D(const std::string& name, const std::string& param, int bins, double min, double max) : Histogram1D::Histogram1D(const std::string& name, const std::string& param, int bins, double min, double max) :
Histogram(name, param), m_nBins(bins), m_xMin(min), m_xMax(max) Histogram(name, param)
{ {
InitBins(); InitBins(bins, min, max);
} }
Histogram1D::~Histogram1D() {} Histogram1D::~Histogram1D() {}
void Histogram1D::InitBins() void Histogram1D::InitBins(int bins, double min, double max)
{ {
if(m_nBins == 0 || (m_xMin >= m_xMax)) m_params.nbins_x = bins;
m_params.min_x = min;
m_params.max_x = max;
if(m_params.nbins_x == 0 || (m_params.min_x >= m_params.max_x))
{ {
NAV_WARN("Attempting to create an illegal Histogram1D {0} with {1} bins and a range from {2} to {3}. Historgram not initialized.", m_name, m_nBins, m_xMin, m_xMax); NAV_WARN("Attempting to create an illegal Histogram1D {0} with {1} bins and a range from {2} to {3}. Historgram not initialized.", m_params.name, m_params.nbins_x, m_params.min_x, m_params.max_x);
m_initFlag = false; m_initFlag = false;
return; return;
} }
m_binWidth = (m_xMax - m_xMin)/m_nBins; m_binWidth = (m_params.max_x - m_params.min_x)/m_params.nbins_x;
m_binCenters.resize(m_nBins); m_binCenters.resize(m_params.nbins_x);
m_binCounts.resize(m_nBins); m_binCounts.resize(m_params.nbins_x);
for(int i=0; i<m_nBins; i++) for(int i=0; i<m_params.nbins_x; i++)
{ {
m_binCenters[i] = m_xMin + i*m_binWidth + m_binWidth*0.5; m_binCenters[i] = m_params.min_x + i*m_binWidth + m_binWidth*0.5;
m_binCounts[i] = 0; m_binCounts[i] = 0;
} }
@ -45,10 +48,10 @@ namespace Navigator {
//Note: only x is used here, y is simply present to maintain compliance with 2D case and can be ignored //Note: only x is used here, y is simply present to maintain compliance with 2D case and can be ignored
void Histogram1D::FillData(double x, double y) void Histogram1D::FillData(double x, double y)
{ {
if(x < m_xMin || x >= m_xMax || !m_initFlag) if(x < m_params.min_x || x >= m_params.max_x || !m_initFlag)
return; return;
int bin = int((x - m_xMin)/(m_binWidth)); int bin = int((x - m_params.min_x)/(m_binWidth));
m_binCounts[bin] += 1.0; m_binCounts[bin] += 1.0;
} }
@ -56,12 +59,13 @@ namespace Navigator {
//Can only be used within an ImGui / ImPlot context!! //Can only be used within an ImGui / ImPlot context!!
void Histogram1D::Draw() void Histogram1D::Draw()
{ {
ImPlot::PlotBars(m_name.c_str(), &m_binCenters.data()[0], &m_binCounts.data()[0], m_nBins, m_binWidth); ImPlot::SetupAxes(m_params.x_par.c_str(), "Counts",0, ImPlotAxisFlags_LockMin);
ImPlot::PlotBars(m_params.name.c_str(), &m_binCenters.data()[0], &m_binCounts.data()[0], m_params.nbins_x, m_binWidth);
} }
void Histogram1D::ClearData() void Histogram1D::ClearData()
{ {
for(int i=0; i<m_nBins; i++) for(int i=0; i<m_params.nbins_x; i++)
m_binCounts[i] = 0; m_binCounts[i] = 0;
} }
@ -71,42 +75,49 @@ namespace Navigator {
*/ */
Histogram2D::Histogram2D(const std::string& name, const std::string& param_x, const std::string& param_y, int bins_x, double min_x, double max_x, Histogram2D::Histogram2D(const std::string& name, const std::string& param_x, const std::string& param_y, int bins_x, double min_x, double max_x,
int bins_y, double min_y, double max_y) : int bins_y, double min_y, double max_y) :
Histogram(name, param_x, param_y), m_nXBins(bins_x), m_nYBins(bins_y), m_xMin(min_x), m_xMax(max_x), m_yMin(min_y), m_yMax(max_y) Histogram(name, param_x, param_y)
{ {
InitBins(); InitBins(bins_x, min_x, max_x, bins_y, min_y, max_y);
} }
Histogram2D::~Histogram2D() {} Histogram2D::~Histogram2D() {}
void Histogram2D::InitBins() void Histogram2D::InitBins(int bins_x, double min_x, double max_x, int bins_y, double min_y, double max_y)
{ {
if(m_nXBins == 0 || m_nYBins == 0 || m_xMin >= m_xMax || m_yMin >= m_yMax) m_params.nbins_x = bins_x;
m_params.min_x = min_x;
m_params.max_x = max_x;
m_params.nbins_y = bins_y;
m_params.min_y = min_y;
m_params.max_y = max_y;
if(m_params.nbins_x <= 0 || m_params.nbins_y <= 0 || m_params.min_x >= m_params.max_x || m_params.min_y >= m_params.max_y)
{ {
NAV_WARN("Attempting to create illegal Histogram2D {0} with {1} x bins, {2} y bins, an x range of {3} to {4}, and a y range of {5} to {6}. Not initialized.", m_name, m_nXBins, m_nYBins, NAV_WARN("Attempting to create illegal Histogram2D {0} with {1} x bins, {2} y bins, an x range of {3} to {4}, and a y range of {5} to {6}. Not initialized.", m_params.name, m_params.nbins_x, m_params.nbins_y,
m_xMin, m_xMax, m_yMin, m_yMax); m_params.min_x, m_params.max_x, m_params.min_y, m_params.max_y);
m_initFlag = false; m_initFlag = false;
return; return;
} }
m_binWidthX = (m_xMax - m_xMin)/m_nXBins; m_binWidthX = (m_params.max_x - m_params.min_x)/m_params.nbins_x;
m_binWidthY = (m_yMax - m_yMin)/m_nYBins; m_binWidthY = (m_params.max_y - m_params.min_y)/m_params.nbins_y;
m_nBins = m_nXBins*m_nYBins; m_nBinsTotal = m_params.nbins_x*m_params.nbins_y;
m_binCounts.resize(m_nBins); m_binCounts.resize(m_nBinsTotal);
for(int i=0; i<m_nBins; i++) for(int i=0; i<m_nBinsTotal; i++)
m_binCounts[i] = 0; m_binCounts[i] = 0;
m_maxBinContent = 0; m_maxBinContent = 0;
} }
void Histogram2D::FillData(double x, double y) void Histogram2D::FillData(double x, double y)
{ {
if(x < m_xMin || x >= m_xMax || y < m_yMin || y >= m_yMax || !m_initFlag) if(x < m_params.min_x || x >= m_params.max_x || y < m_params.min_y || y >= m_params.max_y || !m_initFlag)
return; return;
int bin_x = int((x - m_xMin)/m_binWidthX); int bin_x = int((x - m_params.min_x)/m_binWidthX);
int bin_y = int((y - m_yMin)/m_binWidthY); int bin_y = int((y - m_params.min_y)/m_binWidthY);
int bin = bin_y*m_nXBins + bin_x; int bin = bin_y*m_params.nbins_x + bin_x;
m_binCounts[bin] += 1.0; m_binCounts[bin] += 1.0;
@ -116,12 +127,14 @@ namespace Navigator {
//Can only be used within an ImGui / ImPlot context!! //Can only be used within an ImGui / ImPlot context!!
void Histogram2D::Draw() void Histogram2D::Draw()
{ {
ImPlot::PlotHeatmap(m_name.c_str(), &m_binCounts.data()[0], m_nYBins, m_nXBins, 0, m_maxBinContent, NULL, ImPlotPoint(m_xMin, m_yMin), ImPlotPoint(m_xMax, m_yMax)); ImPlot::SetupAxes(m_params.x_par.c_str(), m_params.y_par.c_str(), 0, 0);
ImPlot::PlotHeatmap(m_params.name.c_str(), &m_binCounts.data()[0], m_params.nbins_y, m_params.nbins_x, 0, m_maxBinContent, NULL,
ImPlotPoint(m_params.min_x, m_params.min_y), ImPlotPoint(m_params.max_x, m_params.max_y));
} }
void Histogram2D::ClearData() void Histogram2D::ClearData()
{ {
for(int i=0; i<m_nBins; i++) for(int i=0; i<m_nBinsTotal; i++)
m_binCounts[i] = 0; m_binCounts[i] = 0;
m_maxBinContent = 0; m_maxBinContent = 0;
} }

View File

@ -5,15 +5,32 @@
namespace Navigator { namespace Navigator {
struct NAV_API HistogramParameters
{
HistogramParameters(const std::string& n, const std::string& x, const std::string& y) :
name(n), x_par(x), y_par(y)
{
}
std::string name;
std::string x_par;
std::string y_par;
int nbins_x = 0;
double min_x = 0;
double max_x = 0;
int nbins_y = 0;
double min_y = 0;
double max_y = 0;
};
class NAV_API Histogram class NAV_API Histogram
{ {
public: public:
Histogram() : Histogram() :
m_name("None"), m_xParam("None"), m_yParam("None"), m_initFlag(false) m_params("None", "None", "None"), m_initFlag(false)
{ {
} }
Histogram(const std::string& name, const std::string& param_x, const std::string& param_y="None") : Histogram(const std::string& name, const std::string& param_x, const std::string& param_y="None") :
m_name(name), m_xParam(param_x), m_yParam(param_y), m_initFlag(false) m_params(name, param_x, param_y), m_initFlag(false)
{ {
} }
@ -21,14 +38,15 @@ namespace Navigator {
virtual void FillData(double x, double y = 0) { NAV_WARN("Trying to fill a default histogram!"); } virtual void FillData(double x, double y = 0) { NAV_WARN("Trying to fill a default histogram!"); }
virtual void Draw() {} virtual void Draw() {}
virtual void ClearData() {} virtual void ClearData() {}
inline const std::string& GetXParam() const { return m_xParam; }; inline virtual bool Is1D() const { return false; }
inline const std::string& GetYParam() const { return m_yParam; }; inline virtual bool Is2D() const { return false; }
inline const std::string& GetName() const { return m_name; } inline const HistogramParameters& GetParameters() const { return m_params; }
inline const std::string& GetXParam() const { return m_params.x_par; };
inline const std::string& GetYParam() const { return m_params.y_par; };
inline const std::string& GetName() const { return m_params.name; }
protected: protected:
std::string m_name; HistogramParameters m_params;
std::string m_xParam;
std::string m_yParam;
bool m_initFlag; bool m_initFlag;
}; };
@ -40,17 +58,16 @@ namespace Navigator {
virtual void FillData(double x, double y=0) override; virtual void FillData(double x, double y=0) override;
virtual void Draw() override; virtual void Draw() override;
virtual void ClearData() override; virtual void ClearData() override;
inline virtual bool Is1D() const override { return true; }
inline virtual bool Is2D() const override { return false; }
private: private:
void InitBins(); void InitBins(int bins, double min, double max);
std::vector<double> m_binCenters; std::vector<double> m_binCenters;
std::vector<double> m_binCounts; std::vector<double> m_binCounts;
int m_nBins;
double m_binWidth; double m_binWidth;
double m_xMin;
double m_xMax;
}; };
class NAV_API Histogram2D : public Histogram class NAV_API Histogram2D : public Histogram
@ -62,18 +79,14 @@ namespace Navigator {
virtual void FillData(double x, double y=0) override; virtual void FillData(double x, double y=0) override;
virtual void Draw() override; virtual void Draw() override;
virtual void ClearData() override; virtual void ClearData() override;
inline virtual bool Is1D() const override { return false; }
inline virtual bool Is2D() const override { return true; }
private: private:
void InitBins(); void InitBins(int bins_x, double min_x, double max_x, int bins_y, double min_y, double max_y);
std::vector<double> m_binCounts; std::vector<double> m_binCounts;
int m_nBins; int m_nBinsTotal;
int m_nXBins;
int m_nYBins;
double m_xMin;
double m_xMax;
double m_yMin;
double m_yMax;
double m_binWidthY; double m_binWidthY;
double m_binWidthX; double m_binWidthX;
double m_maxBinContent; double m_maxBinContent;

View File

@ -2,15 +2,15 @@
#include "ParameterMap.h" #include "ParameterMap.h"
namespace Navigator { namespace Navigator {
Navigator::HistogramMap::HistogramMap() HistogramMap::HistogramMap()
{ {
} }
Navigator::HistogramMap::~HistogramMap() HistogramMap::~HistogramMap()
{ {
} }
void Navigator::HistogramMap::UpdateHistograms() void HistogramMap::UpdateHistograms()
{ {
std::lock_guard<std::mutex> guard(m_histMutex); std::lock_guard<std::mutex> guard(m_histMutex);
std::string xpar, ypar; std::string xpar, ypar;
@ -20,7 +20,7 @@ namespace Navigator {
xpar = pair.second->GetXParam(); xpar = pair.second->GetXParam();
ypar = pair.second->GetYParam(); ypar = pair.second->GetYParam();
if (ypar == "None") if (pair.second->Is1D())
{ {
auto iter = pmap.find(xpar); auto iter = pmap.find(xpar);
if (iter == pmap.end() || !iter->second->validFlag) if (iter == pmap.end() || !iter->second->validFlag)
@ -47,6 +47,16 @@ namespace Navigator {
} }
} }
std::vector<HistogramParameters> HistogramMap::GetListOfHistogramParams()
{
std::lock_guard<std::mutex> guard(m_histMutex);
std::vector<HistogramParameters> params;
params.reserve(m_map.size());
for (auto& pair : m_map)
params.push_back(pair.second->GetParameters());
return params;
}
//Only to be used within ImGui context!! //Only to be used within ImGui context!!
void Navigator::HistogramMap::DrawHistograms() void Navigator::HistogramMap::DrawHistograms()
{ {
@ -54,4 +64,13 @@ namespace Navigator {
for (auto& pair : m_map) for (auto& pair : m_map)
pair.second->Draw(); pair.second->Draw();
} }
//Only to be used within ImGui context!!
void Navigator::HistogramMap::DrawHistogram(const std::string& name)
{
std::lock_guard<std::mutex> guard(m_histMutex);
auto iter = m_map.find(name);
if (iter != m_map.end())
iter->second->Draw();
}
} }

View File

@ -16,17 +16,26 @@ namespace Navigator {
HistogramMap(); HistogramMap();
~HistogramMap(); ~HistogramMap();
inline void AddHistogram(const std::string& name, const std::string& param, int bins, double min, double max) { m_map[name].reset(new Histogram1D(name, param, bins, min, max)); } inline void AddHistogram(const std::string& name, const std::string& param, int bins, double min, double max)
{
std::lock_guard<std::mutex> guard(m_histMutex);
m_map[name].reset(new Histogram1D(name, param, bins, min, max));
}
inline void AddHistogram(const std::string& name, const std::string& paramx, const std::string& paramy, int bins_x, double min_x, double max_x, inline void AddHistogram(const std::string& name, const std::string& paramx, const std::string& paramy, int bins_x, double min_x, double max_x,
int bins_y, double min_y, double max_y) int bins_y, double min_y, double max_y)
{ {
std::lock_guard<std::mutex> guard(m_histMutex);
m_map[name].reset(new Histogram2D(name, paramx, paramy, bins_x, min_x, max_x, bins_y, min_y, max_y)); m_map[name].reset(new Histogram2D(name, paramx, paramy, bins_x, min_x, max_x, bins_y, min_y, max_y));
} }
void UpdateHistograms(); void UpdateHistograms();
void DrawHistograms(); void DrawHistograms();
void DrawHistogram(const std::string& name);
std::vector<HistogramParameters> GetListOfHistogramParams(); //thread safe access for GUI to the underlying parameters. Only needs to be called when a gram is added/removed
/*Not in general thread safe*/
inline Iter begin() { return m_map.begin(); } inline Iter begin() { return m_map.begin(); }
inline Iter end() { return m_map.end(); } inline Iter end() { return m_map.end(); }