public function filter($table)
    {
        // set of all column names in the pivoted table mapped with the sum of all column
        // values. used later in truncating and ordering the pivoted table's columns.
        $columnSet = array();

        // if no pivot column was set, use the first one found in the row
        if (empty($this->pivotColumn)) {
            $this->pivotColumn = $this->getNameOfFirstNonLabelColumnInTable($table);
        }

        Log::debug("PivotByDimension::%s: pivoting table with pivot column = %s", __FUNCTION__, $this->pivotColumn);

        foreach ($table->getRows() as $row) {
            $row->setColumns(array('label' => $row->getColumn('label')));

            $associatedTable = $this->getIntersectedTable($table, $row);
            if (!empty($associatedTable)) {
                foreach ($associatedTable->getRows() as $columnRow) {
                    $pivotTableColumn = $columnRow->getColumn('label');

                    $columnValue = $this->getColumnValue($columnRow, $this->pivotColumn);

                    if (isset($columnSet[$pivotTableColumn])) {
                        $columnSet[$pivotTableColumn] += $columnValue;
                    } else {
                        $columnSet[$pivotTableColumn] = $columnValue;
                    }

                    $row->setColumn($pivotTableColumn, $columnValue);
                }

                Common::destroy($associatedTable);
                unset($associatedTable);
            }
        }

        Log::debug("PivotByDimension::%s: pivoted columns set: %s", __FUNCTION__, $columnSet);

        $others = Piwik::translate('General_Others');
        $defaultRow = $this->getPivotTableDefaultRowFromColumnSummary($columnSet, $others);

        Log::debug("PivotByDimension::%s: un-prepended default row: %s", __FUNCTION__, $defaultRow);

        // post process pivoted datatable
        foreach ($table->getRows() as $row) {
            // remove subtables from rows
            $row->removeSubtable();
            $row->deleteMetadata('idsubdatatable_in_db');

            // use default row to ensure column ordering and add missing columns/aggregate cut-off columns
            $orderedColumns = $defaultRow;
            foreach ($row->getColumns() as $name => $value) {
                if (isset($orderedColumns[$name])) {
                    $orderedColumns[$name] = $value;
                } else {
                    $orderedColumns[$others] += $value;
                }
            }
            $row->setColumns($orderedColumns);
        }

        $table->clearQueuedFilters(); // TODO: shouldn't clear queued filters, but we can't wait for them to be run
                                      //       since generic filters are run before them. remove after refactoring
                                      //       processed metrics.

        // prepend numerals to columns in a queued filter (this way, disable_queued_filters can be used
        // to get machine readable data from the API if needed)
        $prependedColumnNames = $this->getOrderedColumnsWithPrependedNumerals($defaultRow, $others);

        Log::debug("PivotByDimension::%s: prepended column name mapping: %s", __FUNCTION__, $prependedColumnNames);

        $table->queueFilter(function (DataTable $table) use ($prependedColumnNames) {
            foreach ($table->getRows() as $row) {
                $row->setColumns(array_combine($prependedColumnNames, $row->getColumns()));
            }
        });
    }