def to_xlsx(self, filename=None, workbook=None):
        """
        Write worksheet to a .xlsx file using xlsxwriter.

        :param str filename: Filename to write to. If None no file is written.
        :param xltable.Workbook: Workbook this sheet belongs to. If None a new workbook
        will be created with this worksheet as the only sheet.
        :return: :py:class:`xlsxwriter.workbook.Workbook` instance.
        """
        from .workbook import Workbook
        if not workbook:
            workbook = Workbook(filename=filename)
            workbook.append(self)
            return workbook.to_xlsx()
        ws = workbook.add_xlsx_worksheet(self, self.name)

        _styles = {}
        def _get_xlsx_style(cell_style):
            """
            convert rb.excel style to xlsx writer style
            """
            style_args = (
                cell_style.bold,
                cell_style.excel_number_format,
                cell_style.text_color,
                cell_style.bg_color,
                cell_style.size,
                cell_style.text_wrap,
                cell_style.text_wrap,
                cell_style.border,
                cell_style.align,
                cell_style.valign
            )
            if (style_args) not in _styles:
                style = workbook.add_format()
                if cell_style.bold:
                    style.set_bold()
                if cell_style.excel_number_format is not None:
                    style.set_num_format(cell_style.excel_number_format)
                if cell_style.text_color is not None:
                    style.set_font_color("#%06x" % cell_style.text_color)
                if cell_style.bg_color is not None:
                    style.set_bg_color("#%06x" % cell_style.bg_color)
                if cell_style.size is not None:
                    style.set_font_size(cell_style.size)
                if cell_style.text_wrap:
                    style.set_text_wrap()
                if cell_style.border:
                    if isinstance(cell_style.border, frozenset):
                        for border_position, border_style in cell_style.border:
                            if border_position == "bottom":
                                style.set_bottom(border_style)
                            elif border_position == "top":
                                style.set_top(border_style)
                            elif border_position == "left":
                                style.set_left(border_style)
                            elif border_position == "right":
                                style.set_right(border_style)
                            else:
                                raise AssertionError("Unknown border position '%s'." % border_position)
                    else:
                        style.set_border(cell_style.border)
                if cell_style.align:
                    style.set_align(cell_style.align)
                if cell_style.valign:
                    style.set_valign(cell_style.valign)

                _styles[style_args] = style

            return _styles[style_args]

        # pre-compute the cells with non-default styles
        ws_styles = self._get_all_styles()
        ws_styles = {(r, c): _get_xlsx_style(s) for ((r, c), s) in ws_styles.items()}
        plain_style = _get_xlsx_style(CellStyle())

        # get any array formula tables
        array_formula_tables = []
        for table, (row, col) in self.__tables.values():
            if isinstance(table, ArrayFormula):
                array_formula_tables.append((row, col, row + table.height, col + table.width))

        def _is_in_array_formula_table(row, col):
            """returns True if this formula cell is part of an array formula table"""
            for top, left, bottom, right in array_formula_tables:
                if bottom >= row >= top and left <= col <= right:
                    return True
            return False

        # write the rows to the worksheet
        for ir, row in enumerate(self.iterrows(workbook)):
            for ic, cell in enumerate(row):
                style = ws_styles.get((ir, ic), plain_style)
                if isinstance(cell, str):
                    if cell.startswith("="):
                        formula_value = self.__formula_values.get((ir, ic), 0)
                        ws.write_formula(ir, ic, cell, style, value=formula_value)
                    elif cell.startswith("{="):
                        # array formulas tables are written after everything else,
                        # but individual cells can also be array formulas
                        if not _is_in_array_formula_table(ir, ic):
                            formula_value = self.__formula_values.get((ir, ic), 0)
                            ws.write_array_formula(ir, ic, ir, ic,
                                                   cell, style,
                                                   value=formula_value)
                    else:
                        ws.write(ir, ic, cell, style)
                else:
                    if isinstance(cell, self._xlsx_unsupported_types):
                        ws.write(ir, ic, str(cell), style)
                    else:
                        try:
                            ws.write(ir, ic, cell, style)
                        except TypeError:
                            ws.write(ir, ic, str(cell), style)
                            unsupported_types = set(self._xlsx_unsupported_types)
                            unsupported_types.add(type(cell))
                            self.__class__._xlsx_unsupported_types = tuple(unsupported_types)

        # set any array formulas
        for table, (row, col) in self.__tables.values():
            if isinstance(table, ArrayFormula):
                style = ws_styles.get((row, col), plain_style)
                data = table.get_data(workbook, row, col)
                height, width = data.shape
                bottom, right = (row + height - 1, col + width -1)
                formula = table.formula.get_formula(workbook, row, col)
                ws.write_array_formula(row, col, bottom, right, formula, style, value=data[0][0])

                for y in range(height):
                    for x in range(width):
                        if y == 0 and x == 0:
                            continue
                        ir, ic = row + y, col + x
                        style = ws_styles.get((ir, ic), plain_style)
                        cell = data[y][x]
                        if isinstance(cell, str):
                            cell_str = cell.encode("ascii", "xmlcharrefreplace").decode("ascii")
                            ws.write_formula(ir, ic, cell_str, style)
                        else:
                            ws.write(ir, ic, cell, style)

        # set any non-default column widths
        for ic, width in self._get_column_widths().items():
            ws.set_column(ic, ic, width)

        # add any charts
        for chart, (row, col) in self.__charts:
            kwargs = {"type": chart.type}
            if chart.subtype:
                kwargs["subtype"] = chart.subtype
            xl_chart = workbook.workbook_obj.add_chart(kwargs)

            if chart.show_blanks:
                xl_chart.show_blanks_as(chart.show_blanks)

            for series in chart.iter_series(workbook, row, col):
                # xlsxwriter expects the sheetname in the formula
                values = series.get("values")
                if isinstance(values, str) and values.startswith("=") and "!" not in values:
                    series["values"] = "='%s'!%s" % (self.name, values.lstrip("="))
                    
                categories = series.get("categories")
                if isinstance(categories, str) and categories.startswith("=") and "!" not in categories:
                    series["categories"] = "='%s'!%s" % (self.name, categories.lstrip("="))

                xl_chart.add_series(series)

            xl_chart.set_size({"width": chart.width, "height": chart.height})

            if chart.title:
                xl_chart.set_title({"name": chart.title})

            if chart.legend_position:
                xl_chart.set_legend({"position": chart.legend_position})

            if chart.x_axis:
                xl_chart.set_x_axis(chart.x_axis)

            if chart.y_axis:
                xl_chart.set_y_axis(chart.y_axis)

            ws.insert_chart(row, col, xl_chart)

        # add any groups
        for tables, collapsed in self.__groups:
            min_row, max_row = 1000000, -1

            for table, (row, col) in self.__tables.values():
                if table in tables:
                    min_row = min(min_row, row)
                    max_row = max(max_row, row + table.height)
            for i in range(min_row, max_row+1):
                ws.set_row(i, None, None, {'level': 1, 'hidden': collapsed})

        if filename:
            workbook.close()
        return workbook