1

I am currently having an issue with the displayed x labels overlapping on the x axis causing the labels to be illegible.

What I have already tried:

1) The axis has been rotated the ticks to 60 degrees, but some plots still overlap

2) Locator_params has been tried, but it throws an error of " AttributeError: 'List' object has no attribute 'locator_params' "

3)using mdates to access year and month locator has been unsuccessful as well. Following is the example code I tried; from source; Matplotlib date manipulation so that the year tick show up every 12 months

        years = mdates.YearLocator()
        months = mdates.MonthLocator()
        monthsFmt = mdates.DateFormatter('%b-%y')
        yearsformat=mdates.DateFormatter('\n\n%Y')
        ###
        ax.xaxis.set_minor_locator(months)
        ax.xaxis.set_minor_formatter(monthsFmt)
        ####
        plt.setp(ax.xaxis.get_minorticklabels(), rotation=90)
        ax.xaxis.set_major_formatter(years)
        ax.xaxis.set_major_formatter(yearsformat)

I believe I may be misunderstanding how to use locator_params & mdates.

Notes:

1) I am using a loop to make ~200 plots that have varying amount of xticks, some with 400+, others with only 15. For this reason, I want to try and set the maximum number of ticks at ~30-40 if possible. However, I am also open to other ideas and suggestions.

Segment of Code:

 def plotme(df,string,ref):
        for i in range(0,len(df.columns)):
             #Scatter plot the active ingredient data. 
             plotdf=df.iloc[:,i].dropna()
             #Store length of df
             length=len(plotdf.index) 



    #Decide on length to cutoff. If index is shorter then 10 datapoints, 
        exclude it
        if length > 10:
            #Dataframes setup for Statistics Fucntion
            statss=pd.to_numeric(df.iloc[:,i],errors='coerce')
            #Last value in the dataframe, aka the most recent
            lastvalue=statss[-1]
            lastvalue=round(lastvalue,2)
            #String Manipulations
            #Possibly make a function for this
            temp5=str(ref[i])
            table = str.maketrans(dict.fromkeys("([)]'"))
            temp5=temp5.translate(table)
            temp6=temp5.split(',')

            #The Iterative Dict split up for accessing
            low=float(temp6[1])
            low=round(low,2)
            high=float(temp6[2])
            high=round(high,2)
            active=str(temp6[0])
            uom=str(temp6[3])
            usl=' USL ' + str(high)
            lsl=' LSL ' + str(low)

            #Call to fucntion for Statistical analysis; a list is returned
            #List order; 0==Cp, 1==Cpk, 2==Mean, 3==Standard          
            stat=statistics(statss,high,low)
            mean=stat[2]
            standard=stat[3]
            cp=stat[0]
            cpk=stat[1]
            meanstr=str(mean) + ' $\mu$'
            title=string + ' ' + active
            subtitle='The Cp is ' +str(cp) + ' while the CpK is ' +str(cpk)
            ylabel=active + '  (' + uom +')'
            plt.figure(0)
            #Index is date logged currently, change when index is greater than 100, as overcrowding occurs
            ax,=plt.plot(plotdf.index,plotdf, marker='o', linewidth=1, markersize=3)
            #ax.locator_params(nbins=4)
            #Changing Plot Axis and adding the reference line
            plt.title(title)
            plt.ylabel(ylabel)
            plt.xlabel('Date Logged',fontsize=8)
            plt.rc('xtick', labelsize=7)
            plt.plot([0,length],[low,low],'r-',lw=3)
            plt.plot([0,length],[high,high],'r-',lw=3)
            plt.xlim(0,length)
            plt.xticks(rotation=60)
            #plt.xticks(plt.xticks()[0][1::2], 
            #plt.xticks()[1][1::2])
            #plt.gca().xaxis.set_major_locator(mdates.DayLocator((1,15)))
            #plt.gca().xaxis.set_major_formatter(mdates.DateFormatter("%d %b %Y"))
            ax.locator_params(axis='x',nbins=40)

            plt.plot([0,length],[mean,mean],'g',lw=2,label='$\mu$')
            #Add the USL and LSL
            #Possibly use Hline subclass instead for efficiency(?)
            plt.text((length+0.5),high,usl,fontsize=7,color='red')
            plt.text((length+0.5),low,lsl,fontsize=7,color='red')
            plt.text((length+0.5),mean,meanstr,fontsize=7,color='green')
            #For loop to plot the sigma lines
            for i in range(1,5):
                minsig=mean-i*standard
                adsig=mean+i*standard
                cond1=math.isnan(adsig)
                cond2=math.isnan(minsig)
               ####Figure out later####
                # if (minsig or adsig) 
                ##Some of the minsig and adsig calculations are nan resulting in an error converting nan to an integer.
                if ((cond1==False) and (cond2==False)):
                    plt.plot([0,length],[minsig,minsig],'k--',lw=1,label='+' + str(i)+' ' + '$\sigma$')
                    plt.plot([0,length],[adsig,adsig],'k--',lw=1,label='-' + str(i)+ ' ' + '$\sigma$')
                    plt.text((length+0.1),minsig,'-' + str(i)+' ' + '$\sigma$',fontsize=6)
                    plt.text((length+0.1),adsig,'+' + str(i)+' ' + '$\sigma$',fontsize=6)
            #Save the plots as the name of the title and delete the white space in order to maximize viewability
            plt.savefig(title + '.png', bbox_inches='tight',format='png',dpi=800)   
            plt.show()    
            plt.figure(1)
            plt.rc('xtick', labelsize=8)
            sns.distplot(a=plotdf,bins=20,hist_kws=dict(edgecolor='k',linewidth=2))
            plt.axvline(low, color='r', linestyle='solid', linewidth=2)
            plt.axvline(mean, color='g', linestyle='dashed', linewidth=2)
            plt.axvline(high, color='r', linestyle='solid', linewidth=2)

            plt.xlabel(ylabel)
            plt.title(title + '\n' + subtitle)
            plt.savefig(title + ' Normal' +'.png',bbox_inches='tight',format='png',dpi=800)

Example of Issue: The Issue image with overlapping x axis labels

Example of well spaced, ideal case

Thank you everyone for any help in advance.

  • 1
    It looks like you are plotting strings instead of dates. You can hardly leave out `"Banana"` in between `"Apple"` and `"Cherry"` on the axes. Possibly see [this question](https://stackoverflow.com/questions/44213781/pandas-dataframe-line-plot-display-date-on-xaxis). – ImportanceOfBeingErnest Aug 13 '18 at 18:27
  • maybe this helps https://stackoverflow.com/q/12608788/9754169 – Yuca Aug 13 '18 at 18:48

2 Answers2

0

If there is some overlapping still after rotation maybe if you use plt.tight_layout() it get's better. So try this

plt.xlabel(ylabel)
plt.title(title + '\n' + subtitle)
plt.tight_layout()
plt.savefig(title + ' Normal' +'.png',bbox_inches='tight',format='png',dpi=800)
Yuca
  • 6,010
  • 3
  • 22
  • 42
0

Is the problem that the tick labels are too large? You can adjust the size to something smaller using "labelsize" in set_tick_params

ax.xaxis.set_tick_params(rotation=30, labelsize=3)

from the matplotlib tutorial:

or, this is what I use in my own code:

plt.gca().xaxis.set_tick_params(rotation = 30, labelsize=3)
Heather Claxton
  • 1,001
  • 8
  • 11