'Provides metadata about columns for data visualization.
:return: dict, with the fields name, type, is_date, is_dim and agg.'

@property
def columns(self):

    if self.__df.empty:
        return None
    columns = []
    sample_size = min(INFER_COL_TYPES_SAMPLE_SIZE, len(self.__df.index))
    sample = self.__df
    if sample_size:
        sample = self.__df.sample(sample_size)
    for col in self.__df.dtypes.keys():
        col_db_type = self.db_type(self.__df.dtypes[col])
        column = {u'name': col, u'agg': self.agg_func(self.__df.dtypes[col], col), u'type': col_db_type, u'is_date': self.is_date(self.__df.dtypes[col]), u'is_dim': self.is_dimension(self.__df.dtypes[col], col)}
        if (column[u'type'] in (u'OBJECT', None)):
            v = (sample[col].iloc[0] if (not sample[col].empty) else None)
            if isinstance(v, basestring):
                column[u'type'] = u'STRING'
            elif isinstance(v, int):
                column[u'type'] = u'INT'
            elif isinstance(v, float):
                column[u'type'] = u'FLOAT'
            elif isinstance(v, (datetime, date)):
                column[u'type'] = u'DATETIME'
                column[u'is_date'] = True
                column[u'is_dim'] = False
            if ((column[u'type'] == u'STRING') and (self.datetime_conversion_rate(sample[col]) > INFER_COL_TYPES_THRESHOLD)):
                column.update({u'is_date': True, u'is_dim': False, u'agg': None})
        if (not column[u'agg']):
            column.pop(u'agg', None)
        columns.append(column)
    return columns
