Source code for node_table_sort
# This file is part of Sympathy for Data.
# Copyright (c) 2013, Combine Control Systems AB
#
# SYMPATHY FOR DATA COMMERCIAL LICENSE
# You should have received a link to the License with Sympathy for Data.
from sympathy.api import node as synode
from sympathy.api import node_helper
from sympathy.api.nodeconfig import Tag, Tags, adjust, Port, Ports
import numpy as np
_sort_options = dict([
('Ascending', 'Standard'),
('Descending', 'Reverse'),
])
[docs]
class SortRowsTable(synode.Node):
"""
Sort the rows of a table according to a sort column.
The rows in the Tables are sorted by the selected *Sort column*. If *Sort
order* is "Standard" numbers will be sorted increasingly, strings will be
sorted alphabetically etc. If it is instead "Reverse" the order is instead
reversed.
Sorting by multiple rows
========================
The sorting algorithm used is stable, meaning that if two or more rows have
the same value in the *Sort column* they will keep the same relative order
as in the input. This can be used to sort the table by multiple columns.
If you want to sort by multiple columns you can use multple sorting nodes
in series. For example if you have the following table ad want to sort the
table such that high priority tasks come first, and tasks with equal
priority are sorted by lowest time needed:
+----------------+----------+-------------+
| Task | Priority | Time needed |
+================+==========+=============+
| Do dishes | A | 30 |
+----------------+----------+-------------+
| Mop floors | C | 45 |
+----------------+----------+-------------+
| Clean windows | C | 30 |
+----------------+----------+-------------+
| Take out trash | A | 5 |
+----------------+----------+-------------+
| Buy groceries | B | 60 |
+----------------+----------+-------------+
then first use a Sort rows in Table node to sort the rows by increasing
time, then use a second Sort rows in Table node to sort the rows by highest
priority. The result would then be:
+----------------+----------+-------------+
| Task | Priority | Time needed |
+================+==========+=============+
| Take out trash | A | 5 |
+----------------+----------+-------------+
| Do dishes | A | 30 |
+----------------+----------+-------------+
| Buy groceries | B | 60 |
+----------------+----------+-------------+
| Clean windows | C | 30 |
+----------------+----------+-------------+
| Mop floors | C | 45 |
+----------------+----------+-------------+
"""
author = 'Greger Cronquist'
icon = 'sort_table_rows.svg'
tags = Tags(Tag.DataProcessing.TransformStructure)
name = 'Sort rows in Table'
nodeid = 'org.sysess.sympathy.data.table.sorttable'
description = 'Sort rows in Table by selected column'
inputs = Ports([Port.Table('Input', name='Input')])
outputs = Ports([Port.Table('Input', name='Output')])
parameters = synode.parameters()
parameters.set_list(
'column', label='Sort column',
description='Column to sort',
editor=synode.editors.combo_editor('', filter=True, edit=True))
parameters.set_list(
'sort_order', label='Sort order',
list=['Ascending', 'Descending'],
value=[0],
description='Sort order',
editor=synode.editors.combo_editor(options=_sort_options))
def adjust_parameters(self, node_context):
adjust(node_context.parameters['column'], node_context.input['Input'])
def execute(self, node_context):
in_table = node_context.input['Input']
out_table = node_context.output['Output']
parameters = node_context.parameters
if in_table.is_empty():
return
column_param = parameters['column']
column = in_table._require_column(column_param)
idx = np.ma.argsort(column, kind='mergesort')
if parameters['sort_order'].selected == 'Descending':
idx = idx[::-1]
if isinstance(column, np.ma.MaskedArray):
masked = np.ma.getmaskarray(column)[idx]
if parameters['sort_order'].selected == 'Ascending':
# Ascending: put masked values last
idx = np.concatenate((idx[~masked], idx[masked]))
else:
# Descending: put masked values first
idx = np.concatenate((idx[masked], idx[~masked]))
for column_name in in_table.column_names():
array = in_table.get_column_to_array(column_name)
out_table.set_column_from_array(column_name, array[idx])
out_table.set_attributes(in_table.get_attributes())
out_table.set_name(in_table.get_name())
[docs]
@node_helper.list_node_decorator(['Input'], ['Output'])
class SortRowsTables(SortRowsTable):
name = 'Sort rows in Tables'
nodeid = 'org.sysess.sympathy.data.table.sorttables'