[GRASS-SVN] r57761 - sandbox/turek/scatter_plot

svn_grass at osgeo.org svn_grass at osgeo.org
Fri Sep 20 05:39:40 PDT 2013


Author: turek
Date: 2013-09-20 05:39:39 -0700 (Fri, 20 Sep 2013)
New Revision: 57761

Modified:
   sandbox/turek/scatter_plot/testing_patch.diff
Log:
scatter plot: signaling busy state and show coorinates of cursor in plot heading

Modified: sandbox/turek/scatter_plot/testing_patch.diff
===================================================================
--- sandbox/turek/scatter_plot/testing_patch.diff	2013-09-20 10:39:00 UTC (rev 57760)
+++ sandbox/turek/scatter_plot/testing_patch.diff	2013-09-20 12:39:39 UTC (rev 57761)
@@ -1,413 +1,3 @@
-Index: lib/imagery/scatt_sccats.c
-===================================================================
---- lib/imagery/scatt_sccats.c	(revision 0)
-+++ lib/imagery/scatt_sccats.c	(working copy)
-@@ -0,0 +1,405 @@
-+/*!
-+   \file lib/imagery/scatt_cat_rast.c
-+
-+   \brief Imagery library - functions for manipulation with scatter plot structs.
-+
-+   Copyright (C) 2013 by the GRASS Development Team
-+
-+   This program is free software under the GNU General Public License
-+   (>=v2).  Read the file COPYING that comes with GRASS for details.
-+
-+   \author Stepan Turek <stepan.turek at seznam.cz> (Mentor: Martin Landa)
-+ */
-+
-+#include <grass/raster.h>
-+#include <grass/imagery.h>
-+#include <grass/gis.h>
-+
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <math.h>
-+#include <string.h>
-+
-+/*!
-+   \brief Compute band ids from scatter plot id.
-+
-+    Scatter plot id describes which bands defines the scatter plot.
-+
-+    Let say we have 3 bands, their ids are 0, 1 and 2.
-+    Scatter plot with id 0 consists of band 1 (b_1_id) 0 and  band 2 (b_2_id) 1.
-+    All scatter plots:
-+    scatt_id b_1_id b_2_id
-+    0        0      1
-+    1        0      2
-+    2        1      2
-+
-+   \param scatt_id scatter plot id
-+   \param n_bands number of bands
-+   \param [out] b_1_id id of band1
-+   \param[out] b_2_id id of band2
-+
-+   \return 0
-+ */
-+int I_id_scatt_to_bands(const int scatt_id, const int n_bands, int * b_1_id, int * b_2_id)
-+{   
-+    int n_b1 = n_bands - 1;
-+
-+    * b_1_id = (int) ((2 * n_b1 + 1 - sqrt((double)((2 * n_b1 + 1) * (2 * n_b1 + 1) - 8 * scatt_id))) / 2);
-+
-+    * b_2_id = scatt_id - ((* b_1_id) * (2 * n_b1 + 1) - (* b_1_id) * (* b_1_id)) / 2 + (* b_1_id) + 1;
-+
-+    return 0;
-+}
-+
-+
-+/*!
-+   \brief Compute scatter plot id from band ids.
-+
-+    See also I_id_scatt_to_bands().
-+
-+   \param n_bands number of bands
-+   \param b_1_id id of band1
-+   \param b_1_id id of band2
-+   \param [out] scatt_id scatter plot id
-+
-+   \return 0
-+ */
-+int I_bands_to_id_scatt(const int b_1_id, const int b_2_id, const int n_bands, int * scatt_id)
-+{   
-+    int n_b1 = n_bands - 1;
-+
-+    * scatt_id = (b_1_id * (2 * n_b1 + 1) - b_1_id * b_1_id) / 2 + b_2_id - b_1_id - 1;
-+
-+    return 0;
-+}
-+
-+/*!
-+   \brief Initialize structure for storing scatter plots data.
-+
-+   \param cats pointer to scCats struct 
-+   \param n_bands number of bands
-+   \param type SC_SCATT_DATA - stores scatter plots 
-+   \param type SC_SCATT_CONDITIONS - stores selected areas in scatter plots
-+ */
-+void I_sc_init_cats(struct scCats * cats, int n_bands, int type)
-+{
-+    int i_cat;
-+
-+    cats->type = type;
-+
-+    cats->n_cats = 100;
-+    cats->n_a_cats = 0;
-+
-+    cats->n_bands = n_bands;
-+    cats->n_scatts = (n_bands - 1) * n_bands / 2;
-+
-+    cats->cats_arr = (struct scScatts **) G_malloc(cats->n_cats * sizeof(struct scScatts *));
-+    memset(cats->cats_arr, 0, cats-> n_cats * sizeof(struct scScatts *));
-+
-+    cats->cats_ids = (int *)  G_malloc(cats->n_cats * sizeof(int));
-+    cats->cats_idxs =(int *)  G_malloc(cats->n_cats * sizeof(int));
-+
-+    for(i_cat = 0; i_cat < cats->n_cats; i_cat++)
-+        cats->cats_idxs[i_cat] = -1;
-+
-+    return;
-+}
-+
-+/*!
-+   \brief Free data of struct scCats, the structure itself remains alocated.
-+
-+   \param cats pointer to existing scCats struct
-+ */
-+void I_sc_free_cats(struct scCats * cats)
-+{
-+    int i_cat;
-+
-+    for(i_cat = 0; i_cat < cats->n_a_cats; i_cat++)
-+    {        
-+        if(cats->cats_arr[i_cat])
-+        {   
-+            G_free(cats->cats_arr[i_cat]->scatt_idxs);
-+            G_free(cats->cats_arr[i_cat]->scatts_bands);
-+            G_free(cats->cats_arr[i_cat]->scatts_arr);
-+            G_free(cats->cats_arr[i_cat]);
-+        }
-+    }
-+
-+    G_free(cats->cats_ids);
-+    G_free(cats->cats_idxs);
-+    G_free(cats->cats_arr);
-+
-+    cats->n_cats = 0;
-+    cats->n_a_cats = 0;
-+    cats->n_bands = 0;
-+    cats->n_scatts = 0;
-+    cats->type = -1;
-+
-+    return;
-+}
-+
-+#if 0
-+void I_sc_get_active_categories(int * a_cats_ids, int * n_a_cats, struct scCats * cats)
-+{
-+    a_cats_ids = cats->cats_ids;
-+    * n_a_cats = cats->n_a_cats;
-+}
-+#endif
-+
-+/*!
-+   \brief Add category.
-+    
-+    Category represents group of scatter plots.
-+
-+   \param cats pointer to scCats struct
-+
-+   \return assigned category id (starts with 0)
-+   \return -1 if maximum nuber of categories was reached
-+ */
-+int I_sc_add_cat(struct scCats * cats)
-+{
-+    int i_scatt, i_cat_id, cat_id;
-+    int n_a_cats = cats->n_a_cats;
-+
-+    if(cats->n_a_cats >= cats->n_cats)
-+        return -1;
-+
-+    for(i_cat_id = 0; i_cat_id < cats->n_cats; i_cat_id++)
-+        if(cats->cats_idxs[i_cat_id] < 0) {
-+            cat_id = i_cat_id;
-+            break;
-+        }
-+
-+    cats->cats_ids[n_a_cats] = cat_id;
-+    cats->cats_idxs[cat_id] = n_a_cats;
-+    
-+    cats->cats_arr[n_a_cats] = (struct scScatts *) G_malloc(sizeof(struct scScatts));
-+
-+    cats->cats_arr[n_a_cats]->scatts_arr = (struct scdScattData **) G_malloc(cats->n_scatts * sizeof(struct scdScattData *));
-+    memset((cats->cats_arr[n_a_cats]->scatts_arr), 0, cats->n_scatts * sizeof(struct scdScattData *));
-+    
-+    cats->cats_arr[n_a_cats]->n_a_scatts = 0;
-+
-+    cats->cats_arr[n_a_cats]->scatts_bands = (int *) G_malloc(cats->n_scatts * 2 * sizeof(int));
-+     
-+    cats->cats_arr[n_a_cats]->scatt_idxs = (int *) G_malloc(cats->n_scatts * sizeof(int));
-+    for(i_scatt = 0; i_scatt < cats->n_scatts; i_scatt++)
-+        cats->cats_arr[n_a_cats]->scatt_idxs[i_scatt] = -1;
-+    
-+    ++cats->n_a_cats;
-+
-+    return cat_id;
-+}
-+
-+#if 0
-+int I_sc_delete_cat(struct scCats * cats, int cat_id)
-+{
-+    int cat_idx, i_cat;
-+
-+    if(cat_id < 0 || cat_id >= cats->n_cats)
-+        return -1;
-+
-+    cat_idx = cats->cats_idxs[cat_id];
-+    if(cat_idx < 0)
-+        return -1;
-+
-+    G_free(cats->cats_arr[cat_idx]->scatt_idxs);
-+    G_free(cats->cats_arr[cat_idx]->scatts_bands);
-+    G_free(cats->cats_arr[cat_idx]->scatts_arr);
-+    G_free(cats->cats_arr[cat_idx]);
-+
-+    for(i_cat = cat_idx; i_cat < cats->n_a_cats - 1; i_cat++)
-+    {
-+        cats->cats_arr[i_cat] = cats->cats_arr[i_cat + 1];
-+        cats->cats_ids[i_cat] = cats->cats_ids[i_cat + 1];
-+    }
-+    cats->cats_idxs[cat_id] = -1; 
-+
-+    --cats->n_a_cats;
-+    
-+    return 0;
-+}
-+#endif
-+
-+/*!
-+   \brief Insert scatter plot data .
-+    Inserted scatt_data struct must have same type as cats struct (SC_SCATT_DATA or SC_SCATT_CONDITIONS).
-+
-+   \param cats pointer to scCats struct
-+   \param cat_id id number of category.
-+   \param scatt_id id number of scatter plot.
-+
-+   \return  0 on success
-+   \return -1 on failure
-+ */
-+int I_sc_insert_scatt_data(struct scCats * cats, struct scdScattData * scatt_data, int cat_id, int scatt_id)
-+{
-+    int band_1, band_2, cat_idx, n_a_scatts;
-+    struct scScatts * scatts;
-+
-+    if(cat_id < 0 || cat_id >= cats->n_cats)
-+        return -1;
-+
-+    cat_idx = cats->cats_idxs[cat_id];
-+    if(cat_idx < 0)
-+        return -1;
-+
-+    if(scatt_id < 0 && scatt_id >= cats->n_scatts)
-+        return -1;
-+
-+    scatts = cats->cats_arr[cat_idx];
-+    if(scatts->scatt_idxs[scatt_id] >= 0)
-+        return -1;
-+
-+    if(!scatt_data->b_conds_arr && cats->type == SC_SCATT_CONDITIONS)
-+        return -1;
-+
-+    if(!scatt_data->scatt_vals_arr && cats->type == SC_SCATT_DATA)
-+        return -1;
-+
-+    n_a_scatts = scatts->n_a_scatts;
-+
-+    scatts->scatt_idxs[scatt_id] = n_a_scatts;
-+
-+    I_id_scatt_to_bands(scatt_id, cats->n_bands, &band_1, &band_2);
-+
-+    scatts->scatts_bands[n_a_scatts * 2] = band_1;
-+    scatts->scatts_bands[n_a_scatts * 2 + 1] = band_2;
-+
-+    scatts->scatts_arr[n_a_scatts] = scatt_data;
-+    ++scatts->n_a_scatts;
-+
-+    return 0;
-+}
-+
-+#if 0
-+int I_sc_remove_scatt_data(struct scCats * cats, struct scdScattData * scatt_data, int cat_id, int scatt_id)
-+{
-+    int cat_idx, scatt_idx, n_init_scatts, i_scatt;
-+    struct scScatts * scatts;
-+
-+    if(cat_id < 0 && cat_id >= cats->n_cats)
-+        return -1;
-+
-+    cat_idx = cats->cats_idxs[cat_id];
-+    if(cat_idx < 0)
-+        return -1;
-+
-+    if(scatt_id < 0 || scatt_id >= cats->n_scatts)
-+        return -1;
-+
-+    scatts = cats->cats_arr[cat_idx];
-+    if(scatts->scatt_idxs[scatt_id] < 0)
-+        return -1;
-+
-+    scatt_data = scatts->scatts_arr[scatt_idx];
-+
-+    for(i_scatt = scatt_idx; i_scatt < scatts->n_a_scatts - 1; i_scatt++)
-+    {
-+        scatts->scatts_arr[i_scatt] = scatts->scatts_arr[i_scatt + 1];
-+        scatts->scatts_bands[i_scatt * 2] = scatts->scatts_bands[(i_scatt + 1)* 2];
-+        scatts->scatts_bands[i_scatt * 2 + 1] = scatts->scatts_bands[(i_scatt + 1) * 2 + 1];
-+    }
-+    scatts->scatts_arr[scatts->n_a_scatts] = NULL;
-+
-+    scatts->scatt_idxs[scatt_id] = -1;
-+
-+    scatt_data = scatts->scatts_arr[scatt_id];
-+    scatts->n_a_scatts--;
-+
-+    return 0;
-+}
-+
-+int I_sc_set_value(struct scCats * cats, int cat_id, int scatt_id, int value_idx, int value)
-+{
-+    int n_a_scatts = cats->cats_arr[cat_id]->n_a_scatts;
-+    int cat_idx, scatt_idx, ret;
-+
-+    cat_idx = cats->cats_idxs[cat_id];
-+    if(cat_idx < 0)
-+        return -1;
-+    
-+    if(cats->cats_arr[cat_idx]->scatt_idxs[scatt_id] < 0)
-+        return -1;
-+
-+    cat_idx = cats->cats_idxs[cat_id];
-+    scatt_idx = cats->cats_arr[cat_idx]->scatt_idxs[scatt_id];
-+
-+    I_scd_set_value(cats->cats_arr[cat_idx]->scatts_arr[scatt_idx], value_idx, value);
-+
-+    return 0;
-+}
-+#endif
-+
-+/*!
-+   \brief Insert scatter plot data.
-+    
-+   \param scatt_data pointer to existing struct scdScattData
-+   \param type SC_SCATT_DATA for scatter plots or SC_SCATT_CONDITIONS for selected areas in scatter plot
-+   \param n_vals number of data values
-+   \param data array of values (unsigned char for SC_SCATT_CONDITIONS, unsigned int for SC_SCATT_DATA)
-+ */
-+void I_scd_init_scatt_data(struct scdScattData * scatt_data, int type, int n_vals, void * data)
-+{
-+    scatt_data->n_vals = n_vals;
-+
-+    if(type == SC_SCATT_DATA)
-+    {   
-+        if(data)
-+            scatt_data->scatt_vals_arr = (unsigned int *) data;
-+        else {
-+            scatt_data->scatt_vals_arr = (unsigned int *) G_malloc(n_vals * sizeof(unsigned int));
-+            memset(scatt_data->scatt_vals_arr, 0, n_vals * sizeof(unsigned int)); 
-+        }
-+        scatt_data->b_conds_arr = NULL;
-+    }
-+    else if(type == SC_SCATT_CONDITIONS)
-+    {
-+        if(data)
-+            scatt_data->b_conds_arr = (unsigned char *) data;
-+        else {
-+            scatt_data->b_conds_arr = (unsigned char *) G_malloc(n_vals * sizeof(unsigned char));
-+            memset(scatt_data->b_conds_arr, 0, n_vals * sizeof(unsigned char));
-+        }
-+        scatt_data->scatt_vals_arr = NULL;
-+    }
-+
-+    return;
-+}
-+
-+
-+#if 0
-+void I_scd_get_range_min_max(struct scdScattData * scatt_data, CELL * band_1_min, CELL * band_1_max, CELL * band_2_min, CELL * band_2_max)
-+{
-+
-+    Rast_get_range_min_max(&(scatt_data->band_1_range), band_1_min, band_2_min);
-+    Rast_get_range_min_max(&(scatt_data->band_2_range), band_2_min, band_2_max);
-+
-+    return;
-+}
-+s
-+void * I_scd_get_data_ptr(struct scdScattData * scatt_data)
-+{
-+    if(!scatt_data->b_conds_arr)
-+        return scatt_data->b_conds_arr;
-+    else if(!scatt_data->scatt_vals_arr)
-+        return scatt_data->scatt_vals_arr;
-+
-+    return NULL;
-+}
-+
-+int I_scd_set_value(struct scdScattData * scatt_data, unsigned int val_idx, unsigned int val)
-+{
-+    if(val_idx < 0 && val_idx >  scatt_data->n_vals)
-+        return -1;
-+
-+    if(scatt_data->b_conds_arr)
-+        scatt_data->b_conds_arr[val_idx] = val;
-+    else if(scatt_data->scatt_vals_arr)
-+        scatt_data->scatt_vals_arr[val_idx] = val;
-+    else
-+        return -1;
-+
-+    return 0;
-+}
-+#endif
 Index: lib/imagery/scatt.c
 ===================================================================
 --- lib/imagery/scatt.c	(revision 0)
@@ -1284,9 +874,419 @@
 +    G_free(perimeter.points);  
 +    return 0;
 +}
+Index: lib/imagery/scatt_sccats.c
+===================================================================
+--- lib/imagery/scatt_sccats.c	(revision 0)
++++ lib/imagery/scatt_sccats.c	(working copy)
+@@ -0,0 +1,405 @@
++/*!
++   \file lib/imagery/scatt_cat_rast.c
++
++   \brief Imagery library - functions for manipulation with scatter plot structs.
++
++   Copyright (C) 2013 by the GRASS Development Team
++
++   This program is free software under the GNU General Public License
++   (>=v2).  Read the file COPYING that comes with GRASS for details.
++
++   \author Stepan Turek <stepan.turek at seznam.cz> (Mentor: Martin Landa)
++ */
++
++#include <grass/raster.h>
++#include <grass/imagery.h>
++#include <grass/gis.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <math.h>
++#include <string.h>
++
++/*!
++   \brief Compute band ids from scatter plot id.
++
++    Scatter plot id describes which bands defines the scatter plot.
++
++    Let say we have 3 bands, their ids are 0, 1 and 2.
++    Scatter plot with id 0 consists of band 1 (b_1_id) 0 and  band 2 (b_2_id) 1.
++    All scatter plots:
++    scatt_id b_1_id b_2_id
++    0        0      1
++    1        0      2
++    2        1      2
++
++   \param scatt_id scatter plot id
++   \param n_bands number of bands
++   \param [out] b_1_id id of band1
++   \param[out] b_2_id id of band2
++
++   \return 0
++ */
++int I_id_scatt_to_bands(const int scatt_id, const int n_bands, int * b_1_id, int * b_2_id)
++{   
++    int n_b1 = n_bands - 1;
++
++    * b_1_id = (int) ((2 * n_b1 + 1 - sqrt((double)((2 * n_b1 + 1) * (2 * n_b1 + 1) - 8 * scatt_id))) / 2);
++
++    * b_2_id = scatt_id - ((* b_1_id) * (2 * n_b1 + 1) - (* b_1_id) * (* b_1_id)) / 2 + (* b_1_id) + 1;
++
++    return 0;
++}
++
++
++/*!
++   \brief Compute scatter plot id from band ids.
++
++    See also I_id_scatt_to_bands().
++
++   \param n_bands number of bands
++   \param b_1_id id of band1
++   \param b_1_id id of band2
++   \param [out] scatt_id scatter plot id
++
++   \return 0
++ */
++int I_bands_to_id_scatt(const int b_1_id, const int b_2_id, const int n_bands, int * scatt_id)
++{   
++    int n_b1 = n_bands - 1;
++
++    * scatt_id = (b_1_id * (2 * n_b1 + 1) - b_1_id * b_1_id) / 2 + b_2_id - b_1_id - 1;
++
++    return 0;
++}
++
++/*!
++   \brief Initialize structure for storing scatter plots data.
++
++   \param cats pointer to scCats struct 
++   \param n_bands number of bands
++   \param type SC_SCATT_DATA - stores scatter plots 
++   \param type SC_SCATT_CONDITIONS - stores selected areas in scatter plots
++ */
++void I_sc_init_cats(struct scCats * cats, int n_bands, int type)
++{
++    int i_cat;
++
++    cats->type = type;
++
++    cats->n_cats = 100;
++    cats->n_a_cats = 0;
++
++    cats->n_bands = n_bands;
++    cats->n_scatts = (n_bands - 1) * n_bands / 2;
++
++    cats->cats_arr = (struct scScatts **) G_malloc(cats->n_cats * sizeof(struct scScatts *));
++    memset(cats->cats_arr, 0, cats-> n_cats * sizeof(struct scScatts *));
++
++    cats->cats_ids = (int *)  G_malloc(cats->n_cats * sizeof(int));
++    cats->cats_idxs =(int *)  G_malloc(cats->n_cats * sizeof(int));
++
++    for(i_cat = 0; i_cat < cats->n_cats; i_cat++)
++        cats->cats_idxs[i_cat] = -1;
++
++    return;
++}
++
++/*!
++   \brief Free data of struct scCats, the structure itself remains alocated.
++
++   \param cats pointer to existing scCats struct
++ */
++void I_sc_free_cats(struct scCats * cats)
++{
++    int i_cat;
++
++    for(i_cat = 0; i_cat < cats->n_a_cats; i_cat++)
++    {        
++        if(cats->cats_arr[i_cat])
++        {   
++            G_free(cats->cats_arr[i_cat]->scatt_idxs);
++            G_free(cats->cats_arr[i_cat]->scatts_bands);
++            G_free(cats->cats_arr[i_cat]->scatts_arr);
++            G_free(cats->cats_arr[i_cat]);
++        }
++    }
++
++    G_free(cats->cats_ids);
++    G_free(cats->cats_idxs);
++    G_free(cats->cats_arr);
++
++    cats->n_cats = 0;
++    cats->n_a_cats = 0;
++    cats->n_bands = 0;
++    cats->n_scatts = 0;
++    cats->type = -1;
++
++    return;
++}
++
++#if 0
++void I_sc_get_active_categories(int * a_cats_ids, int * n_a_cats, struct scCats * cats)
++{
++    a_cats_ids = cats->cats_ids;
++    * n_a_cats = cats->n_a_cats;
++}
++#endif
++
++/*!
++   \brief Add category.
++    
++    Category represents group of scatter plots.
++
++   \param cats pointer to scCats struct
++
++   \return assigned category id (starts with 0)
++   \return -1 if maximum nuber of categories was reached
++ */
++int I_sc_add_cat(struct scCats * cats)
++{
++    int i_scatt, i_cat_id, cat_id;
++    int n_a_cats = cats->n_a_cats;
++
++    if(cats->n_a_cats >= cats->n_cats)
++        return -1;
++
++    for(i_cat_id = 0; i_cat_id < cats->n_cats; i_cat_id++)
++        if(cats->cats_idxs[i_cat_id] < 0) {
++            cat_id = i_cat_id;
++            break;
++        }
++
++    cats->cats_ids[n_a_cats] = cat_id;
++    cats->cats_idxs[cat_id] = n_a_cats;
++    
++    cats->cats_arr[n_a_cats] = (struct scScatts *) G_malloc(sizeof(struct scScatts));
++
++    cats->cats_arr[n_a_cats]->scatts_arr = (struct scdScattData **) G_malloc(cats->n_scatts * sizeof(struct scdScattData *));
++    memset((cats->cats_arr[n_a_cats]->scatts_arr), 0, cats->n_scatts * sizeof(struct scdScattData *));
++    
++    cats->cats_arr[n_a_cats]->n_a_scatts = 0;
++
++    cats->cats_arr[n_a_cats]->scatts_bands = (int *) G_malloc(cats->n_scatts * 2 * sizeof(int));
++     
++    cats->cats_arr[n_a_cats]->scatt_idxs = (int *) G_malloc(cats->n_scatts * sizeof(int));
++    for(i_scatt = 0; i_scatt < cats->n_scatts; i_scatt++)
++        cats->cats_arr[n_a_cats]->scatt_idxs[i_scatt] = -1;
++    
++    ++cats->n_a_cats;
++
++    return cat_id;
++}
++
++#if 0
++int I_sc_delete_cat(struct scCats * cats, int cat_id)
++{
++    int cat_idx, i_cat;
++
++    if(cat_id < 0 || cat_id >= cats->n_cats)
++        return -1;
++
++    cat_idx = cats->cats_idxs[cat_id];
++    if(cat_idx < 0)
++        return -1;
++
++    G_free(cats->cats_arr[cat_idx]->scatt_idxs);
++    G_free(cats->cats_arr[cat_idx]->scatts_bands);
++    G_free(cats->cats_arr[cat_idx]->scatts_arr);
++    G_free(cats->cats_arr[cat_idx]);
++
++    for(i_cat = cat_idx; i_cat < cats->n_a_cats - 1; i_cat++)
++    {
++        cats->cats_arr[i_cat] = cats->cats_arr[i_cat + 1];
++        cats->cats_ids[i_cat] = cats->cats_ids[i_cat + 1];
++    }
++    cats->cats_idxs[cat_id] = -1; 
++
++    --cats->n_a_cats;
++    
++    return 0;
++}
++#endif
++
++/*!
++   \brief Insert scatter plot data .
++    Inserted scatt_data struct must have same type as cats struct (SC_SCATT_DATA or SC_SCATT_CONDITIONS).
++
++   \param cats pointer to scCats struct
++   \param cat_id id number of category.
++   \param scatt_id id number of scatter plot.
++
++   \return  0 on success
++   \return -1 on failure
++ */
++int I_sc_insert_scatt_data(struct scCats * cats, struct scdScattData * scatt_data, int cat_id, int scatt_id)
++{
++    int band_1, band_2, cat_idx, n_a_scatts;
++    struct scScatts * scatts;
++
++    if(cat_id < 0 || cat_id >= cats->n_cats)
++        return -1;
++
++    cat_idx = cats->cats_idxs[cat_id];
++    if(cat_idx < 0)
++        return -1;
++
++    if(scatt_id < 0 && scatt_id >= cats->n_scatts)
++        return -1;
++
++    scatts = cats->cats_arr[cat_idx];
++    if(scatts->scatt_idxs[scatt_id] >= 0)
++        return -1;
++
++    if(!scatt_data->b_conds_arr && cats->type == SC_SCATT_CONDITIONS)
++        return -1;
++
++    if(!scatt_data->scatt_vals_arr && cats->type == SC_SCATT_DATA)
++        return -1;
++
++    n_a_scatts = scatts->n_a_scatts;
++
++    scatts->scatt_idxs[scatt_id] = n_a_scatts;
++
++    I_id_scatt_to_bands(scatt_id, cats->n_bands, &band_1, &band_2);
++
++    scatts->scatts_bands[n_a_scatts * 2] = band_1;
++    scatts->scatts_bands[n_a_scatts * 2 + 1] = band_2;
++
++    scatts->scatts_arr[n_a_scatts] = scatt_data;
++    ++scatts->n_a_scatts;
++
++    return 0;
++}
++
++#if 0
++int I_sc_remove_scatt_data(struct scCats * cats, struct scdScattData * scatt_data, int cat_id, int scatt_id)
++{
++    int cat_idx, scatt_idx, n_init_scatts, i_scatt;
++    struct scScatts * scatts;
++
++    if(cat_id < 0 && cat_id >= cats->n_cats)
++        return -1;
++
++    cat_idx = cats->cats_idxs[cat_id];
++    if(cat_idx < 0)
++        return -1;
++
++    if(scatt_id < 0 || scatt_id >= cats->n_scatts)
++        return -1;
++
++    scatts = cats->cats_arr[cat_idx];
++    if(scatts->scatt_idxs[scatt_id] < 0)
++        return -1;
++
++    scatt_data = scatts->scatts_arr[scatt_idx];
++
++    for(i_scatt = scatt_idx; i_scatt < scatts->n_a_scatts - 1; i_scatt++)
++    {
++        scatts->scatts_arr[i_scatt] = scatts->scatts_arr[i_scatt + 1];
++        scatts->scatts_bands[i_scatt * 2] = scatts->scatts_bands[(i_scatt + 1)* 2];
++        scatts->scatts_bands[i_scatt * 2 + 1] = scatts->scatts_bands[(i_scatt + 1) * 2 + 1];
++    }
++    scatts->scatts_arr[scatts->n_a_scatts] = NULL;
++
++    scatts->scatt_idxs[scatt_id] = -1;
++
++    scatt_data = scatts->scatts_arr[scatt_id];
++    scatts->n_a_scatts--;
++
++    return 0;
++}
++
++int I_sc_set_value(struct scCats * cats, int cat_id, int scatt_id, int value_idx, int value)
++{
++    int n_a_scatts = cats->cats_arr[cat_id]->n_a_scatts;
++    int cat_idx, scatt_idx, ret;
++
++    cat_idx = cats->cats_idxs[cat_id];
++    if(cat_idx < 0)
++        return -1;
++    
++    if(cats->cats_arr[cat_idx]->scatt_idxs[scatt_id] < 0)
++        return -1;
++
++    cat_idx = cats->cats_idxs[cat_id];
++    scatt_idx = cats->cats_arr[cat_idx]->scatt_idxs[scatt_id];
++
++    I_scd_set_value(cats->cats_arr[cat_idx]->scatts_arr[scatt_idx], value_idx, value);
++
++    return 0;
++}
++#endif
++
++/*!
++   \brief Insert scatter plot data.
++    
++   \param scatt_data pointer to existing struct scdScattData
++   \param type SC_SCATT_DATA for scatter plots or SC_SCATT_CONDITIONS for selected areas in scatter plot
++   \param n_vals number of data values
++   \param data array of values (unsigned char for SC_SCATT_CONDITIONS, unsigned int for SC_SCATT_DATA)
++ */
++void I_scd_init_scatt_data(struct scdScattData * scatt_data, int type, int n_vals, void * data)
++{
++    scatt_data->n_vals = n_vals;
++
++    if(type == SC_SCATT_DATA)
++    {   
++        if(data)
++            scatt_data->scatt_vals_arr = (unsigned int *) data;
++        else {
++            scatt_data->scatt_vals_arr = (unsigned int *) G_malloc(n_vals * sizeof(unsigned int));
++            memset(scatt_data->scatt_vals_arr, 0, n_vals * sizeof(unsigned int)); 
++        }
++        scatt_data->b_conds_arr = NULL;
++    }
++    else if(type == SC_SCATT_CONDITIONS)
++    {
++        if(data)
++            scatt_data->b_conds_arr = (unsigned char *) data;
++        else {
++            scatt_data->b_conds_arr = (unsigned char *) G_malloc(n_vals * sizeof(unsigned char));
++            memset(scatt_data->b_conds_arr, 0, n_vals * sizeof(unsigned char));
++        }
++        scatt_data->scatt_vals_arr = NULL;
++    }
++
++    return;
++}
++
++
++#if 0
++void I_scd_get_range_min_max(struct scdScattData * scatt_data, CELL * band_1_min, CELL * band_1_max, CELL * band_2_min, CELL * band_2_max)
++{
++
++    Rast_get_range_min_max(&(scatt_data->band_1_range), band_1_min, band_2_min);
++    Rast_get_range_min_max(&(scatt_data->band_2_range), band_2_min, band_2_max);
++
++    return;
++}
++s
++void * I_scd_get_data_ptr(struct scdScattData * scatt_data)
++{
++    if(!scatt_data->b_conds_arr)
++        return scatt_data->b_conds_arr;
++    else if(!scatt_data->scatt_vals_arr)
++        return scatt_data->scatt_vals_arr;
++
++    return NULL;
++}
++
++int I_scd_set_value(struct scdScattData * scatt_data, unsigned int val_idx, unsigned int val)
++{
++    if(val_idx < 0 && val_idx >  scatt_data->n_vals)
++        return -1;
++
++    if(scatt_data->b_conds_arr)
++        scatt_data->b_conds_arr[val_idx] = val;
++    else if(scatt_data->scatt_vals_arr)
++        scatt_data->scatt_vals_arr[val_idx] = val;
++    else
++        return -1;
++
++    return 0;
++}
++#endif
 Index: include/defs/vedit.h
 ===================================================================
---- include/defs/vedit.h	(revision 57747)
+--- include/defs/vedit.h	(revision 57760)
 +++ include/defs/vedit.h	(working copy)
 @@ -33,6 +33,8 @@
  int Vedit_merge_lines(struct Map_info *, struct ilist *);
@@ -1299,7 +1299,7 @@
  
 Index: include/defs/imagery.h
 ===================================================================
---- include/defs/imagery.h	(revision 57747)
+--- include/defs/imagery.h	(revision 57760)
 +++ include/defs/imagery.h	(working copy)
 @@ -111,6 +111,28 @@
  FILE *I_fopen_subgroup_ref_new(const char *, const char *);
@@ -1332,7 +1332,7 @@
  int I_new_signature(struct Signature *);
 Index: include/imagery.h
 ===================================================================
---- include/imagery.h	(revision 57747)
+--- include/imagery.h	(revision 57760)
 +++ include/imagery.h	(working copy)
 @@ -135,6 +135,56 @@
      
@@ -1391,24 +1391,9 @@
  #define SIGNATURE_TYPE_MIXED 1
  
  #define GROUPFILE "CURGROUP"
-Index: gui/icons/grass/polygon.png
-===================================================================
-Cannot display: file marked as a binary type.
-svn:mime-type = application/octet-stream
-Index: gui/icons/grass/polygon.png
-===================================================================
---- gui/icons/grass/polygon.png	(revision 57747)
-+++ gui/icons/grass/polygon.png	(working copy)
-
-Property changes on: gui/icons/grass/polygon.png
-___________________________________________________________________
-Added: svn:mime-type
-## -0,0 +1 ##
-+application/octet-stream
-\ No newline at end of property
 Index: gui/wxpython/vdigit/wxdigit.py
 ===================================================================
---- gui/wxpython/vdigit/wxdigit.py	(revision 57747)
+--- gui/wxpython/vdigit/wxdigit.py	(revision 57760)
 +++ gui/wxpython/vdigit/wxdigit.py	(working copy)
 @@ -17,7 +17,7 @@
  (and NumPy would be an excellent candidate for acceleration via
@@ -1438,7 +1423,7 @@
 +
 +        # signals which describes features changes during digitization, 
 +        # activate them using EmitSignals method 
-+        #TODO signal for errors?
++        #TODO handle errors?
 +        self.featureAdded = Signal('IVDigit.featureAdded')
 +        self.areasDeleted = Signal('IVDigit.areasDeleted')
 +        self.vertexMoved = Signal('IVDigit.vertexMoved')
@@ -1473,7 +1458,7 @@
          layer = self._getNewFeaturesLayer()
          cat = self._getNewFeaturesCat()
          
-@@ -419,10 +439,14 @@
+@@ -419,10 +439,15 @@
              return (-1, None)
          
          self.toolbar.EnableUndo()
@@ -1485,14 +1470,15 @@
 +        ret = self._addFeature(vtype, points, layer, cat,
 +                               self._getSnapMode(), self._display.GetThreshold())
 +        if ret[0] > -1 and self.emit_signals:
-+            self.featureAdded.emit(new_bboxs = [self._createBbox(points)], new_areas_cats = [[{layer : [cat]}, None]])
++            self.featureAdded.emit(new_bboxs=[self._createBbox(points)], 
++                                   new_areas_cats=[[{layer : [cat]}, None]])
 +
 +        return ret
 +
      def DeleteSelectedLines(self):
          """!Delete selected features
  
-@@ -434,16 +458,27 @@
+@@ -434,16 +459,27 @@
          # collect categories for deleting if requested
          deleteRec = UserSettings.Get(group = 'vdigit', key = 'delRecord', subkey = 'enabled')
          catDict = dict()
@@ -1525,19 +1511,20 @@
          
          poList = self._display.GetSelectedIList()
          nlines = Vedit_delete_lines(self.poMapInfo, poList)
-@@ -456,7 +491,10 @@
+@@ -456,7 +492,11 @@
                  self._deleteRecords(catDict)
              self._addChangeset()
              self.toolbar.EnableUndo()
 -        
 +
 +            if self.emit_signals:
-+                self.featuresDeleted.emit(old_bboxs = old_bboxs, old_areas_cats = old_areas_cats)
++                self.featuresDeleted.emit(old_bboxs=old_bboxs, 
++                                          old_areas_cats=old_areas_cats)
 +
          return nlines
              
      def _deleteRecords(self, cats):
-@@ -512,22 +550,173 @@
+@@ -512,22 +552,173 @@
  
          @return number of deleted 
          """
@@ -1570,7 +1557,8 @@
              self._addChangeset()
              self.toolbar.EnableUndo()
 +            if self.emit_signals:
-+                self.areasDeleted.emit(old_bboxs = old_bboxs, old_areas_cats = old_areas_cats)        
++                self.areasDeleted.emit(old_bboxs=old_bboxs, 
++                                       old_areas_cats=old_areas_cats)        
 +
 +        return nareas
 +   
@@ -1578,7 +1566,7 @@
 +        ltype = Vect_read_line(self.poMapInfo, None, None, ln_id)
 +
 +        if ltype == GV_CENTROID:
-+            #TODO centroid opttimization, can be adited also its area -> it will appear two times in new_ lists
++            #TODO centroid opttimization, can be edited also its area -> it will appear two times in new_ lists
 +            return self._getCentroidAreaBboxCats(ln_id)
 +        else: 
 +            return [self._getBbox(ln_id)], [self._getLineAreasCategories(ln_id)]
@@ -1595,7 +1583,6 @@
 +            return None
 +
 +    def _getaAreaBboxCats(self, area):
-+
 +        po_b_list = Vect_new_list()
 +        Vect_get_area_boundaries(self.poMapInfo, area, po_b_list);
 +        b_list = po_b_list.contents
@@ -1713,7 +1700,7 @@
      def MoveSelectedLines(self, move):
          """!Move selected features
  
-@@ -536,16 +725,45 @@
+@@ -536,16 +727,45 @@
          if not self._checkMap():
              return -1
          
@@ -1760,22 +1747,22 @@
          if nlines > 0 and self._settings['breakLines']:
              for i in range(1, nlines):
                  self._breakLineAtIntersection(nlines + i, None, changeset)
-@@ -553,7 +771,13 @@
+@@ -553,7 +773,13 @@
          if nlines > 0:
              self._addChangeset()
              self.toolbar.EnableUndo()
 -        
 +            
 +            if self.emit_signals:
-+                self.featuresMoved.emit(new_bboxs = new_bboxs,
-+                                        old_bboxs = old_bboxs, 
-+                                        old_areas_cats = old_areas_cats, 
-+                                        new_areas_cats = new_areas_cats)
++                self.featuresMoved.emit(new_bboxs=new_bboxs,
++                                        old_bboxs=old_bboxs, 
++                                        old_areas_cats=old_areas_cats, 
++                                        new_areas_cats=new_areas_cats)
 +
          return nlines
  
      def MoveSelectedVertex(self, point, move):
-@@ -571,12 +795,21 @@
+@@ -571,12 +797,21 @@
          
          if len(self._display.selected['ids']) != 1:
              return -1
@@ -1801,7 +1788,7 @@
          moved = Vedit_move_vertex(self.poMapInfo, self.popoBgMapInfo, int(self.poBgMapInfo is not None),
                                    poList, self.poPoints,
                                    self._display.GetThreshold(type = 'selectThresh'),
-@@ -584,7 +817,17 @@
+@@ -584,7 +819,17 @@
                                    move[0], move[1], 0.0,
                                    1, self._getSnapMode())
          Vect_destroy_list(poList)
@@ -1820,22 +1807,22 @@
          if moved > 0 and self._settings['breakLines']:
              self._breakLineAtIntersection(Vect_get_num_lines(self.poMapInfo),
                                            None)
-@@ -592,7 +835,13 @@
+@@ -592,7 +837,13 @@
          if moved > 0:
              self._addChangeset()
              self.toolbar.EnableUndo()
 -        
 +
 +            if self.emit_signals:
-+                self.vertexMoved.emit(new_bboxs = new_bboxs,  
-+                                      new_areas_cats = new_areas_cats, 
-+                                      old_areas_cats = old_areas_cats, 
-+                                      old_bboxs = old_bboxs)
++                self.vertexMoved.emit(new_bboxs=new_bboxs,  
++                                      new_areas_cats=new_areas_cats, 
++                                      old_areas_cats=old_areas_cats, 
++                                      old_bboxs=old_bboxs)
 +
          return moved
  
      def AddVertex(self, coords):
-@@ -681,6 +930,10 @@
+@@ -681,6 +932,10 @@
              self._error.ReadLine(line)
              return -1
          
@@ -1846,7 +1833,7 @@
          # build feature geometry
          Vect_reset_line(self.poPoints)
          for p in coords:
-@@ -696,6 +949,9 @@
+@@ -696,6 +951,9 @@
          
          newline = Vect_rewrite_line(self.poMapInfo, line, ltype,
                                      self.poPoints, self.poCats)
@@ -1856,22 +1843,22 @@
          
          if newline > 0 and self._settings['breakLines']:
              self._breakLineAtIntersection(newline, None)
-@@ -703,7 +959,13 @@
+@@ -703,7 +961,13 @@
          if newline > 0:
              self._addChangeset()
              self.toolbar.EnableUndo()
 -        
 +    
 +            if self.emit_signals:
-+                self.lineEdited.emit(old_bboxs = old_bboxs, 
-+                                     old_areas_cats = old_areas_cats, 
-+                                     new_bboxs = new_bboxs, 
-+                                     new_areas_cats = new_areas_cats)
++                self.lineEdited.emit(old_bboxs=old_bboxs, 
++                                     old_areas_cats=old_areas_cats, 
++                                     new_bboxs=new_bboxs, 
++                                     new_areas_cats=new_areas_cats)
 +
          return newline
  
      def FlipLine(self):
-@@ -1514,6 +1776,16 @@
+@@ -1514,6 +1778,16 @@
              return 0
          
          poList  = self._display.GetSelectedIList()
@@ -1888,7 +1875,7 @@
          Vect_reset_line(self.poPoints)
          Vect_append_point(self.poPoints, coords[0], coords[1], 0.0)
          
-@@ -1525,15 +1797,35 @@
+@@ -1525,15 +1799,35 @@
          else:
              ret = Vedit_remove_vertex(self.poMapInfo, poList,
                                        self.poPoints, thresh)
@@ -1916,19 +1903,19 @@
 +
 +        if ret > 0 and self.emit_signals:
 +            if add:
-+                self.vertexAdded.emit(old_bboxs = old_bboxs, new_bboxs = new_bboxs)
++                self.vertexAdded.emit(old_bboxs=old_bboxs, new_bboxs=new_bboxs)
 +            else:
-+                self.vertexRemoved.emit(old_bboxs = old_bboxs, 
-+                                        new_bboxs = new_bboxs,
-+                                        old_areas_cats = old_areas_cats,
-+                                        new_areas_cats = new_areas_cats)
++                self.vertexRemoved.emit(old_bboxs=old_bboxs, 
++                                        new_bboxs=new_bboxs,
++                                        old_areas_cats=old_areas_cats,
++                                        new_areas_cats=new_areas_cats)
 +
          return 1
      
      def GetLineCats(self, line):
 Index: gui/wxpython/vdigit/toolbars.py
 ===================================================================
---- gui/wxpython/vdigit/toolbars.py	(revision 57747)
+--- gui/wxpython/vdigit/toolbars.py	(revision 57760)
 +++ gui/wxpython/vdigit/toolbars.py	(working copy)
 @@ -17,6 +17,7 @@
  import wx
@@ -1955,600 +1942,9 @@
          return True
  
      def StopEditing(self):
-Index: gui/wxpython/vnet/toolbars.py
-===================================================================
---- gui/wxpython/vnet/toolbars.py	(revision 57747)
-+++ gui/wxpython/vnet/toolbars.py	(working copy)
-@@ -19,9 +19,9 @@
- 
- import wx
- 
--from icon              import MetaIcon
-+from icons.icon import MetaIcon
- from gui_core.toolbars import BaseToolbar, BaseIcons
--from core.gcmd         import RunCommand
-+from core.gcmd import RunCommand
- from core.utils import _
- 
- class PointListToolbar(BaseToolbar):
-Index: gui/wxpython/vnet/dialogs.py
-===================================================================
---- gui/wxpython/vnet/dialogs.py	(revision 57747)
-+++ gui/wxpython/vnet/dialogs.py	(working copy)
-@@ -1218,7 +1218,7 @@
-                       pos = (row, 1))
- 
-         row += 1
--        gridSizer.Add(item = self.settings["invert_colors"], flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
-+        gridSizer.Add(item=self.settings["invert_colors"], flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
- 
-         gridSizer.AddGrowableCol(1)
-         styleBoxSizer.Add(item = gridSizer, flag = wx.EXPAND)
-Index: gui/wxpython/Makefile
-===================================================================
---- gui/wxpython/Makefile	(revision 57747)
-+++ gui/wxpython/Makefile	(working copy)
-@@ -13,7 +13,7 @@
- 	$(wildcard animation/* core/*.py dbmgr/* gcp/*.py gmodeler/* \
- 	gui_core/*.py iclass/* lmgr/*.py location_wizard/*.py mapwin/*.py mapdisp/*.py \
- 	mapswipe/* modules/*.py nviz/*.py psmap/* rlisetup/* timeline/* vdigit/* \
--	vnet/*.py web_services/*.py wxplot/*.py) \
-+	vnet/*.py web_services/*.py wxplot/*.py scatt_plot/*.py) \
- 	gis_set.py gis_set_error.py wxgui.py README
- 
- DSTFILES := $(patsubst %,$(ETCDIR)/%,$(SRCFILES)) \
-@@ -21,8 +21,9 @@
- 
- PYDSTDIRS := $(patsubst %,$(ETCDIR)/%,animation core dbmgr gcp gmodeler \
- 	gui_core iclass lmgr location_wizard mapwin mapdisp modules nviz psmap \
--	mapswipe vdigit wxplot web_services rlisetup vnet timeline)
-+	mapswipe vdigit wxplot web_services rlisetup vnet timeline scatt_plot)
- 
-+
- DSTDIRS := $(patsubst %,$(ETCDIR)/%,icons scripts xml)
- 
- default: $(DSTFILES)
-Index: gui/wxpython/mapdisp/frame.py
-===================================================================
---- gui/wxpython/mapdisp/frame.py	(revision 57747)
-+++ gui/wxpython/mapdisp/frame.py	(working copy)
-@@ -231,6 +231,7 @@
-         #
-         self.dialogs = {}
-         self.dialogs['attributes'] = None
-+        self.dialogs['scatt_plot'] = None
-         self.dialogs['category'] = None
-         self.dialogs['vnet'] = None
-         self.dialogs['query'] = None
-@@ -1199,6 +1200,19 @@
-         """!Returns toolbar with zooming tools"""
-         return self.toolbars['map']
- 
-+    def OnIScatt(self, event):
-+        """!Init interactive scatterplot tools
-+        """
-+        if self.dialogs['scatt_plot']:
-+            self.dialogs['scatt_plot'].Raise()
-+            return
-+
-+        from scatt_plot.frame import IScattDialog
-+        self.dialogs['scatt_plot'] = IScattDialog(parent=self, giface=self._giface)
-+        
-+        self.dialogs['scatt_plot'].CenterOnScreen()
-+        self.dialogs['scatt_plot'].Show()
-+
-     def OnVNet(self, event):
-         """!Dialog for v.net* modules 
-         """
-Index: gui/wxpython/mapdisp/toolbars.py
-===================================================================
---- gui/wxpython/mapdisp/toolbars.py	(revision 57747)
-+++ gui/wxpython/mapdisp/toolbars.py	(working copy)
-@@ -49,6 +49,8 @@
-                             label = _('Create histogram of raster map')),
-     'vnet'       : MetaIcon(img = 'vector-tools',
-                             label = _('Vector network analysis tool')),
-+    'interact_scatter' : MetaIcon(img = 'layer-raster-profile',
-+                            label = _("Interactive scatter plot tool")),
-     }
- 
- NvizIcons = {
-@@ -239,7 +241,9 @@
-                       (MapIcons["scatter"],     self.parent.OnScatterplot),
-                       (MapIcons["histogram"],   self.parent.OnHistogramPyPlot),
-                       (BaseIcons["histogramD"], self.parent.OnHistogram),
--                      (MapIcons["vnet"],        self.parent.OnVNet)))
-+                      (MapIcons["vnet"],        self.parent.OnVNet),
-+                      (MapIcons["interact_scatter"], 
-+                       self.parent.OnIScatt)))
-         
-     def OnDecoration(self, event):
-         """!Decorations overlay menu
-Index: gui/wxpython/iclass/dialogs.py
-===================================================================
---- gui/wxpython/iclass/dialogs.py	(revision 57747)
-+++ gui/wxpython/iclass/dialogs.py	(working copy)
-@@ -337,7 +337,6 @@
-     def OnClose(self, event):
-         self.catList.DeselectAll()
-         
--        self.catList.UpdateChoice()
-         self.Hide()
-         #if not isinstance(event, wx.CloseEvent):
-             #self.Destroy()
-@@ -403,12 +402,26 @@
-             except UnicodeEncodeError:
-                 GMessage(parent = self, message = _("Please use only ASCII characters."))
-                 return
-+        if attr == 'color':
-+            try:
-+                colors = map(int, text.split(":"))
-+            except:
-+                return
- 
-+            if len(colors) != 3:
-+                return
- 
-+            for i, c in enumerate(colors):
-+                if c < 0:
-+                    colors[i] = 0 
-+                elif c > 255:
-+                    colors[i] = 255
-+
-+            text = ":".join(map(str, colors))
-+
-         cat = self.stats_data.GetCategories()[row]
-         self.stats_data.GetStatistics(cat).SetStatistics(stats = {attr : text})
-         
--        self.UpdateChoice()
-         toolbar = self.mapWindow.toolbars['iClass']
-         toolbar.choice.SetSelection(row)
-         self.Select(row)
-@@ -431,7 +444,6 @@
-         self.stats_data.AddStatistics(cat, name, color)
-         self.SetItemCount(len(self.stats_data.GetCategories()))
-         
--        self.UpdateChoice()
-         self.mapWindow.UpdateChangeState(changes = True)
-                 
-     def DeleteCategory(self):
-@@ -452,32 +464,10 @@
-             
-         self.SetItemCount(len(self.stats_data.GetCategories()))
-         
--        self.UpdateChoice()
-         self.mapWindow.UpdateChangeState(changes = True)
-         
-         self.mapWindow.DeleteAreas(cats = del_cats)
--    
--    def UpdateChoice(self):
--        toolbar = self.mapWindow.toolbars['iClass']
--        name = toolbar.GetSelectedCategoryName()
--        catNames = []
--
--        cats = self.stats_data.GetCategories()
--        for cat in cats:
--            stat = self.stats_data.GetStatistics(cat)
--            catNames.append(stat.name)
--        toolbar.SetCategories(catNames = catNames, catIdx = cats)
--        if name in catNames:
--            toolbar.choice.SetStringSelection(name)
--        elif catNames:
--            toolbar.choice.SetSelection(0)
-             
--        if toolbar.choice.IsEmpty():
--            toolbar.EnableControls(False)
--        else:
--            toolbar.EnableControls(True)
--        # don't forget to update maps, histo, ...
--        
-     def GetSelectedIndices(self, state =  wx.LIST_STATE_SELECTED):
-         indices = []
-         lastFound = -1
-@@ -560,6 +550,29 @@
-     def OnGetItemAttr(self, item):
-         return None
- 
-+    def OnGetItemAttr(self, item):
-+        back_c = wx.Colour(*map(int, self.OnGetItemText(item, 1).split(':')))
-+        text_c = wx.Colour(*ContrastColor(back_c))
-+
-+        # if it is in scope of the method, gui falls, using self solved it 
-+        self.l = wx.ListItemAttr(colText = text_c, colBack =  back_c)
-+        return self.l
-+    
-+def ContrastColor(color):
-+    """!Decides which value shoud have text to be contrast with backgroud color (bright bg -> black, dark bg -> white)
-+
-+    @todo could be useful by other apps, consider to move it to gui_core 
-+    """
-+    #gacek, http://stackoverflow.com/questions/1855884/determine-font-color-based-on-background-color
-+    a = 1 - ( 0.299 * color[0] + 0.587 * color[1] + 0.114 * color[2])/255;
-+
-+    if a < 0.5:
-+        d = 0
-+    else:
-+        d = 255 
-+
-+    return (d, d, d)
-+
- class IClassSignatureFileDialog(wx.Dialog):
-     def __init__(self, parent, group, subgroup, 
-                  file = None, title = _("Save signature file"), id = wx.ID_ANY,
-Index: gui/wxpython/iclass/toolbars.py
-===================================================================
---- gui/wxpython/iclass/toolbars.py	(revision 57747)
-+++ gui/wxpython/iclass/toolbars.py	(working copy)
-@@ -23,7 +23,7 @@
- from core.utils import _
- from gui_core.toolbars import BaseToolbar, BaseIcons
- from icons.icon import MetaIcon
--from iclass.dialogs import IClassMapDialog
-+from iclass.dialogs import IClassMapDialog, ContrastColor
- from gui_core.forms import GUI
- 
- import grass.script as grass
-@@ -46,9 +46,7 @@
-         'importAreas' : MetaIcon(img = 'layer-import',
-                             label = _('Import training areas from vector map')),
-         'addRgb' : MetaIcon(img = 'layer-rgb-add',
--                            label = _('Add RGB map layer')),
--        'scatt_plot'    : MetaIcon(img = 'layer-raster-analyze',
--                                   label = _('Open Scatter Plot Tool (EXPERIMENTAL GSoC 2013)')),
-+                            label = _('Add RGB map layer'))
-         }
-         
- class IClassMapToolbar(BaseToolbar):
-@@ -117,17 +115,16 @@
-                                      ("zoomBack", icons["zoomBack"],
-                                       self.parent.OnZoomBack),
-                                      ("zoomToMap", icons["zoomExtent"],
--                                      self.parent.OnZoomToMap),
--                                     (None, ),
--                                     ("scatt_plot", iClassIcons["scatt_plot"],
--                                      self.parent.OnScatterplot)
-+                                      self.parent.OnZoomToMap)
-                                     ))
- class IClassToolbar(BaseToolbar):
-     """!IClass toolbar
-     """
--    def __init__(self, parent):
-+    def __init__(self, parent, stats_data):
-         """!IClass toolbar constructor
-         """
-+        self.stats_data = stats_data
-+
-         BaseToolbar.__init__(self, parent)
-         self.InitToolbar(self._toolbarData())
-         
-@@ -148,7 +145,12 @@
-         
-         self.combo.Bind(wx.EVT_COMBOBOX, self.OnStdChangeSelection)
-         self.combo.Bind(wx.EVT_TEXT_ENTER, self.OnStdChangeText)
--        
-+    
-+        self.stats_data.statisticsAdded.connect(self.Update)
-+        self.stats_data.statisticsDeleted.connect(self.Update)
-+        self.stats_data.allStatisticsDeleted.connect(self.Update)
-+        self.stats_data.statisticsSet.connect(self.Update)
-+
-         # realize the toolbar
-         self.Realize()
-         
-@@ -171,13 +173,30 @@
-                                       ("sigFile", icons['sigFile'],
-                                       self.parent.OnSaveSigFile),
-                                     ))
--                                    
-+
-+    def OnMotion(self, event):
-+        print self.choice.GetStringSelection()
-+                                
-     def OnSelectCategory(self, event):
-         idx = self.choice.GetSelection()
-         cat = self.choice.GetClientData(idx)
--        
-+
-+        self._updateColor(cat)
-         self.parent.CategoryChanged(currentCat = cat)
-         
-+    def _updateColor(self, cat):
-+
-+        if cat:
-+            stat = self.stats_data.GetStatistics(cat)
-+            back_c = wx.Colour(*map(int, stat.color.split(':')))
-+            text_c = wx.Colour(*ContrastColor(back_c))
-+        else:
-+            back_c = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
-+            text_c = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNTEXT)
-+
-+        self.choice.SetForegroundColour(text_c)
-+        self.choice.SetBackgroundColour(back_c)
-+
-     def SetCategories(self, catNames, catIdx):
-         self.choice.Clear()
-         for name, idx in zip(catNames, catIdx):
-@@ -231,6 +250,33 @@
-     def EnableControls(self, enable = True):
-         self.combo.Enable(enable)
-         self.choice.Enable(enable)
-+
-+    def Update(self, *args, **kwargs):
-+        name = self.GetSelectedCategoryName()
-+        catNames = []
-+
-+        cats = self.stats_data.GetCategories()
-+        for cat in cats:
-+            stat = self.stats_data.GetStatistics(cat)
-+            catNames.append(stat.name)
-+        self.SetCategories(catNames = catNames, catIdx = cats)
-+        if name in catNames:
-+            self.choice.SetStringSelection(name)
-+            cat = self.GetSelectedCategoryIdx()
-+        elif catNames:
-+            self.choice.SetSelection(0)
-+            cat = self.GetSelectedCategoryIdx()
-+        else:
-+            cat = None
-+
-+        if self.choice.IsEmpty():
-+            self.EnableControls(False)
-+        else:
-+            self.EnableControls(True)
-+
-+        self._updateColor(cat)
-+        self.parent.CategoryChanged(cat)
-+        # don't forget to update maps, histo, ...
-         
- class IClassMapManagerToolbar(BaseToolbar):
-     """!IClass toolbar
-Index: gui/wxpython/iclass/frame.py
-===================================================================
---- gui/wxpython/iclass/frame.py	(revision 57747)
-+++ gui/wxpython/iclass/frame.py	(working copy)
-@@ -64,6 +64,8 @@
-                                IClassExportAreasDialog, IClassMapDialog
- from iclass.plots       import PlotPanel
- 
-+from grass.pydispatch.signal import Signal
-+
- class IClassMapFrame(DoubleMapFrame):
-     """! wxIClass main frame
-     
-@@ -114,6 +116,12 @@
-             lambda:
-             self.statusbarManager.statusbarItems['coordinates'].SetAdditionalInfo(None))
-         self.SetSize(size)
-+
-+        self.groupSet = Signal("IClassMapFrame.groupSet")
-+        self.categoryChanged = Signal('IClassMapFrame.categoryChanged')
-+
-+        self.InitStatistics()
-+
-         #
-         # Add toolbars
-         #
-@@ -162,9 +170,7 @@
-                                              Map = self.GetFirstMap())
-         self.previewMapManager = MapManager(self, mapWindow = self.GetSecondWindow(),
-                                             Map = self.GetSecondMap())
--                                           
--        self.InitStatistics()
--        
-+                                                   
-         self.changes = False
-         self.exportVector = None
-         
-@@ -177,7 +183,7 @@
-         self.dialogs['category']   = None
-         
-         # PyPlot init
--        self.plotPanel = PlotPanel(self, stats_data = self.stats_data)
-+        self.plotPanel = PlotPanel(self, giface = self._giface, stats_data = self.stats_data)
-                                    
-         self._addPanes()
-         self._mgr.Update()
-@@ -237,7 +243,7 @@
-             return False
-         
-         return vectorName
--        
-+    
-     def RemoveTempVector(self):
-         """!Removes temporary vector map with training areas"""
-         ret = RunCommand(prog = 'g.remove',
-@@ -282,7 +288,7 @@
-                               BestSize((self.toolbars[name].GetBestSize())))
-                               
-         if name == "iClass":
--            self.toolbars[name] = IClassToolbar(self)
-+            self.toolbars[name] = IClassToolbar(self, stats_data=self.stats_data)
-             
-             self._mgr.AddPane(self.toolbars[name],
-                               wx.aui.AuiPaneInfo().
-@@ -334,11 +340,12 @@
-             self._addPaneMapWindow(name = 'preview')
-             self._addPaneToolbar(name = 'iClassTrainingMapManager')
-             self._addPaneMapWindow(name = 'training')
--        
-+
-+        self._mgr.SetDockSizeConstraint(0.5, 0.5) 
-         self._mgr.AddPane(self.plotPanel, wx.aui.AuiPaneInfo().
-                   Name("plots").Caption(_("Plots")).
-                   Dockable(False).Floatable(False).CloseButton(False).
--                  Left().Layer(1).BestSize((400, -1)))
-+                  Left().Layer(1).BestSize((300, -1)))
-         
-     def _addPaneToolbar(self, name):
-         if name == 'iClassPreviewMapManager':
-@@ -489,12 +496,14 @@
-                     group = grass.find_file(name=g, element='group')
-                     self.g['group'] = group['name']
-                     self.g['subgroup'] = s
-+                    self.groupSet.emit(group=self.g['group'],
-+                                       subgroup=self.g['subgroup'])
-                     break
-             else: 
-                 break
-         
-         dlg.Destroy()
--    
-+
-     def OnImportAreas(self, event):
-         """!Import training areas"""
-         # check if we have any changes
-@@ -771,17 +780,20 @@
-         
-         Updates number of stddev, histograms, layer in preview display. 
-         """
--        stat = self.stats_data.GetStatistics(currentCat)
--        nstd = stat.nstd
--        self.toolbars['iClass'].UpdateStddev(nstd)
--        
--        self.plotPanel.UpdateCategory(currentCat)
--        self.plotPanel.OnPlotTypeSelected(None)
-+        if currentCat:
-+          stat = self.stats_data.GetStatistics(currentCat)
-+          nstd = stat.nstd
-+          self.toolbars['iClass'].UpdateStddev(nstd)
-+          
-+          self.plotPanel.UpdateCategory(currentCat)
-+          self.plotPanel.OnPlotTypeSelected(None)
-                                    
--        name = stat.rasterName
--        name = self.previewMapManager.GetAlias(name)
--        if name:
--            self.previewMapManager.SelectLayer(name)
-+          name = stat.rasterName
-+          name = self.previewMapManager.GetAlias(name)
-+          if name:
-+              self.previewMapManager.SelectLayer(name)
-+
-+        self.categoryChanged.emit(cat = currentCat)
-         
-     def DeleteAreas(self, cats):
-         """!Removes all training areas of given categories
-@@ -808,12 +820,12 @@
-     def UpdateRasterName(self, newName, cat):
-         """!Update alias of raster map when category name is changed"""
-         origName = self.stats_data.GetStatistics(cat).rasterName
--        self.previewMapManager.SetAlias(origName, newName)
-+        self.previewMapManager.SetAlias(origName, self._addSuffix(newName))
-         
-     def StddevChanged(self, cat, nstd):
-         """!Standard deviation multiplier changed, rerender map, histograms"""
-         stat = self.stats_data.GetStatistics(cat)
--        stat.nstd = nstd
-+        stat.SetStatistics({"nstd" : nstd})
-         
-         if not stat.IsReady():
-             return
-@@ -925,7 +937,7 @@
-                 
-                 self.ConvertToNull(name = stats.rasterName)
-                 self.previewMapManager.AddLayer(name = stats.rasterName,
--                                                alias = stats.name, resultsLayer = True)
-+                                                alias = self._addSuffix(stats.name), resultsLayer = True)
-                 # write statistics
-                 I_iclass_add_signature(self.signatures, statistics)
-                 
-@@ -938,7 +950,11 @@
-         
-         self.UpdateChangeState(changes = False)
-         return True
--        
-+
-+    def _addSuffix(self, name):
-+        suffix = _('results')
-+        return '_'.join((name, suffix))
-+
-     def OnSaveSigFile(self, event):
-         """!Asks for signature file name and saves it."""
-         if not self.g['group']:
-@@ -1115,27 +1131,13 @@
-         self.GetFirstWindow().SetModePointer()
-         self.GetSecondWindow().SetModePointer()
- 
--    def OnScatterplot(self, event):
--        """!Init interactive scatterplot tools
--        """
--        if self.dialogs['scatt_plot']:
--            self.dialogs['scatt_plot'].Raise()
--            return
-+    def GetMapManagers(self):
-+      """!Get map managers of wxIClass 
- 
--        try:
--          from scatt_plot.dialogs import ScattPlotMainDialog
--        except:
--          GError(parent  = self, message = _("The Scatter Plot Tool is not installed."))
--          return
-+      @return trainingMapManager, previewMapManager 
-+      """
-+      return self.trainingMapManager, self.previewMapManager
- 
--        self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface, iclass_mapwin = self.GetFirstWindow())
--
--        scatt_mgr = self.dialogs['scatt_plot'].GetScattMgr()
--        scatt_mgr.DigitDataChanged(self.toolbars['vdigit'].mapLayer.GetName(), self.GetFirstWindow().GetDigit())
--
--        self.dialogs['scatt_plot'].CenterOnScreen()
--        self.dialogs['scatt_plot'].Show()
--
- class MapManager:
-     """! Class for managing map renderer.
-     
-@@ -1178,7 +1180,6 @@
-         self.frame.Render(self.mapWindow)
-         
-         if alias is not None:
--            alias = self._addSuffix(alias)
-             self.layerName[alias] = name
-             name = alias
-         else:
-@@ -1235,7 +1236,11 @@
-                 self.toolbar.choice.SetSelection(0)
-         
-         self.frame.Render(self.mapWindow)
--        
-+    
-+    def Render(self):
-+        """@todo giface shoud be used instead of this method"""
-+        self.frame.Render(self.mapWindow)
-+
-     def RemoveLayer(self, name, idx):
-         """!Removes layer from Map and update toolbar"""
-         name = self.layerName[name]
-@@ -1291,11 +1296,7 @@
-     def _changeOpacity(self, layer, opacity):
-         self.map.ChangeOpacity(layer=layer, opacity=opacity)
-         self.frame.Render(self.mapWindow)
--        
--    def _addSuffix(self, name):
--        suffix = _('results')
--        return '_'.join((name, suffix))
--        
-+                
-     def GetAlias(self, name):
-         """!Returns alias for layer"""
-         name =  [k for k, v in self.layerName.iteritems() if v == name]
-@@ -1306,11 +1307,11 @@
-     def SetAlias(self, original, alias):
-         name = self.GetAlias(original)
-         if name:
--            self.layerName[self._addSuffix(alias)] = original
-+            self.layerName[alias] = original
-             del self.layerName[name]
-             idx = self.toolbar.choice.FindString(name)
-             if idx != wx.NOT_FOUND:
--                self.toolbar.choice.SetString(idx, self._addSuffix(alias))
-+                self.toolbar.choice.SetString(idx, alias)
- 
- def test():
-     import core.render as render
 Index: gui/wxpython/iclass/plots.py
 ===================================================================
---- gui/wxpython/iclass/plots.py	(revision 57747)
+--- gui/wxpython/iclass/plots.py	(revision 57760)
 +++ gui/wxpython/iclass/plots.py	(working copy)
 @@ -19,6 +19,7 @@
  import wx.lib.plot as plot
@@ -2558,21 +1954,9 @@
  
  class PlotPanel(scrolled.ScrolledPanel):
      """!Panel for drawing multiple plots.
-@@ -28,7 +29,7 @@
-     for each band and for one category. Coincidence plots show min max range
-     of classes for each band.
-     """
--    def __init__(self, parent, stats_data):
-+    def __init__(self, parent, giface, stats_data):
-         scrolled.ScrolledPanel.__init__(self, parent)
-         
-         self.SetupScrolling(scroll_x = False, scroll_y = True)
-@@ -38,26 +39,71 @@
-         self.stats_data = stats_data
+@@ -40,25 +41,68 @@
          self.currentCat = None
          
-+        self._giface = giface
-+
          self.mainSizer = wx.BoxSizer(wx.VERTICAL)
 -        
 +
@@ -2645,7 +2029,7 @@
          if self.plotSwitch.GetSelection() == 0:
              stat = self.stats_data.GetStatistics(self.currentCat)
              if not stat.IsReady():
-@@ -66,7 +112,10 @@
+@@ -67,7 +111,10 @@
              self.DrawHistograms(stat)
          else:
              self.DrawCoincidencePlots()
@@ -2657,7 +2041,7 @@
      def StddevChanged(self):
          """!Standard deviation multiplier changed, redraw histograms"""
          if self.plotSwitch.GetSelection() == 0:
-@@ -89,7 +138,7 @@
+@@ -90,7 +137,7 @@
              panel.Destroy()
              
          self.canvasList = []
@@ -2666,7 +2050,7 @@
      def ClearPlots(self):
          """!Clears plot canvases"""
          for bandIdx in range(len(self.bandList)):
-@@ -104,15 +153,15 @@
+@@ -105,15 +152,15 @@
      def CreatePlotCanvases(self):
          """!Create plot canvases according to the number of bands"""
          for band in self.bandList:
@@ -2686,7 +2070,7 @@
          self.Layout()
          
      def UpdatePlots(self, group, subgroup, currentCat, stats_data):
-@@ -139,7 +188,7 @@
+@@ -140,7 +187,7 @@
          
      def UpdateCategory(self, cat):
          self.currentCat = cat
@@ -2695,6 +2079,62 @@
      def DrawCoincidencePlots(self):
          """!Draw coincidence plots"""
          for bandIdx in range(len(self.bandList)):
+Index: gui/wxpython/mapdisp/toolbars.py
+===================================================================
+--- gui/wxpython/mapdisp/toolbars.py	(revision 57760)
++++ gui/wxpython/mapdisp/toolbars.py	(working copy)
+@@ -49,6 +49,8 @@
+                             label = _('Create histogram of raster map')),
+     'vnet'       : MetaIcon(img = 'vector-tools',
+                             label = _('Vector network analysis tool')),
++    'interact_scatter' : MetaIcon(img = 'layer-raster-profile',
++                            label = _("Interactive scatter plot tool")),
+     }
+ 
+ NvizIcons = {
+@@ -239,7 +241,9 @@
+                       (MapIcons["scatter"],     self.parent.OnScatterplot),
+                       (MapIcons["histogram"],   self.parent.OnHistogramPyPlot),
+                       (BaseIcons["histogramD"], self.parent.OnHistogram),
+-                      (MapIcons["vnet"],        self.parent.OnVNet)))
++                      (MapIcons["vnet"],        self.parent.OnVNet),
++                      (MapIcons["interact_scatter"], 
++                       self.parent.OnIScatt)))
+         
+     def OnDecoration(self, event):
+         """!Decorations overlay menu
+Index: gui/wxpython/mapdisp/frame.py
+===================================================================
+--- gui/wxpython/mapdisp/frame.py	(revision 57760)
++++ gui/wxpython/mapdisp/frame.py	(working copy)
+@@ -231,6 +231,7 @@
+         #
+         self.dialogs = {}
+         self.dialogs['attributes'] = None
++        self.dialogs['scatt_plot'] = None
+         self.dialogs['category'] = None
+         self.dialogs['vnet'] = None
+         self.dialogs['query'] = None
+@@ -1199,6 +1200,19 @@
+         """!Returns toolbar with zooming tools"""
+         return self.toolbars['map']
+ 
++    def OnIScatt(self, event):
++        """!Init interactive scatterplot tools
++        """
++        if self.dialogs['scatt_plot']:
++            self.dialogs['scatt_plot'].Raise()
++            return
++
++        from scatt_plot.frame import IScattDialog
++        self.dialogs['scatt_plot'] = IScattDialog(parent=self, giface=self._giface)
++        
++        self.dialogs['scatt_plot'].CenterOnScreen()
++        self.dialogs['scatt_plot'].Show()
++
+     def OnVNet(self, event):
+         """!Dialog for v.net* modules 
+         """
 Index: gui/wxpython/scatt_plot/__init__.py
 ===================================================================
 --- gui/wxpython/scatt_plot/__init__.py	(revision 0)
@@ -2715,7 +2155,7 @@
 ===================================================================
 --- gui/wxpython/scatt_plot/plots.py	(revision 0)
 +++ gui/wxpython/scatt_plot/plots.py	(working copy)
-@@ -0,0 +1,943 @@
+@@ -0,0 +1,950 @@
 +"""!
 + at package scatt_plot.dialogs
 +
@@ -2739,6 +2179,7 @@
 +
 +from copy import deepcopy
 +from scatt_plot.core_c import MergeArrays, ApplyColormap
++from scatt_plot.dialogs import ManageBusyCursorMixin
 +from core.settings import UserSettings
 +
 +try:
@@ -2760,11 +2201,13 @@
 +import grass.script as grass
 +from grass.pydispatch.signal import Signal
 +
-+class ScatterPlotWidget(wx.Panel):
++class ScatterPlotWidget(wx.Panel, ManageBusyCursorMixin):
 +    def __init__(self, parent, scatt_id, scatt_mgr, transpose,
 +                 id = wx.ID_ANY):
-+
++        #TODO should not be transpose and scatt_id but x, y
 +        wx.Panel.__init__(self, parent, id)
++        # bacause of aui (if floatable it can not take cursor from parent)        
++        ManageBusyCursorMixin.__init__(self, window=self)
 +
 +        self.parent = parent
 +        self.full_extend = None
@@ -2799,6 +2242,7 @@
 +        self.canvas.mpl_connect('button_press_event', self.OnPress)
 +        self.canvas.mpl_connect('button_release_event', self.OnRelease)
 +        self.canvas.mpl_connect('draw_event', self.draw_callback)
++        self.canvas.mpl_connect('figure_leave_event', self.OnLeave)
 +
 +    def draw_callback(self, event):
 +        self.polygon_drawer.draw_callback(event)
@@ -3066,8 +2510,11 @@
 +        if event.inaxes is None: 
 +            return
 +        
-+        self.cursorMove.emit(x=event.xdata, y=event.ydata)
++        self.cursorMove.emit(x=event.xdata, y=event.ydata, scatt_id=self.scatt_id)
 +
++    def OnLeave(self, event):
++        self.cursorMove.emit(x=None, y=None, scatt_id=self.scatt_id)
++
 +    def PanMotion(self, event):
 +        'on mouse movement'
 +        if not self.mode == "pan": 
@@ -3664,7 +3111,7 @@
 ===================================================================
 --- gui/wxpython/scatt_plot/controllers.py	(revision 0)
 +++ gui/wxpython/scatt_plot/controllers.py	(working copy)
-@@ -0,0 +1,888 @@
+@@ -0,0 +1,890 @@
 +"""!
 + at package scatt_plot.controllers
 +
@@ -3866,12 +3313,14 @@
 +        scatt_ids = event.kwds['scatt_ids']
 +        for s_id in scatt_ids:
 +            trans = self.plots[s_id]['transpose']
++
 +            self.plots[s_id]['scatt'] = self.guiparent.NewScatterPlot(scatt_id=s_id, 
 +                                                                      transpose=trans)
 +
 +            self.plots[s_id]['scatt'].plotClosed.connect(self.PlotClosed)
-+            self.plots[s_id]['scatt'].cursorMove.connect(lambda x, y: 
-+                                                          self.cursorPlotMove.emit(x=x, y=y))
++            self.plots[s_id]['scatt'].cursorMove.connect(lambda x, y, scatt_id: 
++                                                         self.cursorPlotMove.emit(x=x, y=y, 
++                                                                                  scatt_id=scatt_id))
 +
 +            if self.plot_mode:
 +                self.plots[s_id]['scatt'].SetMode(self.plot_mode)
@@ -4689,7 +4138,7 @@
 ===================================================================
 --- gui/wxpython/scatt_plot/dialogs.py	(revision 0)
 +++ gui/wxpython/scatt_plot/dialogs.py	(working copy)
-@@ -0,0 +1,468 @@
+@@ -0,0 +1,494 @@
 +"""!
 + at package scatt_plot.dialogs
 +
@@ -4721,7 +4170,6 @@
 +class AddScattPlotDialog(wx.Dialog):
 +
 +    def __init__(self, parent, bands, added_scatts_ids, id  = wx.ID_ANY):
-+        
 +        wx.Dialog.__init__(self, parent, title = ("Add scatter plots"), id = id)
 +
 +        self.added_scatts_ids = added_scatts_ids
@@ -5158,6 +4606,33 @@
 +    def OnClose(self, event):
 +        """!Button 'Cancel' pressed"""
 +        self.Close()
++
++class ManageBusyCursorMixin:
++    def __init__(self, window):
++        self.win = window
++
++        self.is_busy = False
++        self.cur_inside = False
++
++        self.win.Bind(wx.EVT_ENTER_WINDOW, self.OnEnter)
++        self.win.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeave)
++
++    def OnLeave(self, event):   
++        self.cur_inside = False     
++        self.busy_cur = None
++
++    def OnEnter(self, event):
++        self.cur_inside = True
++        if self.is_busy:
++            self.busy_cur = wx.BusyCursor()
++
++    def UpdateCur(self, busy):
++        self.is_busy = busy
++        if self.cur_inside and self.is_busy:
++            self.busy_cur = wx.BusyCursor()
++            return
++
++        self.busy_cur = None
 \ No newline at end of file
 Index: gui/wxpython/scatt_plot/toolbars.py
 ===================================================================
@@ -6487,7 +5962,7 @@
 ===================================================================
 --- gui/wxpython/scatt_plot/frame.py	(revision 0)
 +++ gui/wxpython/scatt_plot/frame.py	(working copy)
-@@ -0,0 +1,811 @@
+@@ -0,0 +1,826 @@
 +"""!
 + at package scatt_plot.dialogs
 +
@@ -6518,8 +5993,8 @@
 +from scatt_plot.controllers import ScattsManager
 +from scatt_plot.toolbars import MainToolbar, EditingToolbar, CategoryToolbar
 +from scatt_plot.scatt_core import idScattToidBands
++from scatt_plot.dialogs import ManageBusyCursorMixin
 +from scatt_plot.plots import ScatterPlotWidget
-+from vnet.dialogs import VnetStatusbar
 +from iclass.dialogs import ContrastColor
 +
 +try:
@@ -6528,13 +6003,14 @@
 +    import wx.lib.agw.aui as aui
 +
 +
-+class IClassIScattPanel(wx.Panel):
++class IClassIScattPanel(wx.Panel, ManageBusyCursorMixin):
 +    def __init__(self, parent, giface, iclass_mapwin = None,
-+                 id = wx.ID_ANY, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
++                 id = wx.ID_ANY):
 +
 +        #wx.SplitterWindow.__init__(self, parent = parent, id = id,
 +        #                           style = wx.SP_LIVE_UPDATE)
-+        wx.Panel.__init__(self, parent = parent, id = wx.ID_ANY, **kwargs)
++        wx.Panel.__init__(self, parent = parent, id = wx.ID_ANY)
++        ManageBusyCursorMixin.__init__(self, window=self)
 +
 +        self.scatt_mgr = self._createScattMgr(guiparent=parent, giface=giface, 
 +                                              iclass_mapwin=iclass_mapwin)
@@ -6548,38 +6024,29 @@
 +
 +        self.plot_panel = ScatterPlotsPanel(self, self.scatt_mgr)
 +
-+        # statusbar
-+        self.stPriors = {'high' : 5, 'info' : 1}
-+        self.stBar = VnetStatusbar(parent = self, style = 0)
-+        self.stBar.SetFieldsCount(number = 1)
-+
 +        self.mainsizer = wx.BoxSizer(wx.VERTICAL)
 +        self.mainsizer.Add(item = self.toolbars['mainToolbar'], proportion = 0, flag = wx.EXPAND)
 +        self.mainsizer.Add(item = self.toolbars['editingToolbar'], proportion = 0, flag = wx.EXPAND)
 +        self.mainsizer.Add(item = self.catsPanel, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT , border = 5)
 +        self.mainsizer.Add(item = self.plot_panel, proportion = 1, flag = wx.EXPAND)
 +
-+        self.mainsizer.Add(item = self.stBar, proportion = 0)
-+
 +        self.catsPanel.Hide()
 +        self.toolbars['editingToolbar'].Hide()
 +
 +        self.SetSizer(self.mainsizer)
 +        
-+        self.scatt_mgr.cursorPlotMove.connect(self.CursorPlotMove)
-+        self.scatt_mgr.renderingStarted.connect(lambda : self.stBar.AddStatusItem(text=_("Rendering..."), 
-+                                                                                 key='comp', 
-+                                                                                 priority=self.stPriors['high']))
-+        self.scatt_mgr.renderingFinished.connect(lambda : self.stBar.RemoveStatusItem(key='comp'))
++        self.scatt_mgr.computingStarted.connect(lambda : self.UpdateCur(busy=True))
++        self.scatt_mgr.renderingStarted.connect(lambda : self.UpdateCur(busy=True))
++        self.scatt_mgr.renderingFinished.connect(lambda : self.UpdateCur(busy=False))
 +
-+        self.scatt_mgr.computingStarted.connect(lambda : self.stBar.AddStatusItem(text=_("Computing data..."), 
-+                                                                                 key='comp', 
-+                                                                                 priority=self.stPriors['high']))
-+
 +        #self.SetSashGravity(0.5)
 +        #self.SplitHorizontally(self.head_panel, self.plot_panel, -50)
 +        self.Layout()
 +
++    def UpdateCur(self, busy):
++        self.plot_panel.SetBusy(busy)
++        ManageBusyCursorMixin.UpdateCur(self, busy)
++
 +    def _selCatInIScatt(self):
 +         return False
 +
@@ -6589,12 +6056,6 @@
 +    def _createScattMgr(self, guiparent, giface, iclass_mapwin):
 +        return ScattsManager(guiparent=self, giface=giface, iclass_mapwin=iclass_mapwin)
 +
-+    def CursorPlotMove(self, x, y):
-+        x = int(round(x))
-+        y = int(round(y))
-+        self.stBar.AddStatusItem(text="%d; %d" % (x, y), 
-+                                 key='coords', 
-+                                 priority=self.stPriors['info'])
 +
 +    def NewScatterPlot(self, scatt_id, transpose):
 +        return self.plot_panel.NewScatterPlot(scatt_id, transpose)
@@ -6679,14 +6140,14 @@
 +         return True
 +
 +class ScatterPlotsPanel(scrolled.ScrolledPanel):
-+    def __init__(self, parent, scatt_mgr, id = wx.ID_ANY):
++    def __init__(self, parent, scatt_mgr, id=wx.ID_ANY):
 +    
 +        scrolled.ScrolledPanel.__init__(self, parent)
-+        self.SetupScrolling(scroll_x = False, scroll_y = True, scrollToTop = False)
++        self.SetupScrolling(scroll_x=False, scroll_y=True, scrollToTop=False)
 +
 +        self.scatt_mgr = scatt_mgr
 +
-+        self.mainPanel = wx.Panel(parent = self, id = wx.ID_ANY)
++        self.mainPanel = wx.Panel(parent=self, id=wx.ID_ANY)
 +
 +        #self._createCategoryPanel()
 +        # Fancy gui
@@ -6713,9 +6174,39 @@
 +
 +        self.scatt_i = 1
 +        self.scatt_id_scatt_i = {}
++        self.transpose = {}
++        self.scatts = {}
 +
 +        self.Bind(wx.EVT_CLOSE, self.OnClose)
++        
++        self.scatt_mgr.cursorPlotMove.connect(self.CursorPlotMove)
 +
++    def SetBusy(self, busy):
++        for scatt in self.scatts.itervalues():
++            scatt.UpdateCur(busy)
++
++    def CursorPlotMove(self, x, y, scatt_id):
++
++        try:
++            x = int(round(x))
++            y = int(round(y))
++            coords = True
++        except:
++            coords = False
++
++        pane = self._getPane(scatt_id)
++        caption = self._creteCaption(scatt_id)
++        if coords:
++            caption += "   %d, %d" % (x, y)
++
++        pane.Caption(caption)
++        self._mgr.RefreshCaptions()
++
++    def _getPane(self, scatt_id):
++        scatt_i = self.scatt_id_scatt_i[scatt_id]
++        name = self._getScatterPlotName(scatt_i)
++        return self._mgr.GetPane(name)
++
 +    def ScatterPlotClosed(self, scatt_id):
 +
 +        scatt_i = self.scatt_id_scatt_i[scatt_id]
@@ -6723,6 +6214,9 @@
 +        name = self._getScatterPlotName(scatt_i)
 +        pane = self._mgr.GetPane(name)
 +
++        del self.scatt_id_scatt_i[scatt_id]
++        del self.scatts[scatt_id]
++
 +        if pane.IsOk(): 
 +          self._mgr.ClosePane(pane) 
 +        self._mgr.Update() 
@@ -6789,22 +6283,9 @@
 +                                  scatt_id = scatt_id, 
 +                                  transpose = transpose)
 +        scatt.plotClosed.connect(self.ScatterPlotClosed)
-+
-+        bands = self.scatt_mgr.GetBands()
-+
-+        #TODO too low level
-+        b1_id, b2_id = idScattToidBands(scatt_id, len(bands))
-+
-+        x_b =  bands[b1_id].split('@')[0]
-+        y_b = bands[b2_id].split('@')[0]
-+
-+        if transpose:
-+            tmp = x_b
-+            x_b = y_b
-+            y_b = tmp
-+
-+        caption = "%s x: %s y: %s" % (_("scatter plot"), x_b, y_b)
-+
++        self.transpose[scatt_id] = transpose
++        
++        caption = self._creteCaption(scatt_id)
 +        self._mgr.AddPane(scatt,
 +                           aui.AuiPaneInfo().Dockable(True).Floatable(True).
 +                           Name(self._newScatterPlotName(scatt_id)).MinSize((-1, 300)).
@@ -6818,8 +6299,28 @@
 +        self.SetVirtualSize(self.GetBestVirtualSize())
 +        self.Layout()
 +
++        self.scatts[scatt_id] = scatt
++
 +        return scatt
 +
++    def _creteCaption(self, scatt_id):
++
++        transpose = self.transpose[scatt_id]
++        bands = self.scatt_mgr.GetBands()
++
++        #TODO too low level
++        b1_id, b2_id = idScattToidBands(scatt_id, len(bands))
++
++        x_b =  bands[b1_id].split('@')[0]
++        y_b = bands[b2_id].split('@')[0]
++
++        if transpose:
++            tmp = x_b
++            x_b = y_b
++            y_b = tmp
++
++        return "%s x: %s y: %s" % (_("scatter plot"), x_b, y_b)
++
 +    def GetScattMgr(self):
 +        return  self.scatt_mgr
 +
@@ -6939,25 +6440,7 @@
 +                lastFound = index
 +                indices.append(index)
 +        return indices        
-+    """
-+    def OnEdit(self, event):
-+        currentItem = event.m_itemIndex
-+        currentCol = event.m_col
 +
-+        if currentCol == 1:
-+            dlg = wx.ColourDialog(self)
-+            dlg.GetColourData().SetChooseFull(True)
-+
-+            if dlg.ShowModal() == wx.ID_OK:
-+                color = dlg.GetColourData().GetColour().Get()
-+                color = ':'.join(map(str, color))
-+                self.SetVirtualData(currentItem, currentCol, color)
-+            dlg.Destroy()
-+            wx.CallAfter(self.SetFocus)
-+        
-+        event.Skip()
-+    """ 
-+        
 +    def DeselectAll(self):
 +        """!Deselect all items"""
 +        indexList = self.GetSelectedIndices()
@@ -7106,9 +6589,15 @@
 +        cat_idx = self.rightClickedItemIdx
 +        cat_id = self.cats_mgr.GetCategories()[cat_idx]
 +
-+        dlg = wx.ColourDialog(self)
++        col = self.cats_mgr.GetCategoryAttrs(cat_id)['color']
++        col = map(int, col.split(':'))
++
++        col_data =  wx.ColourData()
++        col_data.SetColour(wx.Colour(*col))
++
++        dlg = wx.ColourDialog(self, col_data)
 +        dlg.GetColourData().SetChooseFull(True)
-+        
++
 +        if dlg.ShowModal() == wx.ID_OK:
 +            color = dlg.GetColourData().GetColour().Get()
 +            color = ':'.join(map(str, color))
@@ -7299,3 +6788,93 @@
 +
 +    def GetScattId(self):
 +        return self.scatt_id
++
+Index: gui/wxpython/vnet/dialogs.py
+===================================================================
+--- gui/wxpython/vnet/dialogs.py	(revision 57760)
++++ gui/wxpython/vnet/dialogs.py	(working copy)
+@@ -109,7 +109,7 @@
+ 
+         # statusbar
+         self.stPriorities = {'important' : 5, 'iformation' : 1}
+-        self.stBar = VnetStatusbar(parent = self.mainPanel, style = 0)
++        self.stBar = VnetStatusbar(parent = self.mainPanel)
+         self.stBar.SetFieldsCount(number = 1)
+     
+         self.def_isec_turns = None
+@@ -1218,7 +1218,7 @@
+                       pos = (row, 1))
+ 
+         row += 1
+-        gridSizer.Add(item = self.settings["invert_colors"], flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
++        gridSizer.Add(item=self.settings["invert_colors"], flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
+ 
+         gridSizer.AddGrowableCol(1)
+         styleBoxSizer.Add(item = gridSizer, flag = wx.EXPAND)
+@@ -1513,9 +1513,9 @@
+ 
+ class VnetStatusbar(wx.StatusBar):
+     """!Extends wx.StatusBar class with functionality to show multiple messages with the highest priority"""        
+-    def __init__(self, parent, style, id = wx.ID_ANY, **kwargs):
++    def __init__(self, parent, id = wx.ID_ANY, **kwargs):
+ 
+-        wx.StatusBar.__init__(self, parent, id, style, **kwargs)
++        wx.StatusBar.__init__(self, parent, id, **kwargs)
+ 
+         self.maxPriority = 0
+         self.statusItems = []
+Index: gui/wxpython/vnet/toolbars.py
+===================================================================
+--- gui/wxpython/vnet/toolbars.py	(revision 57760)
++++ gui/wxpython/vnet/toolbars.py	(working copy)
+@@ -19,9 +19,9 @@
+ 
+ import wx
+ 
+-from icon              import MetaIcon
++from icons.icon import MetaIcon
+ from gui_core.toolbars import BaseToolbar, BaseIcons
+-from core.gcmd         import RunCommand
++from core.gcmd import RunCommand
+ from core.utils import _
+ 
+ class PointListToolbar(BaseToolbar):
+Index: gui/wxpython/Makefile
+===================================================================
+--- gui/wxpython/Makefile	(revision 57760)
++++ gui/wxpython/Makefile	(working copy)
+@@ -13,7 +13,7 @@
+ 	$(wildcard animation/* core/*.py dbmgr/* gcp/*.py gmodeler/* \
+ 	gui_core/*.py iclass/* lmgr/*.py location_wizard/*.py mapwin/*.py mapdisp/*.py \
+ 	mapswipe/* modules/*.py nviz/*.py psmap/* rlisetup/* timeline/* vdigit/* \
+-	vnet/*.py web_services/*.py wxplot/*.py) \
++	vnet/*.py web_services/*.py wxplot/*.py scatt_plot/*.py) \
+ 	gis_set.py gis_set_error.py wxgui.py README
+ 
+ DSTFILES := $(patsubst %,$(ETCDIR)/%,$(SRCFILES)) \
+@@ -21,8 +21,9 @@
+ 
+ PYDSTDIRS := $(patsubst %,$(ETCDIR)/%,animation core dbmgr gcp gmodeler \
+ 	gui_core iclass lmgr location_wizard mapwin mapdisp modules nviz psmap \
+-	mapswipe vdigit wxplot web_services rlisetup vnet timeline)
++	mapswipe vdigit wxplot web_services rlisetup vnet timeline scatt_plot)
+ 
++
+ DSTDIRS := $(patsubst %,$(ETCDIR)/%,icons scripts xml)
+ 
+ default: $(DSTFILES)
+Index: gui/icons/grass/polygon.png
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = application/octet-stream
+Index: gui/icons/grass/polygon.png
+===================================================================
+--- gui/icons/grass/polygon.png	(revision 57760)
++++ gui/icons/grass/polygon.png	(working copy)
+
+Property changes on: gui/icons/grass/polygon.png
+___________________________________________________________________
+Added: svn:mime-type
+## -0,0 +1 ##
++application/octet-stream
+\ No newline at end of property



More information about the grass-commit mailing list