diff --git a/core/ViewDataTable.php b/core/ViewDataTable.php
index 740dd9f5b55127efc264590b5ca2958effa0e91f..92da2d9e5473014990c3f3302bbb19ae7cf32404 100644
--- a/core/ViewDataTable.php
+++ b/core/ViewDataTable.php
@@ -147,6 +147,7 @@ class ViewDataTable
         $this->viewProperties['metadata'] = array();
         $this->viewProperties['translations'] = array();
         $this->viewProperties['filters'] = array();
+        $this->viewProperties['after_data_loaded_functions'] = array();
         $this->viewProperties['related_reports'] = array();
         $this->viewProperties['subtable_controller_action'] = $currentControllerAction;
 
@@ -407,6 +408,7 @@ class ViewDataTable
 
         if ($name == 'translations'
             || $name == 'filters'
+            || $name == 'after_data_loaded_functions'
         ) {
             $this->viewProperties[$name] = array_merge($this->viewProperties[$name], $value);
         } else if ($name == 'related_reports') { // TODO: should process after (in overrideViewProperties)
@@ -1046,6 +1048,7 @@ class ViewDataTable
         try {
             $this->loadDataTableFromAPI();
             $this->postDataTableLoadedFromAPI();
+            $this->executeAfterDataLoadedCallbacks();
         } catch (NoAccessException $e) {
             throw $e;
         } catch (\Exception $e) {
@@ -1088,6 +1091,13 @@ class ViewDataTable
         $this->view = $view;
     }
 
+    private function executeAfterDataLoadedCallbacks()
+    {
+        foreach ($this->after_data_loaded_functions as $callback) {
+            $callback($this->dataTable, $this);
+        }
+    }
+
     private function getFooterIconsToShow()
     {
         $result = array();
diff --git a/core/ViewDataTable/Properties.php b/core/ViewDataTable/Properties.php
index 2519dd087a0c337a8055771626aeb92996eebb0b..5c5d0630fa31144fb30417d5790f462d72824230 100644
--- a/core/ViewDataTable/Properties.php
+++ b/core/ViewDataTable/Properties.php
@@ -187,20 +187,6 @@ class Properties
      */
     const CUSTOM_PARAMETERS = 'custom_parameters';
 
-    /**
-     * Contains the column (if any) of the values used in the Row Picker.
-     * 
-     * @see self::ROW_PICKER_VISIBLE_VALUES
-     */
-    const ROW_PICKER_VALUE_COLUMN = 'row_picker_match_rows_by';
-
-    /**
-     * Contains the list of values available for the Row Picker.
-     * 
-     * @see self::ROW_PICKER_VALUE_COLUMN
-     */
-    const ROW_PICKER_VISIBLE_VALUES = 'row_picker_visible_rows';
-
     /**
      * Whether to run generic filters on the DataTable before rendering or not.
      * 
@@ -364,6 +350,18 @@ class Properties
      */
     const FILTERS = 'filters';
 
+    /**
+     * Array of callbacks that are called after the data for a ViewDataTable is successfully
+     * loaded. Each callback is invoked with the DataTable instance obtained from the API
+     * and the ViewDatable instance that loaded it.
+     * 
+     * Functions can be appended to this array property when it's necessary to configure
+     * a ViewDataTable after data has been loaded. If you need to use properties that are
+     * only set after data is loaded (like 'columns_to_display'), you'll have to use this
+     * property.
+     */
+    const AFTER_DATA_LOADED_FUNCTIONS = 'after_data_loaded_functions';
+
     /**
      * Contains the controller action to call when requesting subtables of the current report.
      */
@@ -551,6 +549,7 @@ class Properties
             'documentation' => false,
             'datatable_css_class' => false,
             'filters' => array(),
+            'after_data_loaded_functions' => array(),
             'hide_annotations_view' => true,
             'columns_to_display' => array(),
         );
diff --git a/core/Visualization/Graph.php b/core/Visualization/Graph.php
index a5953029947bcf68346958e8098d18cb3f4c252d..38da416d97cdc7d7bfc79ab9be935b72713ee43f 100644
--- a/core/Visualization/Graph.php
+++ b/core/Visualization/Graph.php
@@ -11,6 +11,7 @@
 namespace Piwik\Visualization;
 
 use Piwik\Common;
+use Piwik\DataTable\Row;
 use Piwik\DataTableVisualization;
 
 /**
@@ -38,6 +39,30 @@ abstract class Graph extends DataTableVisualization
      */
     const SELECTABLE_COLUMNS = 'selectable_columns';
 
+    /**
+     * Contains the column (if any) of the values used in the Row Picker.
+     * 
+     * @see self::ROW_PICKER_VISIBLE_VALUES
+     */
+    const ROW_PICKER_VALUE_COLUMN = 'row_picker_match_rows_by';
+
+    /**
+     * Contains the list of values available for the Row Picker.
+     * TODO: row_picker_visible_rows & selectable_rows are different, but it seems like they shouldn't
+     *       be...
+     * 
+     * @see self::ROW_PICKER_VALUE_COLUMN
+     */
+    const ROW_PICKER_VISIBLE_VALUES = 'row_picker_visible_rows';
+
+    /**
+     * Contains the list of values available for the Row Picker. Currently set to be all visible
+     * rows, if the row_picker_match_rows_by property is set.
+     * 
+     * @see self::ROW_PICKER_VALUE_COLUMN
+     */
+    const SELECTABLE_ROWS = 'selectable_rows';
+
     /**
      * Controls whether all ticks & labels are shown on a graph's x-axis or just some.
      */
@@ -64,6 +89,13 @@ abstract class Graph extends DataTableVisualization
      */
     const DISPLAY_PERCENTAGE_IN_TOOLTIP = 'display_percentage_in_tooltip';
 
+    public static $clientSideProperties = array(
+        'show_series_picker',
+        'allow_multi_select_series_picker',
+        'selectable_columns',
+        'selectable_rows'
+    );
+
     public static $clientSideParameters = array(
         'columns'
     );
@@ -91,16 +123,13 @@ abstract class Graph extends DataTableVisualization
         if ($view->visualization_properties->max_graph_elements) {
             $view->request_parameters_to_modify['filter_truncate'] = $view->visualization_properties->max_graph_elements - 1;
         }
+
+        $this->transformSelectableColumns($view);
+        $this->transformSelectableRows($view);
     }
 
     public static function getDefaultPropertyValues()
     {
-        // selectable columns
-        $selectableColumns = array('nb_visits', 'nb_actions');
-        if (Common::getRequestVar('period', false) == 'day') { // TODO: should depend on columns datatable has.
-            $selectableColumns[] = 'nb_uniq_visitors';
-        }
-
         return array(
             'visualization_properties' => array(
                 'graph' => array(
@@ -108,11 +137,89 @@ abstract class Graph extends DataTableVisualization
                     'show_all_ticks' => false,
                     'allow_multi_select_series_picker' => true,
                     'max_graph_elements' => false,
-                    'selectable_columns' => $selectableColumns,
+                    'selectable_columns' => false,
                     'show_series_picker' => true,
                     'display_percentage_in_tooltip' => true,
+                    'row_picker_match_rows_by' => false,
+                    'row_picker_visible_rows' => array(),
                 )
             )
         );
     }
+
+    /**
+     * TODO
+     */
+    private function transformSelectableColumns($view)
+    {
+        $view->after_data_loaded_functions[] = function ($dataTable, $view) {
+            $selectableColumns = $view->visualization_properties->selectable_columns;
+
+            // set default selectable columns, if none specified
+            if ($selectableColumns === false) {
+                $selectableColumns = array('nb_visits', 'nb_actions');
+
+                if (in_array('nb_uniq_visitors', $dataTable->getColumns())) {
+                    $selectableColumns[] = 'nb_uniq_visitors';
+                }
+            }
+
+            $transformed = array();
+            foreach ($selectableColumns as $column) {
+                $transformed[] = array(
+                    'column'      => $column,
+                    'translation' => @$view->translations[$column],
+                    'displayed'   => in_array($column, $view->columns_to_display)
+                );
+            }
+            $view->visualization_properties->selectable_columns = $transformed;
+        };
+    }
+
+    /**
+     * TODO
+     */
+    private function transformSelectableRows($view)
+    {
+        if ($view->visualization_properties->row_picker_match_rows_by === false) {
+            return;
+        }
+
+        // collect all selectable rows
+        $selectableRows = array();
+        $view->filters[] = function ($dataTable, $view) use (&$selectableRows) {
+            if ($dataTable->getRowsCount() > 0) {
+                $rows = $dataTable->getRows();
+            } else {
+                $rows = array(new Row());
+            }
+
+            foreach ($rows as $row) {
+                $rowLabel = $row->getColumn('label');
+                if ($rowLabel === false) {
+                    continue;
+                }
+
+                // determine whether row is visible
+                $isVisible = true;
+                if ($view->visualization_properties->row_picker_match_rows_by == 'label') {
+                    $isVisible = in_array($rowLabel, $view->visualization_properties->row_picker_visible_rows);
+                }
+
+                // build config
+                if (!isset($selectableRows[$rowLabel])) {
+                    $selectableRows[$rowLabel] = array(
+                        'label'     => $rowLabel,
+                        'matcher'   => $rowLabel,
+                        'displayed' => $isVisible
+                    );
+                }
+            }
+        };
+
+        // set selectable rows as a view property
+        $view->after_data_loaded_functions[] = function ($dataTable, $view) use (&$selectableRows) {
+            $view->visualization_properties->selectable_rows = array_values($selectableRows);
+        };
+    }
 }
\ No newline at end of file
diff --git a/plugins/CoreVisualizations/CoreVisualizations.php b/plugins/CoreVisualizations/CoreVisualizations.php
index a1b970459e4152d4794c1d4ec91e23002f3eef5f..3c14a5dcaeadbb34d22c0785608ec3c3d4186363 100644
--- a/plugins/CoreVisualizations/CoreVisualizations.php
+++ b/plugins/CoreVisualizations/CoreVisualizations.php
@@ -53,6 +53,7 @@ class CoreVisualizations extends \Piwik\Plugin
 
     public function getJsFiles(&$jsFiles)
     {
+        $jsFiles[] = "plugins/CoreVisualizations/javascripts/seriesPicker.js";
         $jsFiles[] = "plugins/CoreVisualizations/javascripts/jqplot.js";
     }
 }
\ No newline at end of file
diff --git a/plugins/CoreVisualizations/JqplotDataGenerator.php b/plugins/CoreVisualizations/JqplotDataGenerator.php
index 6de29e226b43867d5180eadabb827aed5373ca25..24be6f7cc51686ebe2e6d5485692f28e1fcf920f 100644
--- a/plugins/CoreVisualizations/JqplotDataGenerator.php
+++ b/plugins/CoreVisualizations/JqplotDataGenerator.php
@@ -137,8 +137,6 @@ class JqplotDataGenerator
 
         $units = $this->getUnitsForColumnsToDisplay();
         $visualization->setAxisYUnits($units);
-
-        $this->addSeriesPickerToView();
     }
 
     protected function getUnitsForColumnsToDisplay()
@@ -172,27 +170,4 @@ class JqplotDataGenerator
         }
         return $units;
     }
-
-    /**
-     * Used in initChartObjectData to add the series picker config to the view object
-     */
-    protected function addSeriesPickerToView()
-    {
-        $defaultShowSeriesPicker = $this->properties['visualization_properties']->show_series_picker;
-        if (count($this->properties['visualization_properties']->selectable_columns)
-            && Common::getRequestVar('showSeriesPicker', $defaultShowSeriesPicker) == 1
-        ) {
-            $selectableColumns = array();
-            foreach ($this->properties['visualization_properties']->selectable_columns as $column) {
-                $selectableColumns[] = array(
-                    'column'      => $column,
-                    'translation' => @$this->properties['translations'][$column],
-                    'displayed'   => in_array($column, $this->properties['columns_to_display'])
-                );
-            }
-
-            $this->visualization->setSelectableColumns(
-                $selectableColumns, $this->properties['visualization_properties']->allow_multi_select_series_picker);
-        }
-    }
-}
+}
\ No newline at end of file
diff --git a/plugins/CoreVisualizations/JqplotDataGenerator/Evolution.php b/plugins/CoreVisualizations/JqplotDataGenerator/Evolution.php
index 05ff6ab3b3029b0dc7a6957bb58dfa9a0c7c479c..d54bb618244a5fb9f8096d0753d8f7c1c61e3b53 100644
--- a/plugins/CoreVisualizations/JqplotDataGenerator/Evolution.php
+++ b/plugins/CoreVisualizations/JqplotDataGenerator/Evolution.php
@@ -64,14 +64,11 @@ class Evolution extends JqplotDataGenerator
             foreach ($rows as $row) {
                 $rowLabel = $row->getColumn('label');
 
-                // put together configuration for row picker.
-                // do this for every data table in the array because rows do not
-                // have to present for each date.
-                if ($this->properties['row_picker_match_rows_by'] !== false) {
-                    $rowVisible = $this->handleRowForRowPicker($rowLabel);
-                    if (!$rowVisible) {
-                        continue;
-                    }
+                // only process 'visible' rows (visibility is determined by row_picker_visible_rows property)
+                if ($this->properties['visualization_properties']->row_picker_match_rows_by == 'label'
+                    && !in_array($rowLabel, $this->properties['visualization_properties']->row_picker_visible_rows)
+                ) {
+                    continue;
                 }
 
                 // build data for request columns
@@ -138,40 +135,6 @@ class Evolution extends JqplotDataGenerator
             }
             $visualization->setAxisXOnClick($axisXOnClick);
         }
-
-        $this->addSeriesPickerToView();
-
-        // configure the row picker
-        if ($this->properties['row_picker_match_rows_by'] !== false) {
-            $visualization->setSelectableRows(array_values($this->rowPickerConfig));
-        }
-    }
-
-    /**
-     * This method is called for every row of every table in the DataTable_Array.
-     * It incrementally builds the row picker configuration and determines whether
-     * the row is initially visible or not.
-     * @param string $rowLabel
-     * @return bool
-     */
-    private function handleRowForRowPicker(&$rowLabel)
-    {
-        // determine whether row is visible
-        $isVisible = true;
-        if ($this->properties['row_picker_match_rows_by'] == 'label') {
-            $isVisible = in_array($rowLabel, $this->properties['row_picker_visible_rows']);
-        }
-
-        // build config
-        if (!isset($this->rowPickerConfig[$rowLabel])) {
-            $this->rowPickerConfig[$rowLabel] = array(
-                'label'     => $rowLabel,
-                'matcher'   => $rowLabel,
-                'displayed' => $isVisible
-            );
-        }
-
-        return $isVisible;
     }
 
     /**
diff --git a/plugins/CoreVisualizations/Visualizations/JqplotGraph.php b/plugins/CoreVisualizations/Visualizations/JqplotGraph.php
index 71a9ef9b2c84c08042c4e9f323725f9a6aee450a..666b9a510f04077f9ca25536c240b0db5e039b5c 100644
--- a/plugins/CoreVisualizations/Visualizations/JqplotGraph.php
+++ b/plugins/CoreVisualizations/Visualizations/JqplotGraph.php
@@ -77,8 +77,6 @@ class JqplotGraph extends Graph
             'show_search' => false,
             'show_export_as_image_icon' => true,
             'y_axis_unit' => '',
-            'row_picker_match_rows_by' => false,
-            'row_picker_visible_rows' => array(),
             'visualization_properties' => array(
                 'jqplot_graph' => array(
                     'external_series_toggle' => false,
diff --git a/plugins/CoreVisualizations/javascripts/jqplot.js b/plugins/CoreVisualizations/javascripts/jqplot.js
index 499e14bfe16d68a8cc68e4653c228f7bce4e9779..a521f76563385023ce3580731c3c440c0ae617c6 100644
--- a/plugins/CoreVisualizations/javascripts/jqplot.js
+++ b/plugins/CoreVisualizations/javascripts/jqplot.js
@@ -331,7 +331,6 @@ JQPlot.prototype = {
 
     prepareEvolutionChart: function (targetDivId, lang) {
         this.setYTicks();
-        this.addSeriesPicker(targetDivId, lang);
 
         defaultParams.axes = {
             xaxis: {
@@ -419,8 +418,6 @@ JQPlot.prototype = {
     // ------------------------------------------------------------
 
     preparePieChart: function (targetDivId, lang) {
-        this.addSeriesPicker(targetDivId, lang);
-
         this.params.seriesDefaults = {
             renderer: $.jqplot.PieRenderer,
             rendererOptions: {
@@ -465,7 +462,6 @@ JQPlot.prototype = {
 
     prepareBarChart: function (targetDivId, lang) {
         this.setYTicks();
-        this.addSeriesPicker(targetDivId, lang);
 
         this.params.seriesDefaults = {
             renderer: $.jqplot.BarRenderer,
@@ -567,19 +563,6 @@ JQPlot.prototype = {
         return value;
     },
 
-    addSeriesPicker: function (targetDivId, lang) {
-        this.params.seriesPicker = {
-            show: typeof this.seriesPicker.selectableColumns == 'object'
-                || typeof this.seriesPicker.selectableRows == 'object',
-            selectableColumns: this.seriesPicker.selectableColumns,
-            selectableRows: this.seriesPicker.selectableRows,
-            multiSelect: this.seriesPicker.multiSelect,
-            targetDivId: targetDivId,
-            dataTableId: this.dataTableId,
-            lang: lang
-        };
-    },
-
     /**
      * Add an external series toggle.
      * As opposed to addSeriesPicker, the external series toggle can only show/hide
@@ -1051,248 +1034,28 @@ RowEvolutionSeriesToggle.prototype.beforeReplot = function () {
 
 // ------------------------------------------------------------
 //  SERIES PICKER
-//  For line charts
 // ------------------------------------------------------------
 
 (function ($) {
-
-    $.jqplot.SeriesPicker = function (options) {
-        // dom element
-        this.domElem = null;
-        // render the picker?
-        this.show = false;
-        // the columns that can be selected
-        this.selectableColumns = null;
-        // the rows that can be selected
-        this.selectableRows = null;
-        // can multiple rows we selected?
-        this.multiSelect = true;
-        // css id of the target div dom element
-        this.targetDivId = "";
-        // the id of the current data table
-        this.dataTableId = "";
-        // language strings
-        this.lang = {};
-
-        $.extend(true, this, options);
-    };
-
-    $.jqplot.SeriesPicker.init = function (target, data, opts) {
+    $.jqplot.preInitHooks.push(function (target, data, options) {
         // add plugin as an attribute to the plot
-        var options = opts || {};
-        this.plugins.seriesPicker = new $.jqplot.SeriesPicker(options.seriesPicker);
-    };
+        var dataTable = $('#' + target).closest('.dataTable').data('dataTableInstance');
+        var seriesPicker = new piwik.SeriesPicker(dataTable);
 
-    // render the link to add series
-    $.jqplot.SeriesPicker.postDraw = function () {
         var plot = this;
-        var picker = plot.plugins.seriesPicker;
-
-        if (!picker.show) {
-            return;
-        }
-
-        // initialize dom element
-        picker.domElem = $(document.createElement('a'))
-            .addClass('jqplot-seriespicker')
-            .attr('href', '#').html('+')
-            .css('marginLeft', (plot._gridPadding.left + plot.plugins.canvasLegend.width - 1) + 'px');
-
-        picker.domElem.on('hide',function () {
-            $(this).css('opacity', .55);
-        }).trigger('hide');
-
-        plot.baseCanvas._elem.before(picker.domElem);
-
-        // show picker on hover
-        picker.domElem.hover(function () {
-            picker.domElem.css('opacity', 1);
-            if (!picker.domElem.hasClass('open')) {
-                picker.domElem.addClass('open');
-                showPicker(picker, plot._width);
-            }
-        },function () {
-            // do nothing on mouseout because using this event doesn't work properly.
-            // instead, the timeout check beneath is used (checkPickerLeave()).
-        }).click(function () {
-                return false;
-            });
-    };
-
-    // show the series picker
-    function showPicker(picker, plotWidth) {
-        var pickerLink = picker.domElem;
-        var pickerPopover = $(document.createElement('div'))
-            .addClass('jqplock-seriespicker-popover');
-
-        var pickerState = {manipulated: false};
-
-        // headline
-        var title = picker.multiSelect ? picker.lang.metricsToPlot : picker.lang.metricToPlot;
-        pickerPopover.append($(document.createElement('p'))
-            .addClass('headline').html(title));
-
-        if (picker.selectableColumns !== null) {
-            // render the selectable columns
-            for (var i = 0; i < picker.selectableColumns.length; i++) {
-                var column = picker.selectableColumns[i];
-                pickerPopover.append(createPickerPopupItem(picker, column, 'column', pickerState, pickerPopover, pickerLink));
-            }
-        }
-
-        if (picker.selectableRows !== null) {
-            // "records to plot" subheadline
-            pickerPopover.append($(document.createElement('p'))
-                .addClass('headline').addClass('recordsToPlot')
-                .html(picker.lang.recordsToPlot));
-
-            // render the selectable rows
-            for (var i = 0; i < picker.selectableRows.length; i++) {
-                var row = picker.selectableRows[i];
-                pickerPopover.append(createPickerPopupItem(picker, row, 'row', pickerState, pickerPopover, pickerLink));
-            }
-        }
-
-        $('body').prepend(pickerPopover.hide());
-        var neededSpace = pickerPopover.outerWidth() + 10;
-
-        // try to display popover to the right
-        var linkOffset = pickerLink.offset();
-        if (navigator.appVersion.indexOf("MSIE 7.") != -1) {
-            linkOffset.left -= 10;
-        }
-        var margin = (parseInt(pickerLink.css('marginLeft'), 10) - 4);
-        if (margin + neededSpace < plotWidth
-            // make sure it's not too far to the left
-            || margin - neededSpace + 60 < 0) {
-            pickerPopover.css('marginLeft', (linkOffset.left - 4) + 'px').show();
-        } else {
-            // display to the left
-            pickerPopover.addClass('alignright')
-                .css('marginLeft', (linkOffset.left - neededSpace + 38) + 'px')
-                .css('backgroundPosition', (pickerPopover.outerWidth() - 25) + 'px 4px')
-                .show();
-        }
-        pickerPopover.css('marginTop', (linkOffset.top - 5) + 'px').show();
-
-        // hide and replot on mouse leave
-        checkPickerLeave(pickerPopover, function () {
-            var replot = pickerState.manipulated;
-            hidePicker(picker, pickerPopover, pickerLink, replot);
-        });
-    }
-
-    function createPickerPopupItem(picker, config, type, pickerState, pickerPopover, pickerLink) {
-        var checkbox = $(document.createElement('input')).addClass('select')
-            .attr('type', picker.multiSelect ? 'checkbox' : 'radio');
-
-        if (config.displayed && !(!picker.multiSelect && pickerState.oneChecked)) {
-            checkbox.prop('checked', true);
-            pickerState.oneChecked = true;
-        }
-
-        // if we are rendering a column, remember the column name
-        // if it's a row, remember the string that can be used to match the row
-        checkbox.data('name', type == 'column' ? config.column : config.matcher);
-
-        var el = $(document.createElement('p'))
-            .append(checkbox)
-            .append('<label>' + (type == 'column' ? config.translation : config.label) + '</label>')
-            .addClass(type == 'column' ? 'pickColumn' : 'pickRow');
-
-        var replot = function () {
-            unbindPickerLeaveCheck();
-            hidePicker(picker, pickerPopover, pickerLink, true);
-        };
-
-        var checkBox = function (box) {
-            if (!picker.multiSelect) {
-                pickerPopover.find('input.select:not(.current)').prop('checked', false);
-            }
-            box.prop('checked', true);
-            replot();
-        };
-
-        el.click(function (e) {
-            pickerState.manipulated = true;
-            var box = $(this).find('input.select');
-            if (!$(e.target).is('input.select')) {
-                if (box.is(':checked')) {
-                    box.prop('checked', false);
-                } else {
-                    checkBox(box);
-                }
-            } else {
-                if (box.is(':checked')) {
-                    checkBox(box);
-                }
-            }
-        });
-
-        return el;
-    }
-
-    // check whether the mouse has left the picker
-    var onMouseMove;
-
-    function checkPickerLeave(pickerPopover, onLeaveCallback) {
-        var offset = pickerPopover.offset();
-        var minX = offset.left;
-        var minY = offset.top;
-        var maxX = minX + pickerPopover.outerWidth();
-        var maxY = minY + pickerPopover.outerHeight();
-        var currentX, currentY;
-        onMouseMove = function (e) {
-            currentX = e.pageX;
-            currentY = e.pageY;
-            if (currentX < minX || currentX > maxX
-                || currentY < minY || currentY > maxY) {
-                unbindPickerLeaveCheck();
-                onLeaveCallback();
-            }
-        };
-        $(document).mousemove(onMouseMove);
-    }
-
-    function unbindPickerLeaveCheck() {
-        $(document).unbind('mousemove', onMouseMove);
-    }
-
-    function hidePicker(picker, pickerPopover, pickerLink, replot) {
-        // hide picker
-        pickerPopover.hide();
-        pickerLink.trigger('hide').removeClass('open');
-
-        // replot
-        if (replot) {
-            var columns = [];
-            var rows = [];
-            pickerPopover.find('input:checked').each(function () {
-                if ($(this).closest('p').hasClass('pickRow')) {
-                    rows.push($(this).data('name'));
-                } else {
-                    columns.push($(this).data('name'));
-                }
-            });
-            var noRowSelected = pickerPopover.find('.pickRow').size() > 0
-                && pickerPopover.find('.pickRow input:checked').size() == 0;
-            if (columns.length > 0 && !noRowSelected) {
-
-                $('#' + picker.targetDivId).trigger('changeSeries', [columns, rows]);
-                // inform dashboard widget about changed parameters (to be restored on reload)
-                $('#' + picker.targetDivId).parents('[widgetId]').trigger('setParameters', {columns: columns, rows: rows});
-            }
-        }
-
-        pickerPopover.remove();
-    }
+        $(seriesPicker).bind('placeSeriesPicker', function () {
+            this.domElem.css('margin-left', (plot._gridPadding.left + plot.plugins.canvasLegend.width - 1) + 'px');
+            plot.baseCanvas._elem.before(this.domElem);
+        })
 
-    $.jqplot.preInitHooks.push($.jqplot.SeriesPicker.init);
-    $.jqplot.postDrawHooks.push($.jqplot.SeriesPicker.postDraw);
+        this.plugins.seriesPicker = seriesPicker;
+    });
 
+    $.jqplot.postDrawHooks.push(function () {
+        this.plugins.seriesPicker.createElement(this);
+    });
 })(jQuery);
 
-
 // ------------------------------------------------------------
 //  PIE CHART LEGEND PLUGIN FOR JQPLOT
 //  Render legend inside the pie graph
diff --git a/plugins/CoreVisualizations/javascripts/seriesPicker.js b/plugins/CoreVisualizations/javascripts/seriesPicker.js
new file mode 100644
index 0000000000000000000000000000000000000000..97e93a69f7f759139b3b0d535f0294c37b34584d
--- /dev/null
+++ b/plugins/CoreVisualizations/javascripts/seriesPicker.js
@@ -0,0 +1,273 @@
+/**
+ * Piwik - Web Analytics
+ *
+ * Adapter for jqplot
+ *
+ * @link http://www.jqplot.com
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+(function ($) {
+
+    /**
+     * This class creates and manages the Series Picker for certain DataTable visualizations.
+     * 
+     * @param {dataTable} The dataTable instance to add a series picker to.
+     */
+    var SeriesPicker = function (dataTable) {
+
+        // dom element
+        this.domElem = null;
+
+        // the columns that can be selected
+        this.selectableColumns = dataTable.props.selectable_columns;
+
+        // the rows that can be selected
+        this.selectableRows = dataTable.props.selectable_rows;
+
+        // render the picker?
+        this.show = !! dataTable.props.show_series_picker
+                 && (this.selectableColumns || this.selectableRows);
+        
+        // can multiple rows we selected?
+        this.multiSelect = !! dataTable.props.allow_multi_select_series_picker;
+
+        this.dataTableId = dataTable.workingDivId;
+
+        // language strings
+        this.lang =
+        {
+            metricsToPlot: _pk_translate('General_MetricsToPlot_js'),
+            metricToPlot: _pk_translate('General_MetricToPlot_js'),
+            recordsToPlot: _pk_translate('General_RecordsToPlot_js')
+        };
+    };
+
+    SeriesPicker.prototype = {
+
+        /**
+         * TODO
+         */
+        createElement: function (plot) {
+            if (!this.show) {
+                return;
+            }
+
+            // initialize dom element
+            this.domElem = $(document.createElement('a'))
+                .addClass('jqplot-seriespicker')
+                .attr('href', '#').html('+');
+
+            this.domElem.on('hide', function () {
+                $(this).css('opacity', .55);
+            }).trigger('hide');
+
+            // show picker on hover
+            var self = this;
+            this.domElem.hover(
+                function () {
+                    self.domElem.css('opacity', 1);
+                    if (!self.domElem.hasClass('open')) {
+                        self.domElem.addClass('open');
+                        self.showPicker(plot._width); // TODO: ???
+                    }
+                },
+                function () {
+                    // do nothing on mouseout because using this event doesn't work properly.
+                    // instead, the timeout check beneath is used (checkPickerLeave()).
+                }
+            ).click(function (e) {
+                e.preventDefault();
+                return false;
+            });
+
+            $(this).trigger('placeSeriesPicker'); // TODO: document this & other events
+        },
+
+        /**
+         * TODO
+         */
+        showPicker: function (plotWidth) {
+            var pickerLink = this.domElem;
+            var pickerPopover = $(document.createElement('div'))
+                .addClass('jqplot-seriespicker-popover');
+
+            var pickerState = {manipulated: false};
+
+            // headline
+            var title = this.multiSelect ? this.lang.metricsToPlot : this.lang.metricToPlot;
+            pickerPopover.append($(document.createElement('p'))
+                .addClass('headline').html(title));
+
+            if (this.selectableColumns) {
+                // render the selectable columns
+                for (var i = 0; i < this.selectableColumns.length; i++) {
+                    var column = this.selectableColumns[i];
+                    pickerPopover.append(this.createPickerPopupItem(column, 'column', pickerState, pickerPopover, pickerLink));
+                }
+            }
+
+            if (this.selectableRows) {
+                // "records to plot" subheadline
+                pickerPopover.append($(document.createElement('p'))
+                    .addClass('headline').addClass('recordsToPlot')
+                    .html(this.lang.recordsToPlot));
+
+                // render the selectable rows
+                for (var i = 0; i < this.selectableRows.length; i++) {
+                    var row = this.selectableRows[i];
+                    pickerPopover.append(this.createPickerPopupItem(row, 'row', pickerState, pickerPopover, pickerLink));
+                }
+            }
+
+            $('body').prepend(pickerPopover.hide());
+            var neededSpace = pickerPopover.outerWidth() + 10;
+
+            // try to display popover to the right
+            var linkOffset = pickerLink.offset();
+            if (navigator.appVersion.indexOf("MSIE 7.") != -1) {
+                linkOffset.left -= 10;
+            }
+            var margin = (parseInt(pickerLink.css('marginLeft'), 10) - 4);
+            if (margin + neededSpace < plotWidth
+                // make sure it's not too far to the left
+                || margin - neededSpace + 60 < 0) {
+                pickerPopover.css('marginLeft', (linkOffset.left - 4) + 'px').show();
+            } else {
+                // display to the left
+                pickerPopover.addClass('alignright')
+                    .css('marginLeft', (linkOffset.left - neededSpace + 38) + 'px')
+                    .css('backgroundPosition', (pickerPopover.outerWidth() - 25) + 'px 4px')
+                    .show();
+            }
+            pickerPopover.css('marginTop', (linkOffset.top - 5) + 'px').show();
+
+            // hide and replot on mouse leave
+            var self = this;
+            this.checkPickerLeave(pickerPopover, function () {
+                var replot = pickerState.manipulated;
+                self.hidePicker(pickerPopover, pickerLink, replot);
+            });
+        },
+
+        /**
+         * TODO
+         */
+        createPickerPopupItem: function (config, type, pickerState, pickerPopover, pickerLink) {
+            var self = this;
+            var checkbox = $(document.createElement('input')).addClass('select')
+                .attr('type', this.multiSelect ? 'checkbox' : 'radio');
+
+            if (config.displayed && !(!this.multiSelect && pickerState.oneChecked)) {
+                checkbox.prop('checked', true);
+                pickerState.oneChecked = true;
+            }
+
+            // if we are rendering a column, remember the column name
+            // if it's a row, remember the string that can be used to match the row
+            checkbox.data('name', type == 'column' ? config.column : config.matcher);
+
+            var el = $(document.createElement('p'))
+                .append(checkbox)
+                .append('<label>' + (type == 'column' ? config.translation : config.label) + '</label>')
+                .addClass(type == 'column' ? 'pickColumn' : 'pickRow');
+
+            var replot = function () {
+                self.unbindPickerLeaveCheck();
+                self.hidePicker(pickerPopover, pickerLink, true);
+            };
+
+            var checkBox = function (box) {
+                if (!self.multiSelect) {
+                    pickerPopover.find('input.select:not(.current)').prop('checked', false);
+                }
+                box.prop('checked', true);
+                replot();
+            };
+
+            el.click(function (e) {
+                pickerState.manipulated = true;
+                var box = $(this).find('input.select');
+                if (!$(e.target).is('input.select')) {
+                    if (box.is(':checked')) {
+                        box.prop('checked', false);
+                    } else {
+                        checkBox(box);
+                    }
+                } else {
+                    if (box.is(':checked')) {
+                        checkBox(box);
+                    }
+                }
+            });
+
+            return el;
+        },
+
+        /**
+         * TODO
+         */
+        checkPickerLeave: function (pickerPopover, onLeaveCallback) {
+            var offset = pickerPopover.offset();
+            var minX = offset.left;
+            var minY = offset.top;
+            var maxX = minX + pickerPopover.outerWidth();
+            var maxY = minY + pickerPopover.outerHeight();
+            var currentX, currentY;
+            var self = this;
+            this.onMouseMove = function (e) {
+                currentX = e.pageX;
+                currentY = e.pageY;
+                if (currentX < minX || currentX > maxX
+                    || currentY < minY || currentY > maxY) {
+                    self.unbindPickerLeaveCheck();
+                    onLeaveCallback();
+                }
+            };
+            $(document).mousemove(this.onMouseMove);
+        },
+
+        /**
+         * TODO
+         */
+        unbindPickerLeaveCheck: function () {
+            $(document).unbind('mousemove', this.onMouseMove);
+        },
+
+        /**
+         * TODO
+         */
+        hidePicker: function (pickerPopover, pickerLink, replot) {
+            // hide picker
+            pickerPopover.hide();
+            pickerLink.trigger('hide').removeClass('open');
+
+            // replot
+            if (replot) {
+                var columns = [];
+                var rows = [];
+                pickerPopover.find('input:checked').each(function () {
+                    if ($(this).closest('p').hasClass('pickRow')) {
+                        rows.push($(this).data('name'));
+                    } else {
+                        columns.push($(this).data('name'));
+                    }
+                });
+                var noRowSelected = pickerPopover.find('.pickRow').size() > 0
+                    && pickerPopover.find('.pickRow input:checked').size() == 0;
+                if (columns.length > 0 && !noRowSelected) {
+
+                    $('#' + this.dataTableId + ' .piwik-graph').trigger('changeSeries', [columns, rows]);
+                    // inform dashboard widget about changed parameters (to be restored on reload)
+                    $('#' + this.dataTableId + ' .piwik-graph').parents('[widgetId]').trigger('setParameters', {columns: columns, rows: rows});
+                }
+            }
+
+            pickerPopover.remove();
+        }
+    };
+
+    piwik.SeriesPicker = SeriesPicker;
+
+})(jQuery);
\ No newline at end of file
diff --git a/plugins/CoreVisualizations/stylesheets/jqplot.css b/plugins/CoreVisualizations/stylesheets/jqplot.css
index 5a55ba760d7df7f15f7c3ef8fd459201e4d04f23..c0c6b3e0efd569c300df0193979aa948d20d169c 100644
--- a/plugins/CoreVisualizations/stylesheets/jqplot.css
+++ b/plugins/CoreVisualizations/stylesheets/jqplot.css
@@ -211,7 +211,7 @@ a.rowevolution-startmulti:hover {
     text-indent: -999px;
 }
 
-.jqplock-seriespicker-popover {
+.jqplot-seriespicker-popover {
     display: block;
     position: absolute;
     z-index: 1010; /* must be above ui dialog */
@@ -227,33 +227,33 @@ a.rowevolution-startmulti:hover {
     box-shadow: 1px 1px 2px #666;
 }
 
-.jqplock-seriespicker-popover p {
+.jqplot-seriespicker-popover p {
     margin: 0;
     padding: 0 4px 0 0;
     line-height: 15px;
     vertical-align: middle;
 }
 
-.jqplock-seriespicker-popover p.headline {
+.jqplot-seriespicker-popover p.headline {
     font-weight: bold;
     font-size: 12px;
     padding: 0 0 6px 22px;
     color: #7E7363;
 }
 
-.jqplock-seriespicker-popover p.headline.recordsToPlot {
+.jqplot-seriespicker-popover p.headline.recordsToPlot {
     padding: 8px 0 3px 0;
 }
 
-.jqplock-seriespicker-popover.alignright p.headline {
+.jqplot-seriespicker-popover.alignright p.headline {
     padding: 0 22px 6px 0;
 }
 
-.jqplock-seriespicker-popover input.select {
+.jqplot-seriespicker-popover input.select {
     margin-right: 8px;
 }
 
-.jqplock-seriespicker-popover p.pickColumn,
-.jqplock-seriespicker-popover p.pickRow {
+.jqplot-seriespicker-popover p.pickColumn,
+.jqplot-seriespicker-popover p.pickRow {
     cursor: pointer;
 }
\ No newline at end of file
diff --git a/plugins/Dashboard/stylesheets/standalone.css b/plugins/Dashboard/stylesheets/standalone.css
index cc16f156d8a5916409ce93fbc276380c63012b8b..aaa1df8b9fcaeb159b9ae7f18c4c3647769bbb38 100644
--- a/plugins/Dashboard/stylesheets/standalone.css
+++ b/plugins/Dashboard/stylesheets/standalone.css
@@ -67,7 +67,7 @@ body {
     margin-right: 10px;
 }
 
-.jqplock-seriespicker-popover {
+.jqplot-seriespicker-popover {
     top: 0;
 }
 
diff --git a/plugins/PleineLune/stylesheets/_dataTable.less b/plugins/PleineLune/stylesheets/_dataTable.less
index 26c4393a25e0dffc4ec54a27e0dc24f181e38ce4..69a69ac70962c3b209e59a8310b10343773945af 100644
--- a/plugins/PleineLune/stylesheets/_dataTable.less
+++ b/plugins/PleineLune/stylesheets/_dataTable.less
@@ -1,3 +1,7 @@
+div.dataTable {
+    position:relative;
+}
+
 table.dataTable {
   border-collapse: collapse;
 }
diff --git a/plugins/PleineLune/stylesheets/_jqplot.less b/plugins/PleineLune/stylesheets/_jqplot.less
index 14f4ec053ade8cbfce7cf99c47719bb8ae39c75a..0da3075e40888a8dd5a8d0fb19db0439f3980c09 100644
--- a/plugins/PleineLune/stylesheets/_jqplot.less
+++ b/plugins/PleineLune/stylesheets/_jqplot.less
@@ -1,18 +1,18 @@
-.jqplock-seriespicker-popover {
+.jqplot-seriespicker-popover {
   background-color: @theme-color-background-base;
   border: 1px solid @theme-color-background-contrast;
   border-radius: 0;
   color: @theme-color-text-link;
 }
 
-.jqplock-seriespicker-popover > p:hover > label {
+.jqplot-seriespicker-popover > p:hover > label {
   color: @theme-color-text-focus;
 }
 
-.jqplock-seriespicker-popover :checked + label {
+.jqplot-seriespicker-popover :checked + label {
   color: @theme-color-text-active;
 }
 
-.jqplock-seriespicker-popover p.headline {
+.jqplot-seriespicker-popover p.headline {
   color: @theme-color-text-active;
 }
\ No newline at end of file
diff --git a/plugins/Referers/Controller.php b/plugins/Referers/Controller.php
index 7aea4328044c3532971f3dfa101481b715333f23..407437ac86f6e81107dfb34891de6d685ee06bf4 100644
--- a/plugins/Referers/Controller.php
+++ b/plugins/Referers/Controller.php
@@ -300,8 +300,8 @@ class Controller extends \Piwik\Controller
             $visibleRows = array($label, $total);
             $view->request_parameters_to_modify['rows'] = $label . ',' . $total;
         }
-        $view->row_picker_match_rows_by = 'label';
-        $view->row_picker_visible_rows = $visibleRows;
+        $view->visualization_properties->row_picker_match_rows_by = 'label';
+        $view->visualization_properties->row_picker_visible_rows = $visibleRows;
 
         $view->documentation = Piwik_Translate('Referers_EvolutionDocumentation') . '<br />'
             . Piwik_Translate('General_BrokenDownReportDocumentation') . '<br />'
diff --git a/plugins/Zeitgeist/stylesheets/ieonly.css b/plugins/Zeitgeist/stylesheets/ieonly.css
index 92bdda7e34e5dba7003e939322300a1e756555d5..bb2f7e71f1ad4dc4f126b37ab9c8cadfc33cb696 100644
--- a/plugins/Zeitgeist/stylesheets/ieonly.css
+++ b/plugins/Zeitgeist/stylesheets/ieonly.css
@@ -35,7 +35,7 @@ input[type=checkbox], input[type=radio] {
 	background: url(../images/chart_line_edit_bg.png) no-repeat center center;
 }
 
-.jqplock-seriespicker-popover p input {
+.jqplot-seriespicker-popover p input {
 	width: 15px;
 	margin: 0;
 	padding: 0;