horizontal bar chart (using graphics)

This is the place for queries that don't fit in any of the other categories.

horizontal bar chart (using graphics)

Postby luishp » Tue May 06, 2014 1:39 pm

Hi,
I have created a horizontal bar chart of student exam score by taking in input from a file that contains the count of students in the file, and a student's last name followed by their score in each subsequent line. I am using the graphics module created by John Zelle primarily for beginners to try out a simple graphics.
http://mcsp.wartburg.edu/zelle/python/graphics.py
The following I have written works:
Code: Select all
# horizontal bar chart
#   This program creates a horizontal bar chart of student exam scores by taking in input from a file that contains the count of students in the file, and a student's last name followed by their score (from 0 to 100) in each subsequent line.
# by: Luis Henriquez-Perez

from graphics import*

def main():
   
   # get the input
   # fname = input("Enter filename: ")
   fname = 'class_sample.txt'
   file = open(fname, 'r')
   list1 = file.readlines()
   
   # get the number of students in the file
   students = int(list1[0])
   
   # create the window
   # set the coordinates so that the chart is scalable
   win = GraphWin('Grade Chart', 400, 400)
   win.setCoords(0, 0, 500, 500)
   
   # access the information in the file
   scores = []
   names = []
   for item in list1[1:]:
      scores += [int(item.split()[1])]
      names += [item.split()[0]]

   # initial rectangle
   rect = Rectangle(Point(140, 20), Point(140 + 3.4 * scores[0], 460/(students)))
   rect.setFill('green')
   rect.draw(win)
   
   # initial name
   text = Text(Point(70, 230/students + 10), names[0])
   text.setStyle('bold')
   text.setSize(10)
   text.draw(win)
      
   for i in range(students-1):
      rect = Rectangle(Point(140, rect.getP1().getY() + 460/students), Point(140 + 3.4 * scores[i + 1], rect.getP2().getY() + 460/students))
      rect.setFill('green')
      rect.draw(win)

      # create the names next to the bars
      text1 = Text(Point(70, (rect.getP1().getY() + rect.getP2().getY())/2) , names[i + 1])
      text1.setStyle('bold')
      text1.setSize(10)
      text1.draw(win)

      
   # wait for mouse click
   win.getMouse()
      
main()


It creates this image:
Screenshot 2014-05-06 09.23.33.png
Screenshot 2014-05-06 09.23.33.png (24.9 KiB) Viewed 224 times


using a text file named 'class_sample.txt' with this information.
15
Anderson 10
Moore 30
Ford 50
Smith 96
Harris 67
White 89
Rodriguez 22
Cuban 12
Le 83
Thomas 90
Lewis 95
Wang 45
Brown 52
Williams 34
Taylor 89


I have a couple concerns about this code however that I would like advice to address. First, I realize that I am drawing rectangles (or bars) twice. I create the first one outside of the for loop and all the other ones in the for loop. Since I do this work twice it becomes a bit annoying because whenever I want to change something about the bars I have to do it in two places. Second, I realize that I can make the code a lot easier to read by creating functions for creating the rectangle and maybe also for initializing the window and opening the file. As python programmers, what would you suggest I can do to make this code more readable and efficient?
luishp
 
Posts: 13
Joined: Wed Feb 05, 2014 12:44 am

Re: horizontal bar chart (using graphics)

Postby Kebap » Tue May 06, 2014 1:54 pm

Hi luishp! I don't know too much about graphics. Another suggestion would be to get rid of the first line in your text file. You can just count the number of students by counting the number of subsequent lines. No need to write it there explicitly.

Code: Select all
students = len(names)
Learn: How To Ask Questions The Smart Way
Join the #python-forum IRC channel on irc.freenode.net and chat with uns directly!
Kebap
 
Posts: 396
Joined: Thu Apr 04, 2013 1:17 pm
Location: Germany, Europe

Re: horizontal bar chart (using graphics)

Postby luishp » Tue May 06, 2014 3:36 pm

That's true. Thank you for that insight. :)
luishp
 
Posts: 13
Joined: Wed Feb 05, 2014 12:44 am

Re: horizontal bar chart (using graphics)

Postby luishp » Wed May 07, 2014 10:16 pm

I've answered my own question. I know that part of the problem my code had was that it was very intimidating to read, particularly that for loop with the rectangle. So I wanted to organize things—and maybe even shorten some code as well—with functions. Here is the code I came up with:

Code: Select all
# horizontal bar chart
#   This program creates a horizontal bar chart of student exam scores by taking in imput from a file that contains the count of students in the file, and a student's last name followed by their score (from 0 to 100) in each subsequent line.
# by: Luis Henriquez-Perez

from graphics import*

def main():
   
   def make_labled_window(name, length, width):
      # sets up the window
      win = GraphWin(name, length, width)
      win.setCoords(0, 0, 500, 500)
      return win
   
   def get_file_info(fname = 'class_sample.txt'):
      # fname = input("Enter filename: ")
      # returns the names and scores in text file
      file = open(fname, 'r')
      list1 = file.readlines()
      scores = []
      names = []
      for item in list1:
         scores += [int(item.split()[1])]
         names += [item.split()[0]]
      return names, scores
         
   def make_bar(window, x1, y1, score, width):
      # returns a bar
      length = 3.4 * score
      bar = Rectangle(Point(x1, y1), Point(x1 + length, y1 + width))
      bar.setFill('green')
      return bar
      
   def make_text(window, bar, x1, name):
      # returns a text with the name
      mean_x = x1/2
      mean_y = (bar.getP1().getY() + bar.getP2().getY())/2
      text = Text(Point(mean_x, mean_y), name)
      text.setStyle('bold')
      text.setSize(10)
      # text.draw(window)
      return text
      
   def make_labled_chart(window, x1, y1, names, scores):
      count = len(scores)
      width = 230/count
      for i in range(len(scores)):
         bar = make_bar(window, x1, y1, scores[i], width)
         text = make_text(window, bar, x1, names[i])
         bar.draw(window)
         text.draw(window)
         y1 = y1 + 2 * width # makes space2
               
   # main program
   win = make_labled_window('Grade Chart', 500, 500)
   names, scores = get_file_info('class_sample.txt')
   make_labled_chart(win, 140, 20, names, scores)
   win.getMouse()   
      
main()   


Hopefully, I've succeeded in making the code nearly self-documenting. One of my favorite lines is:
Code: Select all
bar = Rectangle(Point(x1, y1), Point(x1 + length, y1 + width))
because of how noticeably more readable it is from its counterpart in my old code:
Code: Select all
rect = Rectangle(Point(140, rect.getP1().getY() + 460/students), Point(140 + 3.4 * scores[i + 1], rect.getP2().getY() + 460/students))
. I hope that even though I did figure this out on myself, that this post may still help someone who may be trying to simplify and organize their code for readability. :)
luishp
 
Posts: 13
Joined: Wed Feb 05, 2014 12:44 am

Re: horizontal bar chart (using graphics)

Postby Kebap » Thu May 08, 2014 10:18 am

Well, congratulations! :)

There is always room for improvement though. Consider the following sequence:

Code: Select all
      list1 = file.readlines()
      scores = []
      names = []
      for item in list1:
         scores += [int(item.split()[1])]
         names += [item.split()[0]]


How about some more readability:

Code: Select all
      for item in list1:
         item_name, item_score = item.split()
         names.append(item_name)
         scores.append(int(item_score))


I am sure somebody can point out a function in the python library which can solve this even easier (if you already know it, which I don't)
Last edited by Kebap on Fri May 09, 2014 11:32 am, edited 1 time in total.
Learn: How To Ask Questions The Smart Way
Join the #python-forum IRC channel on irc.freenode.net and chat with uns directly!
Kebap
 
Posts: 396
Joined: Thu Apr 04, 2013 1:17 pm
Location: Germany, Europe

Re: horizontal bar chart (using graphics)

Postby luishp » Thu May 08, 2014 7:10 pm

I agree there's always room for improvement. Thanks for that helpful suggestion Kebap! :D I have just one question though, in your code we should be appending item.name and item.score should be item_name and item_score right?
Code: Select all
item_name, item_score = item.split()
         names.append(item_name)
         scores.append(int(item_score))
luishp
 
Posts: 13
Joined: Wed Feb 05, 2014 12:44 am

Re: horizontal bar chart (using graphics)

Postby Kebap » Fri May 09, 2014 11:34 am

luishp wrote:in your code we should be appending item.name and item.score should be item_name and item_score right?

Yes, of course. You are absolutely correct. My bad. I have corrected it above.
Learn: How To Ask Questions The Smart Way
Join the #python-forum IRC channel on irc.freenode.net and chat with uns directly!
Kebap
 
Posts: 396
Joined: Thu Apr 04, 2013 1:17 pm
Location: Germany, Europe


Return to General Coding Help

Who is online

Users browsing this forum: snippsat and 7 guests