2

I am plotting "McDonald's menu" data from kaggle. I plotted nutrients with food items. But, y-tick-labels are very long. How to truncate them so they fit in properly ?

grouped = df.groupby(df["Protein"])
item = grouped["Item"].sum()
item_list = item.sort_index()
item_list = item_list[-20:]
#Sizing the image canvas
plt.figure(figsize=(8,9))
#To plot bargraph
sns.barplot(item_list.index,item_list.values)

The plot that I got

How to correct it and would it improve size of my plot ?

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
vaibhav chawla
  • 103
  • 1
  • 5
  • You have to decide how you want to compress the information. e.g. do you just want to use the last 6 letters in each string? That is easy to do but probably not very informative. – mwaskom Mar 12 '17 at 14:44
  • Is it possible that I can keep last 6-10 letters and when I hover over bars, it shows me both x&y lables for that particular bar ? – vaibhav chawla Mar 13 '17 at 05:28
  • @vaibhavchawla http://stackoverflow.com/questions/7908636/possible-to-make-labels-appear-when-hovering-over-a-point-in-matplotlib – Paul H Mar 13 '17 at 06:20

1 Answers1

4

One idea could be to let the text in the labels roll like a marquee.

enter image description here

import matplotlib.pyplot as plt
import matplotlib.text
import matplotlib.animation

class Roller():
    def __init__(self):
        self.texts = []

    def append(self, text, **kwargs):
        RollingText.assimilate(text,  **kwargs)
        self.texts.append(text)

    def roll(self, i=0):
        for text in self.texts:
            text.roll()

    def ticklabelroll(self, i=0):
        self.roll()
        ticklabels = [t.get_text() for t in self.texts]
        plt.gca().set_yticklabels(ticklabels)



class RollingText(matplotlib.text.Text):
    n = 10
    p = 0
    def __init__(self, *args, **kwargs):
        self.n = kwargs.pop("n", self.n)
        matplotlib.text.Text(*args, **kwargs)
        self.set_myprops()

    def set_myprops(self, **kwargs):
        self.fulltext = kwargs.get("fulltext", self.get_text())
        self.n = kwargs.get("n", self.n)
        if len(self.fulltext) <=self.n:
            self.showntext = self.fulltext
        else:
            self.showntext = self.fulltext[:self.n]
        self.set_text(self.showntext)

    def roll(self, by=1):
        self.p += by
        self.p = self.p % len(self.fulltext)
        if self.p+self.n <= len(self.fulltext):
            self.showntext = self.fulltext[self.p:self.p+self.n]
        else:
            self.showntext = self.fulltext[self.p:] + " " + \
                        self.fulltext[0:(self.p+self.n) % len(self.fulltext)]          
        self.set_text(self.showntext)

    @classmethod
    def assimilate(cls, instance, **kwargs):
        # call RollingText.assimilate(Text, n=10, ...)
        instance.__class__ = cls 
        instance.set_myprops(**kwargs)

if __name__ == "__main__":
    import pandas as pd
    import seaborn as sns

    fn = r"data\nutrition-facts-for-mcdonald-s-menu\menu.csv"
    df = pd.read_csv(fn)

    grouped = df.groupby(df["Protein"])
    item = grouped["Item"].sum()
    item_list = item.sort_index()
    item_list = item_list[-20:]

    fig, ax = plt.subplots(figsize=(10,7.5))
    plt.subplots_adjust(left=0.3)

    sns.barplot(item_list.index,item_list.values, ax=ax)

    # create a Roller instance
    r = Roller()
    # append all ticklabels to the Roller
    for tl in ax.get_yticklabels():
        r.append(tl, n=25) 

    #animate the ticklabels
    ani = matplotlib.animation.FuncAnimation(fig, r.ticklabelroll, 
                            frames=36, repeat=True, interval=300)
    ani.save(__file__+".gif", writer="imagemagick")
    plt.show()
ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712