شخصی‌سازی گردش تصادفی

شکل دادن به گردش

در این بخش نمودارهای خود را شخصی می‌کنیم تا بدون توجه به عناصر گم‌راه‌کننده، بر روی ویژگی‌های مهم هر گردش تاکید کنیم. برای چنین کاری باید ویژگی‌هایی را که مورد تاکید ما هستند، معلوم کنیم، مانند جایی که گردش شروع شده، جایی که پایان یافته و مسیری که پیش گرفته شده. سپس ویژگی‌هایی را که نمی‌خواهیم بر آن‌ها تاکید کنیم تعیین می‌کنیم مانند نشانه‌گذاری‌ها و برچسب‌های محورها. نتیجه باید یک نمایش ساده‌ی بصری باشد که به وضوح مسیری را که در هر گردش تصادفی در پیش گرفته شده به هم متّصل می‌کند.

رنگ‌آمیزی نقطه‌ها

برای نمایش ترتیب نقاط در گردش از نقشه‌های رنگی استفاده می‌کنیم و سپس حاشیه‌ی سیاه هر نقطه را حذف می‌کنیم تا واضح‌تر به نظر بیایند. برای رنگ‌آمیزی نقطه‌ها بر اساس موقعیّت آن‌ها در گردش، لیستی را شامل جایگاه هر نقطه به عنوان نشان‌وند c به متد می‌دهیم. از آن‌جا که نقطه‌ها به ترتیب رسم می‌شوند این لیست تنها شامل اعداد ۰ تا ۴۹۹۹ است، مانند زیر:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
--snip--

while True:
    # Make a random walk.
    rw = RandomWalk()
    rw.fill_walk()

    # Plot the points in the walk.
    plt.style.use('classic')
    fig, ax = plt.subplots()
    point_numbers = range(rw.num_points)
    ax.scatter(rw.x_values, rw.y_values, c=point_numbers, cmap=plt.cm.Blues,
        edgecolors='none', s=15)

    plt.show()

    keep_running = input("Make another walk? (y/n): ")
    --snip--

از range() برای تولید لیستی از اعداد به تعداد نقطه‌های موجود در گردش استفاده می‌کنیم. سپس آن‌ها را در لیست point_numbers ذخیره می‌کنیم که بعداً برای تعیین رنگ هر نقطه به کار خواهد آمد. point_numbers را به نشان‌وند c می‌دهیم، از نقشه‌ی رنگی Blues استفاده می‌کنیم و سپس edgecolors='none' را به تابع می‌دهیم تا از خط سیاه دور هر نقطه خلاص شویم. نتیجه نموداری از گردش است که رنگ آن به صورت تدریجی از آبی روشن به سمت تیره می‌رود، مانند شکل ۱۵-۱۰.

![][image25]

شکل ۱۵-۱۰: یک گردش تصادفی که به نقشه‌ی رنگی Blues رنگ‌آمیزی شده است.

رسم نقاط آغازی و انتهایی

علاوه بر رنگ‌آمیزی نقطه‌ها برای نمایش جایگاه آن‌ها در طول گردش خوب است که شروع و پایان گردش را هم ببینیم. برای چنین کاری می‌توانیم نقطه‌های آغاز و پایان را پس از رسم نمودار دوباره بکشیم. این دو نقطه را بزرگتر و رنگ آن‌ها را متفاوت انتخاب می‌کنیم تا آن‌ها را متمایز کنیم، مانند زیر:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
--snip--

while True:
    --snip--
    ax.scatter(rw.x_values, rw.y_values, c=point_numbers, cmap=plt.cm.Blues,
        edgecolors='none', s=15)

    # Emphasize the first and last points.
    ax.scatter(0, 0, c='green', edgecolors='none', s=100)
    ax.scatter(rw.x_values[-1], rw.y_values[-1], c='red', edgecolors='none',
        s=100)

    plt.show()
    --snip--

برای نمایش نقطه‌ی آغاز، نقطه‌ی (0, 0) را سبزرنگ و در اندازه‌ی بزرگ‌تر از دیگر نقاط (s=100) رسم می‌کنیم. برای مشخّص کردن نقطه‌ی پایانی آخرین مقدار x و y را با اندازه‌ی ۱۰۰ و رنگ قرمز می‌کشیم. مطمئن شوید که این کد را درست پیش از فراخوانی plt.show() بیاورید تا نقطه‌های آغاز و پایان روی دیگر نقطه‌ها رسم شوند.

اگر این کد را اجرا کنید باید قادر باشید محل شروع و پایان گردش را تشخیص دهید. (اگر این دو نقطه به خوبی متمایز نشده‌اند رنگ و اندازه‌ی آن‌ها را تنظیم کنید تا چنین شود.)

پاک‌سازی محورها

محورها را از این نمودار حذف می‌کنیم تا حواس ما را از مسیر هر گردش پرت نکنند. برای پاک کردن محورها از این کد استفاده کنید:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
--snip--

while True:
    --snip--
    ax.scatter(rw.x_values[-1], rw.y_values[-1], c='red', edgecolors='none',
        s=100)

    # Remove the axes.
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)

    plt.show()
    --snip--

برای تغییر دادن محورها از متدهای ax.get_xaxis() و ax.get_yaxis() استفاده می‌کنیم تا قابلیّت دیدن هر کدام را False کنیم. هنگامی که به کار بصری‌سازی ادامه می‌دهید به هم پیوستن متدها را به این شیوه به تناوب خواهید دید.

حال rw_visual.py را اجرا کنید؛ باید دنباله‌ای از نمودارها را بدون محور ببینید.

افزایش نقاط نمودار

بیایید تعداد نقطه‌ها را افزایش دهیم تا داده‌های بیشتری برای کار کردن داشته باشیم. برای این کار مقدار num_points را هنگام ساختن نمونه‌ی RandomWalk افزایش می‌دهیم و اندازه‌ی هر نقطه را هنگام رسم تنظیم می‌کنیم، مانند زیر:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
--snip--

while True:
    # Make a random walk.
    rw = RandomWalk(50_000)
    rw.fill_walk()

    # Plot the points in the walk.
    plt.style.use('classic')
    fig, ax = plt.subplots()
    point_numbers = range(rw.num_points)
    ax.scatter(rw.x_values, rw.y_values, c=point_numbers, cmap=plt.cm.Blues,
        edgecolor='none', s=1)
    --snip--

این مثال گردشی تصادفی با ۵۰،۰۰۰ نقطه می‌سازد تا منعکس‌کننده‌ی داده‌های دنیای واقعی باشد و هر نقطه را با اندازه‌ی s=1 می‌کشد. همان‌طور که در شکل ۱۵-۱۱ می‌بینیم گردش نهایی ابری‌شکل است. چنان‌که می‌بینید که با یک نمودار پراکندگی ساده اثری هنری خلق کرده‌ایم!

این کد را با افزایش تعداد نقاط داخل گردش آزمایش کنید تا زمانی که سرعت سیستم شما به طور محسوسی کاهش یابد یا نمودار جذابیّت بصری خود را از دست بدهد.

![][image26]

شکل ۱۵-۱۱: گردشی با ۵۰،۰۰۰ نقطه

تغییر دادن اندازه برای پر کردن صفحه

اگر یک بصری‌سازی به زیبایی در صفحه جا شود، در ارتباط دادن الگوها در داده‌ها موثرتر خواهد بود. برای این که پنجره‌ی نمودار در صفحه‌ی نمایش شما بهتر جا شود، اندازه‌ی خروجی Matplotlib را مانند زیر تنظیم کنید:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
--snip--

while True:
    # Make a random walk.
    rw = RandomWalk(50_000)
    rw.fill_walk()

    # Plot the points in the walk.
    plt.style.use('classic')
    fig, ax = plt.subplots(figsize=(15, 9))
    --snip--

زمانی که نموداری می‌سازید می‌توانید نشان‌وند figsize را برای تعیین اندازه‌ی شکل به آن بدهید. پارامتر figsize یک چندتایی می‌گیرد که ابعاد پنجره‌ی نمودار را به اینچ به Matplotlib می‌گوید.

Matplotlib فرض می‌کند که وضوح صفحه‌ی شما ۱۰۰ پیکسل بر اینچ است؛ اگر این کد اندازه‌ی دقیقی برای نمودار فراهم نکرد اعداد را تغییر دهید. یا اگر وضوح تصویر سیستم خود را می‌دانید آن را با پارامتر dpi به plt.subplots() بدهید تا اندازه را طوری تعیین کند که از فضای موجود در صفحه نمایش شما به خوبی استفاده کند، مانند زیر:

1
fig, ax = plt.subplots(figsize=(10, 6), dpi=128)

خودآزمایی

۱۵-۳. جنبش مولکولی: برنامه rw_visual.py را تغییر دهید و plt.scatter() را با plt.plot() جایگزین کنید. برای شبیه‌سازی حرکت دانه‌ی گرده روی سطح یک قطره‌ی آب مقادیر rw.x_values و rw.y_values را به تابع بدهید و نشان‌وند linewidth را هم اضافه کنید. به جای ۵۰،۰۰۰ نقطه از ۵۰۰۰ نقطه استفاده کنید.

۱۵-۴. گردش‌های تصادفی تغییریافته: در کلاس RandomWalk، x_step و y_step با مجموعه‌ی مشابهی از شرط‌ها تولید می‌شوند. جهت به طور تصادفی از لیست [1, -1] و مسافت از لیست [0, 1, 2, 3, 4] انتخاب می‌شود. مقدارهای این دو لیست را عوض کنید تا ببینید در شکل کلی گردش‌ها چه تغییری ایجاد می‌شود. لیست طولانی‌تر را برای مسافت امتحان کنید (مثلاً از ۰ تا ۸) و -۱ را از لیست جهت x و y حذف کنید.

۱۵-۵. بازآرایی: متد fill_walk() طولانی است. متد جدیدی به نام get_step() بسازید تا جهت و مسافت هر گام را تعیین کند و سپس گام را محاسبه کند. شما در نهایت باید به دو فراخوانی get_step() در fill_walk() برسید:

1
2
x_step = self.get_step()
y_step = self.get_step()

این بازآرایی باید اندازه‌ی fill_walk() را کاهش داده و خواندن و درک متد را آسان‌تر کند.