Python Print to String - string

I have some code that works perfectly, but am now trying to move it into a GUI. The issue so far is that I'm using pygame, and I have so far only managed to show text from a single assigned string.
# --- calculate all variables
for i in range(0, num_rows):
ticker['ticker{0}'.format(i+1)] = df['Ticker'][i] #could also use 'ticker'+str(i) instead of .format
tickerci['tickerci{0}'.format(i+1)] = df['Carbon Intensity'][i]
tickerobject['tickerobject{0}'.format(i+1)] = yf.Ticker(ticker['ticker{0}'.format(i+1)])
tickervalue['tickervalue{0}'.format(i+1)] = (tickerobject['tickerobject{0}'.format(i+1)]).info['marketCap']
tickerprice['tickerprice{0}'.format(i+1)] = (tickerobject['tickerobject{0}'.format(i+1)]).info['regularMarketPrice']
socialcost['socialcost{0}'.format(i+1)] = round((tickervalue['tickervalue{0}'.format(i+1)])*(tickerci['tickerci{0}'.format(i+1)])*carbonprice)
print ("the current price of ", ticker['ticker'+str(i+1)]," is €", tickerprice['tickerprice'+str(i+1)], ".")
print ("the current market cap of ", ticker['ticker'+str(i+1)]," is €", tickervalue['tickervalue'+str(i+1)], ".")
print ("the current social cost of ", ticker['ticker'+str(i+1)],"'s CO2 emissions is €", socialcost['socialcost'+str(i+1)])
print ()
# --- main ---
pygame.init()
screen = pygame.display.set_mode((960, 720))#, pygame.FULLSCREEN, vsync=1)
screen_rect = screen.get_rect()
font = pygame.font.SysFont(None, 50)
description = "put the text to display here"
desc_text = font.render(description, True, (255, 255, 255))
desc_rect = desc_text.get_rect(left=screen_rect.right)
Basically I want to assign the outputs of the print command in the loop to a string (or a string dictionary), which can then be called in the "description" part of the pygame module.
The end goal here is to have the strings that are currently printed, shown scrolling endlessly like a marquee.
There should be some way of modifying this basic bit of string io to work, I think, but I haven't been able to figure it out yet.
import io
def print_to_string(*args, **kwargs):
output = io.StringIO()
print(*args, file=output, **kwargs)
contents = output.getvalue()
output.close()
return contents

Related

Python program freezes (using pandas and turtle modules)

The problem is my program freezes and I can't find what's wrong: I've being re-reading the code over and over, I've searched here and I've also googled and couldn't find a reason. I've seen a theme where the program of one coder froze because of an infinite loop and looked for it in my code but didn't see one. Here is the code below. Thank you for your time!
P.S. I've read the recommendation on less code in the question but it seemed to me that in my case every part is important, maybe that's because I'm a newbie yet.
First, I import the csv file with the names of the states. It has 50 states and it looks like this:
state,x,y
Alabama,139,-77
Alaska,-204,-170
Arizona,-203,-40
etc...
Now this is the code of my program:
import turtle
import pandas
screen = turtle.Screen()
screen.title("U.S. States Game")
# This belowe is the image with the blank_country where my guessed states names will be viewed. It use it as a background.
image = "blank_states_img.gif"
screen.addshape(image)
Tim = turtle.Turtle()
Tim.hideturtle()
Tim.penup()
turtle.shape(image)
print(screen.screensize())
states_data = pandas.read_csv("50_states.csv")
states_list = states_data.state.to_list()
number_of_states = len(states_list)
guessed_states = []
number_of_guessed_states = len(guessed_states)
answer_state = screen.textinput(title="Guess the state", prompt="What's another state's name?").title()
print(answer_state)
while number_of_guessed_states < 50:
if answer_state == "Exit":
missing_states = []
for state in states_list:
if state not in guessed_states:
missing_states.append(state)
new_data = pandas.DataFrame(missing_states)
new_data.to_csv("states_to_learn.csv")
break
if answer_state in states_list:
guessed_states.append(answer_state)
current_state = states_data[states_data.state == answer_state]
Tim.goto(int(current_state.x) - 15, int(current_state.y))
Tim.pendown()
Tim.write(answer_state, align="left", font=("Arial", 6, "bold"))
Tim.penup()
answer_state = screen.textinput(title=f"{number_of_guessed_states}/{number_of_states} states correct",
prompt="What's another state's name?").title()
states_list.pop(states_list.index(answer_state))
if number_of_guessed_states == number_of_states:
Tim.goto(-30, 0)
Tim.pendown()
Tim.write("Congratulations. This doesn't make you smart, but you've guessed all the states and won.",
font=("Arial", 10, "normal"))
One problem with your code is you lock in the value of number_of_guessed_states before the loop and never update it:
number_of_guessed_states = len(guessed_states)
so even though guessed_states is changing, number_of_guessed_states isn't. Also, this seems an odd choice:
screen.addshape(image)
...
turtle.shape(image)
vs. doing:
screen.bgpic(image)
Duplicating this prompt:
answer_state = screen.textinput(...).title()
seems error prone vs. having it once at the top of the loop. For example, here:
answer_state = screen.textinput(...).title()
states_list.pop(states_list.index(answer_state))
You remove the current answer but never removed the answer from before the loop. See if the following rework of your code runs as you intended:
from turtle import Screen, Turtle
import pandas
# This belowe is the image with the blank_country where my guessed states names will be viewed. It use it as a background.
image = "blank_states_img.gif"
screen = Screen()
screen.title("U.S. States Game")
screen.bgpic(image)
turtle = Turtle()
turtle.hideturtle()
turtle.penup()
states_data = pandas.read_csv("50_states.csv")
states_list = states_data.state.to_list()
number_of_states = len(states_list)
guessed_states = []
while len(guessed_states) < number_of_states:
answer_state = screen.textinput(title=f"{len(guessed_states)}/{number_of_states} states correct", prompt="What's another state's name?").title()
if answer_state == 'Exit':
missing_states = []
for state in states_list:
if state not in guessed_states:
missing_states.append(state)
new_data = pandas.DataFrame(missing_states)
new_data.to_csv("states_to_learn.csv")
screen.bye()
if answer_state in states_list:
guessed_states.append(states_list.pop(states_list.index(answer_state)))
current_state = states_data[states_data.state == answer_state]
turtle.goto(int(current_state.x) - 15, int(current_state.y))
turtle.write(answer_state, align='left', font=('Arial', 6, 'bold'))
if len(guessed_states) == number_of_states:
turtle.goto(-30, 0)
turtle.write("Congratulations. This doesn't make you smart, but you've guessed all the states and won.", font=('Arial', 10, 'normal'))
screen.mainloop()

Why is the webcolors library giving me an atribute error when the function is specified in the documentation

I am trying to create a color mixer-calculator type thing that will tell you the color name based on the RGB code you input. As in the webcolor database there are no 256^3 color names (niether in real life, I think) I included aproximations to the colors that didn't have names to the nearest similar color. The problem pops out when using the
webcolors.cc3_hex_to_name
It raises an atribute error:
AttributeError: module 'webcolors' has no attribute 'css3_hex_to_name'
This is very strange as the webcolor's documentation clearly includes this atribute:
Webcolors documentation extract
Here's the whole code for reference:
import webcolors
webcolors.css3_hex_to_name
def closest_colour(requested_colour):
min_colours = {}
for key, name in webcolors.css3_hex_to_names.items(): #Error line
r_c, g_c, b_c = webcolors.hex_to_rgb(key)
rd = (r_c - requested_colour[0]) ** 2
gd = (g_c - requested_colour[1]) ** 2
bd = (b_c - requested_colour[2]) ** 2
min_colours[(rd + gd + bd)] = name
return min_colours[min(min_colours.keys())]
def get_colour_name(requested_colour):
try:
closest_name = actual_name = webcolors.rgb_to_name(requested_colour)
except ValueError:
closest_name = closest_colour(requested_colour)
actual_name = None
return actual_name, closest_name
requested_colour = (119, 172, 152)
actual_name, closest_name = get_colour_name(requested_colour)
print ("Actual colour name:", actual_name, ", closest colour name:", closest_name)
try this webcolors.CSS3_HEX_TO_NAMES

Y position of an Ascii art doesn't change whereas, X position does

I have this code here:
import sys
import subprocess
import os
from colorama import init
init()
path = os.getcwd()
frame_logo = []
frame_data = []
frame_name = ["frame1.txt", "frame2.txt", "frame3.txt", "frame4.txt"]
for i in frame_name:
fullPath = "{}\\assets\\".format(path)
with open(fullPath + str(i), "r+") as f:
readData = f.read()
frame_data.append(readData)
with open(fullPath + "ldr_logo.txt", "r+") as f:
readData = f.read()
frame_logo.append(readData)
def printPos(x, y, text_to_print):
sys.stdout.write("\x1b[%d;%df%s" % (x, y, text_to_print))
sys.stdout.flush()
def Animation():
print(" ")
printPos(1, 20, frame_data[0])
...
So, each file in frame_name list contains Ascii art and, the file content is saved in frame_data (so, frame_data[0] contains Ascii art of frame1.txt etc...). When I try to use the printPos function (to print at a specific position) against a simple string ("foo" for example) it works but, when I try to do it against an Ascii art (frame_data[0] for example) only the X position moves and the Y stays the same.
I tried printPos(1, 20, str(frame_data[0])) and it gives the same output and even made another simple "foo" string in a list to test (because I suspected lists when I tried to print the Ascii art) to printPos it and it worked. I don't know why the Y pos doesn't change with the Ascii art, any clue? And thanks!

Never resets list

I am trying to create a calorie counter the standard input goes like this:
python3 calories.txt < test.txt
Inside calories the food is the following format: apples 500
The problem I am having is that whenever I calculate the values for the person it seems to never return to an empty list..
import sys
food = {}
eaten = {}
finished = {}
total = 0
#mappings
def calories(x):
with open(x,"r") as file:
for line in file:
lines = line.strip().split()
key = " ".join(lines[0:-1])
value = lines[-1]
food[key] = value
def calculate(x):
a = []
for keys,values in x.items():
for c in values:
try:
a.append(int(food[c]))
except:
a.append(100)
print("before",a)
a = []
total = sum(a) # Problem here
print("after",a)
print(total)
def main():
calories(sys.argv[1])
for line in sys.stdin:
lines = line.strip().split(',')
for c in lines:
values = lines[0]
keys = lines[1:]
eaten[values] = keys
calculate(eaten)
if __name__ == '__main__':
main()
Edit - forgot to include what test.txt would look like:
joe,almonds,almonds,blue cheese,cabbage,mayonnaise,cherry pie,cola
mary,apple pie,avocado,broccoli,butter,danish pastry,lettuce,apple
sandy,zuchini,yogurt,veal,tuna,taco,pumpkin pie,macadamia nuts,brazil nuts
trudy,waffles,waffles,waffles,chicken noodle soup,chocolate chip cookie
How to make it easier on yourself:
When reading the calories-data, convert the calories to int() asap, no need to do it every time you want to sum up somthing that way.
Dictionary has a .get(key, defaultvalue) accessor, so if food not found, use 100 as default is a 1-liner w/o try: ... except:
This works for me, not using sys.stdin but supplying the second file as file as well instead of piping it into the program using <.
I modified some parsings to remove whitespaces and return a [(name,cal),...] tuplelist from calc.
May it help you to fix it to your liking:
def calories(x):
with open(x,"r") as file:
for line in file:
lines = line.strip().split()
key = " ".join(lines[0:-1])
value = lines[-1].strip() # ensure no whitespaces in
food[key] = int(value)
def getCal(foodlist, defValueUnknown = 100):
"""Get sum / total calories of a list of ingredients, unknown cost 100."""
return sum( food.get(x,defValueUnknown ) for x in foodlist) # calculate it, if unknown assume 100
def calculate(x):
a = []
for name,foods in x.items():
a.append((name, getCal(foods))) # append as tuple to list for all names/foods eaten
return a
def main():
calories(sys.argv[1])
with open(sys.argv[2]) as f: # parse as file, not piped in via sys.stdin
for line in f:
lines = line.strip().split(',')
for c in lines:
values = lines[0].strip()
keys = [x.strip() for x in lines[1:]] # ensure no whitespaces in
eaten[values] = keys
calced = calculate(eaten) # calculate after all are read into the dict
print (calced)
Output:
[('joe', 1400), ('mary', 1400), ('sandy', 1600), ('trudy', 1000)]
Using sys.stdin and piping just lead to my console blinking and waiting for manual input - maybe VS related...

Linux, ReportLab and LPR: Printing fails somehow

I'm working on a python3 script that creates a batch of pdf-files using ReportLab and sends them to my local printer by calling subprocess(['LPR', filename]).
The first file is not printed completely (in fact, it's just the image - logo and the first two paragraphs), the print-outs are just non-readable nonsense.
Same behaviour when trying to print from bash.
The pdf-files do not contain anything weird, just a png-logo, some paragraphs and some tables. File size is < 20kB each.
No problems expirienced when printing these files from evince.
No problems to print other pdf files via lpr.
What's the problem with ReportLab?
Edit: Here's part of the code generating the pdf. There are some more functions, but these are called in any case. Printing stopps after Paragraph 2 in generateHeader()
class ZXPolicy:
doc = None
story = None
styles = None
filename = None
def __init__(self, filename):
self.filename = filename
self.doc = SimpleDocTemplate(
filename, pagesize=A4,
rightMargin=18, leftMargin=24, topMargin=18, bottomMargin=18)
self.story = []
self.styles = getSampleStyleSheet()
self.styles.add(ParagraphStyle(name='Right', alignment=TA_RIGHT))
self.styles.add(ParagraphStyle(name='Justify', alignment=TA_JUSTIFY))
self.styles.add(ParagraphStyle(name='Center', alignment=TA_CENTER))
self.styles.add(ParagraphStyle(name='Left', alignment=TA_LEFT))
self.styles.add(ParagraphStyle(name='Header', alignment=TA_CENTER, fontSize=16))
self.styles.add(ParagraphStyle(name='Header2', alignment=TA_CENTER, fontSize=14))
def generateHeader(self):
img = Image('logo.png')
img.hAlign = 'RIGHT'
self.story.append(img)
style = self.styles['Right']
self.story.append(Spacer(1, -24))
self.story.append(Paragraph('<font size=10>xxxxx e.U.</font>', style))
self.story.append(Paragraph('<font size=9>Allersdorf 29</font>', style))
self.story.append(Paragraph('<font size=9>41 dfhousdhuftin i. M.</font>', style))
self.story.append(Paragraph('<font size=9>Tel.: 07xxxxxx53 0</font>', style))
self.story.append(
Paragraph('<font size=9>E-Mail: offxxxxrer.at</font>', style))
self.story.append(
Paragraph('<font size=9>Web: www.spoxxxxxxxt</font', style))
self.story.append(Spacer(1, 24))
def generateTitle(self, id, adjust=True, service=False):
if adjust is True and service is False:
self.story.append(Paragraph('Bindungseinstellkarte', self.styles['Header']))
if adjust is True and service is True:
self.story.append(Paragraph('Bindungseinstellkarte und Service-Auftrag', self.styles['Header']))
if adjust is False and service is True:
self.story.append(Paragraph('Service-Auftrag', self.styles['Header']))
self.story.append(Spacer(1, 6))
self.story.append(Paragraph('Auftragsnummer: ' + str(id), self.styles['Header2']))
self.story.append(Spacer(1, 24))
def saveAndPrint(self, n=2):
self.doc.build(self.story)
self.lineprint(self.filename, n)
def lineprint(self, filename, n):
if n > 0:
subprocess.Popen(['lpr', 'form_letter.pdf'])
self.lineprint(filename, n-1)

Resources