visualdataset.py: 31 points
We are at last ready to add our graphical visualization! We will do this by creating a new class, VisualDataSet
, which inherits from our DataSet
class and overrides the display
method to replace our text-based visualization with a graphical version using the picture module. Starter code for this class is provided in the visualdataset.py
file.
Your workflow for this section will be be similar to the way you created your DataSet class. Read through the VisualDataSet
Class Summary to get a quick feel for what’s involved, then proceed to the Detailed Description of Methods and implement each method according to the specifications given. The following section, Test Your Work will help you determine that your class is functioning properly. Once you’re satisfied that it’s behaving as expected, the final section, Update the main menu, explains how to incorporate this new feature into your main program.
VisualDataSet
Class SummaryThe VisualDataSet
Class is similar to the DataSet
class that it inherits from, but instead of printing its values to the terminal, it displays them as a collection of vertical bars, where each bar has a height in pixels equal to the corresponding value. For example, a VisualDataSet
object representing the list of values [171, 324, 62, 43, 267, 221, 360, 398, 330, 176]
might display them as:
The exact appearance of the display depends on values that the user chooses when creating an instance of the object. The example above shows the output for a 600 x 400 pixel image in which each bar is 58 pixels wide.
width
(int): The width of the display in pixels.height
(int): The height of the display in pixels.bar_width
(int): The width in pixels of a single vertical bar.bg_color
(string): The color to be used for the background of our graphical display.fg_color
(string): The color we’ll use for our vertical bars.space
(int): Distance in pixels between each individual bar.DataSet
size
(int): The total number of values in the dataset.minimum
(int): The lowest value in the dataset.maximum
(int): The highest value in the dataset.data
(list): A list containing the values themselves.__init__
(extends __init__
from parent class)clear_canvas
(new for the VisualDataSet
class!)display
(overrides display
from parent class)This section contains the requirements for each method your VisualDataSet
class will need to include, as well as some implementation suggestions. Note that you’ll need to import anything you use from other modules, like picture
, DataSet
, etc.
import
-ant note!
Note that only one import
statement has been included in the starter file, but you’ll definitely need more. Expect to import anything you use from other modules, like picture
, sorts
, etc.
__init__(self, width, height, bar_width)
Initialize all of the attributes to the appropriate values. Note that this includes both the attributes listed above and all the attributes we inherited from the DataSet
class (hint: super
is your friend here).
For our purposes, it’s convenient to group our attributes into three categories corresponding to how we will set them up.
The first group includes width
, height
and bar_width
. These should be set to the values passed in as arguments to the corresponding parameters of __init__
. This means they get chosen by whoever creates an instance of the class, and can vary from one instance to the next.
The next group consists of bg_color
, fg_color
and space
. These will be hard-coded in the body of the __init__
method (at least for now). Please write your __init__
function to assign the following values:
bg_color
to "skyblue"
fg_color
to "lightgoldenrodyellow"
space
to 2.Finally, in order to call the parent object’s __init__
function, we need to know what values to use for size
, minimum
and maximum
. These values will be calculated based on the size of the display the user requested so we optimize the use of the display window (similar to the pyramid exercise from Lab 3).
Specifically, these attributes should be calculated as follows:
size
, representing the total number of values in our data set, should set to the maximum number of vertical bars of width bar_width
that will fit in the display, accounting for the fact that there will be space
pixels between each bar.minimum
sets the smallest value in the range of values our object will generate. It should be no smaller than 5% of the height of the entire display in pixels.maximum
sets the largest possible value in our dataset. It should be equal to the height of the display in pixels.For example, in the output given at the top of the VisualDataSet
Class Summary, the object has been initialized with a width
of 600, a height
of 400, and a bar_width
of 58. Based on these values, it produces a dataset of 10 items chosen randomly between 20 and 400.
Last, but not least: once all attributes have been set, our __init__
method should use the picture module’s new_picture
function to create the canvas we’ll use to display our visual data. The width and height of the new picture should match the values of the width
and height
attributes.
clear_canvas(self)
This method sets all the pixels in our picture to the color indicated by bg_color
, and then calls picture.display()
to show the image. This is very useful for creating the background of our visualization. For ideas about how to implement it, you may want to look back at the code you used to create your pyramid in Lab 3.
display(self)
We’re now ready to override the display
function that you implemented in the parent class (DataSet
). This method has three main steps:
clear_canvas
method you implemented above.self.data
. (See below for more details about how this should look.)input()
function pause the program until the user hits the Return key. Just as in the DataSet
class, we are slightly misusing the input function to create a pause effect, and not actually storing any user input.The image you create in step 2 must meet all of the following requirements:
bar_width
and a height in pixels equal to the value of the data element it represents.fg_color
.space
pixels between each bar.Note that for some choices of width
and bar_width
, there will be a space leftover between the end of the last bar and the right edge of the image. This is fine. If you’ve chosen the number of elements in your dataset correctly, the leftover space should be less than the width of one bar.
Don’t forget your docstrings!
Again, just a reminder that writing proper documentation is an important part of writing code (and, therefore, also part of your grade for this assignment). Remember to fill out the docstring for each method you implement.
The function test_visualdataset_class()
, which is called in the main body of visualdataset.py
, is intended to run a few quick checks to verify that your VisualDataSet
class is working as expected. This function has been started for you, but it is incomplete. Read through the code and comments, taking particular note of the parts labeled as TODO
Items 1-5.
Begin by following the instructions in the comments to complete the first 3 TODOs
. A correct solution will:
VisualDataSet
object with width
600, height
400, and bar_width
18.get_data
to access the list of values associated with your new object.actual_size
, actual_lowest
and actual_highest
, respectively.When these three items have been completed correctly, running python3 visualdata.py
should produce terminal output similar to the following:
Expected number of values: 30
Actual number of values: 30
The lowest value should be no lower than 20.
Actual lowest value: 34
The highest value should be no higher than 400.
Actual highest value: 377
Generated values:
[94, 257, 241, 162, 145, 34, 75, 319, 46, 188, 275, 293, 377, 318, 70, 302, 35, 352, 242, 100, 278, 136, 66, 191, 259, 336, 35, 210, 329, 366]
display
methodNow let’s address TODO Item 4: add code to call the VisualDataSet
object’s display
method so you can compare it to the numerical values.
If all has gone well, this should also bring up a graphical window in your Live View window that looks something like this:
Finally, test your selection_sort_demo
by passing in your new VisualDataSet object instead of your DataSet object. If you have implemented it correctly, no modifications should be necessary, and you will now have a working graphical visualization that updates every time you press Enter
at the command line.
Now that we’ve created an amazing new feature, it’s time to add it to our menu in main.py
. Go back to this file and edit your code so it prompts the user to choose between text-based and graphical visualizations. For example, you might display message like:
Please select a visualization style:
1: Text
2: Graphical
If the user requests a text-based visualization, your program should use the DataSet
class (i.e., its current behavior).
If they ask for a graphical visualization, you should instead use an instance of the VisualDataSet
class. For now, we will not ask the user to choose the details of the display: if they request the graphical visualization, you should create your VisualDataSet
object with a width
of 600 pixels, a height
of 400 pixels, and a bar_width
of 18 pixels.
A note on method
Our approach here is analogous to what we did for our text-based visualization. We use sensible default values that should work on most screens, with the understanding that we could come back later and add the ability for advanced users to customize the display.
As before, your program should continue to gracefully handle any invalid selections, and should continue to prompt the user until they choose a valid option.