Skip to content

Commit

Permalink
utility: add cell_autofit_width() function
Browse files Browse the repository at this point in the history
Expose the internal function to calculate autofit string
lenghts to allow users to manually simulate auotfit.

Feature #1106
  • Loading branch information
jmcnamara committed Jan 22, 2025
1 parent e146585 commit c45683f
Show file tree
Hide file tree
Showing 14 changed files with 276 additions and 65 deletions.
Binary file added dev/docs/source/_images/autofit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added dev/docs/source/_images/autofit_manually.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions dev/docs/source/contents.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Contents
chart.rst
chartsheet.rst
exceptions.rst
utility.rst
working_with_cell_notation.rst
working_with_data.rst
working_with_formulas.rst
Expand Down
2 changes: 1 addition & 1 deletion dev/docs/source/example_autofit.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Example: Autofitting columns

An example of simulating autofitting column widths using the :func:`autofit` method:

.. image:: _images/autofit_win.png
.. image:: _images/autofit.png

.. literalinclude:: ../../../examples/autofit.py

20 changes: 20 additions & 0 deletions dev/docs/source/example_autofit_manually.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.. SPDX-License-Identifier: BSD-2-Clause
Copyright 2013-2024, John McNamara, jmcnamara@cpan.org
.. _ex_autofit_manually:

Example: Autofitting columns manually
=====================================

An example of simulating autofitting column widths using the
:func:`cell_autofit_width` utility function.

The following example demonstrates manually auto-fitting the the width of a
column in Excel based on the maximum string width. The worksheet :func:`autofit`
method will do this automatically but occasionally you may need to control the
maximum and minimum column widths yourself.

.. image:: _images/autofit_manually.png

.. literalinclude:: ../../../examples/autofit_manually.py

1 change: 1 addition & 0 deletions dev/docs/source/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ directory of the XlsxWriter distribution.
example_defined_name.rst
example_merge1.rst
example_autofit.rst
example_autofit_manually.rst
example_rich_strings.rst
example_merge_rich.rst
example_images.rst
Expand Down
1 change: 1 addition & 0 deletions dev/docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ It supports Python 3.4+ and PyPy3 and uses standard libraries only.
chart.rst
chartsheet.rst
exceptions.rst
utility.rst

.. toctree::
:maxdepth: 1
Expand Down
182 changes: 182 additions & 0 deletions dev/docs/source/utility.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
.. SPDX-License-Identifier: BSD-2-Clause
Copyright 2013-2024, John McNamara, jmcnamara@cpan.org
.. _utility:

Utility and Helper Functions
----------------------------

The ``XlsxWriter`` ``utility`` module contains several helper functions for
dealing with A1 notation and strings. These functions can be imported as
follows::

from xlsxwriter.utility import xl_rowcol_to_cell

cell = xl_rowcol_to_cell(1, 2) # C2


xl_rowcol_to_cell()
~~~~~~~~~~~~~~~~~~~

.. py:function:: xl_rowcol_to_cell(row, col[, row_abs, col_abs])
Convert a zero indexed row and column cell reference to a A1 style string.

:param int row: The cell row.
:param int col: The cell column.
:param bool row_abs: Optional flag to make the row absolute.
:param bool col_abs: Optional flag to make the column absolute.
:return: ``A1`` style string.
:rtype: str


The ``xl_rowcol_to_cell()`` function converts a zero indexed row and column
cell values to an ``A1`` style string::

cell = xl_rowcol_to_cell(0, 0) # A1
cell = xl_rowcol_to_cell(0, 1) # B1
cell = xl_rowcol_to_cell(1, 0) # A2

The optional parameters ``row_abs`` and ``col_abs`` can be used to indicate
that the row or column is absolute::

str = xl_rowcol_to_cell(0, 0, col_abs=True) # $A1
str = xl_rowcol_to_cell(0, 0, row_abs=True) # A$1
str = xl_rowcol_to_cell(0, 0, row_abs=True, col_abs=True) # $A$1


xl_cell_to_rowcol()
~~~~~~~~~~~~~~~~~~~

.. py:function:: xl_cell_to_rowcol(cell_str)
Convert a cell reference in ``A1`` notation to a zero indexed row and column.

:param string cell_str: ``A1`` style string, absolute or relative.
:return: Tuple of ints for (row, col).
:rtype: (int, int).


The ``xl_cell_to_rowcol()`` function converts an Excel cell reference in ``A1``
notation to a zero based row and column. The function will also handle Excel's
absolute, ``$``, cell notation::

(row, col) = xl_cell_to_rowcol('A1') # (0, 0)
(row, col) = xl_cell_to_rowcol('B1') # (0, 1)
(row, col) = xl_cell_to_rowcol('C2') # (1, 2)
(row, col) = xl_cell_to_rowcol('$C2') # (1, 2)
(row, col) = xl_cell_to_rowcol('C$2') # (1, 2)
(row, col) = xl_cell_to_rowcol('$C$2') # (1, 2)


xl_col_to_name()
~~~~~~~~~~~~~~~~

.. py:function:: xl_col_to_name(col[, col_abs])
Convert a zero indexed column cell reference to a string.

:param int col: The cell column.
:param bool col_abs: Optional flag to make the column absolute.
:return: Column style string.
:rtype: str


The ``xl_col_to_name()`` converts a zero based column reference to a string::

column = xl_col_to_name(0) # A
column = xl_col_to_name(1) # B
column = xl_col_to_name(702) # AAA

The optional parameter ``col_abs`` can be used to indicate if the column is
absolute::

column = xl_col_to_name(0, False) # A
column = xl_col_to_name(0, True) # $A
column = xl_col_to_name(1, True) # $B


xl_range()
~~~~~~~~~~

.. py:function:: xl_range(first_row, first_col, last_row, last_col)
Converts zero indexed row and column cell references to a A1:B1 range
string.

:param int first_row: The first cell row.
:param int first_col: The first cell column.
:param int last_row: The last cell row.
:param int last_col: The last cell column.
:return: ``A1:B1`` style range string.
:rtype: str


The ``xl_range()`` function converts zero based row and column cell references
to an ``A1:B1`` style range string::

cell_range = xl_range(0, 0, 9, 0) # A1:A10
cell_range = xl_range(1, 2, 8, 2) # C2:C9
cell_range = xl_range(0, 0, 3, 4) # A1:E4
cell_range = xl_range(0, 0, 0, 0) # A1


xl_range_abs()
~~~~~~~~~~~~~~

.. py:function:: xl_range_abs(first_row, first_col, last_row, last_col)
Converts zero indexed row and column cell references to a $A$1:$B$1
absolute range string.

:param int first_row: The first cell row.
:param int first_col: The first cell column.
:param int last_row: The last cell row.
:param int last_col: The last cell column.
:return: ``$A$1:$B$1`` style range string.
:rtype: str


The ``xl_range_abs()`` function converts zero based row and column cell
references to an absolute ``$A$1:$B$1`` style range string::

cell_range = xl_range_abs(0, 0, 9, 0) # $A$1:$A$10
cell_range = xl_range_abs(1, 2, 8, 2) # $C$2:$C$9
cell_range = xl_range_abs(0, 0, 3, 4) # $A$1:$E$4
cell_range = xl_range_abs(0, 0, 0, 0) # $A$1




cell_autofit_width()
~~~~~~~~~~~~~~~~~~~~

.. py:function:: cell_autofit_width(string)
Calculate the width required to auto-fit a string in a cell.

:param String string: The string to calculate the cell width for.
:return: The string autofit width in pixels. Returns 0 if the
string is empty.
:rtype: int

The Worksheet :func:`autofit` method can be used to auto-fit cell data to the
optimal column width. However, in some cases you may wish to handle auto-fitting
yourself and apply additional logic to limit the maximum and minimum ranges.

The ``cell_autofit_width()`` function can be used to perform the required
calculation. It works by estimating the pixel width of a string based on the
width of each character. It also adds a 7 pixel padding for the cell
boundary in the same way that Excel does.

You can use the calculated width in conjunction with Worksheet :func:`autofit`
method::

worksheet.set_column('A:A', cell_autofit_width('Some long text'))

worksheet.autofit('A:A')

worksheet.write('A1', 'Some long text')

The same limitation applies to this function as to the Worksheet ``autofit``
method. See the docs on :func:`autofit` for more information.
66 changes: 8 additions & 58 deletions dev/docs/source/working_with_cell_notation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -114,30 +114,21 @@ See also :ref:`ex_defined_name`.
Cell Utility Functions
----------------------

The ``XlsxWriter`` ``utility`` module contains several helper functions for
The :func:`XlsxWriter`` ``utility`` module contains several helper functions for
dealing with A1 notation as shown below. These functions can be imported as
follows::

from xlsxwriter.utility import xl_rowcol_to_cell

cell = xl_rowcol_to_cell(1, 2) # C2

See the documentation for :ref:`utility` for more details.


xl_rowcol_to_cell()
~~~~~~~~~~~~~~~~~~~

.. py:function:: xl_rowcol_to_cell(row, col[, row_abs, col_abs])
Convert a zero indexed row and column cell reference to a A1 style string.

:param int row: The cell row.
:param int col: The cell column.
:param bool row_abs: Optional flag to make the row absolute.
:param bool col_abs: Optional flag to make the column absolute.
:rtype: A1 style string.


The ``xl_rowcol_to_cell()`` function converts a zero indexed row and column
The :func:`xl_rowcol_to_cell` function converts a zero indexed row and column
cell values to an ``A1`` style string::

cell = xl_rowcol_to_cell(0, 0) # A1
Expand All @@ -155,15 +146,7 @@ that the row or column is absolute::
xl_cell_to_rowcol()
~~~~~~~~~~~~~~~~~~~

.. py:function:: xl_cell_to_rowcol(cell_str)
Convert a cell reference in A1 notation to a zero indexed row and column.

:param string cell_str: A1 style string, absolute or relative.
:rtype: Tuple of ints for (row, col).


The ``xl_cell_to_rowcol()`` function converts an Excel cell reference in ``A1``
The :func:`xl_cell_to_rowcol` function converts an Excel cell reference in ``A1``
notation to a zero based row and column. The function will also handle Excel's
absolute, ``$``, cell notation::

Expand All @@ -178,16 +161,7 @@ absolute, ``$``, cell notation::
xl_col_to_name()
~~~~~~~~~~~~~~~~

.. py:function:: xl_col_to_name(col[, col_abs])
Convert a zero indexed column cell reference to a string.

:param int col: The cell column.
:param bool col_abs: Optional flag to make the column absolute.
:rtype: Column style string.


The ``xl_col_to_name()`` converts a zero based column reference to a string::
The :func:`xl_col_to_name` converts a zero based column reference to a string::

column = xl_col_to_name(0) # A
column = xl_col_to_name(1) # B
Expand All @@ -204,19 +178,7 @@ absolute::
xl_range()
~~~~~~~~~~

.. py:function:: xl_range(first_row, first_col, last_row, last_col)
Converts zero indexed row and column cell references to a A1:B1 range
string.

:param int first_row: The first cell row.
:param int first_col: The first cell column.
:param int last_row: The last cell row.
:param int last_col: The last cell column.
:rtype: A1:B1 style range string.


The ``xl_range()`` function converts zero based row and column cell references
The :func:`xl_range` function converts zero based row and column cell references
to an ``A1:B1`` style range string::

cell_range = xl_range(0, 0, 9, 0) # A1:A10
Expand All @@ -228,19 +190,7 @@ to an ``A1:B1`` style range string::
xl_range_abs()
~~~~~~~~~~~~~~

.. py:function:: xl_range_abs(first_row, first_col, last_row, last_col)
Converts zero indexed row and column cell references to a $A$1:$B$1
absolute range string.

:param int first_row: The first cell row.
:param int first_col: The first cell column.
:param int last_row: The last cell row.
:param int last_col: The last cell column.
:rtype: $A$1:$B$1 style range string.


The ``xl_range_abs()`` function converts zero based row and column cell
The :func:`xl_range_abs` function converts zero based row and column cell
references to an absolute ``$A$1:$B$1`` style range string::

cell_range = xl_range_abs(0, 0, 9, 0) # $A$1:$A$10
Expand Down
9 changes: 7 additions & 2 deletions dev/docs/source/worksheet.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1247,9 +1247,9 @@ on the largest string/number in the column::
# Autofit the worksheet.
worksheet.autofit()

.. image:: _images/autofit_win.png
.. image:: _images/autofit.png

See :ref:`ex_autofit`
See :ref:`ex_autofit`.

Excel autofits columns at runtime when it has access to all of the required
worksheet information as well as the Windows functions for calculating display
Expand Down Expand Up @@ -1281,6 +1281,11 @@ compromise between column width and readability::

worksheet.autofit(300)

If you need more control over the autofit effect you can use the
:func:`cell_autofit_width` utility function to calculate the autofit width for a
cell value. This is the same calculation used internally by ``autofit()``. See
also See :ref:`ex_autofit_manually`.

**Performance**: By default ``autofit()`` performs a length calculation for each
populated cell in a worksheet. For very large worksheets this could be slow.
However, it is possible to mitigate this by calling ``autofit()`` after writing
Expand Down
Loading

0 comments on commit c45683f

Please sign in to comment.