Search code examples
pythonarraysnumpymatplotlibattributeerror

Why am I getting "AttributeError: 'tuple' object has no attribute 'savefig'"?



Edit 3/15/2017 12:00 PM CDT: I have managed to fix the error in the program and complete the program as it was designed. I would like to thank berna1111 and TigerhawkT3 for their answer submissions, as they allowed me to complete this program. Thanks again, Stack Overflow!


I am attempting to save a series of array-built histograms (arrays made with numpy and histograms using matplotlib) to .png type files. I am receiving the following error message:

Traceback (most recent call last):
  File "C:/Users/Ryan/PycharmProjects/NWS/weather_data.py", line 475, in <module>
    figure1.savefig("{}_temperature.png".format(filename))
AttributeError: 'tuple' object has no attribute 'savefig'

The section the error refers to is below:

figure1 = plt.hist(temperature_graph_array, color="blue")
figure2 = plt.hist(feelslike_graph_array, color="blue")
figure3 = plt.hist(windspeed_graph_array, color="blue")
figure4 = plt.hist(windgustspeed_graph_array, color="blue")
figure5 = plt.hist(pressure_graph_array, color="blue")
figure6 = plt.hist(humidity_graph_array, color="blue")

figure1.savefig("{}_temperature.png".format(filename), format='png')
figure2.savefig("{}_feelslike.png".format(filename), format='png')
figure3.savefig("{}_windspeed.png".format(filename), format='png')
figure4.savefig("{}_windgustspeed.png".format(filename), format='png')
figure5.savefig("{}_pressure.png".format(filename), format='png')
figure6.savefig("{}_humidity.png".format(filename), format='png')

Why am I receiving this error, and how can I fix it? If someone could let me know I would greatly appreciate it.


Notes:

  • I have done some google searching and found a few similar errors, but none where the figure was interpreted as a tuple. I do not understand where the tuple part is coming from.

  • The "_graph_array" items in the histogram creation steps are arrays of dimensions 10 long, 1 tall. 10 total items inside, designated as type Float.

  • The "filename" variable in the saving step represents a string containing the date and time.



Solution

  • I've adapted your code and took the liberty to change the several lines creating a figure by list in comprehension of for loops:

    import matplotlib.pyplot as plt
    # should be equal when using .pylab
    import numpy.random as rnd
    
    # generate_data
    n_points = 1000
    temperature_graph_array = rnd.random(n_points)
    feelslike_graph_array = rnd.random(n_points)
    windspeed_graph_array = rnd.random(n_points)
    windgustspeed_graph_array = rnd.random(n_points)
    pressure_graph_array = rnd.random(n_points)
    humidity_graph_array = rnd.random(n_points)
    list_of_data = [temperature_graph_array,
                    feelslike_graph_array,
                    windspeed_graph_array,
                    windgustspeed_graph_array,
                    pressure_graph_array,
                    humidity_graph_array]
    list_of_names = ['temperature',
                     'feelslike',
                     'windspeed',
                     'windgustspeed',
                     'pressure',
                     'humidity']
    
    # create the figures:
    #figure1 = plt.figure()
    #figure2 = plt.figure()
    #figure3 = plt.figure()
    #figure4 = plt.figure()
    #figure5 = plt.figure()
    #figure6 = plt.figure()
    #list_of_figs = [figure1, figure2, figure3, figure4, figure5, figure6]
    ## could be:
    list_of_figs = [plt.figure() for i in range(6)]
    
    # create the axis:
    #ax1 = figure1.add_subplot(111)
    #ax2 = figure2.add_subplot(111)
    #ax3 = figure3.add_subplot(111)
    #ax4 = figure4.add_subplot(111)
    #ax5 = figure5.add_subplot(111)
    #ax6 = figure6.add_subplot(111)
    #list_of_axis = [ax1, ax2, ax3, ax4, ax5, ax6]
    ## could be:
    list_of_axis = [fig.add_subplot(111) for fig in list_of_figs]
    
    # plot the histograms
    # notice `plt.hist` returns a tuple (n, bins, patches) or
    # ([n0, n1, ...], bins, [patches0, patches1,...]) if the input
    # contains multiple data
    #hist1 = ax1.hist(temperature_graph_array, color="blue")
    #hist2 = ax2.hist(feelslike_graph_array, color="blue")
    #hist3 = ax3.hist(windspeed_graph_array, color="blue")
    #hist4 = ax4.hist(windgustspeed_graph_array, color="blue")
    #hist5 = ax5.hist(pressure_graph_array, color="blue")
    #hist6 = ax6.hist(humidity_graph_array, color="blue")
    #list_of_hists = [hist1, hist2, hist3, hist4, hist5, hist6]
    ## could be:
    list_of_hists = []
    for i, ax in enumerate(list_of_axis):
        list_of_hists.append(ax.hist(list_of_data[i], color="blue"))
    
    filename = 'output_graph'
    for i, fig in enumerate(list_of_figs):
        name = list_of_names[i].capitalize()
        list_of_axis[i].set_title(name)
        fig.tight_layout()
        fig.savefig("{}_{}.png".format(filename,name), format='png')
    

    Will not post the resulting figures, but this gives me 6 little .png files in the same folder as the script.

    Even better, you can use a function to do all that to your data:

    def save_hist(data, name, filename):
        fig = plt.figure()
        ax = fig.add_subplot(111)
        ax.hist(data, color="blue")
        ax.set_title(name)
        fig.tight_layout()
        fig.savefig("{}_{}.png".format(filename,name), format='png')
        plt.close(fig)
    
    filename = 'output_graph_2'
    for data, name in zip(list_of_data, list_of_names):
        save_hist(data, name, filename)