From e9a59b82972d9ad68db2bdbac0f8efa6b708d9ed Mon Sep 17 00:00:00 2001 From: Xun Li Date: Tue, 4 Dec 2018 14:04:15 -0700 Subject: [PATCH 01/10] no summary for geometric centroids in spectral and hdbscan #1762 --- DialogTools/HDBScanDlg.cpp | 12 ++++++++++-- DialogTools/SpectralClusteringDlg.cpp | 15 +++++++++++---- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/DialogTools/HDBScanDlg.cpp b/DialogTools/HDBScanDlg.cpp index 293343b3e..98520915a 100644 --- a/DialogTools/HDBScanDlg.cpp +++ b/DialogTools/HDBScanDlg.cpp @@ -488,23 +488,31 @@ void HDBScanDlg::OnOKClick(wxCommandEvent& event ) */ double** ragged_distances = distancematrix(rows, columns, input_data, mask, weight, dist, transpose); double** distances = DataUtils::fullRaggedMatrix(ragged_distances, rows, rows); + for (int i = 1; i < rows; i++) free(ragged_distances[i]); free(ragged_distances); // add weight to input_data + double** data = new double*[rows]; for (int i=0; i clusters(rows, 0); diff --git a/DialogTools/SpectralClusteringDlg.cpp b/DialogTools/SpectralClusteringDlg.cpp index 26a10ac79..20ddf6c8f 100644 --- a/DialogTools/SpectralClusteringDlg.cpp +++ b/DialogTools/SpectralClusteringDlg.cpp @@ -611,13 +611,16 @@ void SpectralClusteringDlg::OnOK(wxCommandEvent& event ) int affinity_type = 0; // add weight to input_data + double** data = new double*[rows]; for (int i=0; iIsChecked()) { @@ -629,9 +632,13 @@ void SpectralClusteringDlg::OnOK(wxCommandEvent& event ) affinity_type = 1; } spectral.cluster(affinity_type); - - + vector clusters = spectral.get_assignments(); + + for (int i=0; i clusters_undef; From 25ed4087f8371dbc896512ee3f4a3a633a0082f1 Mon Sep 17 00:00:00 2001 From: Xun Li Date: Tue, 4 Dec 2018 14:13:29 -0700 Subject: [PATCH 02/10] Update CsvFieldConfDlg.cpp Fix a bug that change field type in csv configuration dialog doesn't reflect in X/Y choice control --- DialogTools/CsvFieldConfDlg.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DialogTools/CsvFieldConfDlg.cpp b/DialogTools/CsvFieldConfDlg.cpp index 160efd06a..f971d601b 100644 --- a/DialogTools/CsvFieldConfDlg.cpp +++ b/DialogTools/CsvFieldConfDlg.cpp @@ -67,7 +67,7 @@ CsvFieldConfDlg::CsvFieldConfDlg(wxWindow* parent, { wxLogMessage("Open CsvFieldConfDlg."); - + HEADERS = 1; lat_box = NULL; n_max_rows = 10; filepath = _filepath; From 13ae4842138975236355998ef95de216d25c5f0c Mon Sep 17 00:00:00 2001 From: Xun Li Date: Tue, 4 Dec 2018 16:08:06 -0700 Subject: [PATCH 03/10] spanning tree save issue skater spanning tree weights properties incorrect #1765 skater spanning tree gwt format incorrect #1764 no id variable for gwt skater spanning tree #1763 --- DataViewer/OGRTable.cpp | 4 +-- DataViewer/VarOrderPtree.cpp | 6 ++--- DialogTools/AbstractClusterDlg.cpp | 2 +- DialogTools/RedcapDlg.cpp | 41 +++++++++++++++++++++++++----- DialogTools/SkaterDlg.cpp | 39 +++++++++++++++++++++++----- ShapeOperations/WeightUtils.cpp | 7 +++-- ShapeOperations/WeightUtils.h | 2 +- VarCalc/WeightsMetaInfo.cpp | 5 ++++ VarCalc/WeightsMetaInfo.h | 2 +- 9 files changed, 84 insertions(+), 24 deletions(-) diff --git a/DataViewer/OGRTable.cpp b/DataViewer/OGRTable.cpp index cb250a042..6db3e3b81 100644 --- a/DataViewer/OGRTable.cpp +++ b/DataViewer/OGRTable.cpp @@ -1582,7 +1582,7 @@ int OGRTable::FindOGRColId(int wxgrid_col_pos, int time) int OGRTable::FindOGRColId(const wxString& name) { for (size_t i=0; i < org_var_names.size(); i++ ) { - if (name == org_var_names[i] ) { + if (name.CmpNoCase(org_var_names[i]) == 0 ) { return i; } } @@ -1601,7 +1601,7 @@ OGRColumn* OGRTable::FindOGRColumn(const wxString& name) if (name.IsEmpty()) return NULL; for (size_t i=0; i ds_var_set; - BOOST_FOREACH(const wxString &v, ds_var_list) { ds_var_set.insert(v); } + BOOST_FOREACH(const wxString &v, ds_var_list) { ds_var_set.insert(v.Lower()); } set var_set; set group_nm_set; BOOST_FOREACH(const VarGroup& e, var_grps) { if (e.vars.size() == 0) { - var_set.insert(e.name); + var_set.insert(e.name.Lower()); } else { group_nm_set.insert(e.name); BOOST_FOREACH(const wxString& v, e.vars) { - if (!v.empty()) var_set.insert(v); + if (!v.empty()) var_set.insert(v.Lower()); } } } diff --git a/DialogTools/AbstractClusterDlg.cpp b/DialogTools/AbstractClusterDlg.cpp index 1ad086458..beed5f250 100644 --- a/DialogTools/AbstractClusterDlg.cpp +++ b/DialogTools/AbstractClusterDlg.cpp @@ -739,7 +739,7 @@ double AbstractClusterDlg::CreateSummary(const vector >& solution, c summary << _printConfiguration(); // auto weighting - if (m_use_centroids->IsChecked()) { + if (m_use_centroids != NULL && m_use_centroids->IsChecked()) { wxString w_val = m_wc_txt->GetValue(); double w_valf = 0; if (w_val.ToDouble(&w_valf)) { diff --git a/DialogTools/RedcapDlg.cpp b/DialogTools/RedcapDlg.cpp index e8b506cf7..8799c11b4 100644 --- a/DialogTools/RedcapDlg.cpp +++ b/DialogTools/RedcapDlg.cpp @@ -387,11 +387,31 @@ void RedcapDlg::OnSaveTree(wxCommandEvent& event ) { if (weights && redcap) { wxString filter = "GWT|*.gwt"; - wxFileDialog dialog(NULL, _("Save Spanning Tree to a Weights File"), wxEmptyString, + wxFileDialog dialog(NULL, _("Save Spanning Tree to a Weights File"), + wxEmptyString, wxEmptyString, filter, wxFD_SAVE | wxFD_OVERWRITE_PROMPT); - if (dialog.ShowModal() != wxID_OK) + if (dialog.ShowModal() != wxID_OK) { return; + } + // get info from input weights + vector weights_ids; + WeightsManInterface* w_man_int = project->GetWManInt(); + w_man_int->GetIds(weights_ids); + int sel = combo_weights->GetSelection(); + if (sel < 0) sel = 0; + if (sel >= weights_ids.size()) sel = weights_ids.size()-1; + boost::uuids::uuid w_id = weights_ids[sel]; + GalWeight* gw = w_man_int->GetGal(w_id); + GeoDaWeight* gdw = (GeoDaWeight*)gw; + wxString id = gdw->GetIDName(); + int col = table_int->FindColId(id); + if (col < 0) { + return; + } + vector ids; + table_int->GetColData(col, 0, ids); + wxFileName fname = wxFileName(dialog.GetPath()); wxString new_main_dir = fname.GetPathWithSep(); wxString new_main_name = fname.GetName(); @@ -402,20 +422,27 @@ void RedcapDlg::OnSaveTree(wxCommandEvent& event ) file.Clear(); wxString header; - header << "0 " << project->GetNumRecords() << " " << project->GetProjectTitle(); + header << "0 " << project->GetNumRecords() << " " << project->GetProjectTitle() << " " << id; file.AddLine(header); + for (int i=0; iordered_edges.size(); i++) { wxString line; - line << redcap->ordered_edges[i]->orig->id+1<< " " << redcap->ordered_edges[i]->dest->id +1<< " " << redcap->ordered_edges[i]->length ; - file.AddLine(line); + int from_idx = redcap->ordered_edges[i]->orig->id; + int to_idx = redcap->ordered_edges[i]->dest->id; + double cost = redcap->ordered_edges[i]->length; + wxString line1; + line1 << ids[from_idx] << " " << ids[to_idx] << " " << cost; + file.AddLine(line1); + wxString line2; + line2 << ids[to_idx] << " " << ids[from_idx] << " " << cost; + file.AddLine(line2); } file.Write(); file.Close(); // Load the weights file into Weights Manager - WeightsManInterface* w_man_int = project->GetWManInt(); - WeightUtils::LoadGwtInMan(w_man_int, new_txt, table_int); + WeightUtils::LoadGwtInMan(w_man_int, new_txt, table_int, id); } } diff --git a/DialogTools/SkaterDlg.cpp b/DialogTools/SkaterDlg.cpp index 8bc82eae0..660cac2ad 100644 --- a/DialogTools/SkaterDlg.cpp +++ b/DialogTools/SkaterDlg.cpp @@ -225,12 +225,31 @@ void SkaterDlg::OnSaveTree(wxCommandEvent& event ) { if (skater) { wxString filter = "GWT|*.gwt"; - wxFileDialog dialog(NULL, _("Save Spanning Tree to a Weights File"), wxEmptyString, + wxFileDialog dialog(NULL, _("Save Spanning Tree to a Weights File"), + wxEmptyString, wxEmptyString, filter, wxFD_SAVE | wxFD_OVERWRITE_PROMPT); if (dialog.ShowModal() != wxID_OK) { return; } + // get info from input weights + vector weights_ids; + WeightsManInterface* w_man_int = project->GetWManInt(); + w_man_int->GetIds(weights_ids); + int sel = combo_weights->GetSelection(); + if (sel < 0) sel = 0; + if (sel >= weights_ids.size()) sel = weights_ids.size()-1; + boost::uuids::uuid w_id = weights_ids[sel]; + GalWeight* gw = w_man_int->GetGal(w_id); + GeoDaWeight* gdw = (GeoDaWeight*)gw; + wxString id = gdw->GetIDName(); + int col = table_int->FindColId(id); + if (col < 0) { + return; + } + vector ids; + table_int->GetColData(col, 0, ids); + wxFileName fname = wxFileName(dialog.GetPath()); wxString new_main_dir = fname.GetPathWithSep(); wxString new_main_name = fname.GetName(); @@ -241,20 +260,26 @@ void SkaterDlg::OnSaveTree(wxCommandEvent& event ) file.Clear(); wxString header; - header << "0 " << project->GetNumRecords() << " " << project->GetProjectTitle(); + header << "0 " << project->GetNumRecords() << " " << project->GetProjectTitle() << " " << id; file.AddLine(header); + for (int i=0; iordered_edges.size(); i++) { - wxString line; - line << skater->ordered_edges[i]->orig->id+1<< " " << skater->ordered_edges[i]->dest->id +1<< " " << skater->ordered_edges[i]->length ; - file.AddLine(line); + int from_idx = skater->ordered_edges[i]->orig->id; + int to_idx = skater->ordered_edges[i]->dest->id; + double cost = skater->ordered_edges[i]->length; + wxString line1; + line1 << ids[from_idx] << " " << ids[to_idx] << " " << cost; + file.AddLine(line1); + wxString line2; + line2 << ids[to_idx] << " " << ids[from_idx] << " " << cost; + file.AddLine(line2); } file.Write(); file.Close(); // Load the weights file into Weights Manager - WeightsManInterface* w_man_int = project->GetWManInt(); - WeightUtils::LoadGwtInMan(w_man_int, new_txt, table_int); + WeightUtils::LoadGwtInMan(w_man_int, new_txt, table_int, id); } } diff --git a/ShapeOperations/WeightUtils.cpp b/ShapeOperations/WeightUtils.cpp index 4a63ce081..1c8def1d3 100644 --- a/ShapeOperations/WeightUtils.cpp +++ b/ShapeOperations/WeightUtils.cpp @@ -857,7 +857,7 @@ GalElement* WeightUtils::Gwt2Gal(GwtElement* Gwt, long obs) } -void WeightUtils::LoadGwtInMan(WeightsManInterface* w_man_int, wxString filepath, TableInterface* table_int) +void WeightUtils::LoadGwtInMan(WeightsManInterface* w_man_int, wxString filepath, TableInterface* table_int, wxString id_field) { int rows = table_int->GetNumberRows(); @@ -872,10 +872,13 @@ void WeightUtils::LoadGwtInMan(WeightsManInterface* w_man_int, wxString filepath w->num_obs = rows; w->wflnm = filepath; w->gal = tempGal; - w->id_field = "unknown"; + w->id_field = id_field; + w->is_symmetric = true; w->GetNbrStats(); wmi.num_obs = w->GetNumObs(); + wmi.id_var = id_field; + wmi.SetSymmetric(w->is_symmetric); wmi.SetMinNumNbrs(w->GetMinNumNbrs()); wmi.SetMaxNumNbrs(w->GetMaxNumNbrs()); wmi.SetMeanNumNbrs(w->GetMeanNumNbrs()); diff --git a/ShapeOperations/WeightUtils.h b/ShapeOperations/WeightUtils.h index 19766d567..aea3a9820 100644 --- a/ShapeOperations/WeightUtils.h +++ b/ShapeOperations/WeightUtils.h @@ -35,7 +35,7 @@ namespace WeightUtils { TableInterface* table_int); GwtElement* ReadGwt(const wxString& w_fname, TableInterface* table_int); GalElement* Gwt2Gal(GwtElement* Gwt, long obs); - void LoadGwtInMan(WeightsManInterface* w_man_int, wxString filepath, TableInterface* table_int); + void LoadGwtInMan(WeightsManInterface* w_man_int, wxString filepath, TableInterface* table_int, wxString id_field); } #endif diff --git a/VarCalc/WeightsMetaInfo.cpp b/VarCalc/WeightsMetaInfo.cpp index 25d06f109..8bb70eae8 100644 --- a/VarCalc/WeightsMetaInfo.cpp +++ b/VarCalc/WeightsMetaInfo.cpp @@ -92,6 +92,11 @@ void WeightsMetaInfo::SetToCustom(const wxString& idv) id_var = idv; } +void WeightsMetaInfo::SetSymmetric(bool is_sym) +{ + sym_type = is_sym ? SYM_symmetric : SYM_unknown; +} + void WeightsMetaInfo::SetToRook(const wxString& idv, long order_, bool inc_lower_orders_) { SetToDefaults(); diff --git a/VarCalc/WeightsMetaInfo.h b/VarCalc/WeightsMetaInfo.h index 05756904d..7c0bdc319 100644 --- a/VarCalc/WeightsMetaInfo.h +++ b/VarCalc/WeightsMetaInfo.h @@ -162,7 +162,7 @@ struct WeightsMetaInfo void SetMaxNumNbrs(int val); void SetMeanNumNbrs(double val); void SetMedianNumNbrs(double val); - + void SetSymmetric(bool is_sym); }; #endif From 7f063fe754c833ad36107d0cf7db2d114a69491e Mon Sep 17 00:00:00 2001 From: Xun Li Date: Tue, 4 Dec 2018 16:08:55 -0700 Subject: [PATCH 04/10] Update version.h --- version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.h b/version.h index 27619bad7..fc674416c 100644 --- a/version.h +++ b/version.h @@ -4,8 +4,8 @@ namespace Gda { const int version_build = 1; const int version_subbuild = 179; const int version_year = 2018; - const int version_month = 11; - const int version_day = 26; + const int version_month = 12; + const int version_day = 4; const int version_night = 0; const int version_type = 2; // 0: alpha, 1: beta, 2: release } From 47746bf2b0099fcba452650f1990d6a5731ede2b Mon Sep 17 00:00:00 2001 From: Xun Li Date: Tue, 4 Dec 2018 21:21:22 -0700 Subject: [PATCH 05/10] update for windows --- BuildTools/windows/GeoDa.vcxproj | 20 +++- BuildTools/windows/GeoDa.vcxproj.filters | 144 ++++++++++++++--------- Weights/DistUtils.cpp | 4 + kNN/ANN/ANN.h | 3 +- 4 files changed, 111 insertions(+), 60 deletions(-) diff --git a/BuildTools/windows/GeoDa.vcxproj b/BuildTools/windows/GeoDa.vcxproj index 5ec5c80ec..254e974dc 100644 --- a/BuildTools/windows/GeoDa.vcxproj +++ b/BuildTools/windows/GeoDa.vcxproj @@ -389,12 +389,19 @@ + + + + + + + - + @@ -423,6 +430,7 @@ + @@ -538,9 +546,11 @@ - - - + + + + + @@ -548,7 +558,6 @@ - @@ -711,6 +720,7 @@ + diff --git a/BuildTools/windows/GeoDa.vcxproj.filters b/BuildTools/windows/GeoDa.vcxproj.filters index eb6d733be..fe8d541fa 100644 --- a/BuildTools/windows/GeoDa.vcxproj.filters +++ b/BuildTools/windows/GeoDa.vcxproj.filters @@ -50,6 +50,12 @@ {85fd04ff-4aa4-45d8-8492-8a7d69f0dc17} + + {5afad44a-83ce-4cf0-bb16-70dcd9e4b1e6} + + + {dcde4097-4967-4ebe-98cd-897b7657a5d2} + @@ -729,39 +735,6 @@ DialogTools - - kNN - - - kNN - - - kNN - - - kNN - - - kNN - - - kNN - - - kNN - - - kNN - - - kNN - - - kNN - - - kNN - Algorithms @@ -841,6 +814,45 @@ DialogTools + + kNN + + + kNN + + + kNN + + + kNN + + + kNN + + + kNN + + + kNN + + + kNN + + + kNN + + + Weights + + + kNN\ANN + + + kNN\ANN + + + kNN\ANN + @@ -1419,27 +1431,6 @@ DialogTools - - kNN - - - kNN - - - kNN - - - kNN - - - kNN - - - kNN - - - kNN - Algorithms @@ -1509,5 +1500,50 @@ DialogTools + + kNN + + + kNN + + + kNN + + + kNN + + + kNN + + + kNN + + + kNN + + + kNN + + + kNN + + + kNN + + + kNN + + + kNN + + + kNN + + + kNN + + + Weights + \ No newline at end of file diff --git a/Weights/DistUtils.cpp b/Weights/DistUtils.cpp index 68dce194e..80afbc16b 100644 --- a/Weights/DistUtils.cpp +++ b/Weights/DistUtils.cpp @@ -9,6 +9,10 @@ #include #include "DistUtils.h" +#ifndef M_PI + #define M_PI 3.1415926535897932384626433832795 +#endif + using namespace GeoDa; DistUtils::DistUtils(const std::vector >& input_data, int distance_metric) diff --git a/kNN/ANN/ANN.h b/kNN/ANN/ANN.h index c523608ed..00c4a145f 100755 --- a/kNN/ANN/ANN.h +++ b/kNN/ANN/ANN.h @@ -76,7 +76,8 @@ #ifdef DLL_EXPORTS #define DLL_API __declspec(dllexport) #else - #define DLL_API __declspec(dllimport) + //#define DLL_API __declspec(dllimport) + #define DLL_API #endif //---------------------------------------------------------------------- // DLL_API is ignored for all other systems From a0964db0aca92f3433e3cc8bef3ca721b7622abb Mon Sep 17 00:00:00 2001 From: Xun Li Date: Wed, 5 Dec 2018 22:16:27 -0700 Subject: [PATCH 06/10] conditional map - custom classification doesn't work #1774 --- Explore/CatClassifManager.cpp | 2 + Explore/CatClassifState.cpp | 11 +++- Explore/CatClassifState.h | 2 +- Explore/ConditionalClusterMapView.cpp | 4 +- Explore/ConditionalHistogramView.cpp | 3 +- Explore/ConditionalHistogramView.h | 4 +- Explore/ConditionalMapView.cpp | 88 +++++++++++++++++++++++--- Explore/ConditionalMapView.h | 6 +- Explore/ConditionalNewView.cpp | 7 +- Explore/ConditionalNewView.h | 2 + Explore/ConditionalScatterPlotView.cpp | 4 +- Explore/ConditionalScatterPlotView.h | 2 +- GdaConst.h | 1 + Project.cpp | 9 +-- 14 files changed, 116 insertions(+), 29 deletions(-) diff --git a/Explore/CatClassifManager.cpp b/Explore/CatClassifManager.cpp index a5cc95ed7..45a46e349 100644 --- a/Explore/CatClassifManager.cpp +++ b/Explore/CatClassifManager.cpp @@ -39,6 +39,7 @@ CatClassifManager::~CatClassifManager() for (std::list::iterator it=classif_states.begin(); it != classif_states.end(); it++) { (*it)->closeAndDeleteWhenEmpty(); + delete *it; } table_state->removeObserver(this); } @@ -76,6 +77,7 @@ void CatClassifManager::RemoveClassifState(CatClassifState* ccs) { ccs->closeAndDeleteWhenEmpty(); classif_states.remove(ccs); + delete ccs; } bool CatClassifManager::VerifyAgainstTable() diff --git a/Explore/CatClassifState.cpp b/Explore/CatClassifState.cpp index 1444338df..0a60821bc 100644 --- a/Explore/CatClassifState.cpp +++ b/Explore/CatClassifState.cpp @@ -27,13 +27,14 @@ CatClassifState::CatClassifState() CatClassifState::~CatClassifState() { + } void CatClassifState::closeAndDeleteWhenEmpty() { delete_self_when_empty = true; if (observers.size() == 0) { - delete this; + //delete this; } } @@ -44,8 +45,12 @@ void CatClassifState::registerObserver(CatClassifStateObserver* o) void CatClassifState::removeObserver(CatClassifStateObserver* o) { - observers.remove(o); - if (observers.size() == 0 && delete_self_when_empty) delete this; + if (observers.size() > 0) { + observers.remove(o); + } + if (observers.size() == 0 && delete_self_when_empty) { + delete this; + } } void CatClassifState::notifyObservers() diff --git a/Explore/CatClassifState.h b/Explore/CatClassifState.h index 6a915e200..3c82ee877 100644 --- a/Explore/CatClassifState.h +++ b/Explore/CatClassifState.h @@ -43,7 +43,7 @@ class CatClassifState { wxString GetTitle() { return cc_data.title; } int GetNumberObservers() { return observers.size(); } -private: +protected: /** The list of registered CatClassifStateObserver objects. */ std::list observers; /** When the project is being closed, this is set to true so that diff --git a/Explore/ConditionalClusterMapView.cpp b/Explore/ConditionalClusterMapView.cpp index a0973ac35..17677e68b 100644 --- a/Explore/ConditionalClusterMapView.cpp +++ b/Explore/ConditionalClusterMapView.cpp @@ -71,10 +71,9 @@ num_categories(1),bin_bm(0), bin_bg_map_pen(wxColor(200,200,200)), bin_bg_map_brush(wxColor(200,200,200)), cc_state_map(0), -full_map_redraw_needed(true), title(ttl) { - + full_map_redraw_needed = true; } ConditionalClusterMapCanvas::~ConditionalClusterMapCanvas() @@ -599,6 +598,7 @@ void ConditionalClusterMapCanvas::PopulateCanvas() shp->setPen(bin_bg_map_pen); shp->setBrush(bin_bg_map_brush); } + isResize = true; full_map_redraw_needed = false; } } else { diff --git a/Explore/ConditionalHistogramView.cpp b/Explore/ConditionalHistogramView.cpp index d9060066e..159e201d6 100644 --- a/Explore/ConditionalHistogramView.cpp +++ b/Explore/ConditionalHistogramView.cpp @@ -65,9 +65,9 @@ ConditionalHistogramCanvas(wxWindow *parent, const wxPoint& pos, const wxSize& size) : ConditionalNewCanvas(parent, t_frame, project_s, v_info, col_ids, false, true, pos, size), -full_map_redraw_needed(true), show_axes(true), scale_x_over_time(true), scale_y_over_time(true) { + full_map_redraw_needed = true; int hist_var_tms = data[HIST_VAR].shape()[0]; data_stats.resize(hist_var_tms); @@ -524,6 +524,7 @@ void ConditionalHistogramCanvas::PopulateCanvas() last_scale_trans.left_margin = virtual_screen_marg_left; last_scale_trans.right_margin = virtual_screen_marg_right; + isResize = true; ResizeSelectableShps(); } diff --git a/Explore/ConditionalHistogramView.h b/Explore/ConditionalHistogramView.h index c307abc29..2d8737e10 100644 --- a/Explore/ConditionalHistogramView.h +++ b/Explore/ConditionalHistogramView.h @@ -82,9 +82,7 @@ class ConditionalHistogramCanvas : public ConditionalNewCanvas { void sel_shp_to_cell(int i, int& r, int& c, int& ival); int cell_to_sel_shp_gen(int r, int c, int ival, int cols, int ivals); - - bool full_map_redraw_needed; - + static const int HIST_VAR; // histogram variable // size = time_steps if HIST_VAR is time variant diff --git a/Explore/ConditionalMapView.cpp b/Explore/ConditionalMapView.cpp index 25218dbbb..7fcbdeca7 100644 --- a/Explore/ConditionalMapView.cpp +++ b/Explore/ConditionalMapView.cpp @@ -64,9 +64,9 @@ ConditionalMapCanvas(wxWindow *parent, num_categories(1),bin_bm(0), bin_bg_map_pen(wxColor(200,200,200)), bin_bg_map_brush(wxColor(200,200,200)), -cc_state_map(0), -full_map_redraw_needed(true) +cc_state_map(0) { + full_map_redraw_needed = true; using namespace Shapefile; SetCatType(CatClassification::no_theme); @@ -113,7 +113,7 @@ void ConditionalMapCanvas::DisplayRightClickMenu(const wxPoint& pos) wxMenu* optMenu = wxXmlResource::Get()->LoadMenu("ID_COND_MAP_VIEW_MENU_OPTIONS"); AddTimeVariantOptionsToMenu(optMenu); - TemplateCanvas::AppendCustomCategories(optMenu, project->GetCatClassifManager()); + AppendCustomCategories(optMenu, project->GetCatClassifManager()); SetCheckMarks(optMenu); template_frame->UpdateContextMenuItems(optMenu); @@ -121,6 +121,75 @@ void ConditionalMapCanvas::DisplayRightClickMenu(const wxPoint& pos) template_frame->UpdateOptionMenuItems(); } +void ConditionalMapCanvas::AppendCustomCategories(wxMenu* menu, CatClassifManager* ccm) +{ + // search for ID_CAT_CLASSIF_A(B,C)_MENU submenus + const int num_sub_menus=3; + vector menu_id(num_sub_menus); + vector sub_menu_id(num_sub_menus); + vector base_id(num_sub_menus); + menu_id[0] = XRCID("ID_NEW_CUSTOM_CAT_CLASSIF_A"); + menu_id[1] = XRCID("ID_NEW_CUSTOM_CAT_CLASSIF_B"); // conditional horizontal menu + menu_id[2] = XRCID("ID_NEW_CUSTOM_CAT_CLASSIF_C"); // conditional verticle menu + sub_menu_id[0] = XRCID("ID_CAT_CLASSIF_A_MENU"); + sub_menu_id[1] = XRCID("ID_CAT_CLASSIF_B_MENU"); + sub_menu_id[2] = XRCID("ID_CAT_CLASSIF_C_MENU"); + base_id[0] = GdaConst::ID_CUSTOM_CAT_CLASSIF_CHOICE_A0; + base_id[1] = GdaConst::ID_CUSTOM_CAT_CLASSIF_CHOICE_B0; + base_id[2] = GdaConst::ID_CUSTOM_CAT_CLASSIF_CHOICE_C0; + + for (int i=0; iFindItem(sub_menu_id[i]); + if (!smii) continue; + wxMenu* smi = smii->GetSubMenu(); + if (!smi) continue; + int m_id = smi->FindItem(_("Custom Breaks")); + wxMenuItem* mi = smi->FindItem(m_id); + if (!mi) continue; + + wxMenu* sm = mi->GetSubMenu(); + // clean + wxMenuItemList items = sm->GetMenuItems(); + for (int i=0; iDelete(items[i]); + } + + sm->Append(menu_id[i], _("Create New Custom"), _("Create new custom categories classification.")); + sm->AppendSeparator(); + + vector titles; + ccm->GetTitles(titles); + for (size_t j=0; jAppend(base_id[i]+j, titles[j]); + } + + if (i==0) { + // regular map men + GdaFrame::GetGdaFrame()->Bind(wxEVT_COMMAND_MENU_SELECTED, + &ConditionalMapCanvas::OnCustomCategoryClick, this, GdaConst::ID_CUSTOM_CAT_CLASSIF_CHOICE_A0, GdaConst::ID_CUSTOM_CAT_CLASSIF_CHOICE_A0 + titles.size()); + } else if (i==1) { + // conditional horizontal map menu + GdaFrame::GetGdaFrame()->Bind(wxEVT_COMMAND_MENU_SELECTED, &GdaFrame::OnCustomCategoryClick_B, GdaFrame::GetGdaFrame(), GdaConst::ID_CUSTOM_CAT_CLASSIF_CHOICE_B0, GdaConst::ID_CUSTOM_CAT_CLASSIF_CHOICE_B0 + titles.size()); + } else if (i==2) { + // conditional verticle map menu + GdaFrame::GetGdaFrame()->Bind(wxEVT_COMMAND_MENU_SELECTED, &GdaFrame::OnCustomCategoryClick_C, GdaFrame::GetGdaFrame(), GdaConst::ID_CUSTOM_CAT_CLASSIF_CHOICE_C0, GdaConst::ID_CUSTOM_CAT_CLASSIF_CHOICE_C0 + titles.size()); + } + } +} + +void ConditionalMapCanvas::OnCustomCategoryClick(wxCommandEvent& event) +{ + int xrc_id = event.GetId(); + CatClassifManager* ccm = project->GetCatClassifManager(); + if (!ccm) return; + vector titles; + ccm->GetTitles(titles); + int idx = xrc_id - GdaConst::ID_CUSTOM_CAT_CLASSIF_CHOICE_A0; + if (idx < 0 || idx >= titles.size()) return; + wxString cc_title = titles[idx]; + + ((ConditionalMapFrame*) template_frame)->ChangeThemeType(CatClassification::custom, 4, cc_title); +} /** * Overwrite TemplaceCanvas Scroll */ @@ -648,11 +717,13 @@ void ConditionalMapCanvas::PopulateCanvas() { int canvas_ts = cat_data.GetCurrentCanvasTmStep(); - if (!map_valid[canvas_ts]) full_map_redraw_needed = true; + if (map_valid[canvas_ts] == false) { + full_map_redraw_needed = true; + } // Note: only need to delete selectable shapes if the cartogram // relative positions change. Otherwise, just reuse. - if (full_map_redraw_needed) { + if (full_map_redraw_needed == true) { BOOST_FOREACH( GdaShape* shp, selectable_shps ) { delete shp; } selectable_shps.clear(); } @@ -661,12 +732,13 @@ void ConditionalMapCanvas::PopulateCanvas() foreground_shps.clear(); if (map_valid[canvas_ts]) { - if (full_map_redraw_needed) { + if (full_map_redraw_needed == true) { CreateSelShpsFromProj(selectable_shps, project); BOOST_FOREACH( GdaShape* shp, selectable_shps ) { shp->setPen(bin_bg_map_pen); shp->setBrush(bin_bg_map_brush); } + isResize = true; full_map_redraw_needed = false; } } else { @@ -725,9 +797,9 @@ void ConditionalMapCanvas::CreateAndUpdateCategories() { cat_var_sorted.clear(); map_valid.resize(num_time_vals); - for (int t=0; tremoveObserver(this); + } cat_classif_def_vert = ccs->GetCatClassif(); cc_state_vert = ccs; @@ -493,6 +495,7 @@ ChangeThemeType(int var_id, VarInfoAttributeChange(); CreateAndUpdateCategories(var_id); UserChangedCellCategories(); + full_map_redraw_needed = true; PopulateCanvas(); if (template_frame) { template_frame->UpdateTitle(); diff --git a/Explore/ConditionalNewView.h b/Explore/ConditionalNewView.h index 6bafc0459..952cf68e9 100644 --- a/Explore/ConditionalNewView.h +++ b/Explore/ConditionalNewView.h @@ -99,6 +99,8 @@ class ConditionalNewCanvas virtual void UpdateStatusBar(); protected: + bool full_map_redraw_needed; + TableInterface* table_int; CatClassifState* cc_state_vert; CatClassifState* cc_state_horiz; diff --git a/Explore/ConditionalScatterPlotView.cpp b/Explore/ConditionalScatterPlotView.cpp index 2fe93189f..53a4985fe 100644 --- a/Explore/ConditionalScatterPlotView.cpp +++ b/Explore/ConditionalScatterPlotView.cpp @@ -59,7 +59,6 @@ ConditionalScatterPlotCanvas(wxWindow *parent, const wxPoint& pos, const wxSize& size) : ConditionalNewCanvas(parent, t_frame, project_s, v_info, col_ids, false, true, pos, size), -full_map_redraw_needed(true), X(project_s->GetNumRecords()), Y(project_s->GetNumRecords()), XY_undef(project_s->GetNumRecords()), @@ -68,6 +67,7 @@ display_slope_values(true), show_linear_smoother(true), show_lowess_smoother(false) { + full_map_redraw_needed = true; double x_max = var_info[IND_VAR].max_over_time; double x_min = var_info[IND_VAR].min_over_time; double y_max = var_info[DEP_VAR].max_over_time; @@ -450,7 +450,7 @@ void ConditionalScatterPlotCanvas::ResizeSelectableShps(int virtual_scrn_w, col_c = horiz_cat_data.categories[h_time].id_to_cat[i]; selectable_shps[i]->applyScaleTrans(st[row_c][col_c]); } - + isResize = true; layer0_valid = false; Refresh(); diff --git a/Explore/ConditionalScatterPlotView.h b/Explore/ConditionalScatterPlotView.h index 7771b81eb..d8d32c517 100644 --- a/Explore/ConditionalScatterPlotView.h +++ b/Explore/ConditionalScatterPlotView.h @@ -78,7 +78,7 @@ class ConditionalScatterPlotCanvas : public ConditionalNewCanvas { virtual void UpdateStatusBar(); protected: - bool full_map_redraw_needed; + std::vector X; std::vector Y; std::vector XY_undef; diff --git a/GdaConst.h b/GdaConst.h index a6df5b925..db44ca061 100644 --- a/GdaConst.h +++ b/GdaConst.h @@ -144,6 +144,7 @@ class GdaConst { static const int ID_PLOTS_PER_VIEW_OTHER = wxID_HIGHEST + 3100; static const int ID_PLOTS_PER_VIEW_ALL = wxID_HIGHEST + 3200; static const int ID_HISTOGRAM_CLASSIFICATION = wxID_HIGHEST + 3300; + static const int ID_CONDITION_CLASSIFICATION = wxID_HIGHEST + 3400; static const int ID_CUSTOM_CAT_CLASSIF_CHOICE_A0 = wxID_HIGHEST + 4000; static const int ID_CUSTOM_CAT_CLASSIF_CHOICE_B0 = wxID_HIGHEST + 4100; diff --git a/Project.cpp b/Project.cpp index 5a9f9e331..54f43f32c 100644 --- a/Project.cpp +++ b/Project.cpp @@ -189,10 +189,6 @@ Project::~Project() if (project_conf) delete project_conf; project_conf=0; // datasource* has been deleted in project_conf* layer* datasource = 0; - if (cat_classif_manager) { - delete cat_classif_manager; - cat_classif_manager=0; - } // Again, WeightsManInterface is not needed. if (WeightsNewManager* o = dynamic_cast(w_man_int)) { @@ -236,6 +232,11 @@ Project::~Project() // clean up any global settings MapCanvas::ResetEmptyFlag(); + if (cat_classif_manager) { + delete cat_classif_manager; + cat_classif_manager=0; + } + wxLogMessage("Exiting Project::~Project"); } From 864649aa4609f270ba847582c112256244e503d4 Mon Sep 17 00:00:00 2001 From: Xun Li Date: Thu, 6 Dec 2018 11:55:12 -0700 Subject: [PATCH 07/10] conditional map - custom classification doesn't work #1774 fix possible crash caused by memory leak --- Explore/CatClassifManager.cpp | 1 - Explore/CatClassifManager.h | 16 +++++++++++----- Explore/CatClassifState.cpp | 7 +++---- Explore/ConditionalMapView.cpp | 7 +++++-- Explore/ConditionalNewView.cpp | 14 +++++++++++++- Explore/ConditionalNewView.h | 3 ++- 6 files changed, 34 insertions(+), 14 deletions(-) diff --git a/Explore/CatClassifManager.cpp b/Explore/CatClassifManager.cpp index 45a46e349..71ac600bb 100644 --- a/Explore/CatClassifManager.cpp +++ b/Explore/CatClassifManager.cpp @@ -39,7 +39,6 @@ CatClassifManager::~CatClassifManager() for (std::list::iterator it=classif_states.begin(); it != classif_states.end(); it++) { (*it)->closeAndDeleteWhenEmpty(); - delete *it; } table_state->removeObserver(this); } diff --git a/Explore/CatClassifManager.h b/Explore/CatClassifManager.h index 1a0154081..7220a56e6 100644 --- a/Explore/CatClassifManager.h +++ b/Explore/CatClassifManager.h @@ -34,16 +34,22 @@ class TableInterface; class CatClassifManager : public TableStateObserver { public: CatClassifManager(TableInterface* table_int, - TableState* table_state, CustomClassifPtree* cc_ptree); + TableState* table_state, + CustomClassifPtree* cc_ptree); virtual ~CatClassifManager(); + void GetTitles(std::vector& titles); - CatClassifState* FindClassifState(const wxString& title); - /** Create and return a new CatClassifState object and associate + + CatClassifState* FindClassifState(const wxString& title); + + /** Create and return a new CatClassifState object and associate with a default variable db field name. If the name is blank, then no default preview variable associated. */ CatClassifState* CreateNewClassifState(const CatClassifDef& cc_data); - void RemoveClassifState(CatClassifState* ccs); - bool VerifyAgainstTable(); + + void RemoveClassifState(CatClassifState* ccs); + + bool VerifyAgainstTable(); /** Implementation of TableStateObserver interface */ virtual void update(TableState* o); diff --git a/Explore/CatClassifState.cpp b/Explore/CatClassifState.cpp index 0a60821bc..f1001cefc 100644 --- a/Explore/CatClassifState.cpp +++ b/Explore/CatClassifState.cpp @@ -34,7 +34,7 @@ void CatClassifState::closeAndDeleteWhenEmpty() { delete_self_when_empty = true; if (observers.size() == 0) { - //delete this; + delete this; } } @@ -45,9 +45,8 @@ void CatClassifState::registerObserver(CatClassifStateObserver* o) void CatClassifState::removeObserver(CatClassifStateObserver* o) { - if (observers.size() > 0) { - observers.remove(o); - } + observers.remove(o); + if (observers.size() == 0 && delete_self_when_empty) { delete this; } diff --git a/Explore/ConditionalMapView.cpp b/Explore/ConditionalMapView.cpp index 7fcbdeca7..fb909fc45 100644 --- a/Explore/ConditionalMapView.cpp +++ b/Explore/ConditionalMapView.cpp @@ -101,7 +101,10 @@ cc_state_map(0) ConditionalMapCanvas::~ConditionalMapCanvas() { - if (cc_state_map) cc_state_map->removeObserver(this); + if (cc_state_map) { + cc_state_map->removeObserver(this); + cc_state_map = NULL; + } } void ConditionalMapCanvas::DisplayRightClickMenu(const wxPoint& pos) @@ -382,7 +385,7 @@ void ConditionalMapCanvas::ChangeCatThemeType( if (cc_state_map) { cc_state_map->removeObserver(this); } - cc_state_map = 0; + cc_state_map = NULL; } SetCatType(new_cat_theme); VarInfoAttributeChange(); diff --git a/Explore/ConditionalNewView.cpp b/Explore/ConditionalNewView.cpp index c23bc72f3..b48ec5c4c 100644 --- a/Explore/ConditionalNewView.cpp +++ b/Explore/ConditionalNewView.cpp @@ -484,7 +484,10 @@ ChangeThemeType(int var_id, cat_classif_def_horiz = cc_state_horiz->GetCatClassif(); } } else { - if (ccs) ccs->removeObserver(this); + if (ccs) { + ccs->removeObserver(this); + ccs = 0; + } if (var_id == VERT_VAR) { cc_state_vert = 0; } else { @@ -742,6 +745,8 @@ ConditionalNewFrame(wxFrame *parent, : TemplateFrame(parent, project, title, pos, size, style) { LOG_MSG("In ConditionalNewFrame::ConditionalNewFrame"); + + Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(ConditionalNewFrame::OnClose)); } ConditionalNewFrame::~ConditionalNewFrame() @@ -749,6 +754,13 @@ ConditionalNewFrame::~ConditionalNewFrame() LOG_MSG("In ConditionalNewFrame::~ConditionalNewFrame"); } +void ConditionalNewFrame::OnClose( wxCloseEvent& event ) +{ + delete template_canvas; + Destroy(); + event.Skip(); +} + void ConditionalNewFrame::MapMenus() { LOG_MSG("In ConditionalNewFrame::MapMenus"); diff --git a/Explore/ConditionalNewView.h b/Explore/ConditionalNewView.h index 952cf68e9..abe06f8ca 100644 --- a/Explore/ConditionalNewView.h +++ b/Explore/ConditionalNewView.h @@ -184,7 +184,8 @@ class ConditionalNewFrame : public TemplateFrame { CatClassification::CatClassifType new_theme, int num_categories, const wxString& cc_title = wxEmptyString); - + void OnClose( wxCloseEvent& event ); + DECLARE_EVENT_TABLE() }; From 092f6fe763820e5fbca9b9b53db60fa2c2f70c08 Mon Sep 17 00:00:00 2001 From: Xun Li Date: Thu, 6 Dec 2018 16:32:15 -0700 Subject: [PATCH 08/10] conditional plots - allow a single dimension of conditioning #1775 --- DataViewer/OGRTable.cpp | 10 ++ DataViewer/OGRTable.h | 3 +- DataViewer/TableInterface.h | 3 +- DialogTools/VariableSettingsDlg.cpp | 170 ++++++++++++++++++++++++---- DialogTools/VariableSettingsDlg.h | 34 +++++- Explore/ConditionalMapView.cpp | 10 +- Explore/ConditionalNewView.cpp | 42 +++++-- GeoDa.cpp | 7 +- VarTools.h | 12 +- 9 files changed, 229 insertions(+), 62 deletions(-) diff --git a/DataViewer/OGRTable.cpp b/DataViewer/OGRTable.cpp index 6db3e3b81..802a4b2d3 100644 --- a/DataViewer/OGRTable.cpp +++ b/DataViewer/OGRTable.cpp @@ -557,6 +557,16 @@ bool OGRTable::DoesNameExist(const wxString& name, bool case_sensitive) const return var_order.DoesNameExist(name, case_sensitive); } +int OGRTable::GetFirstNumericCol() +{ + int n = GetNumberCols(); // var_order size + for (size_t i=0; iGetTableInt()), +no_weights_found_fail(false), +is_time(project_s->GetTableInt()->IsTimeVariant()), +time_steps(project_s->GetTableInt()->GetTimeSteps()), +title(title_s), +var1_title(var1_title_s), +var2_title(var2_title_s), +var3_title(var3_title_s), +var4_title(var4_title_s), +num_cats_spin(0), +num_categories(4), +hide_time(hide_time), +all_init(false), +style(style_s), +show_weights(style & SHOW_WEIGHTS), +show_distance(style & SHOW_DISTANCE), +set_second_from_first_mode(style & SET_SECOND_FROM_FIRST), +set_fourth_from_third_mode(style & SET_FOURTH_FROM_THIRD), +var1_str(style & ALLOW_STRING_IN_FIRST), +var2_str(style & ALLOW_STRING_IN_SECOND), +var3_str(style & ALLOW_STRING_IN_THIRD), +var4_str(style & ALLOW_STRING_IN_FOURTH) +{ + wxLogMessage("Open VariableSettingsDlg"); + + default_var_name1 = project->GetDefaultVarName(0); + default_var_name2 = project->GetDefaultVarName(1); + default_var_name3 = project->GetDefaultVarName(2); + default_var_name4 = project->GetDefaultVarName(3); + + if (show_weights && project->GetWManInt()->GetIds().size() == 0) { + no_weights_found_fail = true; + wxXmlResource::Get()->LoadDialog(this, GetParent(), + "ID_VAR_SETTINGS_NO_W_FAIL_DLG"); + SetTitle("No Weights Found"); + } else { + Init(v_type_s); + } + SetParent(0); + GetSizer()->Fit(this); + GetSizer()->SetSizeHints(this); + Centre(); + all_init = true; +} + VariableSettingsDlg::~VariableSettingsDlg() { @@ -974,7 +1030,10 @@ void VariableSettingsDlg::OnVar1Change(wxCommandEvent& event) { if (!all_init) return; - lb1_cur_sel = lb1->GetSelection(); + lb1_cur_sel = lb1->GetSelection(); + if (style & ALLOW_EMPTY_IN_FIRST) { + lb1_cur_sel = lb1_cur_sel == 0 ? 0 : lb1_cur_sel - 1; + } if (lb1_cur_sel >= 0) { int x_pos = sel1_idx_map[lb1_cur_sel]; if (x_pos >= 0) @@ -994,7 +1053,10 @@ void VariableSettingsDlg::OnVar2Change(wxCommandEvent& event) { if (!all_init) return; - lb2_cur_sel = lb2->GetSelection(); + lb2_cur_sel = lb2->GetSelection(); + if (style & ALLOW_EMPTY_IN_SECOND) { + lb2_cur_sel = lb2_cur_sel == 0 ? 0 : lb2_cur_sel - 1; + } if (lb2_cur_sel >= 0) { int x_pos = sel2_idx_map[lb2_cur_sel]; if (x_pos >= 0) @@ -1054,6 +1116,22 @@ void VariableSettingsDlg::OnCancelClick(wxCommandEvent& event) event.Skip(); EndDialog(wxID_CANCEL); } + +bool VariableSettingsDlg::IsFirstVariableEmpty() +{ + if (style & ALLOW_EMPTY_IN_FIRST) { + return lb1->GetSelection() == 0; + } + return false; +} + +bool VariableSettingsDlg::IsSecondVariableEmpty() +{ + if (style & ALLOW_EMPTY_IN_SECOND) { + return lb2->GetSelection() == 0; + } + return false; +} void VariableSettingsDlg::OnOkClick(wxCommandEvent& event) { @@ -1063,7 +1141,18 @@ void VariableSettingsDlg::OnOkClick(wxCommandEvent& event) EndDialog(wxID_CANCEL); return; } - + + if ((style & ALLOW_EMPTY_IN_FIRST) && + (style & ALLOW_EMPTY_IN_SECOND)) { + if (lb1->GetSelection() == 0 && + lb2->GetSelection() == 0) { + wxString msg(_("No field chosen for first and second variable.")); + wxMessageDialog dlg (this, msg, _("Error"), wxOK | wxICON_ERROR); + dlg.ShowModal(); + return; + } + } + if (map_theme_ch) { m_theme = map_theme_ch->GetSelection(); } @@ -1074,8 +1163,11 @@ void VariableSettingsDlg::OnOkClick(wxCommandEvent& event) dlg.ShowModal(); return; } - - v1_col_id = col_id_map[sel1_idx_map[lb1->GetSelection()]]; + int sel_idx = lb1->GetSelection(); + if (style & ALLOW_EMPTY_IN_FIRST) { + sel_idx = sel_idx - 1; + } + v1_col_id = col_id_map[sel1_idx_map[sel_idx]]; v1_name = table_int->GetColName(v1_col_id); project->SetDefaultVarName(0, v1_name); @@ -1093,8 +1185,12 @@ void VariableSettingsDlg::OnOkClick(wxCommandEvent& event) wxMessageDialog dlg (this, msg, _("Error"), wxOK | wxICON_ERROR); dlg.ShowModal(); return; - } - v2_col_id = col_id_map[sel2_idx_map[lb2->GetSelection()]]; + } + int sel_idx = lb2->GetSelection(); + if (style & ALLOW_EMPTY_IN_SECOND) { + sel_idx = sel_idx - 1; + } + v2_col_id = col_id_map[sel2_idx_map[sel_idx]]; v2_name = table_int->GetColName(v2_col_id); project->SetDefaultVarName(1, v2_name); if (is_time) { @@ -1150,9 +1246,9 @@ void VariableSettingsDlg::OnOkClick(wxCommandEvent& event) } else { - if (show_weights) + if (show_weights) { project->GetWManInt()->MakeDefault(GetWeightsId()); - + } if (GetDistanceMetric() != WeightsMetaInfo::DM_unspecified) { project->SetDefaultDistMetric(GetDistanceMetric()); } @@ -1316,6 +1412,14 @@ void VariableSettingsDlg::InitFieldChoices() int sel2_idx = 0; int sel3_idx = 0; int sel4_idx = 0; + + if (style & ALLOW_EMPTY_IN_FIRST) { + lb1->Append(" "); // empty selection + } + + if (style & ALLOW_EMPTY_IN_SECOND) { + lb2->Append(" "); // empty selection + } for (int i=0, iend=col_id_map.size(); iGetColType(col_id_map[i]); @@ -1380,6 +1484,8 @@ void VariableSettingsDlg::InitFieldChoices() } } + + for (int i=0, iend=col_id_map.size(); iGetColName(col_id_map[i]); @@ -1446,11 +1552,21 @@ bool VariableSettingsDlg::CheckEmptyColumn(int col_id, int time) wxString VariableSettingsDlg::FillData() { wxString emptyVar; + col_ids.resize(num_var); var_info.resize(num_var); - if (num_var >= 1) { - int sel_idx = lb1->GetSelection(); + if (num_var >= 1) { + int sel_idx = lb1->GetSelection(); + if (style & ALLOW_EMPTY_IN_FIRST) { + if (sel_idx == 0) { + // no selection: case ConditionalMap, + sel_idx = table_int->GetFirstNumericCol(); + var_info[0].is_hide = true; + } else { + sel_idx = sel_idx - 1; + } + } int col_idx = sel1_idx_map[sel_idx]; v1_col_id = col_id_map[col_idx]; v1_name = table_int->GetColName(v1_col_id); @@ -1461,17 +1577,25 @@ wxString VariableSettingsDlg::FillData() emptyVar = v1_name; } } - if (num_var >= 2) { - //v2_col_id = col_id_map[lb2->GetSelection()]; - int sel_idx = lb2->GetSelection(); - int col_idx = sel2_idx_map[sel_idx]; - v2_col_id = col_id_map[col_idx]; - v2_name = table_int->GetColName(v2_col_id); - col_ids[1] = v2_col_id; - var_info[1].time = v2_time; - - if (emptyVar.empty() && CheckEmptyColumn(v2_col_id, v2_time)) { - emptyVar = v2_name; + if (num_var >= 2) { + int sel_idx = lb2->GetSelection(); + if (style & ALLOW_EMPTY_IN_SECOND) { + if (sel_idx == 0) { + // no selection: case ConditionalMap, + sel_idx = table_int->GetFirstNumericCol(); + var_info[1].is_hide = true; + } else { + sel_idx = sel_idx - 1; + } + } + int col_idx = sel2_idx_map[sel_idx]; + v2_col_id = col_id_map[col_idx]; + v2_name = table_int->GetColName(v2_col_id); + col_ids[1] = v2_col_id; + var_info[1].time = v2_time; + + if (emptyVar.empty() && CheckEmptyColumn(v2_col_id, v2_time)) { + emptyVar = v2_name; } } if (num_var >= 3) { diff --git a/DialogTools/VariableSettingsDlg.h b/DialogTools/VariableSettingsDlg.h index cdb3570b1..9b53e5162 100644 --- a/DialogTools/VariableSettingsDlg.h +++ b/DialogTools/VariableSettingsDlg.h @@ -132,9 +132,31 @@ class VariableSettingsDlg: public wxDialog public: enum VarType { univariate, bivariate, trivariate, quadvariate, rate_smoothed - }; + }; + + enum Style { + DEFAULT_STYLE = 0, + SHOW_WEIGHTS = 1, //0b00000001 + SHOW_DISTANCE = 2, //0b00000010 + SET_SECOND_FROM_FIRST = 4, + SET_FOURTH_FROM_THIRD = 8, + SHOW_TIME = 16, + ALLOW_STRING_IN_FIRST = 32, + ALLOW_STRING_IN_SECOND = 64, + ALLOW_STRING_IN_THIRD = 128, + ALLOW_STRING_IN_FOURTH = 256, + ALLOW_EMPTY_IN_FIRST = 512, + ALLOW_EMPTY_IN_SECOND = 1024 + }; + + VariableSettingsDlg(Project* project, VarType v_type, int style, + const wxString& title=_("Variable Settings"), + const wxString& var1_title=_("First Variable (X)"), + const wxString& var2_title=_("Second Variable (Y)"), + const wxString& var3_title=_("Third Variable (Z)"), + const wxString& var4_title=_("Fourth Variable")); - VariableSettingsDlg( Project* project, VarType v_type, + VariableSettingsDlg(Project* project, VarType v_type, bool show_weights = false, bool show_distance = false, const wxString& title=_("Variable Settings"), @@ -169,7 +191,10 @@ class VariableSettingsDlg: public wxDialog void OnSpinCtrl( wxSpinEvent& event ); void OnOkClick( wxCommandEvent& event ); void OnCancelClick( wxCommandEvent& event ); - + + bool IsFirstVariableEmpty(); + bool IsSecondVariableEmpty(); + std::vector var_info; std::vector col_ids; CatClassification::CatClassifType GetCatClassifType(); // for rate smoothed @@ -180,7 +205,8 @@ class VariableSettingsDlg: public wxDialog protected: int m_theme; // for rate_smoothed - + int style; + bool var1_str; bool var2_str; bool var3_str; diff --git a/Explore/ConditionalMapView.cpp b/Explore/ConditionalMapView.cpp index fb909fc45..5d3e8a6f5 100644 --- a/Explore/ConditionalMapView.cpp +++ b/Explore/ConditionalMapView.cpp @@ -956,20 +956,14 @@ BEGIN_EVENT_TABLE(ConditionalMapFrame, ConditionalNewFrame) EVT_ACTIVATE(ConditionalMapFrame::OnActivate) END_EVENT_TABLE() -ConditionalMapFrame::ConditionalMapFrame(wxFrame *parent, Project* project, - const vector& var_info, - const vector& col_ids, - const wxString& title, const wxPoint& pos, - const wxSize& size, const long style) -: ConditionalNewFrame(parent, project, var_info, col_ids, title, pos, - size, style) +ConditionalMapFrame::ConditionalMapFrame(wxFrame *parent, Project* project, const vector& var_info, const vector& col_ids, const wxString& title, const wxPoint& pos, const wxSize& size, const long style) +: ConditionalNewFrame(parent, project, var_info, col_ids, title, pos, size, style) { wxLogMessage("Open ConditionalNewFrame."); int width, height; GetClientSize(&width, &height); - wxSplitterWindow* splitter_win = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_3D|wxSP_LIVE_UPDATE|wxCLIP_CHILDREN); diff --git a/Explore/ConditionalNewView.cpp b/Explore/ConditionalNewView.cpp index b48ec5c4c..20332bb35 100644 --- a/Explore/ConditionalNewView.cpp +++ b/Explore/ConditionalNewView.cpp @@ -97,8 +97,9 @@ full_map_redraw_needed(true) else table_int->GetColData(col_ids[VERT_VAR], s_data[VERT_VAR]); for (size_t i=0; iGetColData(col_ids[i], data[i]); + } table_int->GetColUndefined(col_ids[i], data_undef[i]); template_frame->AddGroupDependancy(var_info[i].name); } @@ -123,12 +124,16 @@ full_map_redraw_needed(true) else horiz_str_var_sorted[t].resize(num_obs); for (int i=0; i Date: Thu, 6 Dec 2018 20:43:50 -0700 Subject: [PATCH 09/10] conditional plots - allow a single dimension of conditioning #1775 update version --- Explore/ConditionalMapView.cpp | 13 ++++++++++++- version.h | 4 ++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Explore/ConditionalMapView.cpp b/Explore/ConditionalMapView.cpp index 5d3e8a6f5..a75afd03d 100644 --- a/Explore/ConditionalMapView.cpp +++ b/Explore/ConditionalMapView.cpp @@ -118,7 +118,18 @@ void ConditionalMapCanvas::DisplayRightClickMenu(const wxPoint& pos) AddTimeVariantOptionsToMenu(optMenu); AppendCustomCategories(optMenu, project->GetCatClassifManager()); SetCheckMarks(optMenu); - + + if (var_info[VERT_VAR].is_hide) { + wxMenuItem* m = optMenu->FindItem(XRCID("ID_CAT_CLASSIF_B_MENU")); + wxMenu* smi = m->GetSubMenu(); + GeneralWxUtils::EnableMenuRecursive(smi, false); + } + if (var_info[HOR_VAR].is_hide) { + wxMenuItem* m = optMenu->FindItem(XRCID("ID_CAT_CLASSIF_C_MENU")); + wxMenu* smi = m->GetSubMenu(); + GeneralWxUtils::EnableMenuRecursive(smi, false); + } + template_frame->UpdateContextMenuItems(optMenu); template_frame->PopupMenu(optMenu, pos + GetPosition()); template_frame->UpdateOptionMenuItems(); diff --git a/version.h b/version.h index fc674416c..c06183662 100644 --- a/version.h +++ b/version.h @@ -2,10 +2,10 @@ namespace Gda { const int version_major = 1; const int version_minor = 12; const int version_build = 1; - const int version_subbuild = 179; + const int version_subbuild = 181; const int version_year = 2018; const int version_month = 12; - const int version_day = 4; + const int version_day = 6; const int version_night = 0; const int version_type = 2; // 0: alpha, 1: beta, 2: release } From eb1e51cf93fa9057d8f29e6ed13b4945c6e29743 Mon Sep 17 00:00:00 2001 From: Xun Li Date: Thu, 6 Dec 2018 21:16:11 -0700 Subject: [PATCH 10/10] update fix of #1775 on windows --- Explore/ConditionalMapView.cpp | 4 ++-- Explore/ConditionalNewView.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Explore/ConditionalMapView.cpp b/Explore/ConditionalMapView.cpp index a75afd03d..04b5f83b0 100644 --- a/Explore/ConditionalMapView.cpp +++ b/Explore/ConditionalMapView.cpp @@ -119,12 +119,12 @@ void ConditionalMapCanvas::DisplayRightClickMenu(const wxPoint& pos) AppendCustomCategories(optMenu, project->GetCatClassifManager()); SetCheckMarks(optMenu); - if (var_info[VERT_VAR].is_hide) { + if (var_info[VERT_VAR].is_hide == true) { wxMenuItem* m = optMenu->FindItem(XRCID("ID_CAT_CLASSIF_B_MENU")); wxMenu* smi = m->GetSubMenu(); GeneralWxUtils::EnableMenuRecursive(smi, false); } - if (var_info[HOR_VAR].is_hide) { + if (var_info[HOR_VAR].is_hide == true) { wxMenuItem* m = optMenu->FindItem(XRCID("ID_CAT_CLASSIF_C_MENU")); wxMenu* smi = m->GetSubMenu(); GeneralWxUtils::EnableMenuRecursive(smi, false); diff --git a/Explore/ConditionalNewView.cpp b/Explore/ConditionalNewView.cpp index 20332bb35..c4077e8b3 100644 --- a/Explore/ConditionalNewView.cpp +++ b/Explore/ConditionalNewView.cpp @@ -181,9 +181,9 @@ full_map_redraw_needed(true) } // case that user only need horizontal axe - if (var_info[VERT_VAR].is_hide) { + if (var_info[VERT_VAR].is_hide == true) { SetCatType(VERT_VAR, CatClassification::no_theme, 1); - } else if (var_info[HOR_VAR].is_hide) { + } else if (var_info[HOR_VAR].is_hide == true) { SetCatType(HOR_VAR, CatClassification::no_theme, 1); }