diff --git a/Navigator/src/Navigator/Editor/EditorLayer.cpp b/Navigator/src/Navigator/Editor/EditorLayer.cpp index 7f0cf45..fa7721a 100644 --- a/Navigator/src/Navigator/Editor/EditorLayer.cpp +++ b/Navigator/src/Navigator/Editor/EditorLayer.cpp @@ -1,5 +1,6 @@ #include "EditorLayer.h" #include "imgui.h" +#include "implot.h" namespace Navigator { @@ -28,7 +29,55 @@ namespace Navigator { 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::BeginMenu("File")) @@ -44,10 +93,122 @@ namespace Navigator { } 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(); } + + static std::vector paramList = m_histMap->GetListOfHistogramParams(); + if (ImGui::Begin("Active View")) + { + if (paramList.size() > 0) + { + static std::vector 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(); + + } } diff --git a/Navigator/src/Navigator/Histogram.cpp b/Navigator/src/Navigator/Histogram.cpp index bfd6e08..ecaeb96 100644 --- a/Navigator/src/Navigator/Histogram.cpp +++ b/Navigator/src/Navigator/Histogram.cpp @@ -12,30 +12,33 @@ namespace Navigator { 1D Histogram class */ 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() {} - 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; 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_binCounts.resize(m_nBins); + m_binCenters.resize(m_params.nbins_x); + m_binCounts.resize(m_params.nbins_x); - for(int i=0; i= m_xMax || !m_initFlag) + if(x < m_params.min_x || x >= m_params.max_x || !m_initFlag) return; - int bin = int((x - m_xMin)/(m_binWidth)); + int bin = int((x - m_params.min_x)/(m_binWidth)); m_binCounts[bin] += 1.0; } @@ -56,12 +59,13 @@ namespace Navigator { //Can only be used within an ImGui / ImPlot context!! 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() { - for(int i=0; i= 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, - m_xMin, m_xMax, m_yMin, m_yMax); + 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_params.min_x, m_params.max_x, m_params.min_y, m_params.max_y); m_initFlag = false; return; } - m_binWidthX = (m_xMax - m_xMin)/m_nXBins; - m_binWidthY = (m_yMax - m_yMin)/m_nYBins; + m_binWidthX = (m_params.max_x - m_params.min_x)/m_params.nbins_x; + 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); - for(int i=0; i= 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; - int bin_x = int((x - m_xMin)/m_binWidthX); - int bin_y = int((y - m_yMin)/m_binWidthY); - int bin = bin_y*m_nXBins + bin_x; + int bin_x = int((x - m_params.min_x)/m_binWidthX); + int bin_y = int((y - m_params.min_y)/m_binWidthY); + int bin = bin_y*m_params.nbins_x + bin_x; m_binCounts[bin] += 1.0; @@ -116,12 +127,14 @@ namespace Navigator { //Can only be used within an ImGui / ImPlot context!! 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() { - for(int i=0; i m_binCenters; std::vector m_binCounts; - int m_nBins; double m_binWidth; - double m_xMin; - double m_xMax; + }; class NAV_API Histogram2D : public Histogram @@ -62,18 +79,14 @@ namespace Navigator { virtual void FillData(double x, double y=0) override; virtual void Draw() override; virtual void ClearData() override; + inline virtual bool Is1D() const override { return false; } + inline virtual bool Is2D() const override { return true; } 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 m_binCounts; - int m_nBins; - int m_nXBins; - int m_nYBins; - double m_xMin; - double m_xMax; - double m_yMin; - double m_yMax; + int m_nBinsTotal; double m_binWidthY; double m_binWidthX; double m_maxBinContent; diff --git a/Navigator/src/Navigator/HistogramMap.cpp b/Navigator/src/Navigator/HistogramMap.cpp index a88475a..3ef308f 100644 --- a/Navigator/src/Navigator/HistogramMap.cpp +++ b/Navigator/src/Navigator/HistogramMap.cpp @@ -2,15 +2,15 @@ #include "ParameterMap.h" namespace Navigator { - Navigator::HistogramMap::HistogramMap() + HistogramMap::HistogramMap() { } - Navigator::HistogramMap::~HistogramMap() + HistogramMap::~HistogramMap() { } - void Navigator::HistogramMap::UpdateHistograms() + void HistogramMap::UpdateHistograms() { std::lock_guard guard(m_histMutex); std::string xpar, ypar; @@ -20,7 +20,7 @@ namespace Navigator { xpar = pair.second->GetXParam(); ypar = pair.second->GetYParam(); - if (ypar == "None") + if (pair.second->Is1D()) { auto iter = pmap.find(xpar); if (iter == pmap.end() || !iter->second->validFlag) @@ -47,6 +47,16 @@ namespace Navigator { } } + std::vector HistogramMap::GetListOfHistogramParams() + { + std::lock_guard guard(m_histMutex); + std::vector 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!! void Navigator::HistogramMap::DrawHistograms() { @@ -54,4 +64,13 @@ namespace Navigator { for (auto& pair : m_map) pair.second->Draw(); } + + //Only to be used within ImGui context!! + void Navigator::HistogramMap::DrawHistogram(const std::string& name) + { + std::lock_guard guard(m_histMutex); + auto iter = m_map.find(name); + if (iter != m_map.end()) + iter->second->Draw(); + } } \ No newline at end of file diff --git a/Navigator/src/Navigator/HistogramMap.h b/Navigator/src/Navigator/HistogramMap.h index fa283fe..5bbdddc 100644 --- a/Navigator/src/Navigator/HistogramMap.h +++ b/Navigator/src/Navigator/HistogramMap.h @@ -16,18 +16,27 @@ namespace Navigator { 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 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, int bins_y, double min_y, double max_y) { + std::lock_guard guard(m_histMutex); m_map[name].reset(new Histogram2D(name, paramx, paramy, bins_x, min_x, max_x, bins_y, min_y, max_y)); } void UpdateHistograms(); void DrawHistograms(); + void DrawHistogram(const std::string& name); - inline Iter begin() { return m_map.begin(); } + std::vector 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 end() { return m_map.end(); } private: