2

I have two sets of data thats needs to be plotted against time. And I need to display them individually and together with the help of a radio button (or a similar way). The radio button code is based on https://stackoverflow.com/a/6697555/3910296

Everything looks good till the first set of data is loaded. I clear the axes and re-plot the data whenever the next set of data is to be plotted. But when I click the next item in radio button, the new data is displayed, but x axis is not rotated. Is there any way to fix this.

Sample code to reproduce the problem I am facing

import datetime
import matplotlib.pyplot as plt
from matplotlib.widgets import RadioButtons
import matplotlib.dates as mdates

data0_usage = [45, 76, 20, 86, 79, 95, 14, 94, 59, 84]
data1_usage = [57, 79, 25, 28, 17, 46, 29, 52, 68, 92]
data0_timestamp = []


def draw_data_plot(ax, data_no):
    if data_no == 0:
        data_usage = data0_usage
        data_color = 'go'
    elif data_no == 1:
        data_usage = data1_usage
        data_color = 'ro'

    ax.plot_date(data0_timestamp, data_usage, data_color)
    ax.plot_date(data0_timestamp, data_usage, 'k', markersize=1)


def draw_plot():
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.grid(True)

    # Adjust the subplots region to leave some space for the sliders and buttons
    fig.subplots_adjust(left=0.25, bottom=0.25)

    # Beautify the dates on x axis
    time_format = mdates.DateFormatter('%Y-%b-%d %H:%M:%S')
    plt.gca().xaxis.set_major_formatter(time_format)
    plt.gcf().autofmt_xdate()

    # Draw data0 plot
    draw_data_plot(ax, 0)

    # Add a set of radio buttons for changing color
    color_radios_ax = fig.add_axes(
        [0.025, 0.5, 0.15, 0.15], axisbg='lightgoldenrodyellow')
    color_radios = RadioButtons(
        color_radios_ax, ('data 0', 'data 1', 'all'),
        active=0)

    def color_radios_on_clicked(label):
        ax.cla()
        ax.grid(True)
        if label == 'all':
            draw_data_plot(ax, 0)
            draw_data_plot(ax, 1)
        else:
            draw_data_plot(ax, int(label[5]))

        ax.xaxis.set_major_formatter(time_format)
        plt.gcf().autofmt_xdate()
        fig.canvas.draw_idle()

    color_radios.on_clicked(color_radios_on_clicked)
    plt.show()


current_date = datetime.datetime.today()
for days in range(0, 10):
    data0_timestamp.append(current_date + datetime.timedelta(days))
draw_plot()

Using Windows 10, Python 2.7.32, matplotlib 2.1.0

MrPavanayi
  • 887
  • 8
  • 17
  • @importanceofbeingernest I am calling plt.gcf().autofmt_xdate() after clearing axes(just before calling draw_idle). I think plt.gcf() might not be referring to the correct figure once axes is cleared – MrPavanayi Jan 10 '18 at 14:55

1 Answers1

4

The problem

The reason plt.gcf().autofmt_xdate() fails for subsequent updates of the axes content is that at the point when it is called, there are axes inside the figure, which are no subplots. This is the axes created by fig.add_axes, being the radiobutton axes. autofmt_xdate will not know what to do with this axes, i.e. it would not know if this is the axes for which to rotate the labels or not, hence it will decide not to do anything. In the matplotlib source code this looks like

allsubplots = all(hasattr(ax, 'is_last_row') for ax in self.axes)
if len(self.axes) == 1:
    # rotate labels
else:
    if allsubplots:
        for ax in self.get_axes():
            if ax.is_last_row():
                #rotate labels
            else:
                #set labels invisible

Because you have an axes, which is not a subplot, allsubplots == False and no rotation takes place.

The solution

The solution would be not to use autofmt_xdate(), but to do the work of rotating the ticklabels manually - which is really only 3 lines of code. Replace the line plt.gcf().autofmt_xdate() by

for label in ax.get_xticklabels():
    label.set_ha("right")
    label.set_rotation(30)
Community
  • 1
  • 1
ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712