Adding Graphics
visualdataset.py: 36 points
Objective
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.
How to Complete This Section
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 Summary
The 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:

VisualDataSet Displaying 10 values
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.
Attributes
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.
Attributes Inherited from 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.
Methods
__init__
(extends__init__
from parent class)clear_canvas
(new for theVisualDataSet
class!)display
(overridesdisplay
from parent class)
Detailed Description of Methods
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:
- Set
bg_color
to"skyblue"
- Set
fg_color
to"lightgoldenrodyellow"
- Set
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 widthbar_width
that will fit in the display, accounting for the fact that there will bespace
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 simply sets all the pixels in our picture to the color indicated by bg_color
. 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:
- Begin by drawing the background of your visualization using the
clear_canvas
method you implemented above. - Use the picture module to draw vertical bars representing each of your data values in the order they appear in
self.data
. (See below for more details about how this should look.) - Call
picture.display()
to show the image. (For a smooth animation, you should only do this once, after you’ve cleared the canvas and drawn all the bars.) - Use the
input()
function pause the program until the user hits the Return key. Just as in theDataSet
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:
- Each vertical bar should have a width equal to
bar_width
and a height in pixels equal to the value of the data element it represents. - The color of the bars should match the value of
fg_color
. - All bars should be drawn so their bottom edge is flush with the bottom of the canvas.
- The left edge of the leftmost bar should also be flush with the left side of the picture.
- Make sure to leave
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.
Tip: 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.
Test your work
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.
Check your data
Begin by following the instructions in the comments to complete the first 3 TODOs
. A correct solution will:
- Create a
VisualDataSet
object withwidth
600,height
400, andbar_width
18. - Use
get_data
to access the list of values associated with your new object. - Check the number of values in the list, as well as the highest and lowest value, and assign correct values to the variables
actual_size
,actual_lowest
andactual_highest
, respectively. - Print the list of generated values to the command line.
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]
Test the display
method
Now 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:VisualDataSet Displaying 30 values
Try visualizing a sorting algorithm
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.
Update the main menu
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.