From e65c279eed0d5d8307c491ecc31d87805f8f8d79 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Mon, 10 Jan 2022 21:45:28 +0100 Subject: [PATCH] Backport PR #21943: DOC: explain too many ticks --- doc/users/faq/howto_faq.rst | 53 ++++++++++++++++++++++ examples/ticks/ticks_too_many.py | 76 ++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 examples/ticks/ticks_too_many.py diff --git a/doc/users/faq/howto_faq.rst b/doc/users/faq/howto_faq.rst index 0076cb335ab4..409b9e04e713 100644 --- a/doc/users/faq/howto_faq.rst +++ b/doc/users/faq/howto_faq.rst @@ -9,6 +9,59 @@ How-to .. contents:: :backlinks: none + +.. _how-to-too-many-ticks: + +Why do I have so many ticks, and/or why are they out of order? +-------------------------------------------------------------- + +One common cause for unexpected tick behavior is passing a *list of strings +instead of numbers or datetime objects*. This can easily happen without notice +when reading in a comma-delimited text file. Matplotlib treats lists of strings +as *categorical* variables +(:doc:`/gallery/lines_bars_and_markers/categorical_variables`), and by default +puts one tick per category, and plots them in the order in which they are +supplied. + +.. plot:: + :include-source: + :align: center + + import matplotlib.pyplot as plt + import numpy as np + + fig, ax = plt.subplots(1, 2, constrained_layout=True, figsize=(6, 2)) + + ax[0].set_title('Ticks seem out of order / misplaced') + x = ['5', '20', '1', '9'] # strings + y = [5, 20, 1, 9] + ax[0].plot(x, y, 'd') + ax[0].tick_params(axis='x', labelcolor='red', labelsize=14) + + ax[1].set_title('Many ticks') + x = [str(xx) for xx in np.arange(100)] # strings + y = np.arange(100) + ax[1].plot(x, y) + ax[1].tick_params(axis='x', labelcolor='red', labelsize=14) + +The solution is to convert the list of strings to numbers or +datetime objects (often ``np.asarray(numeric_strings, dtype='float')`` or +``np.asarray(datetime_strings, dtype='datetime64[s]')``). + +For more information see :doc:`/gallery/ticks/ticks_too_many`. + +.. _howto-determine-artist-extent: + +Determine the extent of Artists in the Figure +--------------------------------------------- + +Sometimes we want to know the extent of an Artist. Matplotlib `.Artist` objects +have a method `.Artist.get_window_extent` that will usually return the extent of +the artist in pixels. However, some artists, in particular text, must be +rendered at least once before their extent is known. Matplotlib supplies +`.Figure.draw_without_rendering`, which should be called before calling +``get_window_extent``. + .. _howto-figure-empty: Check whether a figure is empty diff --git a/examples/ticks/ticks_too_many.py b/examples/ticks/ticks_too_many.py new file mode 100644 index 000000000000..c1f05bf4c17e --- /dev/null +++ b/examples/ticks/ticks_too_many.py @@ -0,0 +1,76 @@ +""" +===================== +Fixing too many ticks +===================== + +One common cause for unexpected tick behavior is passing a list of strings +instead of numbers or datetime objects. This can easily happen without notice +when reading in a comma-delimited text file. Matplotlib treats lists of strings +as *categorical* variables +(:doc:`/gallery/lines_bars_and_markers/categorical_variables`), and by default +puts one tick per category, and plots them in the order in which they are +supplied. If this is not desired, the solution is to convert the strings to +a numeric type as in the following examples. + +""" + +############################################################################ +# Example 1: Strings can lead to an unexpected order of number ticks +# ------------------------------------------------------------------ + +import matplotlib.pyplot as plt +import numpy as np + +fig, ax = plt.subplots(1, 2, constrained_layout=True, figsize=(6, 2.5)) +x = ['1', '5', '2', '3'] +y = [1, 4, 2, 3] +ax[0].plot(x, y, 'd') +ax[0].tick_params(axis='x', color='r', labelcolor='r') +ax[0].set_xlabel('Categories') +ax[0].set_title('Ticks seem out of order / misplaced') + +# convert to numbers: +x = np.asarray(x, dtype='float') +ax[1].plot(x, y, 'd') +ax[1].set_xlabel('Floats') +ax[1].set_title('Ticks as expected') + +############################################################################ +# Example 2: Strings can lead to very many ticks +# ---------------------------------------------- +# If *x* has 100 elements, all strings, then we would have 100 (unreadable) +# ticks, and again the solution is to convert the strings to floats: + +fig, ax = plt.subplots(1, 2, figsize=(6, 2.5)) +x = [f'{xx}' for xx in np.arange(100)] +y = np.arange(100) +ax[0].plot(x, y) +ax[0].tick_params(axis='x', color='r', labelcolor='r') +ax[0].set_title('Too many ticks') +ax[0].set_xlabel('Categories') + +ax[1].plot(np.asarray(x, float), y) +ax[1].set_title('x converted to numbers') +ax[1].set_xlabel('Floats') + +############################################################################ +# Example 3: Strings can lead to an unexpected order of datetime ticks +# -------------------------------------------------------------------- +# A common case is when dates are read from a CSV file, they need to be +# converted from strings to datetime objects to get the proper date locators +# and formatters. + +fig, ax = plt.subplots(1, 2, constrained_layout=True, figsize=(6, 2.75)) +x = ['2021-10-01', '2021-11-02', '2021-12-03', '2021-09-01'] +y = [0, 2, 3, 1] +ax[0].plot(x, y, 'd') +ax[0].tick_params(axis='x', labelrotation=90, color='r', labelcolor='r') +ax[0].set_title('Dates out of order') + +# convert to datetime64 +x = np.asarray(x, dtype='datetime64[s]') +ax[1].plot(x, y, 'd') +ax[1].tick_params(axis='x', labelrotation=90) +ax[1].set_title('x converted to datetimes') + +plt.show()