11.1 Plotting Using PyLab

11 PLOTTING AND MORE ABOUT CLASSES

Often text is the best way to communicate information, but sometimes there is a lot of truth to the Chinese proverb, 圖片的意義可以表達近萬字. Yet most programs rely on textual output to communicate with their users. Why? Because in many programming languages presenting visual data is too hard. Fortunately, it is simple to do in Python.

11.1 Plotting Using PyLab

PyLab is a Python standard library module that provides many of the facilities of MATLAB, “a high- level technical computing language and interactive environment for algorithm development, data visualization, data analysis, and numeric computation.” Later in the book we will look at some of the more advanced features of PyLab, but in this chapter we focus on some of its facilities for plotting data. Other plotting facilities are introduced in later chapters. A complete user’s guide to the plotting capabilities of PyLab is at the Web site: User’s Guide — Matplotlib 2.0.0 documentation

There are also a number of Web sites that provide excellent tutorials. We will not try to provide a user’s guide or a complete tutorial here. Instead, in this chapter we will merely provide a few example plots and explain the code that generated them. Other examples appear in later chapters.

1.A simple example

(1) Simple

Let’s start with a simple example that uses pylab.plot to produce two plots. Executing:

import pylab
pylab.figure(1)
pylab.plot([1,2,3,4,5],[1,7,3,5,12])
pylab.show()

will cause a window to appear on your computer monitor. Its exact appearance may depend on your Python environment, but it will look similar to Figure 11.1 (which was produced using Anaconda). If you run this code with the default parameter settings of most installations of PyLab, the line will probably not be as thick as the line in Figure 11.1. We have used nonstandard default values for line width and font sizes so that the figures will reproduce better in black and white. We discuss how this is done later in this section.

Figure 11.1 A simple plot

Figure 11.1 A simple plot
Figure 11.1 A simple plot
1. Sequences of the same length

The bar at the top of the plot contains the name of the window, in this case “Figure 1.” The middle section of the window contains the plot generated by the invocation of pylab.plot. The two parameters of pylab.plot must be sequences of the same length. The first specifies the x-coordinates of the points to be plotted, and the second specifies the y-coordinates. Together, they provide a sequence of four <x, y> coordinate pairs,[(1,1), (2,7), (3,3), (4,5)]. These are plotted in order. As each point is plotted, a line is drawn connecting it to the previous point.

2. The problem of pylab.show()

The final line of code, pylab.show(), causes the window to appear on the computer screen. In some Python environments, if that line were not present, the figure would still have been produced, but it would not have been displayed. This is not as silly as it at first sounds, since one might well choose to write a figure directly to a file, as we will do later, rather than display it on the screen.

3. Introduction of the Buttons:

The bar at the top of the window contains a number of push buttons. The rightmost button pops up a window with options that can be used to adjust various aspects of the figure. The next button to the left is used to write the plot to a file. The button to the left of that is used to adjust the appearance of the plot in the window. The next two buttons are used for zooming and panning. The two buttons that look like arrows are used to see previous views (like the forward and backward arrows of a Web browser). And the button on the extreme left is used to restore the figure to its original appearance after you are done playing with other buttons.

(2) The multiple figures

It is possible to produce multiple figures and to write them to files. These files can have any name you like, but they will all have the file extension .png. The file extension .png indicates that the file is in the Portable Networks Graphics format. This is a public domain standard for representing images.

multiple figures

pylab.figure(1) #create figure 1
pylab.plot([1,2,3,4], [1,2,3,4]) #draw on figure 1
pylab.figure(2) #create figure 2
pylab.plot([1,4,2,3], [5,6,7,8]) #draw on figure 2
pylab.savefig('Figure-Addie') #save figure 2
pylab.figure(1) #go back to working on figure 1
pylab.plot([5,6,10,3]) #draw again on figure 1
pylab.savefig('Figure-Jane') #save figure 1

produces and saves to files named Figure-Jane.png and Figure- Addie.png the two plots in Figure 11.2.

1. One argument

Observe that the last call to pylab.plot is passed only one argument. This argument supplies the y values. ==The corresponding x values default to the sequence yielded by range(len([5, 6, 10, 3])), which is why they range from 0 to 3 in this case.

2. “Current figure.”

PyLab has a notion of “current figure.” Executing pylab.figure(x) sets the current figure to the figure numbered x. Subsequently executed calls of plotting functions implicitly refer to that figure until another invocation of pylab.figure occurs. This explains why the figure written to the file Figure-Addie.png was the second figure created.

Figure 11.2 Contents of Figure-Jane.png (left) and Figure- Addie.png (right)

2. Compound interest

(1) Simple

values.append(principal) 這里看到List的神奇之處,如若手工操作熄云,多么的繁瑣涮俄。

******Let’s look at another example. The code:**

principal = 10000 #initial investment
interestRate = 0.05
years = 20
values = []
for i in range(years + 1):
    values.append(principal)
    principal += principal*interestRate
pylab.plot(values)
pylab.savefig('FigurePlottingCompoundGrowth')

produces the plot on the left in Figure 11.3.

(2) informative Titles

If we look at the code, we can deduce that this is a plot showing the growth of an initial investment of $10,000 at an annually compounded interest rate of 5%. However, this cannot be easily inferred by looking only at the plot itself. That’s a bad thing. All plots should have informative titles, and all axes should be labeled. If we add to the end of our code the lines

The xlabel,ylabel,title

pylab.title('5% Growth, Compounded Annually') 
pylab.xlabel('Years of Compounding') 
pylab.ylabel('Value of Principal ($)')

we get the plot on the right in Figure 11.3.

Figure 11.3

Figure 11.3
Figure 11.3

(3) Optional argument

For every plotted curve, there is an optional argument that is a format string indicating the color and line type of the plot. The letters and symbols of the format string are derived from those used in MATLAB, and are composed of a color indicator followed by an optional line-style indicator. The default format string is 'b-', which produces a solid blue line. To plot the the growth in principal with black circles, one would replace the call

pylab.plot(values) by pylab.plot(values, 'ko', )

which produces the plot in Figure 11.4. For a complete list of color and line-style indicators, see

Figure 11.4 Another plot of compound growth

Figure 11.5 Strange-looking plot
Figure 11.5 Strange-looking plot

(4) Change the type size and line width

It is also possible to change the type size and line width used in plots. This can be done using keyword arguments in individual calls to functions. E.g., the code:

principal = 10000 #initial 
investment interestRate = 0.05 
years = 20 
values = [] 
for i in range(years + 1): 
    values.append(principal) 
    principal += principal*interestRate 
pylab.plot(values, linewidth = 30) 
pylab.title('5% Growth, Compounded Annually', fontsize = 'xx-large') pylab.xlabel('Years of Compounding', fontsize = 'x- small') 
pylab.ylabel('Value of Principal ($)')

produces the intentionally bizarre-looking plot in Figure 11.5.

Figure 11.5 Strange-looking plot

Figure 11.5 Strange-looking plot
Figure 11.5 Strange-looking plot

3. Change the default values:“rc settings.”

It is also possible to change the default values, which are known as “rc settings.” (The name “rc” is derived from the .rc file extension used for runtime configuration files in Unix.) These values are stored in a dictionary-like variable that can be accessed via the name pylab.rcParams. So, for example, you can set the default line width to 6 points by executing the code

pylab.rcParams['lines.linewidth'] = 6.

There are an enormous number rcParams settings. A complete list can be found at

Customizing matplotlib — Matplotlib 2.0.0 documentation

If you don’t want to worry about customizing individual parameters,there are pre-defined style sheets. A description of these can be found at

Customizing plots with style sheets — Matplotlib 1.5.3 documentation

The values used in most of the remaining examples in this book were set with the code

#set line width
pylab.rcParams['lines.linewidth'] = 4
#set font size for titles
pylab.rcParams['axes.titlesize'] = 20
#set font size for labels on axes
pylab.rcParams['axes.labelsize'] = 20
#set size of numbers on x-axis
pylab.rcParams['xtick.labelsize'] = 16
#set size of numbers on y-axis
pylab.rcParams['ytick.labelsize'] = 16 
#set size of ticks on x-axis
pylab.rcParams['xtick.major.size'] = 7
#set size of ticks on y-axis
pylab.rcParams['ytick.major.size'] = 7
#set size of markers, e.g., circles representing points
pylab.rcParams['lines.markersize'] = 10
#set number of times marker is shown when displaying legend
pylab.rcParams['legend.numpoints'] = 1

If you are viewing plots on a color display, you will have little reason to customize these settings. We customized the settings we used so that it would be easier to read the plots when we shrank them and converted them to black and white.

11.2 Plotting Mortgages, an Extended Example

In Chapter 8, we worked our way through a hierarchy of mortgages as way of illustrating the use of subclassing. We concluded that chapter by observing that “our program should be producing plots designed to show how the mortgage behaves over time.” Figure 11.6 enhances class Mortgage by adding methods that make it convenient to produce such plots. (The function findPayment, which appears in Figure 8.9, is discussed in Section 8.4.)

Figure 11.6 Class Mortgage with plotting methods

print('class Mortgage')

class Mortgage(object):
    """Abstract class for building different kinds of mortgages"""

    def __init__(self, loan, annRate, months):
        """Create a new mortgage"""
        self.loan = loan
        self.rate = annRate/12.0
        self.months = months
        self.paid = [0.0]
        self.outstanding = [loan]
        self.payment = findPayment(loan, self.rate, months)
        self.legend = None #description of mortgage

    def makePayment(self):
        """Make a payment"""
        self.paid.append(self.payment)
        reduction = self.payment - self.outstanding[-1]*self.rate
        self.outstanding.append(self.outstanding[-1] - reduction)

    def getTotalPaid(self):
        """Return the total amount paid so far"""
        return sum(self.paid)

    def __str__(self):
        return self.legend

    def plotPayments(self, style):
        pylab.plot(self.paid[1:], style, label = self.legend)

    def plotBalance(self, style):
        pylab.plot(self.outstanding, style, label = self.legend)

    def plotTotPd(self, style):
        """Plot the cumulative total of the payments made"""
        totPd = [self.paid[0]]
        for i in range(1, len(self.paid)):
            totPd.append(totPd[-1] + self.paid[i])
        pylab.plot(totPd, style, label = self.legend)

    def plotNet(self, style):
        """Plot an approximation to the total cost of the mortgage over time by plotting the cash expended minus the equity acquired by paying off part of the loan"""
        totPd = [self.paid[0]]
        for i in range(1, len(self.paid)):
            totPd.append(totPd[-1] + self.paid[i])
            #Equity acquired through payments is amount of original loan
            #paid to date, which is amount of loan minus what is still outstanding
            equityAcquired = pylab.array([self.loan]*len(self.outstanding))
            equityAcquired = equityAcquired - pylab.array(self.outstanding)
            net = pylab.array(totPd) - equityAcquired
            pylab.plot(net, style, label = self.legend)

The nontrivial methods in class Mortgage are plotTotPd and plotNet. The method plotTotPd simply plots the cumulative total of the payments made. The method plotNet plots an approximation to the total cost of the mortgage over time by plotting the cash expended minus the equity acquired by paying off part of the loan.

The expression pylab.array(self.outstanding) in the function plotNet performs a type conversion. Thus far, we have been calling the plotting functions of PyLab with arguments of type list. Under the covers, PyLab has been converting these lists to a different type, array, which PyLab inherits from numpy. The invocation pylab.array makes this explicit. There are a number of convenient ways to manipulate arrays that are not readily available for lists. In particular, expressions can be formed using arrays and arithmetic operators. There are a number of ways to create arrays in PyLab, but the most common way is to first create a list, and then convert it. Consider the code:

a1 = pylab.array([1, 2, 4]) 
print('a1 =', a1) 
a2 = a1*2 
print('a2 =', a2) 
print('a1 + 3 =', a1 + 3) 
print('3 - a1 =', 3 - a1) 
print('a1 - a2 =', a1 - a2) 
print('a1*a2 =', a1*a2)

The expression a1*2 multiplies each element of a1 by the constant 2. The expression a1 + 3 adds the integer3 to each element of a1. The expression a1 - a2 subtracts each element of a2from the corresponding element of a1 (if the arrays had been of different length, an error would have occurred). The expression a1*a2 multiplies each element of a1 by the corresponding element of a2. When the above code is run it prints:

a1 = [1 2 4] 
a2 = [2 4 8] 
a1 + 3 = [4 5 7] 
3 - a1 = [ 2 1 -1] 
a1 - a2 = [-1 -2 -4] 
a1*a2 = [ 2 8 32]

Figure 11.7 repeats the three subclasses of Mortgage from Figure 8.10. Each has a distinct __init__method that overrides the__init__ method in Mortgage. The subclass TwoRate also overrides the makePayment method of Mortgage.

Figure 11.7 Subclasses of Mortgage

class Fixed(Mortgage):
    def __init__(self, loan, r, months):
        Mortgage.__init__(self, loan, r, months)
        self.legend = 'Fixed, ' + str(r*100) + '%'

class FixedWithPts(Mortgage):
    def __init__(self, loan, r, months, pts):
        Mortgage.__init__(self, loan, r, months)
        self.pts = pts
        self.paid = [loan*(pts/100.0)]
        self.legend = 'Fixed, ' + str(r*100) + '%, '+ str(pts) + ' points'

class TwoRate(Mortgage):
    def __init__(self, loan, r, months, teaserRate, teaserMonths):
         Mortgage.__init__(self, loan, teaserRate, months)
         self.teaserMonths = teaserMonths
         self.teaserRate = teaserRate
         self.nextRate = r/12.0
         self.legend = str(teaserRate*100)\
                        + '% for ' + str(self.teaserMonths)\
                        + ' months, then ' + str(r*100) + '%'

def makePayment(self):
    if len(self.paid) == self.teaserMonths + 1:
        self.rate = self.nextRate
        self.payment = findPayment(self.outstanding[-1], self.rate,
                                    self.months - self.teaserMonths)
    Mortgage.makePayment(self)

Figure 11.8 and Figure 11.9 contain functions that can be used to generate plots intended to provide insight about the different kinds of mortgages.

The function compareMortgages, Figure 11.8, creates a list of different kinds of mortgages, and simulates making a series of payments on each, as it did in Figure 8.11. It then calls plotMortgages, Figure 11.9, to produce the plots.

Figure 11.8 Compare mortgages

print('compareMortgages-Figure 11.8 Compare mortgages')
def compareMortgages(amt, years, fixedRate, pts, ptsRate,
                    varRate1, varRate2, varMonths):
    totMonths = years*12
    fixed1 = Fixed(amt, fixedRate, totMonths)
    fixed2 = FixedWithPts(amt, ptsRate, totMonths, pts)
    twoRate = TwoRate(amt, varRate2, totMonths, varRate1, varMonths)
    morts = [fixed1, fixed2, twoRate]
    for m in range(totMonths):
        for mort in morts:
            mort.makePayment()
    plotMortgages(morts, amt)

The function plotMortgages in Figure 11.9 uses the plotting methods in Mortgage to produce plots containing information about each of three kinds of mortgages. The loop in plotMortgages uses the index i to select elements from the lists morts and styles in a way that ensures that different kinds of mortgages are represented in a consistent way across figures. For example, since the third element in morts is a variable-rate mortgage and the third element in styles is 'k:', the variable-rate mortgage is always plotted using a black dotted line. The local function labelPlot is used to generate appropriate titles and axis labels for each plot. The calls of pylab.figure ensure that titles and labels are associated with the appropriate plot.

The call:

compareMortgages(amt=200000, years=30, 
                 fixedRate=0.07, pts = 3.25, 
                 ptsRate=0.05, varRate1=0.045, 
                 varRate2=0.095, varMonths=48)

produces plots (Figure 11.10 - Figure 11.12) that shed some light on the mortgages discussed in Section 8.4.

Figure 11.9 Generate mortgage plots

def plotMortgages(morts, amt):
    def labelPlot(figure, title, xLabel, yLabel):
        pylab.figure(figure)
        pylab.title(title)
        pylab.xlabel(xLabel)
        pylab.ylabel(yLabel)
        pylab.legend(loc = 'best')
    styles = ['k-','k-', 'k:']
    #Give names to figure numbers
    payments, cost, balance, netCost = 0, 1, 2, 3
    for i in range(len(morts)):
        pylab.figure(payments)
        morts[i].plotPayments(styles[i])
        pylab.figure(cost)
        morts[i].plotTotPd(styles[i])
        pylab.figure(balance)
        morts[i].plotBalance(styles[i])
        pylab.figure(netCost)
        morts[i].plotNet(styles[i])
        pylab.figure(payments)
    labelPlot(payments, 'Monthly Payments of $' + str(amt) +
                ' Mortgages', 'Months', 'Monthly Payments')
    labelPlot(cost, 'Cash Outlay of $' + str(amt) +
                ' Mortgages', 'Months','Total Payments')
    labelPlot(balance, 'Balance Remaining of $' + str(amt) +
                'Mortgages', 'Months', 'Remaining Loan Balance of $')
    labelPlot(netCost, 'Net Cost of $' + str(amt) + ' Mortgages',
              'Months', 'Payments - Equity $')

The plot in Figure 11.10, which was produced by invocations of plotPayments, simply plots each payment of each mortgage against time. The box containing the key appears where it does because of the value supplied to the keyword argument loc used in the call to pylab.legend. When loc is bound to 'best' the location is chosen automatically. This plot makes it clear how the monthly payments vary (or don’t) over time, but doesn’t shed much light on the relative costs of each kind of mortgage.

Figure 11.10 Monthly payments of different kinds of mortgages

運行報錯:

Traceback (most recent call last):
  File "11.PlottingAndMoreAboutClasses.py", line 237, in <module>
    compareMortgages(amt=200000, years=30, fixedRate=0.07, pts=3.25, ptsRate=0.05, varRate1=0.045, varRate2=0.095, varMonths=48)
  File "11.PlottingAndMoreAboutClasses.py", line 199, in compareMortgages
    plotMortgages(morts, amt)
  File "11.PlottingAndMoreAboutClasses.py", line 220, in plotMortgages
    morts[i].plotNet(styles[i])
  File "11.PlottingAndMoreAboutClasses.py", line 145, in plotNet
    net = pylab.array(totPd) - equityAcquired
ValueError: operands could not be broadcast together with shapes (2,) (361,) 
Gaowei:F3.MIT_Python Gaowei$ 

The plots in Figure 11.11 were produced by invocations of plotTotPd. They shed some light on the cost of each kind of mortgage by plotting the cumulative costs that have been incurred at the start of each month. The entire plot is on the left, and an enlargement of the left part of the plot is on the right.

Figure 11.11 Cost over time of different kinds of mortgages

沒有運行

The plots in Figure 11.12 show the remaining debt (on the left) and the total net cost of having the mortgage (on the right).

Figure 11.12 Balance remaining and net cost for different kinds of mortgages

沒有運行

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末握巢,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌剩辟,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異抹沪,居然都是意外死亡刻肄,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門融欧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來敏弃,“玉大人,你說我怎么就攤上這事噪馏÷蟮剑” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵欠肾,是天一觀的道長瓶颠。 經(jīng)常有香客問我,道長刺桃,這世上最難降的妖魔是什么粹淋? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮瑟慈,結(jié)果婚禮上桃移,老公的妹妹穿的比我還像新娘。我一直安慰自己葛碧,他們只是感情好借杰,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著进泼,像睡著了一般蔗衡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上乳绕,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天绞惦,我揣著相機與錄音,去河邊找鬼刷袍。 笑死翩隧,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的呻纹。 我是一名探鬼主播堆生,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼雷酪!你這毒婦竟也來了淑仆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤哥力,失蹤者是張志新(化名)和其女友劉穎蔗怠,沒想到半個月后墩弯,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡寞射,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年渔工,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片桥温。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡引矩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出侵浸,到底是詐尸還是另有隱情旺韭,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布掏觉,位于F島的核電站区端,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏澳腹。R本人自食惡果不足惜织盼,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望酱塔。 院中可真熱鬧悔政,春花似錦、人聲如沸延旧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽迁沫。三九已至,卻和暖如春捌蚊,著一層夾襖步出監(jiān)牢的瞬間集畅,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工缅糟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留挺智,地道東北人。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓窗宦,卻偏偏與公主長得像赦颇,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子赴涵,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 偶爾見一頂羽毛 輕輕落下 劃過天空 那身影 輕盈迷人 長吹一口氣 能打幾個滾 順著風兒 漫步而去 竟忘了從哪兒來
    青云無言閱讀 186評論 2 1
  • 淡泊之守媒怯,須從秾艷場中試來;鎮(zhèn)定之操髓窜,還向紛紜境上勘過扇苞。 ——《小窗幽記?醒》 淡泊清...
    朵娘說閱讀 224評論 0 1
  • 光谷藍燈分社第一期沙盤互助團體從10月18日至今欺殿,已經(jīng)成功走過兩次初體驗的遴選,并深度走過五輪鳖敷,下周最后一輪總結(jié)后...
    子霞_e0db閱讀 802評論 0 0
  • 很早之前注冊了簡書脖苏,由于工作原因,一直沒有寫過文章定踱,現(xiàn)在項目提測棍潘,每天等測試提提bug,分配分配任務(wù)屋吨。時間稍微充裕...
    FortunateStone閱讀 223評論 2 3
  • 早上的陽光伴著些許的清涼至扰,特別勾人憶往鳍徽。清風撲來,腦海里都是小時候奶奶帶著我去買涼鞋的情景敢课。 我記事很晚阶祭,現(xiàn)在的好...
    一只清新脫俗的蚊子閱讀 233評論 0 1