<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 W3 Lab
Step1:  Vega datasets
Before going into the perception experiment, let's first talk about some handy datasets that you can play with. 
It's nice to have clean datasets handy to practice data visualization. There is a nice small package called vega-datasets, from the altair project. 
You can install the package by running
$ pip install vega-datasets
or 
$ pip3 install vega-datasets
Once you install the package, you can import and see the list of datasets
Step2:  or you can work with only smaller, local datasets.
Step3:  Ah, we have the anscombe data here! Let's see the description of the dataset.
Step4:  Anscombe's quartet dataset
How does the actual data look like? Very conveniently, calling the dataset returns a Pandas dataframe for you.
Step5:  Q1
Step6:  Some histograms with pandas
Let's look at a slightly more complicated dataset.
Step7:  Pandas provides useful summary functions. It identifies numerical data columns and provides you with a table of summary statistics.
Step8:  If you ask to draw a histogram, you get all of them. 
Step9:  Well this is too small. You can check out the documentation and change the size of the figure. 
Q2
Step10:  Your own psychophysics experiment!
Let's do an experiment! The procedure is as follows
Step11:  Perception of length
Let's run the experiment.
The random module in Python provides various random number generators, and the random.uniform(a,b) function returns a floating point number in [a,b]. 
We can plot horizontal bars using the pyplot.barh() function. Using this function, we can produce a bar graph that looks like this
Step12:  Btw, np.arange is used to create a simple integer list [0, 1, 2].
Step13:  Now let's define a function to perform the experiment once. When you run this function, it picks a random number between 1.0 and 10.0 and show the bar chart. Then it asks you to input your estimate of the length of the middle bar. It then saves that number to the perceived_length_list and the actual answer to the actual_length_list.
Step14:  Now, run the experiment many times to gather your data. Check the two lists to make sure that you have the proper dataset. The length of the two lists should be the same.
Step15:  Plotting the result
Now we can draw the scatter plot of perceived and actual length. The matplotlib's scatter() function will do this. This is the backend of the pandas' scatterplot. Here is an example of how to use scatter
Step16:  Q3
Step17:  After plotting, let's fit the relation between actual and perceived lengths using a polynomial function. We can easily do it using curve_fit(f, x, y) in Scipy, which is to fit $x$ and $y$ using the function f. In our case, $f = a*x^b +c$. For instance, we can check whether this works by creating a fake dataset that follows the exact form
Step18:  In order to plot the function to check the relationship between the actual and perceived lenghts, you can use two variables x and y to plot the relationship where x equals to a series of continuous numbers. For example, if your x axis ranges from 1 to 9 then the variable x could be equal to np.linspace(1, 10, 50). The variable y will contain the equation that you get from popt. For example, if you get equation 1.00 x^2.00 + 0.00 then the variable y would be equal to 1.0 * x**2.0 + 0. 
After assigning x and y variables you will plot them in combination with the scatter plot of actual and perceived values to check if you get a linear relationship or not.
Q4
Step19:  Perception of area
Similar to the above experiment, we now represent a random number as a circle, and the area of the circle is equal to the number.
First, calculate the radius of a circle from its area and then plot using the Circle() function. plt.Circle((0,0), r) will plot a circle centered at (0,0) with radius r.
Step20:  Let's have two lists for this experiment.
Step21:  And define a function for the experiment.
Step22:  Q5
<ASSISTANT_TASK:>
Python Code:
import pandas as pd
import math
import matplotlib.pyplot as plt
%matplotlib inline
Explanation: W3 Lab: Perception
In this lab, we will learn basic usage of pandas library and then perform a small experiment to test the perception of length and area.
End of explanation
from vega_datasets import data
data.list_datasets()
Explanation: Vega datasets
Before going into the perception experiment, let's first talk about some handy datasets that you can play with. 
It's nice to have clean datasets handy to practice data visualization. There is a nice small package called vega-datasets, from the altair project. 
You can install the package by running
$ pip install vega-datasets
or 
$ pip3 install vega-datasets
Once you install the package, you can import and see the list of datasets:
End of explanation
from vega_datasets import local_data
local_data.list_datasets()
Explanation: or you can work with only smaller, local datasets.
End of explanation
local_data.anscombe.description
Explanation: Ah, we have the anscombe data here! Let's see the description of the dataset.
End of explanation
df = local_data.anscombe()
df.head()
Explanation: Anscombe's quartet dataset
How does the actual data look like? Very conveniently, calling the dataset returns a Pandas dataframe for you.
End of explanation
# TODO: put your code here
Explanation: Q1: can you draw a scatterplot of the dataset "I"? You can filter the dataframe based on the Series column and use plot function that you used for the Snow's map.
End of explanation
car_df = local_data.cars()
car_df.head()
Explanation: Some histograms with pandas
Let's look at a slightly more complicated dataset.
End of explanation
car_df.describe()
Explanation: Pandas provides useful summary functions. It identifies numerical data columns and provides you with a table of summary statistics.
End of explanation
car_df.hist()
Explanation: If you ask to draw a histogram, you get all of them. :)
End of explanation
# TODO: put your code here
Explanation: Well this is too small. You can check out the documentation and change the size of the figure. 
Q2: by consulting the documentation, can you make the figure larger so that we can see all the labels clearly? And then make the layout 2 x 3 not 3 x 2, then change the number of bins to 20?
End of explanation
import random
import time
import numpy as np
l_short_bar = 1
l_long_bar = 10
perceived_length_list = []
actual_length_list = []
Explanation: Your own psychophysics experiment!
Let's do an experiment! The procedure is as follows:
Generate a random number between [1, 10];
Use a horizontal bar to represent the number, i.e., the length of the bar is equal to the number;
Guess the length of the bar by comparing it to two other bars with length 1 and 10 respectively;
Store your guess (perceived length) and actual length to two separate lists;
Repeat the above steps many times;
How does the perception of length differ from that of area?.
First, let's define the length of a short and a long bar. We also create two empty lists to store perceived and actual length.
End of explanation
mystery_length = random.uniform(1, 10)  # generate a number between 1 and 10. this is the *actual* length.
plt.barh(np.arange(3), [l_short_bar, mystery_length, l_long_bar], align='center')
plt.yticks(np.arange(3), ('1', '?', '10'))
plt.xticks([]) # no hint!
Explanation: Perception of length
Let's run the experiment.
The random module in Python provides various random number generators, and the random.uniform(a,b) function returns a floating point number in [a,b]. 
We can plot horizontal bars using the pyplot.barh() function. Using this function, we can produce a bar graph that looks like this:
End of explanation
np.arange(3)
Explanation: Btw, np.arange is used to create a simple integer list [0, 1, 2].
End of explanation
def run_exp_once():
    mystery_length = random.uniform(1, 10)  # generate a number between 1 and 10. 
    plt.barh(np.arange(3), [l_short_bar, mystery_length, l_long_bar], height=0.5, align='center')
    plt.yticks(np.arange(3), ('1', '?', '10'))
    plt.xticks([]) # no hint!
    plt.show()
    
    try:
        perceived_length_list.append( float(input()) )
    except:
        print("This should only fail in workflow. If you are running this in browser, this won't fail.")
        pass
    actual_length_list.append(mystery_length)
run_exp_once()
Explanation: Now let's define a function to perform the experiment once. When you run this function, it picks a random number between 1.0 and 10.0 and show the bar chart. Then it asks you to input your estimate of the length of the middle bar. It then saves that number to the perceived_length_list and the actual answer to the actual_length_list.
End of explanation
# TODO: Run your experiment many times here
Explanation: Now, run the experiment many times to gather your data. Check the two lists to make sure that you have the proper dataset. The length of the two lists should be the same.
End of explanation
plt.scatter(x=[1,5,10], y=[1,10, 5])
Explanation: Plotting the result
Now we can draw the scatter plot of perceived and actual length. The matplotlib's scatter() function will do this. This is the backend of the pandas' scatterplot. Here is an example of how to use scatter:
End of explanation
# TODO: put your code here
Explanation: Q3: Now plot your result using the scatter() function. You should also use plt.title(), plt.xlabel(), and plt.ylabel() to label your axes and the plot itself.
End of explanation
from scipy.optimize import curve_fit
def func(x, a, b, c):
    return a * np.power(x, b) + c
x = np.arange(20)  # [0,1,2,3, ..., 19]
y = np.power(x, 2) # [0,1,4,9, ... ]
popt, pcov = curve_fit(func, x, y)
print('{:.2f} x^{:.2f} + {:.2f}'.format(*popt))
Explanation: After plotting, let's fit the relation between actual and perceived lengths using a polynomial function. We can easily do it using curve_fit(f, x, y) in Scipy, which is to fit $x$ and $y$ using the function f. In our case, $f = a*x^b +c$. For instance, we can check whether this works by creating a fake dataset that follows the exact form:
End of explanation
# TODO: your code here
Explanation: In order to plot the function to check the relationship between the actual and perceived lenghts, you can use two variables x and y to plot the relationship where x equals to a series of continuous numbers. For example, if your x axis ranges from 1 to 9 then the variable x could be equal to np.linspace(1, 10, 50). The variable y will contain the equation that you get from popt. For example, if you get equation 1.00 x^2.00 + 0.00 then the variable y would be equal to 1.0 * x**2.0 + 0. 
After assigning x and y variables you will plot them in combination with the scatter plot of actual and perceived values to check if you get a linear relationship or not.
Q4: Now fit your data! Do you see roughly linear relationship between the actual and the perceived lengths? It's ok if you don't!
End of explanation
n1 = 0.005
n2 = 0.05
radius1 = np.sqrt(n1/np.pi) # area = pi * r * r
radius2 = np.sqrt(n2/np.pi)
random_radius = np.sqrt(n1*random.uniform(1,10)/np.pi)
plt.axis('equal')
plt.axis('off')
circ1 = plt.Circle( (0,0),         radius1, clip_on=False )
circ2 = plt.Circle( (4*radius2,0), radius2, clip_on=False )
rand_circ = plt.Circle((2*radius2,0), random_radius, clip_on=False )
plt.gca().add_artist(circ1)
plt.gca().add_artist(circ2)
plt.gca().add_artist(rand_circ)
Explanation: Perception of area
Similar to the above experiment, we now represent a random number as a circle, and the area of the circle is equal to the number.
First, calculate the radius of a circle from its area and then plot using the Circle() function. plt.Circle((0,0), r) will plot a circle centered at (0,0) with radius r.
End of explanation
perceived_area_list = []
actual_area_list = []
Explanation: Let's have two lists for this experiment.
End of explanation
def run_area_exp_once(n1=0.005, n2=0.05):    
    radius1 = np.sqrt(n1/np.pi) # area = pi * r * r
    radius2 = np.sqrt(n2/np.pi)
    
    mystery_number = random.uniform(1,10)
    random_radius = np.sqrt(n1*mystery_number/math.pi)
    plt.axis('equal')
    plt.axis('off')
    circ1 = plt.Circle( (0,0),         radius1, clip_on=False )
    circ2 = plt.Circle( (4*radius2,0), radius2, clip_on=False )
    rand_circ = plt.Circle((2*radius2,0), random_radius, clip_on=False )
    plt.gca().add_artist(circ1)
    plt.gca().add_artist(circ2)
    plt.gca().add_artist(rand_circ)    
    plt.show()
    
    perceived_area_list.append( float(input()) )
    actual_area_list.append(mystery_number)
Explanation: And define a function for the experiment.
End of explanation
# TODO: put your code here. You can use multiple cells. 
Explanation: Q5: Now you can run the experiment many times, plot the result, and fit a power-law curve!
End of explanation
<END_TASK>