diff --git a/Application/src/tracker/gui/IdentityHeatmap.cpp b/Application/src/tracker/gui/IdentityHeatmap.cpp
index 7801669d514edc5236d8850ba2e88bae5fa3286a..96c8065574c19386eda887a82df13e05af07da11 100644
--- a/Application/src/tracker/gui/IdentityHeatmap.cpp
+++ b/Application/src/tracker/gui/IdentityHeatmap.cpp
@@ -173,6 +173,8 @@ void HeatmapController::sort_data_into_custom_grid() {
     std::vector<double> values;
     std::fill(_array_samples.begin(), _array_samples.end(), _normalization == normalization_t::cell ? 1 : 0);
     std::fill(_array_grid.begin(), _array_grid.end(), 0);
+    if(_normalization == normalization_t::variance)
+        std::fill(_array_sqsum.begin(), _array_sqsum.end(), 0);
     
     if(_normalization == normalization_t::cell
        && isPowerOfTwo(uniform_grid_cell_size))
@@ -194,7 +196,7 @@ void HeatmapController::sort_data_into_custom_grid() {
         });
         
     } else if(isPowerOfTwo(uniform_grid_cell_size)
-              && (_normalization == normalization_t::none || _normalization == normalization_t::value))
+              && (_normalization == normalization_t::none || _normalization == normalization_t::value || _normalization == normalization_t::variance))
     {
         values.clear();
         
@@ -210,10 +212,15 @@ void HeatmapController::sort_data_into_custom_grid() {
             _array_grid.at(i) += r.value_sum();
             _array_samples[i] += r.size();
             
-            if(_normalization != normalization_t::none) {
-                values.push_back(r.value_range().start);
-                values.push_back(r.value_sum() / double(r.size()));
-                values.push_back(r.value_range().end);
+            if(_normalization == normalization_t::variance) {
+                _array_sqsum.at(i) += r.value_sqsum();
+                
+            } else {
+                if(_normalization != normalization_t::none) {
+                    values.push_back(r.value_range().start);
+                    values.push_back(r.value_sum() / double(r.size()));
+                    values.push_back(r.value_range().end);
+                }
             }
             
             //! do not traverse deeper
@@ -221,7 +228,7 @@ void HeatmapController::sort_data_into_custom_grid() {
         });
         
     } else {
-        if(_normalization == normalization_t::value)
+        if(_normalization != normalization_t::none)
             values.reserve(_grid.size());
         
         _grid.apply<Leaf>([&](const Leaf& leaf) -> bool {
@@ -246,6 +253,10 @@ void HeatmapController::sort_data_into_custom_grid() {
                 _array_grid[i] += v;
                 
             } else {
+                if(_normalization == normalization_t::variance) {
+                    _array_sqsum.at(i) += leaf.value_sqsum();
+                }
+                
                 _array_grid[i] += leaf.data().size();
             }
             
@@ -253,6 +264,29 @@ void HeatmapController::sort_data_into_custom_grid() {
         });
     }
     
+    // calculate standard deviation within each cell
+    if(_normalization == normalization_t::variance) {
+        minimum = maximum = infinity<double>();
+        auto m = _grid.root()->value_sum() / double(_grid.size());
+        
+        for (size_t i=0; i<_array_grid.size(); ++i) {
+            if(_array_samples[i] > 1) {
+                //auto m = _array_grid[i] / _array_samples[i];
+                _array_grid[i] = sqrt((- 2 * m * _array_grid[i] + _array_sqsum[i] + N * SQR(m))
+                                        / (_array_samples[i] - 1));
+                
+                if(minimum > _array_grid[i] || minimum == infinity<double>()) {
+                    minimum = _array_grid[i];
+                }
+                if(maximum < _array_grid[i] || maximum == infinity<double>()) {
+                    maximum = _array_grid[i];
+                }
+                
+            } else
+                _array_grid[i] = _array_samples[i] = 0;
+        }
+    }
+    
     if(_normalization != normalization_t::none // none never does any normalization
        && !custom_heatmap_value_range.empty())
     {
@@ -261,6 +295,9 @@ void HeatmapController::sort_data_into_custom_grid() {
         
     } else {
         switch(_normalization) {
+            case normalization_t::variance:
+                break;
+                
             case normalization_t::cell:
                 if(!_array_grid.empty()) {
                     minimum = 0;
@@ -291,7 +328,11 @@ void HeatmapController::sort_data_into_custom_grid() {
     auto mat = grid_image->get();
     
     static auto empty = (cv::Scalar)Viridis::value(0).alpha(0);
-    mat.setTo(empty);
+    static auto empty_variance = (cv::Scalar)Viridis::value(1).alpha(200);
+    if(_normalization == normalization_t::variance)
+        mat.setTo(empty_variance);
+    else
+        mat.setTo(empty);
     
     double percentage;
     double ML = maximum - minimum;
@@ -301,8 +342,10 @@ void HeatmapController::sort_data_into_custom_grid() {
     for (uint32_t x = 0; x < N; ++x) {
         for (uint32_t y = 0; y < N; ++y) {
             size_t i = y * N + x;
-            if(_array_grid[i] > 0) {
+            if(_array_samples[i] > 0) {
                 percentage = (_array_grid[i] / _array_samples[i] - minimum) / ML;
+                if(_normalization == normalization_t::variance)
+                    percentage = 1 - percentage;
                 mat.at<cv::Vec4b>(y, x) = Viridis::value(percentage).alpha(percentage * 200);
             }
         }
@@ -313,6 +356,12 @@ void HeatmapController::sort_data_into_custom_grid() {
     push_timing("sort_data_into_custom_grid", timer.elapsed());
 }
 
+void HeatmapController::frames_deleted_from(long_t frame) {
+    _iterators.clear();
+    _capacities.clear();
+    _grid.keep_only(Range<long_t>(0, max(0, frame-1)));
+}
+
 HeatmapController::UpdatedStats HeatmapController::update_data(long_t current_frame) {
     Timer timer;
             
@@ -332,6 +381,7 @@ HeatmapController::UpdatedStats HeatmapController::update_data(long_t current_fr
                                               current_frame + frame_range + 1);
             //Debug("Clearing grid (%lu).", _grid.size());
             _iterators.clear();
+            _capacities.clear();
             
         } else if(_frame_context != -1) {
             if(current_frame > _frame) {
@@ -374,8 +424,13 @@ HeatmapController::UpdatedStats HeatmapController::update_data(long_t current_fr
                 if(it == _iterators.end()) {
                     kit = fish->iterator_for(frame);
                     //Debug("Frame %d: fish%d, Reit", frame, fish->identity().ID());
-                } else
-                    kit = it->second;
+                } else {
+                    if(_capacities[fish] != fish->frame_segments().capacity()) {
+                        _capacities[fish] = fish->frame_segments().capacity();
+                        kit = fish->iterator_for(frame);
+                    } else
+                        kit = it->second;
+                }
                 
                 if(kit == fish->frame_segments().end() && range.end >= fish->start_frame())
                 {
@@ -516,6 +571,7 @@ bool HeatmapController::update_variables() {
         
         if(_array_grid.size() != N * N) {
             _array_grid.resize(N * N);
+            _array_sqsum.resize(N * N);
             _array_samples.resize(N * N);
         }
         
@@ -676,6 +732,7 @@ void Node::init(const Grid* grid, Node::Ptr parent, const Range<uint32_t>& x, co
     
     _frame_range.start = _frame_range.end = -1;
     _value_sum = 0;
+    _value_sqsum = 0;
     _value_range = Range<double>(infinity<double>(), infinity<double>());
     _IDs.clear();
 }
@@ -859,6 +916,7 @@ size_t Leaf::keep_only(const Range<long_t> &frames) {
 void Leaf::update_ranges() {
     _value_range = Range<double>(infinity<double>(), infinity<double>());
     _value_sum = 0;
+    _value_sqsum = 0;
     
     /*if(_IDs.size() != _grid->identities().size()) {
         _IDs.resize(_grid->identities().size());
@@ -877,6 +935,7 @@ void Leaf::update_ranges() {
             _value_range.end = d.value;
         
         _value_sum += d.value;
+        _value_sqsum += SQR(d.value);
         
         /*++_IDs[d.IDindex];
         _values_per_id[d.IDindex] += d.value;
@@ -1485,6 +1544,7 @@ void Region::insert(std::vector<DataPoint>::iterator start, std::vector<DataPoin
 
 void Region::update_ranges() {
     _value_sum = 0;
+    _value_sqsum = 0;
     _value_range.start = _value_range.end = infinity<double>();
     
     /*if(_IDs.size() != _grid->identities().size()) {
@@ -1508,6 +1568,7 @@ void Region::update_ranges() {
         
         _size += r->size();
         _value_sum += r->value_sum();
+        _value_sqsum += r->value_sqsum();
         
         if(_value_range.start > r->value_range().start)
             _value_range.start = r->value_range().start;
@@ -1620,6 +1681,7 @@ void Leaf::insert(std::vector<DataPoint>::iterator start, std::vector<DataPoint>
     
     for(auto it = start; it != end; ++it) {
         _value_sum += it->value;
+        _value_sqsum += SQR(it->value);
         
         if(_value_range.start > it->value)
             _value_range.start = it->value;
diff --git a/Application/src/tracker/gui/IdentityHeatmap.h b/Application/src/tracker/gui/IdentityHeatmap.h
index c39af38c2f9b2903d82b4837037d6c886f9d5a61..0b97479456c67820a2c6d4abaa4b3e304ee98496 100644
--- a/Application/src/tracker/gui/IdentityHeatmap.h
+++ b/Application/src/tracker/gui/IdentityHeatmap.h
@@ -66,6 +66,7 @@ protected:
     GETTER(Ptr, parent)
     const Grid* _grid;
     GETTER(double, value_sum)
+    GETTER(double, value_sqsum)
     GETTER(Range<double>, value_range)
     
     GETTER(std::vector<uint32_t>, IDs)
@@ -332,10 +333,11 @@ protected:
     OptionsList<Output::Modifiers> _mods;
     std::shared_ptr<ExternalImage> _image;
     
-    std::vector<double> _array_grid, _array_samples;
+    std::vector<double> _array_grid, _array_sqsum, _array_samples;
     
     gpuMat _viridis, _gpuGrid;
     std::map<track::Individual*, track::Individual::segment_map::const_iterator> _iterators;
+    std::map<track::Individual*, size_t> _capacities;
     
 public:
     HeatmapController();
@@ -344,6 +346,8 @@ public:
     void update() override;
     void paint_heatmap();
     void save();
+    void frames_deleted_from(long_t frame);
+    
 private:
     struct UpdatedStats {
         size_t added;
diff --git a/Application/src/tracker/gui/gui.cpp b/Application/src/tracker/gui/gui.cpp
index 5b9a5605eff9e4b6c97931323e325964e08d2abd..f6c279e8ace487c5d03a909a1778a1157fb61cf5 100644
--- a/Application/src/tracker/gui/gui.cpp
+++ b/Application/src/tracker/gui/gui.cpp
@@ -119,6 +119,8 @@ public:
     }
 };
 
+static std::unique_ptr<gui::heatmap::HeatmapController> heatmapController;
+
 void drawOptFlowMap (const cv::Mat& flow, cv::Mat& map) {
     assert(flow.isContinuous());
     assert(map.isContinuous());
@@ -260,8 +262,11 @@ GUI::GUI(pv::File& video_source, const Image& average, Tracker& tracker)
                         Tracker::LockGuard guard("setting_changed_"+name);
                         if(Tracker::recognition())
                             Tracker::recognition()->clear_filter_cache();
-                        if(Tracker::recognition() && Tracker::recognition()->dataset_quality())
-                        Tracker::recognition()->dataset_quality()->remove_frames(Tracker::start_frame());
+                        if(Tracker::recognition() && Tracker::recognition()->dataset_quality()) {
+                            auto start = Tracker::start_frame();
+                            Tracker::recognition()->dataset_quality()->remove_frames(start);
+                            removed_frames(start);
+                        }
                     }
                     
                     std::lock_guard<std::recursive_mutex> lock_guard(this->gui().lock());
@@ -1193,6 +1198,12 @@ void GUI::draw_menu(gui::DrawStructure &base) {
     DrawMenu::draw();
 }
 
+void GUI::removed_frames(long_t including) {
+    std::lock_guard<std::recursive_mutex> gguard(gui().lock());
+    if(heatmapController)
+        heatmapController->frames_deleted_from(including);
+}
+
 void GUI::reanalyse_from(long_t frame, bool in_thread) {
     if(!instance())
         return;
@@ -1209,6 +1220,7 @@ void GUI::reanalyse_from(long_t frame, bool in_thread) {
             if(frame <= Tracker::end_frame()) {
                 Tracker::instance()->wait();
                 Tracker::instance()->_remove_frames(frame);
+                gui->removed_frames(frame);
                 
                 Output::Library::clear_cache();
                 gui->_timeline->reset_events(frame);
@@ -1922,9 +1934,10 @@ void GUI::draw_tracking(DrawStructure& base, long_t frameNr, bool draw_graph) {
                     s->set_pos(ptr_pos);
                 }
                 
-                static auto heatmap = std::make_unique<gui::heatmap::HeatmapController>();
-                heatmap->set_frame(frame());
-                base.wrap_object(*heatmap);
+                if(!heatmapController)
+                    heatmapController = std::make_unique<gui::heatmap::HeatmapController>();
+                heatmapController->set_frame(frame());
+                base.wrap_object(*heatmapController);
             });
         }
         
@@ -4489,7 +4502,9 @@ void GUI::load_state(GUI::GUIType type, file::Path from) {
             });
             
             Except("Cannot load results. Crashed with exception: %s", e.what());
-            Tracker::instance()->_remove_frames(Tracker::start_frame());
+            auto start = Tracker::start_frame();
+            Tracker::instance()->_remove_frames(start);
+            removed_frames(start);
         }
         
         //_analysis->reset_cache();
diff --git a/Application/src/tracker/gui/gui.h b/Application/src/tracker/gui/gui.h
index ec808513c8697c528974199887d2e1adca9307e5..3c19f22fa0006d0b11b08de7a55b8b4c7839352f 100644
--- a/Application/src/tracker/gui/gui.h
+++ b/Application/src/tracker/gui/gui.h
@@ -249,6 +249,8 @@ private:
     void draw_export_options(gui::DrawStructure& base);
     void draw_grid(gui::DrawStructure& base);
     
+    void removed_frames(long_t including);
+    
     void debug_binary(gui::DrawStructure& main_base, long_t frameIndex);
     void debug_optical_flow(gui::DrawStructure& base, long_t frameIndex);
     void redraw();
diff --git a/Application/src/tracker/misc/default_config.cpp b/Application/src/tracker/misc/default_config.cpp
index ebaf812369520839b1743c4536bb181da9da4281..fb809bf71adf6cccbf413f867f3d8f653257afe7 100644
--- a/Application/src/tracker/misc/default_config.cpp
+++ b/Application/src/tracker/misc/default_config.cpp
@@ -44,7 +44,8 @@ namespace default_config {
     ENUM_CLASS_DOCS(heatmap_normalization_t,
                     "No normalization at all. Values will only be averaged per cell.",
                     "Normalization based in value-space. The average of each cell will be divided by the maximum value encountered.",
-                    "The cell sum will be divided by the maximum cell value encountered."
+                    "The cell sum will be divided by the maximum cell value encountered.",
+                    "Displays the variation within each cell."
     )
 
     ENUM_CLASS_DOCS(gui_recording_format_t,
diff --git a/Application/src/tracker/misc/default_config.h b/Application/src/tracker/misc/default_config.h
index 7e5d003b003e8a4ee1c13b83b4c7449d03c7788b..288d83ef753bf1381a63dfa7036de1dbfafdc585 100644
--- a/Application/src/tracker/misc/default_config.h
+++ b/Application/src/tracker/misc/default_config.h
@@ -32,7 +32,7 @@ namespace default_config {
     ENUM_CLASS(recognition_border_t, none, heatmap, outline, shapes, grid, circle);
     ENUM_CLASS_HAS_DOCS(recognition_border_t)
 
-    ENUM_CLASS(heatmap_normalization_t, none, value, cell);
+    ENUM_CLASS(heatmap_normalization_t, none, value, cell, variance);
     ENUM_CLASS_HAS_DOCS(heatmap_normalization_t)
 
     ENUM_CLASS(recognition_normalization_t, none, moments, posture, legacy);
diff --git a/Application/src/tracker/tracking/PairingGraph.cpp b/Application/src/tracker/tracking/PairingGraph.cpp
index 7d9ef93620810280ca2744edb2505194b35a359a..9949514fc613e4999248e5357a5608b2402ecbe3 100644
--- a/Application/src/tracker/tracking/PairingGraph.cpp
+++ b/Application/src/tracker/tracking/PairingGraph.cpp
@@ -873,10 +873,9 @@ PairingGraph::Stack* PairingGraph::work_single(queue_t& stack, Stack &current, c
            // Debug("%d: %d steps in %fms (%d)", frame(), objects, timer.elapsed()*1000, stack.size());
     }*/
     
-    const PairingGraph::Result& PairingGraph::get_optimal_pairing(bool debug, int mode) {
+    const PairingGraph::Result& PairingGraph::get_optimal_pairing(bool debug, default_config::matching_mode_t::Class match_mode) {
         static std::mutex _mutex;
         std::lock_guard<std::mutex> guard(_mutex);
-        const default_config::matching_mode_t::Class match_mode = mode == -1 ? FAST_SETTINGS(match_mode) : default_config::matching_mode_t::Class((default_config::matching_mode_t::data::values)mode);
         
         if(_optimal_pairing)
             delete _optimal_pairing;
diff --git a/Application/src/tracker/tracking/PairingGraph.h b/Application/src/tracker/tracking/PairingGraph.h
index 9abb5fb368f8ae588f13667827e331493cdb1687..a7ec29c8d332bdccadf9d1bb471693e3e6e14853 100644
--- a/Application/src/tracker/tracking/PairingGraph.h
+++ b/Application/src/tracker/tracking/PairingGraph.h
@@ -189,7 +189,7 @@ namespace Match
         //cv::Point2f pos(const Individual*) const;
         //cv::Point2f pos(const Blob*) const;
         
-        const Result& get_optimal_pairing(bool print = false, int mode = -1);
+        const Result& get_optimal_pairing(bool print = false, default_config::matching_mode_t::Class mode = default_config::matching_mode_t::accurate);
         
     public:
         //psets_t _psets;
diff --git a/Application/src/tracker/tracking/Tracker.cpp b/Application/src/tracker/tracking/Tracker.cpp
index 5591398b0c61546abdd3760abf1c6e0d946d7492..887724f44cf61ff61d62d8b584ea78f37e3815f5 100644
--- a/Application/src/tracker/tracking/Tracker.cpp
+++ b/Application/src/tracker/tracking/Tracker.cpp
@@ -2794,7 +2794,13 @@ void Tracker::clear_properties() {
     #endif
             
             try {
-                auto &optimal = graph.get_optimal_pairing(false, frame_uses_approximate ? (int)default_config::matching_mode_t::hungarian.value() : -1 );
+                auto match_mode = frame_uses_approximate
+                    ? default_config::matching_mode_t::hungarian
+                    : FAST_SETTINGS(match_mode);
+                
+                //if(match_mode == default_config::matching_mode_t::accurate)
+                //    U_EXCEPTION("Test %d", frameIndex);
+                auto &optimal = graph.get_optimal_pairing(false, match_mode);
                 
                 if(!frame_uses_approximate) {
                     std::lock_guard<std::mutex> guard(_statistics_mutex);
@@ -2808,7 +2814,7 @@ void Tracker::clear_properties() {
                     _statistics[frameIndex].match_mean_edges_per_fish = mean_edges_per_fish;
                     _statistics[frameIndex].match_improvements_made = optimal.improvements_made;
                     _statistics[frameIndex].match_leafs_visited = optimal.leafs_visited;
-                    _statistics[frameIndex].method_used = (int)FAST_SETTINGS(match_mode).value();
+                    _statistics[frameIndex].method_used = (int)match_mode.value();
                 }
                 
     #if defined(PAIRING_PRINT_STATS)
@@ -2829,7 +2835,6 @@ void Tracker::clear_properties() {
                 
                 graph.print_summary();
     #endif
-
                             
 #if defined(PAIRING_PRINT_STATS)
                 // matching did not work
@@ -2846,7 +2851,7 @@ void Tracker::clear_properties() {
                 Debug("gw ---");
 #endif
                 
-                auto &optimal = graph.get_optimal_pairing(false, (int)default_config::matching_mode_t::hungarian.value());
+                auto &optimal = graph.get_optimal_pairing(false, default_config::matching_mode_t::hungarian);
                 for (auto &p: optimal.pairings) {
                     assign_blob_individual(frameIndex, frame, p.first, ptr2ptr.at(p.second));
                     active_individuals.insert(p.first);
@@ -3501,6 +3506,9 @@ void Tracker::update_iterator_maps(long_t frame, const Tracker::set_of_individua
         _individual_add_iterator_map.clear();
         _segment_map_known_capacity.clear();
         
+        if(_approximative_enabled_in_frame >= frameIndex)
+            _approximative_enabled_in_frame = -1;
+        
         Debug("Removing frames after and including %ld", frameIndex);
         
         if (_endFrame < frameIndex || _startFrame > frameIndex)