1 - نصب Matplotlib و رسم نمودار خطّی

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

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

خوشبختانه برای بصری کردن داده‌های پیچیده نیازی به ابررایانه ندارید. به لطف بازدهی پایتون شما می‌توانید مجموعه‌های داده‌ای شامل میلیون‌ها داده‌ی مجزّا را تنها با یک لپ‌تاپ بکاوید. علاوه بر این لازم نیست حتماً نقاط داده عدد باشند. با مقدّماتی که در بخش اول این کتاب آموخته‌اید می‌توانید داده‌های غیر عددی را نیز تحلیل کنید.

مردم از پایتون برای کارهایی با فشردگیِ بالای داده125 124 استفاده می‌کنند، مانند ژنتیک، پژو‌هش‌های اقلیمی، تحلیل‌های سیاسی و اقتصادی و بسیاری دیگر. دانشمندان علوم داده مجموعه‌ی چشمگیری از ابزارها را برای بصری‌سازی و تحلیل در پایتون نوشته‌اند که بسیاری از آن‌ها در دسترس شما نیز هستند. یکی از محبوب‌ترین ابزارها کتابخانه‌ای برای کشیدن نمودارهای ریاضی به نام Matplotlib است. از این کتابخانه برای ساختن نمودارهای ساده مانند نمودار خطّی و پراکندگی استفاده می‌کنیم. سپس مجموعه‌ی داده‌ی جالب‌تری بر پایه‌ی مفهوم گردش تصادفی خواهیم ساخت— بصری‌سازی‌ای تولیدشده بر اساس مجموعه‌ای از تصمیم‌های تصادفی.

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

نصب Matplotlib

برای استفاده از Matplotlib در اوّلین مجموعه از بصری‌سازی‌های خود باید آن را به کمک pip نصب کنید. pip ماژولی برای دریافت و نصب بسته‌های پایتون است. فرمان زیر را در یک اعلان ترمینال وارد کنید:

1
$ python -m pip install --user matplotlib

این فرمان از پایتون می‌خواهد تا ماژول pip را اجرا کرده و بسته‌ی matplotlib را به مجموعه‌ی پایتون نصب‌شده برای کاربر فعلی اضافه کند. اگر شما در سیستم خود از فرمان دیگری به جز python، مانند python3، برای اجرای برنامه‌ها یا آغاز یک نشست ترمینال استفاده می‌کنید، دستور شما به شکل زیر خواهد بود:

1
$ python3 -m pip install --user matplotlib
نکته
این فرمان در macOS کار نمی‌کند، به جای آن همین فرمان را بدون پرچم --user امتحان کنید.

برای بررسی انواع بصری‌سازی قابل ایجاد با Matplotlib سری به گالری نمونه‌های آن در https://matplotlib.org/gallery/ بزنید. اگر روی هر کدام از بصری‌سازی‌های موجود در گالری کلیک کنید کدی که آن را ایجاد کرده خواهید دید.

رسم یک نمودار خطّی ساده

بیایید به کمک Matplotlib یک نمودار خطّی ساده رسم کنیم و سپس آن را برای ساختن یک بصری‌سازی داده‌ی گویاتر شخصی‌سازی کنیم. از یک دنباله‌ی اعداد مربّع ۱، ۴، ۹، ۱۶ و ۲۵ به عنوان داده‌ی این نمودار استفاده می‌کنیم.

کافی است اعداد را به Matplotlib بدهید، چنان‌که اینجا می‌بینید و Matplotlib باقی کارها را برای شما خواهد کرد:

1
2
3
4
5
6
import matplotlib.pyplot as plt

squares = [1, 4, 9, 16, 25]
fig, ax = plt.subplots()
ax.plot(squares)
plt.show()

ابتدا ماژول pyplot را با نام مستعار plt وارد می‌کنیم تا مجبور نباشیم هر دفعه pyplot را بنویسیم. (این نامگذاری را به صورت یک قرارداد در مثال‌های آنلاین خواهید دید بنابراین ما هم از همین استفاده می‌کنیم.) ماژول پای‌پلات شامل تعدادی تابع برای تولید نمودار است.

لیستی به نام squares می‌سازیم تا داده‌ها را برای رسم ذخیره کند. سپس با فراخوانی تابع subplots() از یکی دیگر از قراردادهای Matplotlib پیروی می‌کنیم. این تابع یکی تا چند نمودار را در یک شکل واحد رسم می‌کند. متغیّر fig بیانگر شکل کلّی یا همان مجموعه‌ی نمودارهایی است که تولید می‌شوند. متغیّر ax یکی از نمودارهای داخل شکل را نشان می‌دهد و متغیّری است که بیشتر اوقات از آن استفاده می‌کنیم.

سپس از متد plot() بهره می‌گیریم که تلاش می‌کند داده‌ی ورودی را به روشی معنادار رسم کند. تابع plt.show() نمایشگر Matplotlib را باز می‌کند و نمودار را نشان می‌دهد، چنانکه در شکل ۱۵-۱ می‌بینیم. نمایشگر به شما امکان بزرگنمایی و پیمایش نمودار را می‌دهد و اگر روی آیکون ذخیره کلید کنید می‌توانید هر نموداری را که خواستید ذخیره کنید.

![][image16]

شکل ۱۵-۱: یکی از ساده‌ترین نمودارهایی که می‌توانید با Matplotlib تولید کنید.

تغییر دادن نوشته‌ی برچسب و ضخامت خط

هرچند نمودار شکل ۱۵-۱ افزایشی بودن اعداد را نشان می‌دهد امّا نوشته‌ی روی محورها کوچک و خط رسم‌شده کمی نازک است که باعث خوانایی پایین می‌شود. خوشبختانه Matplotlib به شما امکان می‌دهد که تمام ویژگی‌های یک بصری‌سازی را تغییر دهید.

ما تعداد کمی از تغییرات ممکن را اعمال می‌کنیم تا خوانایی نمودار را افزایش دهیم:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import matplotlib.pyplot as plt

squares = [1, 4, 9, 16, 25]
fig, ax = plt.subplots()
ax.plot(squares, linewidth=3)

# Set chart title and label axes.
ax.set_title("Square Numbers", fontsize=24)
ax.set_xlabel("Value", fontsize=14)
ax.set_ylabel("Square of Value", fontsize=14)

# Set size of tick labels.
ax.tick_params(axis='both', labelsize=14)

plt.show()

پارامتر linewidth ضخامت خطی را تنظیم می‌کند که plot() تولید می‌کند. متد set_title() عنوانی برای نمودار تعیین می‌کند. پارامترهای fontsize که چند بار در کد تکرار شده‌اند اندازه‌ی متن را در اجزای مختلف نمودار تغییر می‌دهد.

متدهای set_xlabel() و set_ylabel() به شما امکان می‌دهند که برای هر محور عنوانی تعیین کنید و متد tick_params() نشانه‌گذاری‌های روی محور را شکل می‌دهد. نشان‌وندهایی که اینجا آمده بر روی هر دو محور تاثیر می‌گذارد (axis='both') و اندازه‌ی برچسب این نشانه‌گذاری‌ها را ۱۴ قرار می‌دهد (labelsize=14).

چنانکه در شکل ۱۵-۲ می‌بینید خواندن نمودار حاصل بسیار راحت‌تر شده است. نوشته‌ی برچسب‌ها بزرگتر و خط نمودار ضخیم‌تر شده است. اغلب می‌ارزد که با این مقدارها بازی کنید تا به ایده‌ای کلّی درباره‌ی بهتر به نظر رسیدن نمودار نهایی برسید.

![][image17]

شکل ۱۵-۲: اکنون خواندن نمودار بسیار راحت‌تر است.

اصلاح نمودار

حال که می‌توانیم نمودار را بهتر بخوانیم می‌بینیم که داده به درستی رسم نشده است. به انتهای نمودار توجّه کنید که مربّع 4.0، 25 نشان داده شده است! بیایید این مشکل را رفع کنیم.

زمانی که به plot() دنباله‌ای از اعداد می‌دهیم، فرض می‌کند که اوّلین داده متناظر با مقدار 0 در محور x است امّا اوّلین داده‌ی ما مربوط به مقدار ۱ در این محور است. می‌توانیم این رفتار پیش‌فرض را با دادن مقدارهای ورودی و خروجی به‌کاررفته برای محاسبه‌ی مربّعات به این متد تغییر دهیم:

1
2
3
4
5
6
7
8
9
import matplotlib.pyplot as plt

input_values = [1, 2, 3, 4, 5]
squares = [1, 4, 9, 16, 25]
fig, ax = plt.subplots()
ax.plot(input_values, squares, linewidth=3)

# Set chart title and label axes.
--snip--

اکنون plot() داده‌ها را درست رسم می‌کند زیرا مقدارهای ورودی و خروجی را به آن داده‌ایم و دیگر در مورد روش تولید خروجی‌ها فرضی نمی‌کند. نمودار حاصل که در شکل ۱۵-۳ نشان داده شده درست است.

![][image18]

شکل ۱۵-۳: اکنون داده‌ها به درستی رسم شده‌اند.

هنگام استفاده از plot() می‌توانید نشان‌وندهای متعدّدی را تعیین کنید و از تعداد زیادی تابع برای شخصی‌سازی نمودارهای خود بهره بگیرید. این تابع‌های شخصی‌سازی را هنگام کار کردن با مجموعه‌داده‌های جذّاب‌تر در طول فصل بیشتر بررسی خواهیم کرد.

به‌کارگیری شیوه‌های پیش‌ساخته

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

1
2
3
4
>>> import matplotlib.pyplot as plt
>>> plt.style.available
['seaborn-dark', 'seaborn-darkgrid', 'seaborn-ticks', 'fivethirtyeight',
--snip--

برای به‌کارگیری هرکدام از این‌ها یک خط کد را پیش از آغاز ایجاد نمودار اضافه کنید:

1
2
3
4
5
6
7
import matplotlib.pyplot as plt

input_values = [1, 2, 3, 4, 5]
squares = [1, 4, 9, 16, 25]
plt.style.use('seaborn')
fig, ax = plt.subplots()
--snip--

این کد نموداری می‌کشد که در شکل ۱۵-۴ نشان داده شده است. گستره‌ی بزرگی از این شیوه‌های شکل‌دهی وجود دارد؛ با آن‌ها سر و کله بزنید تا چیزی مناسب سلیقه‌ی خود پیدا کنید.

![][image19]

شکل ۱۵-۴: شیوه‌ی شکل‌دهی پیش‌ساخته‌ی seaborn

2 - رسم نقاط با scatter() و ذخیره‌سازی نمودارها

رسم و شکل‌دهی نقاط مجزّا با scatter()

گاهی رسم و شکل دادن به نقطه‌های مجزّا که مبنای آن‌ها خصوصیّات مشترکی است، سودمند است. برای مثال شاید بخواهید مقدارهای کوچک را با یک رنگ و مقدارهای بزرگ را با رنگی دیگر رسم کنید. همچنین می‌توانید مجموعه‌ی بزرگی از داده‌ها را به شکل و شیوه‌ی خاصّی رسم کنید و سپس برای تاکید بیشتر برای نقطه‌های مجزّا و خاصّی، این نقطه‌ها را مجدّداً با تنظیمات دیگری رسم کنید.

برای رسم یک نقطه از متد scatter() استفاده کنید. مقدارهای (x, y) نقطه‌ی مورد نظر خود را به این متد بدهید تا آن را رسم کند:

1
2
3
4
5
6
import matplotlib.pyplot as plt

plt.style.use('seaborn')
fig, ax = plt.subplots()
ax.scatter(2, 4)
plt.show()

بیایید شکل و سیاق خروجی را تغییر دهیم تا جالب‌تر به نظر بیاید. یک عنوان و برچسب محورها را اضافه می‌کنیم و اطمینان حاصل می‌کنیم که نوشته‌ها به اندازه‌ی کافی بزرگ هستند تا راحت خوانده شوند:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import matplotlib.pyplot as plt

plt.style.use('seaborn')
fig, ax = plt.subplots()
ax.scatter(2, 4, s=200)

# Set chart title and label axes.
ax.set_title("Square Numbers", fontsize=24)
ax.set_xlabel("Value", fontsize=14)
ax.set_ylabel("Square of Value", fontsize=14)

# Set size of tick labels.
ax.tick_params(axis='both', which='major', labelsize=14)

plt.show()

در اینجا scatter() را فرامی‌خوانیم و از نشان‌وند s برای تنظیم اندازه‌ی نقطه‌های به‌کاررفته برای رسم نمودار استفاده می‌کنیم. اگر اکنون scatter_squares.py را اجرا کنید باید نقطه‌ای تنها در وسط نمودار ببینید، مانند شکل ۱۵-۵.

![][image20]

شکل ۱۵-۵: رسم یک نقطه‌ی تنها

رسم مجموعه‌ای از نقاط با scatter()

برای رسم مجموعه‌ای از نقطه‌ها می‌توانیم لیستی جداگانه از مقدارهای x و y به آن بدهیم:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import matplotlib.pyplot as plt

x_values = [1, 2, 3, 4, 5]
y_values = [1, 4, 9, 16, 25]

plt.style.use('seaborn')
fig, ax = plt.subplots()
ax.scatter(x_values, y_values, s=100)

# Set chart title and label axes.
--snip--

لیست x_values شامل اعدادی است که باید مربّع شوند و y_values شامل مربّع هر عدد است. زمانی که این دو لیست را به scatter() می‌دهید، Matplotlib هنگام رسم هر نقطه از هر کدام یک مقدار را می‌خواند. نقطه‌هایی که باید رسم شوند (1,1)، (2,4)، (3,9)، (4, 16) و (5, 25) است. شکل ۱۵-۶ نتیجه را نشان می‌دهد.

![][image21]

شکل ۱۵-۶: نمودار پراکندگی با چند نقطه

محاسبه‌ی خودکار داده‌ها

نوشتن دستی لیست‌ها کارآمد نیست به ویژه زمانی که با داده‌های بسیار زیادی سر و کار داریم. به جای انتقال نقطه‌ها به شکل لیست، از یک حلقه استفاده می‌کنیم تا پایتون محاسبات را برای ما انجام دهد.

اینجا این روش را با وجود ۱۰۰۰ نقطه می‌بینیم:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import matplotlib.pyplot as plt

x_values = range(1, 1001)
y_values = [x**2 for x in x_values]

plt.style.use('seaborn')
fig, ax = plt.subplots()
ax.scatter(x_values, y_values, s=10)

# Set chart title and label axes.
--snip--

# Set the range for each axis.
ax.axis([0, 1100, 0, 1100000])

plt.show()

از گستره‌ی مقدارهای x شامل اعداد ۱ تا ۱۰۰۰ شروع می‌کنیم. سپس به کمک روش دربرداری (for x in x_values) در مقدارهای x حلقه می‌زنیم، هر کدام را به توان ۲ می‌رسانیم (x**2) و نتیجه‌ها را در y_values ذخیره می‌کنیم. سپس لیست‌های ورودی و خروجی را به scatter() می‌دهیم. چون تعداد داده‌ها در این مجموعه زیاد است اندازه‌ی نقطه‌ها را کوچک‌تر می‌کنیم.

از متد axis() برای تعیین گستره‌ی هر محور استفاده می‌کنیم. این متد ۴ مقدار می‌پذیرد: کمینه و بیشینه‌ی مقدارهای محور x و y. اینجا محور x را بین ۰ و ۱۱۰۰ و محور y را بین ۰ و ۱،۱۰۰،۰۰۰ قرار می‌دهیم. شکل ۱۵-۷ نتیجه را نشان می‌دهد.

![][image22]

شکل ۱۵-۷: پایتون ۱۰۰۰ نقطه را به همان آسانی ۵ نقطه رسم می‌کند.

تعریف کردن رنگ‌های دلخواه

برای تغییر رنگ نقطه‌ها c را به همراه نام رنگ در علامت نقل قول به scatter() بدهید، مانند زیر:

1
ax.scatter(x_values, y_values, c='red', s=10)

علاوه بر این می‌توانید رنگ‌های دلخواه را به کمک مدل رنگی RGB هم تعیین کنید. برای این کار نشان‌وند c را به همراه یک چندتایی شامل سه مقدار اعشاری بین ۰ و ۱ (به ترتیب برای رنگ قرمز، سبز و آبی) وارد کنید. برای مثال خطّ زیر نموداری با نقطه‌های سبز کم‌رنگ ایجاد می‌کند:

1
ax.scatter(x_values, y_values, c=(0, 0.8, 0), s=10)

مقدارهای نزدیک‌تر به ۰ رنگ‌های تیره و مقدارهای نزدیک‌تر به ۱ رنگ‌های روشن‌تر تولید می‌کنند.

استفاده از نقشه‌ی رنگی

نقشه‌ی رنگی دنباله‌ای از رنگ‌های محوشونده است که126 از یک رنگ آغاز به رنگی ختم می‌شوند. کاربرد نقشه‌های رنگی در بصری‌سازی پررنگ کردن الگویی در داده‌هاست. برای مثال می‌توانید مقدارهای کم را با رنگ روشن و مقادیر زیاد را با رنگی تیره نمایش دهید.

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

1
2
3
4
5
6
7
8
9
import matplotlib.pyplot as plt

x_values = range(1, 1001)
y_values = [x**2 for x in x_values]

ax.scatter(x_values, y_values, c=y_values, cmap=plt.cm.Blues, s=10)

# Set chart title and label axes.
--snip--

لیستی از مقدارهای y را به c نسبت می‌دهیم و سپس با نشان‌وند cmap به pyplot می‌گوییم که از کدام نقشه‌ی رنگی استفاده کند. این کد نقاطی را که مقدار y آن‌ها کمتر است با آبی روشن و آن‌هایی را که مقدار y بیشتری دارند با آبی تیره رنگ‌آمیزی می‌کند.

نکته
می‌توانید تمام نقشه‌های رنگی موجود در pyplot را در آدرس https://matplotlib.org ببینید؛ به قسمت Examples بروید، پایین بروید تا به Colors برسید و روی Colormap reference کلیک کنید.

![][image23]

شکل ۱۵-۸: نموداری با نقشه‌ی رنگی Blues

ذخیره‌سازی خودکار نمودارها

اگر بخواهید که برنامه‌تان نمودار را به طور خودکار در فایلی ذخیره کند، می‌توانید فراخوانی plt.show() را با plt.savefig() جایگزین کنید:

1
plt.savefig('squares_plot.png', bbox_inches='tight')

نشان‌وند نخست نام فایلی است که برای تصویر نمودار انتخاب می‌کنید. این فایل در همان پوشه‌ی scatter_squares.py ذخیره خواهد شد. نشان‌وند دوم فاصله‌های خالی اضافی اطراف نمودار را حذف می‌کند. اگر می‌خواهید این فضای خالی باقی بماند کافی‌است این نشان‌وند را حذف کنید.

خودآزمایی

۱۵-۱. عددهای مکعب‌: توان سوم هر عدد را مکعّب آن می‌خوانند. ابتدا نمودار ۵ عدد مکعّب نخست را بکشید سپس این کار را برای ۵۰۰۰ عدد مکعّب نخست تکرار کنید.

۱۵-۲. اعداد مکعّب رنگی: یک نقشه‌ی رنگی روی نمودار اعداد مکعّب اعمال کنید.

3 - گردش تصادفی

در این بخش از پایتون برای تولید داده برای گردش ت127 صادفی استفاده می‌کنیم و سپس به کمک Matplotlib نمایش بصری جذّابی از این داده‌ها می‌سازیم. گردش تصادفی مسیری است که هیچ جهت مشخّصی ندارد امّا بر اساس دنباله‌ای از تصمیم‌های تصادفی تعیین می‌شود که هر کدام از تصمیم‌ها کاملاً تصادفی گرفته می‌شوند. شما می‌توانید گردش تصادفی را مانند حرکت مورچه‌ای سرگردان در نظر بگیرید که هر قدم خود را در جهتی تصادفی برمی‌دارد.

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

ساختن کلاس RandomWalk()

برای ایجاد یک گردش تصادفی کلاس RandomWalk را ایجاد می‌کنیم که در مورد جهت حرکتی که باید انجام بگیرد تصمیم‌های تصادفی می‌گیرد. کلاس سه مشخّصه نیاز دارد: یک متغیّر برای ذخیره کردن تعداد نقطه‌ها در گردش و دو لیست برای ذخیره کردن مقدار مختصّات x و y هر نقطه‌ی حرکت.

تنها دو متد در کلاس RandomWalk مورد نیاز است: __init__() و fill_walk() که نقطه‌های حرکت را محاسبه می‌کند. از متد __init__() شروع می‌کنیم:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from random import choice

class RandomWalk:
    """A class to generate random walks."""

    def __init__(self, num_points=5000):
        """Initialize attributes of a walk."""
        self.num_points = num_points

        # All walks start at (0, 0).
        self.x_values = [0]
        self.y_values = [0]

برای گرفتن تصمیم‌های تصادفی حرکت‌های ممکن را در لیستی ذخیره می‌کنیم و سپس از تابع choice() از ماژول random استفاده می‌کنیم تا تصمیم بگیریم که در هر گام کدام حرکت را انجام دهیم. سپس تعداد پیش‌فرض نقطه‌ها را در یک گردش ۵۰۰۰ قرار می‌دهیم که برای تولید چند الگوی جالب کافی است و در عین حال برای تولید سریع گردش‌ها به اندازه‌ی کافی کوچک است. سپس دو لیست برای مقدارهای x و y می‌سازیم و شروع هر گردش را نقطه‌ی (0, 0) قرار می‌دهیم.

انتخاب جهت

مانند آن‌چه در ادامه می‌آید، از متد fill_walk() برای پر کردن مسیر گردش خود از نقطه‌ها استفاده و در هر گام جهت حرکت را تعیین می‌کنیم. این متد را به random_walk.py اضافه کنید:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def fill_walk(self):
    """Calculate all the points in the walk."""
    # Keep taking steps until the walk reaches the desired length.
    while len(self.x_values) < self.num_points:
        # Decide which direction to go and how far to go in that direction.
        x_direction = choice([1, -1])
        x_distance = choice([0, 1, 2, 3, 4])
        x_step = x_direction * x_distance

        y_direction = choice([1, -1])
        y_distance = choice([0, 1, 2, 3, 4])
        y_step = y_direction * y_distance

        # Reject moves that go nowhere.
        if x_step == 0 and y_step == 0:
            continue

        # Calculate the new position.
        x = self.x_values[-1] + x_step
        y = self.y_values[-1] + y_step

        self.x_values.append(x)
        self.y_values.append(y)

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

از choice([1, -1]) برای انتخاب مقدار x_direction استفاده می‌کنیم که یا ۱ (برای حرکت به راست) برمی‌گرداند یا -۱ (برای رفتن به چپ). سپس choice([0, 1, 2, 3, 4]) به پایتون می‌گوید که با انتخاب عددی صحیح بین ۰ و ۴، در آن جهت (x_direction) چه‌قدر حرکت کند. (آوردن ۰ در این لیست به ما امکان می‌دهد که در جهت محور y حرکت کنیم و در عین حال بتوانیم گام‌هایی در جهت هر دو محور داشته باشیم.)

طول هر گام در جهت‌های x و y را با ضرب کردنِ جهتِ هر حرکت در فاصله‌ای که انتخاب‌شده حساب می‌کنیم. حاصل مثبت برای x_step به معنای حرکت به راست، حاصل منفی به معنای حرکت به چپ و صفر به معنای حرکت عمودی است. مقداری مثبت برای y_step به معنای حرکت به بالا، مقدار منفی به معنای حرکت به سمت پایین و ۰ به معنای حرکت افقی است. اگر هر دو مقدار x_step و y_step صفر شود به جایی نمی‌رویم در نتیجه با صرف نظر از این حرکت حلقه را ادامه می‌دهیم.

برای به دست آوردن مقدار بعدی x، مقدار x_step را به آخرین مقدار ذخیره‌شده‌ی x_values اضافه می‌کنیم و همین کار را برای مقدارهای y تکرار می‌کنیم. زمانی که این مقدارها محاسبه شدند آن‌ها را به x_values و y_values الحاق می‌کنیم.

رسم گردش تصادفی

کد زیر تمام نقطه‌های یک گردش را رسم می‌کند:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import matplotlib.pyplot as plt
from random_walk import RandomWalk

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

# Plot the points in the walk.
plt.style.use('classic')
fig, ax = plt.subplots()
ax.scatter(rw.x_values, rw.y_values, s=15)

plt.show()

کار را با وارد کردن pyplot و RandomWalk شروع می‌کنیم. سپس گردشی تصادفی می‌سازیم و آن را در rw ذخیره می‌کنیم و سپس از فراخوانی fill_walk() مطمئن می‌شویم. مقادیر x و y گردش را به scatter() می‌دهیم و اندازه‌ی مناسبی برای نقطه‌ها انتخاب می‌کنیم. شکل ۱۵-۹ نمودار حاصل را با ۵۰۰۰ نقطه نشان می‌دهد. (در تصویرهای این بخش نمایشگر Matplotlib حذف شده‌اند ولی شما هنگام اجرای rw_visual.py آن را خواهید دید.)

![][image24]

شکل ۱۵-۹: یک گردش تصادفی با ۵۰۰۰ نقطه

تولید چند گردش تصادفی

هر کدام از گردش‌های تصادفی متفاوت‌اند و کند و کاو الگوهای مختلفی که می‌توانند تولید شوند کار جالبی است. یکی از راه‌ها برای به‌کارگیری کد قبلی برای تولید چند گردش بدون نیاز به اجرای مکرّر برنامه، قرار دادن آن در یک حلقه‌ی while است، مانند زیر:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import matplotlib.pyplot as plt
from random_walk import RandomWalk

# Keep making new walks, as long as the program is active.
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()
    ax.scatter(rw.x_values, rw.y_values, s=15)

    plt.show()

    keep_running = input("Make another walk? (y/n): ")
    if keep_running == 'n':
        break

این کد یک گردش تصادفی تولید می‌کند، آن را در نمایشگر Matplotlib نمایش می‌دهد و نمایشگر را باز نگه می‌دارد. زمانی که آن را ببندید از شما می‌پرسد که آیا می‌خواهید گردشی دیگر تولید کنید. y را وارد کنید تا گردش‌هایی در حوالی نقطه‌ی شروع تولید شود که اغلب در یک جهت حرکت می‌کنند و بخش‌های نازکی دارند که گروه‌های بزرگی از نقطه‌ها را به هم متّصل می‌کنند. برای پایان دادن به برنامه n را بزنید.

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

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

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

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

برای نمایش ترتیب نقاط در گردش از نقشه‌های رنگی استفاده می‌کنیم و سپس حاشیه‌ی سیاه هر نقطه را حذف می‌کنیم تا واضح‌تر به نظر بیایند. برای رنگ‌آمیزی نقطه‌ها بر اساس موقعیّت آن‌ها در گردش، لیستی را شامل جایگاه هر نقطه به عنوان نشان‌وند 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() را کاهش داده و خواندن و درک متد را آسان‌تر کند.

5 - تاس انداختن با پلات‌لی

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

در این پروژه نتایج حاصل از پرتاب تاس را تحلیل می‌کنیم. زمانی که شما تاسی معمولی و شش‌وجهی را پرت می‌کنید، احتمال رخ دادن هر یک از اعداد ۱ تا ۶ یکسان است. با این حال زمانی که از دو تاس استفاده می‌کنید احتمال رخ دادن برخی عددها از اعداد دیگر بیشتر می‌شود. تلاش می‌کنیم که با تولید مجموعه‌داده‌ای که بیانگر پرتاب تاس‌ها است، معلوم کنیم که کدام عددها احتمال بیشتری برای رخ دادن دارند. سپس نتایج تعداد زیادی پرتاب را رسم خواهیم کرد تا ببینیم کدام نتیجه‌ها از دیگر نتایج محتمل‌ترند.

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

نصب کردن پلات‌لی

پلات‌لی را هم مانند Matplotlib به کمک pip نصب کنید:

1
$ python -m pip install --user plotly

اگر هنگام نصب Matplotlib از دستور python3 یا مشابه آن استفاده کردید، اکنون نیز از همان استفاده کنید.

برای بازدید از بصری‌سازی‌های قابل ساخت با پلات‌لی از گالری انواع نمودارهای آن در https://plot.ly/python/ دیدن کنید. هر مثال شامل کد برنامه نیز هست بنابراین می‌توانید ببینید که پلات‌لی چگونه آن بصری‌سازی را تولید کرده است.

ساختن کلاس تاس

کلاس Die زیر را برای شبیه‌سازی پرتاب یک تاس می‌سازیم:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from random import randint

class Die:
    """A class representing a single die."""

    def __init__(self, num_sides=6):
        """Assume a six-sided die."""
        self.num_sides = num_sides

    def roll(self):
        """Return a random value between 1 and number of sides."""
        return randint(1, self.num_sides)

متد __init__() یک نشان‌وند اختیاری می‌پذیرد. در کلاس Die هنگامی که نمونه‌ای از تاس ساخته می‌شود، اگر نشان‌وندی وارد نشود، تعداد وجه‌ها همیشه شش خواهد بود. امّا اگر نشان‌وندی ارائه شود، مقدار آن تعداد وجه‌های تاس را معلوم می‌کند. (تاس‌ها با تعداد وجه‌های آن‌ها نام‌گذاری می‌شوند: تاس شش‌وجهی D6 و تاس هشت‌وجهی D8 نامیده می‌شود و …)

متد roll() از تابع randint() برای برگرداندن یک عدد تصادفی بین ۱ و تعداد وجه‌های تاس استفاده می‌کند. این تابع ممکن است مقدار آغازین (۱)، مقدار پایانی (num_sides) و یا هر عددی صحیح بین این دو را برگرداند.

پرتاب تاس

پیش از آن که بر پایه‌ی کلاس Die بصری‌سازی تولید کنیم بیایید یک تاس D6 را پرتاب کنیم، نتایج را چاپ کنیم و ببینیم که آیا نتایج منطقی است یا نه:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from die import Die

# Create a D6.
die = Die()

# Make some rolls, and store results in a list.
results = []
for roll_num in range(100):
    result = die.roll()
    results.append(result)

print(results)

نمونه‌ای از Die با تعداد پیش‌فرض شش وجه می‌سازیم. این تاس را ۱۰۰ بار می‌اندازیم و نتایج هر پرتاب را در لیست results ذخیره می‌کنیم. این نمونه‌ای از مجموعه‌ی نتایج است:

1
2
3
4
5
[4, 6, 5, 6, 1, 5, 6, 3, 5, 3, 5, 3, 2, 2, 1, 3, 1, 5, 3, 6, 3, 6, 5, 4,
1, 1, 4, 2, 3, 6, 4, 2, 6, 4, 1, 3, 2, 5, 6, 3, 6, 2, 1, 1, 3, 4, 1, 4,
3, 5, 1, 4, 5, 5, 2, 3, 3, 1, 2, 3, 5, 6, 2, 5, 6, 1, 3, 2, 1, 1, 1, 6,
5, 5, 2, 2, 6, 4, 1, 4, 5, 1, 1, 1, 4, 5, 3, 3, 1, 3, 5, 4, 5, 6, 5, 4,
1, 5, 1, 2]

یک نگاه سریع به نتایج نشان می‌دهد که کلاس Die به نظر درست کار می‌کند. مقدارهای ۱ تا ۶ را می‌بینیم که می‌دانیم آن‌ها کوچک‌ترین و بزرگ‌ترین مقدارهای برگشتی ممکن هستند و چون اعداد ۱ یا ۷ را نمی‌بینیم می‌فهمیم که تمام نتایج در بازه‌ی مناسب قرار دارند. همچنین تمام اعداد بین ۱ تا ۶ را در خروجی می‌بینیم که نشان می‌دهد تمام رخ‌دادهای ممکن نمایش داده شده است. بیایید تعداد دقیق نمایان شدن هر عدد را معلوم کنیم.

تحلیل نتایج

نتایج حاصل از پرتاب تاس D6 را با شمردن تعداد رخ دادن هر عدد تحلیل می‌کنیم:

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

# Make some rolls, and store results in a list.
results = []
for roll_num in range(1000):
    result = die.roll()
    results.append(result)

# Analyze the results.
frequencies = []
for value in range(1, die.num_sides+1):
    frequency = results.count(value)
    frequencies.append(frequency)

print(frequencies)

چون دیگر نتایج پرتاب تاس را چاپ نمی‌کنیم می‌توانیم تعداد پرتاب‌های تاس شبیه‌سازی‌شده را به ۱۰۰۰ افزایش دهیم. برای تحلیل پرتاب‌ها لیستی خالی به نام frequencies می‌سازیم تا تعداد رخ دادن هر عدد را در آن ذخیره کنیم. در نتایج ممکن (در این مورد ۱ تا ۶) حلقه می‌زنیم، تعداد نمایان شدن هر عدد را در results می‌شماریم و سپس این مقدار را به لیست frequencies اضافه می‌کنیم. سپس نتایج را پیش از ساختن بصری‌سازی چاپ می‌کنیم:

1
[155, 167, 168, 170, 159, 181]

این نتایج به نظر قابل قبول‌اند: شش بسامد داریم، هر کدام برای هر عدد ممکن در پرتاب تاس D6، و می‌بینیم که هیچ کدام به طرز محسوسی از دیگر بسامدها بیشتر نیستند. حالا بیایید این نتایج را بصری کنیم.

ساختن یک بافت‌نگار

با وجود لیست بسامدها می‌توانیم بافت‌نگار یا هیستوگرام128 نتایج را درست کنیم. بافت‌نگار نموداری میله‌ای است که تعداد رخ دادن هر نتیجه را نمایش می‌دهد. این کد ساختن بافت‌نگار است:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
from plotly.graph_objs import Bar, Layout
from plotly import offline
from die import Die

--snip--

# Analyze the results.
frequencies = []
for value in range(1, die.num_sides+1):
    frequency = results.count(value)
    frequencies.append(frequency)

# Visualize the results.
x_values = list(range(1, die.num_sides+1))
data = [Bar(x=x_values, y=frequencies)]

x_axis_config = {'title': 'Result'}
y_axis_config = {'title': 'Frequency of Result'}
my_layout = Layout(title='Results of rolling one D6 1000 times',
    xaxis=x_axis_config, yaxis=y_axis_config)

offline.plot({'data': data, 'layout': my_layout}, filename='d6.html')

برای ساختن یک بافت‌نگار برای هر نتیجه‌ی ممکن یک میله نیاز داریم. این میله‌ها را در لیستی به نام x_values ذخیره می‌کنیم که از ۱ آغاز و به تعداد وجه‌های تاس ختم می‌شود. پلات‌لی خروجی مستقیم تابع range() را نمی‌پذیرد پس باید این بازه را صریحاً به کمک تابع list() به لیست تبدیل کنیم. کلاس Bar() پلات‌لی بیانگر مجموعه‌داده‌ای است که به شکل نمودار میله‌ای درخواهد آمد. این کلاس به لیستی شامل مقدارهای x و لیستی شامل مقدارهای y نیاز دارد. این کلاس باید داخل کروشه قرار بگیرد زیرا یک مجموعه‌ی داده ممکن است عنصرهای متعدّدی داشته باشد.

هر محور می‌تواند به چند روش تنظیم شود و هر گزینه‌ی پیکربندی به عنوان عضوی از یک دیکشنری ذخیره می‌شود. فعلاً تنها عنوان هر محور را تعیین می‌کنیم. کلاس Layout() شی‌ای برمی‌گرداند که طرح و پیکربندی کلّی نمودار را مشخّص می‌کند. اینجا عنوان نمودار را معلوم کرده و دیکشنری‌های مربوط به محورهای x و y را وارد می‌کنیم.

برای تولید نمودار تابع offline.plot() را فرامی‌خوانیم. این تابع یک دیکشنری شامل داده و شیءهای طرح‌بندی و همچنین نام فایل ذخیره‌سازی نمودار را می‌پذیرد. خروجی را در فایلی به نام d6.html ذخیره می‌کنیم.

زمانی که برنامه‌ی die_visual.py را اجرا کنید احتمالاً مرورگری باز می‌شود که فایل d6.html را نشان می‌دهد. اگر چنین نشد برگه‌ی جدیدی در یک مرورگر باز کنید و سپس فایل d6.html را در آن باز کنید (فایل در همان پوشه‌ای است که die_visual.py را ذخیره کرده‌اید.) باید نموداری شبیه به آنچه در شکل ۱۵-۱۲ آمده ببینید.

![][image27]

شکل ۱۵-۱۲: نمودار میله‌ای ساده‌ای که با پلات‌لی درست شده است.

توجّه کنید که پلات‌لی نمودار را تعاملی کرده است: نشانگر ماوس را روی هر کدام از میله‌های نمودار نگه دارید و داده‌ی مربوط به آن را خواهید دید. این ویژگی به خصوص زمانی سودمند است که چند مجموعه‌داده را روی یک نمودار رسم کنید. همچنین به آیکون‌های بالا سمت راست توجّه کنید که به شما اجازه‌ی جابه‌جا کردن و بزرگنمایی این بصری‌سازی و ذخیره کردن آن به صورت یک عکس را می‌دهد.

6 - پرتاب تاس‌های مختلف و خلاصه

پرتاب دو تاس

پرتاب دو تاس به عددهای بزرگ‌تر و توزیع متفاوتی از نتایج منجر می‌شود. کد را برای ساختن دو تاس D6 تغییر می‌دهیم تا پرتاب یک جفت تاس را شبیه‌سازی کنیم. هر بار که جفت تاس را می‌اندازید دو عدد (هر یک مربوط به یکی از تاس‌ها) را با هم جمع و نتیجه را در results ذخیره می‌کنیم. نسخه‌ای از die_visual.py را به نام dice_visual.py ذخیره کنید و تغییرات زیر را اعمال کنید:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from plotly.graph_objs import Bar, Layout
from plotly import offline
from die import Die

# Create two D6 dice.
die_1 = Die()
die_2 = Die()

# Make some rolls, and store results in a list.
results = []
for roll_num in range(1000):
    result = die_1.roll() + die_2.roll()
    results.append(result)

# Analyze the results.
frequencies = []
max_result = die_1.num_sides + die_2.num_sides
for value in range(2, max_result+1):
    frequency = results.count(value)
    frequencies.append(frequency)

# Visualize the results.
x_values = list(range(2, max_result+1))
data = [Bar(x=x_values, y=frequencies)]

x_axis_config = {'title': 'Result', 'dtick': 1}
y_axis_config = {'title': 'Frequency of Result'}
my_layout = Layout(title='Results of rolling two D6 dice 1000 times',
    xaxis=x_axis_config, yaxis=y_axis_config)

offline.plot({'data': data, 'layout': my_layout}, filename='d6_d6.html')

پس از ساختن دو نمونه از Die، تاس‌ها را پرتاب می‌کنیم و مجموع هر دو را در هر بار پرتاب محاسبه می‌کنیم. بزرگترین حاصل ممکن (۱۲) مجموع بزرگترین عدد دو تاس است که آن را در max_result ذخیره می‌کنیم. کوچکترین نتیجه‌ی ممکن (۲) مجموع کوچک‌ترین عددهای دو تاس است. هنگام تحلیل نتایج تعداد نتایج بین ۲ و max_result را می‌شماریم. (می‌توانستیم از range(2, 13) استفاده کنیم ولی تنها زمانی کاربرد داشت که فقط با دو تاس کار می‌کردیم. هنگام مدل‌سازی وضعیت‌های دنیای واقعی بهتر این است که برنامه را جوری بنویسیم تا به راحتی تغییر یافتن شرایط را مدل کند. این کد به ما امکان می‌دهد که انداختن دو تا با هر تعداد وجه را شبیه‌سازی کنیم.)

هنگام ساختن نمودار کلید dtick را به دیکشنری x_axis_config اضافه می‌کنیم. این تنظیمات فاصله‌ی بین علامت‌گذاری‌های محور x را کنترل می‌کند. حال که تعداد بیشتری میله در نمودار بافت‌نگار داریم، تنظیمات پیش‌فرض پلات‌لی تنها برچسب تعدادی از میله‌ها را نشان می‌دهد. تنظیم 'dtick': 1 به پلات‌لی می‌گوید که تمام علامت‌ها را برچسب بزند. علاوه بر این‌ها عنوان نمودار را هم به‌روز می‌کنیم و نام فایل خروجی را تغییر می‌دهیم.

پس از اجرای برنامه باید نموداری شبیه به شکل ۱۵-۱۳ ببینید.

![][image28]

شکل ۱۵-۱۳: نتایج شبیه‌سازی‌شده‌ی ۱۰۰۰ بار پرتابِ تاس‌های شش‌وجهی

این نمودار نتایج تقریبی پرتاب یک جفت تاس D6 را نشان می‌دهد. چنان‌که می‌بینید کمترین احتمال رخ دادن ۲ یا ۱۲ و بیشترین احتمال برای رخ دادن ۷ است. دلیل این اتّفاق این است که شش راه برای آمدنِ ۷ وجود دارد: ۱ و ۶، ۲ و ۵، ۳ و ۴، ۴ و ۳، ۵ و ۲ یا ۶ و ۱.

پرتاب تاس‌هایی با اندازه‌های متفاوت

حال یک تاس شش‌وجهی و یک تاس ده‌وجهی می‌سازیم و نتیجه‌ی ۵۰،۰۰۰ بار پرتاب آن‌ها را بررسی می‌کنیم:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from plotly.graph_objs import Bar, Layout
from plotly import offline
from die import Die

# Create a D6 and a D10.
die_1 = Die()
die_2 = Die(10)

# Make some rolls, and store results in a list.
results = []
for roll_num in range(50_000):
    result = die_1.roll() + die_2.roll()
    results.append(result)

# Analyze the results.
--snip--

# Visualize the results.
x_values = list(range(2, max_result+1))
data = [Bar(x=x_values, y=frequencies)]

x_axis_config = {'title': 'Result', 'dtick': 1}
y_axis_config = {'title': 'Frequency of Result'}
my_layout = Layout(title='Results of rolling a D6 and a D10 50000 times',
    xaxis=x_axis_config, yaxis=y_axis_config)

offline.plot({'data': data, 'layout': my_layout}, filename='d6_d10.html')

برای ساختن تاس D10 نشان‌وند ۱۰ را به دومین نمونه‌ی Die می‌دهیم و حلقه‌ی اوّل را برای ۵۰،۰۰۰ پرتاب به جای ۱۰۰۰ بار تنظیم می‌کنیم. عنوان نمودار و نام فایل خروجی را نیز تغییر می‌دهیم.

شکل ۱۵-۱۴ نمودار حاصل را نشان می‌دهد. به جای یک نتیجه‌ی با بیشترین احتمال، پنج نتیجه‌ی محتمل داریم. دلیل این نتیجه این است که همچنان برای وقوع کمترین مقدار (۱ و ۱) و بیشترین مقدار (۶ و ۱۰) یک راه وجود دارد امّا تاس کوچک‌تر تعداد روش‌های تولید اعداد میانی را محدود می‌کند: شش راه برای وقوع ۷، ۸، ۹، ۱۰ و ۱۱ وجود دارد. بنابراین این اعداد محتمل‌ترین نتایج‌اند و شما به طور برابر شانس آوردن یکی از این اعداد را بیشتر از باقی اعداد دارید.

![][image29]

شکل ۱۵-۱۴: نتایج ۵۰،۰۰۰ بار پرتاب یک تاس شش‌وجهی و یک تاس ۱۰‌وجهی

توانایی ما برای استفاده از پلات‌لی در مدل کردن پرتاب تاس‌ها به ما برای تحلیل و بررسی این پدیده آزادی عمل می‌دهد. در تنها چند دقیقه می‌توانید تعداد بسیار زیادی پرتاب انواع مختلف تاس را شبیه‌سازی کنید.

خودآزمایی

۱۵-۶. دو تاس D8: یک شبیه‌سازی بسازید که نتایج ۱۰۰۰ بار پرتاب دو تاس هشت‌وجهی را نشان دهد. سعی کنید پیش از اجرای شبیه‌سازی تصور خود از نتیجه‌ی بصری‌سازی تصویر کنید؛ سپس ببینید که درک شهودی شما درست بوده یا نه. تعداد پرتاب‌ها را به تدریج افزایش دهید تا زمانی که به حد توانایی‌های سیستم خود برسید.

۱۵-۷. سه تاس: زمانی که سه تاس D6 پرتاب می‌کنیم کوچک‌ترین عدد ممکن ۳ و بزرگترین عدد ممکن ۱۸ خواهد بود. یک بصری‌سازی ایجاد کنید که نتایج پرتاب سه تاس D6 را نشان دهد.

۱۵-۸. ضرب: زمانی که دو تاس پرتاب می‌کنید معمولاً دو عدد حاصل با هم جمع می‌کنید. یک بصری‌سازی بسازید که نتایج پرتاب را در صورتی‌که دو عدد را به جای جمع کردن ضرب کنید نشان دهد.

۱۵-۹. دربرداری تاس: کدهای این بخش برای شفافیت بیشتر از شکل طولانی حلقه‌ی for استفاده می‌کند. اگر با به‌کارگیری روش دربرداری لیست راحت هستید، یکی یا هر دو حلقه‌ی for این برنامه‌ها را به کمک این روش بازنویسی کنید.

۱۵-۱۰. تمرین کردن با هر دو کتاب‌خانه: سعی کنید از Matplotlib برای بصری‌سازی پرتاب تاس و از پلات‌لی برای بصری‌سازی گردش تصادفی استفاده کنید. (برای تکمیل این تمرین نیاز به کمک گرفتن از مستندات هر کتابخانه دارید.)

خلاصه

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

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

در فصل ۱۶ داده‌ها را از منابع آنلاین دریافت می‌کنید و به استفاده از Matplotlib و پلات‌لی برای کاویدن آن داده‌ها ادامه خواهید داد.