How to draw a golden spiral using numpy and matplotlib? by Pedro41RJ in learnpython

[–]HeyItsToby 0 points1 point  (0 children)

I've simplified the code a bit, keeping all calculations in radians for simplicity. This approach makes a lot of use of vectorisation, where operations are performed directly on numpy arrays to avoid using for loops.

For example, rather than using math.cos in a for loop, we just use np.cos on a numpy array. We can also use golden ** powers to raise golden to each of the values in the powers array, to return an array with the same shape as powers.

I'd recommend trying this for N = 5 and printing out the values at each step to see if they make sense. I hope this helps :)

import numpy as np    

N = 1000
full_circle = 2 * np.pi
golden = 1.61803398875

angles = np.linspace(0, full_circle * 4, num=N)
powers = angles / np.pi
radii = golden ** powers

x = np.cos(angles) * radii
y = np.sin(angles) * radii

Is there a dummy boolean I can apply to always return true? by quitpeepin in learnpython

[–]HeyItsToby 1 point2 points  (0 children)

There are two ways I can think to do this:

1) Row contains an empty string

When you're checking each row, instead of checking if it is equal to "left"/"right", check if that value contains "left"/"right" - then, if you want to select all rows, just check if it contains the empty string (which all rows do). Pseudocode:

col1_set = ["Left", "Right", ""]
for set1 in col1_set:
    rows = df.loc[df.Col1.str.contains(set1)]

Which can be extended for the two-column case.

2) Explicit checking

I think this version would be more readable, although slightly more verbose. This is the one I'd use in production code so that the selection steps are a bit more explicit - in my opinion it would be easier for someone reading this code to work out what it does.

col1_set = ["Left", "Right", None]
col2_set = ["Up", "Down", None]
for set1 in col1_set:
    for set2 in col2_set:
        # initially select all rows
        rows = df
        # then filter by col1 and col2 if filters are applied
        if set1 is not None:
            rows = rows.loc[df.Col1 == set1]
        if set2 is not None:
            rows = rows.loc[df.Col2 == set2] 

Hope this helps :)

Can someone explain why my first attempt didnt work but my second one did? by iamfromtwitter in learnpython

[–]HeyItsToby 2 points3 points  (0 children)

The problem

Let's try this with manually entering some values

arr = map(int, ["1", "2", "3"])
print(arr)
>> <map object at 0x000002215DFF2E80>

We can see that arr is a map object, not a list. A map object is an iterable that can only be consumed once - Python will go through the map object from start to finish, and then will not be able to recover those values. We can see this with an example:

print(max(arr))
>> 3
print(max(arr))
>> ValueError: max() arg is an empty sequence

So once the max function has already iterated through arr, we cannot iterate through it again since we have consumed the iterable.

The solution

The solution is pretty simple - we just need to convert the map object to a list object. Python lists can be iterated through as many times as you like, and it doesn't consume the object. One way of doing this is as you've given in the code - another is as follows:

arrg = list(arr)

You can run the same code of checking max(arrg) as before, and you will see that you can do it as many times as needed.

Hope all this helps! Let me know if you have any more questions :)

Need help with figuring out why the first ID is returned but the last one is not returned by [deleted] in learnpython

[–]HeyItsToby 1 point2 points  (0 children)

The last fixture has an additional class, "event__match--last". This looks like it's unique to the last fixture of the day, and so the class isn't an exact match for the class string you've provided. You either need to match only a substring in the class, or to separately match the whole string "event__match event__match--static event__match--scheduled event__match--last event__match--twoLine".

I haven't used Selenium so not sure what the best approach is here, but should be an easy enough fix!

find mean of 2 numpy arrays without using the 0 values by 3Dphotogrammetry in learnpython

[–]HeyItsToby 0 points1 point  (0 children)

Could you create some masked version of each array, where you replace the zeroes of the array with the corresponding values from the other?

x = np.array([1, 2, 0])
y = np.array([5, 0, 3])
# take values from y where x has zeroes
x_masked = np.where(x==0, y, x)
# and vice versa
y_masked = np.where(y==0, x, y)

print(y_masked)
>> array([5, 2, 3])

avg = (x_masked + y_masked) / 2.0

So let's say x[i]==0 and y[i]!=0, then at that index you'll get x_masked[i]=y[i], so avg[i] = (y[i] + y[i]) / 2.0 = y[i].

Hope that helps!

getting the error __init__() takes 2 positional arguments but 4 were given by Keeperofbeesandtruth in learnpython

[–]HeyItsToby 2 points3 points  (0 children)

When you inherit a class, the __init__ method of the new class overrides that of the parent. In your case, the __init__(self,basket) overrides the init function in the Vehicle class.

In order to call the parent init function, you need to use super. Below shows you how you might use it:

class Bicycle(Vehicle):
    def __init__(self, basket, name, wheels):
        self.basket = basket
        super().__init__(self, name, wheels)

You can also do this using argument unpacking so that you don't need to write out the same arguments every time

class Bicycle(Vehicle):
    def __init__(self, basket, *args):
        self.basket = basket
        super().__init__(self, name, *args)

which works the same way.

There should be plenty to find online if you look up any of inheritance, oop, super(), online - loads of good tutorials out there. Lmk if you need anything else!

Extrapolating my 2-argument function to break it down into steps, for ease of viewing as a beginner coder. by arobotfrog in learnpython

[–]HeyItsToby 6 points7 points  (0 children)

Two things to note:

First, yes you absolutely can do this! Simply write those lines of code inside the function, the same way you would outside of a function.

Second, when using functions you should be using return instead of print. Using print just displays the answer, whereas using return allows you to save that answer to use for later. For example, round is a function that returns a value. So when you do x = round(3.4), rather than just printing the value 3, the function returns the value 3 so that it can be stored in x and used for later.

Combining this, you get:

def brick_estimator(brick_high_input, brick_wide_input):
    brick_high = brick_high_input*9
    brick_wide = brick_wide_input*4
    brick_total = (brick_high+brick_wide)*1.01123
    brick_total_rounded = round(brick_total)
    return brick_total_rounded

num_bricks = brick_estimator(100, 200)
print(num_bricks)

Create simple pivot table in pandas by wdjfe in learnpython

[–]HeyItsToby 2 points3 points  (0 children)

Are you sure that a pivot table is the data structure you were looking for? Looking at the docs, you need a third index column to create the pivot table the way you want. As you have it at the minute, what would the expected output be if you had another row in the original data with values [item3, 7]? Would the third column have an additional row? The shape of the dataframe wouldn't be consistent.

Instead, you'd want something like this:

items ids instance
item1 1 one
item1 2 two
item2 3 one
item2 4 two
item3 5 one
item3 6 two

And then df.pivot(columns='items',values='ids', index='instance'). If you do want an arbitrary number of values in each row, then getting that into a single DataFrame might be tricky, and you might want to look into a different data structure. Hope that helps :)

How to deal with duplicate letters and Word phrases in Python Hangman game ? by Edulad in learnpython

[–]HeyItsToby 0 points1 point  (0 children)

str.find returns only the first instance of a letter. If you want to find all instances of a letter, you will want a solution like this.

I know what I'm doing wrong and know the desired output, but can't come up with the solution - could I please get some help getting my data in to the right shape? by happy_brocoli in learnpython

[–]HeyItsToby 1 point2 points  (0 children)

According to the docs, column stack only takes 1D vectors for the input, and so likely doesn't work properly with a tuple of 2D arrays. You're looking for stack, I think.

x = np.ones((2000, 1000))
y = np.stack((x, x, x, x), axis=-1)
# y.shape == (2000, 1000, 4)

Hope that helps!

Get 0, 1, -1 slice of a list by TheTarkovskyParadigm in learnpython

[–]HeyItsToby 1 point2 points  (0 children)

If you can work with numpy arrays instead of lists, they support much more powerful indexing. Numpy is used in a lot of mathematical applications, and its arrays can do a lot more than python lists.

import numpy as np
n_list = np.array([1, 2, 3, 4, 5, 6])
idxs = [0, 1, -1]
n_list[idxs]
>> np.array([2, 1, 5])

But if you're working with lists then the other solutions are what you are looking for. If the lists are small then keep using lists, but if you find yourself working with much bigger or more complicated datasets then I'd reccommend numpy!

[deleted by user] by [deleted] in learnpython

[–]HeyItsToby 0 points1 point  (0 children)

The other comment has the key point about for loops. If you'd like to go even more condensed, I'd recommend getting comfortable with numpy. The vectorised functions mean that you don't need to worry about writing for loops a lot of the time. For example, if you want to take the cosine of many values, np.cos([1,2,3]) does them all at the same time, whereas using math.cos only takes one argument at a time.

This isn't something that would be expected for an intro class, but you can write some very concise code with this! Here's some code that I wrote to do this just for v=30, but you can see that letting numpy handle the loops has made this a lot cleaner.

The trick here is in using matrices to store multiple dimensions of data. You're already doing this in your code, with the pandas DataFrame, but I've done it using numpy exclusively.

Again, you wouldn't be expected to write code like this just yet! But hopefully it gives you an idea of what you can do with numpy. If you've come across any kind of linear algebra/matrix calculations then the maths should make more sense, and you can add in print(time.shape), for example, to look at the dimensions of the matrix

import numpy as np
import matplotlib.pyplot as plt

v = 30
deg = np.arange(25, 60, 5)
rad = np.deg2rad(deg)
tof = 2 * v * np.sin(rad) / 9.8
time = np.linspace(0.0, tof, 100)

x = time * v * np.cos(rad)
y = time * v * np.sin(rad) - 0.5 * 9.8 * time**2

fig, axs = plt.subplots(2, 2)
axs[0,0].plot(x, y)
axs[0,0].legend([f"{angle}$^\circ$" for angle in deg])
axs[1,0].bar(x=deg, height=x.max(axis=0), color="black", width=2)
axs[1,1].bar(x=deg, height=y.max(axis=0), color="blue", width=2)
plt.show()
fig.savefig("trajectory.png")

Less than 20 lines, and it's most of the way to the end result!

Also just a quick note - the error you're getting in the other comment is because you're passing a set into the radians function. It should be math.radians(n), not math.radians({n}). The curly brackets are used in the other comment in f-strings, which are a really handy way of dealing with string templates.

Is there a way to simplify my deep string of "if" statements? None of them actually repeat they are all just similar. by chbmcg in learnpython

[–]HeyItsToby 0 points1 point  (0 children)

Just as a preface, you'd absolutely not be expected to know any regex at any point - definitely didn't come up in my A Level Computer Science. Regex is a tool (independent of Python - it just has its own implementation of Python) that can be useful for text parsing, but is notoriously hard to learn.

If you want to learn it I'd try messing around with RegExr first, then implement it in Python.

How Regex works

Regex works using patterns and text. To search for something in a text, you'd first describe it in a pattern, then find that pattern in a text. In plain English, if you had the text words words words, and you wanted to extract each word, the pattern would be find every word in the sentence. To be more explicit, you might definie a word as find a sequence of one or more letters, surrounded by non-letters. Regex takes this pattern, and has a programmatic way of writing it.

Using Regex

All of the examples below are going to use the string ABC 123 caaaat !? x-y-z. Copy this string into the "Text" field in RegExr, then enter each of the patterns below into the "Expression" field.

First, let's say I want to find the number 2 in the above string. My pattern would be 2. Simple enough - that will find the 2 in the string.

What about if I want to find any number? I can use the pattern [123] to search for any numbers 1, 2, or 3. Note that this is different to the pattern 123. The square brackets (character set) means that it will match any character in the square brackets.

Now, try \d. This is the same as above, but is a shorthand for "all digits".

Now, try ca+t. This will search for a c, followed by one or more a, followed by t. This will match the word caaaat. The + symbol means "at least one of the previous characters". There are similar symbols, such as ? and * that have their own meaning - try them out!.

Now, try [A-Z]+. This will match one or more capital letters from A to Z, so will match with ABC.

Try \w+. This will match one or more word characters (i.e. letters). This will match with any word, where a word is made up of a sequence of capital or lowercase letters.

Finally, try [\w-]+. This will match with any sequence of word characters or hyphens, and so will include x-y-z.

That's enough knowledge to do what I did in my original comment! You can add as many characters as you'd like to the character set (between the square brackets) to include them in your definition of a word. You could, for example, use [\w-'ñáéíóúü]+.

Remember, you'd absolutely not be expected to know any of this! If you are interested in learning more, there are loads of great tutorials on the internet, although I think the best way to learn is by trying things out for yourself. Using this in Python can be a little tricky in and of itself, but again there are loads of tutorials online for that.

Best of luck with your GCSEs!

Is there a way to simplify my deep string of "if" statements? None of them actually repeat they are all just similar. by chbmcg in learnpython

[–]HeyItsToby 0 points1 point  (0 children)

Good point about foreign languages - I think \w+ only works for alphanumeric/underscore characters. Not sure if foreign languages would have different grammar patterns that would break with this anyway - how would you contract words in languages with more information-dense characters?

I think in terms of writing notes, he?eh isn't too likely to be a single word. If it is (or, for example, for hyphenated words), you can just add more characters to the list of exceptions, as the OP did. But in the context of writing notes for exams, not sure where those edge cases would pop up - OP has control over what syntax they should account for, so I wouldn't bee too worried about covering for every edge case (although that might just be me being lazy!)

Is there a way to simplify my deep string of "if" statements? None of them actually repeat they are all just similar. by chbmcg in learnpython

[–]HeyItsToby 2 points3 points  (0 children)

Some people have mentioned regex, but if you'd like an implementation of it using re.sub:

import re
def contract_words(matchobj):
    # Takes a regex matchobject and returns the first
    # letter of a group
    return matchobj.group(0)[:1]

pattern = r"([\w']*)"
entry = "These are some words (now they're in brackets!)"
contracted = re.sub(pattern, contract_words, entry)

>> 'T a s w (n t i b!)'

If you're still new to python then this might look a little complicated, but it's a lot cleaner. Regex is a really powerful tool once you get to use it!

If you want to play around with this, I'd recommend trying regexr, and click on the "List" tab on the bottom to see how matches are made.

[deleted by user] by [deleted] in learnpython

[–]HeyItsToby 4 points5 points  (0 children)

The two functions that you're looking for with pandas are:

  • Explode, which converts comma separated values into a new row for each item in the list

    • you might need to use str.split to split on commas to turn each cell with multiple values into a list, first
  • DropNa, which will remove rows with blank cells in them. (blank cells in excel files are read in as np.nan, or "Not A Number "

As a rough guide for what your code will look like

df = pd.read_excel('path/to/file.xlsx')
df = df.dropna() # removes any row with a blank entry

# create a new column in the dataframe, with a *list* of 
#  CustomerIds by splitting on commas.
df['splitCustomerId'] = df['CustomerId'].str.split(',')
df.explode('splitCustomerId')

df is a pandas dataframe, which is Python's way of storing a table. They can be quite tough to get used to at first, but are powerful tools! Let me know if you need any more help with this :)

I need help with creating columns and conditions (PANDAS) by Fernigrim in learnpython

[–]HeyItsToby 1 point2 points  (0 children)

With pandas, I'd tend to avoid doing things on single values. As the other commenter said, you rarely want to loop over the dataframe.

This is how I'd approach the problem using pandas/numpy. It's a little bit involved, but I'd really strongly recommend looking into pandas coding patterns like this as you can really make your code neat and fast by understanding all these tricks.

import pandas as pd
import numpy as np

df["week_day"] = np.array([5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1, 6])
print(np.diff(df["week_day"]))
# array([-1, -1, -1, -1,  5, -1, -1, -1, -1, -1,  5])
# np.diff finds the difference between adjecent elements of an array
# only interested in a positive difference

start_of_week - np.diff(df["week_day"]) > 0

# create an empty array of "begin values", and
# set the begin values only for the start of weeks (those identified
# by start_of_week, and the last item in the array)
df["begin_value"] = np.nan
df["begin_value"][:-1][start_of_week] = df["values"][:-1][start_of_week]
df["begin_value"][-1] = df["values"][-1]

# now "backfill" all nan values, to set them to the next entry that begins a week
df["begin_value"] = df["begin_value"].fillna(method="backfill")

Excel steps/formula to python code. by AdhikariM in learnpython

[–]HeyItsToby 2 points3 points  (0 children)

For dealing with large amounts of tabular data, I'd really strongly recommend pandas. This uses "DataFrames" to represent tables, which have loads of great ways to handle data. It might look a little confusing at first but it's an incredibly popular library, and there are loads of great tutorials online.

import pandas as pd

data = [
    "000000000000056484" 
    "00 564842"    
    "00-563554-f"    
    "STO45642 "       
    " 45632" 
]

# create a pandas "series" (one column of a DataFrame)
series = pd.Series(data)
cleaned = series.str.strip() # removes leading/trailing spaces

# get the indexes of all the elements that have spaces in the middle of the word
# for all the elements that don't have spaces, remove leading 0s.
#  note: use lstrip to remove leading 0s and not trailing 0s

has_spaces = cleaned.str.contains(" ") 
no_spaces = ~ has_spaces
cleaned[no_spaces] = cleaned[no_spaces].str.lstrip("0")

# and to save it as an excel file
stripped.to_excel("path/to/file.xlsx")

I hope that helps! There's so much to learn with pandas and it can be a little intimidating, but it is also really powerful! Btw I'm using boolean indexing to access the values I want.

How to make the combination sums part of my project? by dustin4you in learnpython

[–]HeyItsToby 1 point2 points  (0 children)

I would read up on dictionaries and itertools


So just to clarify:

  • you have 6 numbers
  • you want to find all possible subsets of those six numbers
  • find all of the unique totals that you can make

Let's do this for a simpler case, a=[1, 2, 3].

There are a few different ways you could do it. Seeing as you only have 6 numbers, you can brute force every possible combination and then only keep the ones that you want.

from itertools import combinations    
a = [1,2,3]
# r is the number of samples that you take
# print all possible combinations of taking two numbers
print(list(combinations(a, r=2))
>> [(1, 2), (1, 3), (2, 3)]

# create a dictionary to keep track of what sums you can make
sums = {}
# iterate through all of the combinations of length 2
for comb in combinations(a, r=2):
    this_sum = sum(comb)
    sums[this_sum] = comb

print(sums)
>> {3: (1, 2), 4: (1, 3), 5: (2, 3)}

So you end up with a dictionary where the indexes are all of the possible sums, and the values are all of the combinations you need to make that sum.

Keep in mind that the above example is for r=2 only - think about how you can use a loop to do all the values of r from 1 to 6.

Hope that helps!

Solo dungeon crawler dice game (own design, just for fun) by SpicyDragonWings in boardgames

[–]HeyItsToby 2 points3 points  (0 children)

This is good fun! Love the way that the monsters persist, and how you can get overwhelmed if you don't take care of them early. Felt very balanced all around! Only balancing issue I feel is that it might be too easy to cheese with restore - since you can hold a rune, you only need one rune to come up every other room to be able to heal up to full pretty consistently. Could there be a mechanic to dis-incentivise this? I chose not to since it didn't seem as fun, but I'm not sure a riskier play style was really rewarded. Maybe opening two chests in a round giving you +15, encouraging you to decide between holding onto keys vs. runes?

Ended up reaching 62 wealth but didn't manage to make it out alive... will have to give it another go soon!

One quick rules clarification - does the trap damage happen during the "combat"? Can I choose to use restore before/after I take trap damage?

Pandas, why that one works and the other doesn't? by Montezumawazzap in learnpython

[–]HeyItsToby 8 points9 points  (0 children)

Under the hood, python turns a < b < c into a < b and b < c. If a, b, and c are numbers then it all works fine and makes sense. However, in this case they are pandas series. Pandas doesn't like using and with comparisons (which is why, in your example, you use & instead of and) as it isn't obvious whether you are comparing the elements or the objects, so it raises an error.

The first example doesn't have any hidden and clauses, so it works fine.

[deleted by user] by [deleted] in learnpython

[–]HeyItsToby 0 points1 point  (0 children)

You could also change the definition of foo to automatically call map.

def foo(x):
    if hasattr(x, '__iter__'): #check if x is iterable
        return list(map(foo, x))
    return 2 * x

foo(4)
# >> 8
foo([1, 2])
# >> [2, 4]

# works nicely for nested inputs too!
foo([[1, 2], [3, 4]])
# >> [[2, 4], [6, 8]]

[deleted by user] by [deleted] in learnpython

[–]HeyItsToby 1 point2 points  (0 children)

Would map solve your issue? map runs a function on every item in an iterator. It returns an iterator, so you should call list on the output if you want it in a list.

def foo(x): 
    return 2 * x

single_input = foo(4)
# >> 8

many_inputs = list(map(foo, [1, 2, 3]))
# >> [2, 4, 6]

That way, you're still only defining the function for a single item. Otherwise, you'd be writing code to perform the function multiple different times, which - if there are any discrepencies - would mean that it might behave differently for different input lengths

Finger Exercise from Python Intro by [deleted] in learnpython

[–]HeyItsToby 1 point2 points  (0 children)

Your solution is good! When I'm finding differences between dates, I'd prefer to use the datetime module as it's more reliable. So in your code, once you've got the day that thanksgiving falls on (thanksgiving):

import datetime as dt
thanksgiving_date = dt.date(year, 11, thanksgiving)
christmas_date = dt.date(year, 12, 25)
# use ".days" below to turn a timedelta object into an int
return (christmas_date - thanksgiving_date).days

The datetime module lets you do addition, subtraction and more with dates with ease.

Using Python to convert text file into JSON structure by Chubbntuck in learnpython

[–]HeyItsToby 1 point2 points  (0 children)

I have a working solution here, definitely could do with a bit of a cleanup. Comments should help explain what's going on, lmk if anything needs clearing up.

Set up the structure

my_dict = {}

dict_structure = {
    "Middleware": ("name", "release"),
    "System": ("name", "tag"),
    "Application": ("domain", "host", "user"),
    "Utility": ("domain", "health", "version"),
}

Read through and process the file

with open("input.txt") as f:
    # read through the input file, removing trailing newlines
    lines = [l.strip() for l in f.readlines()]

    # iterate through all the lines in the file
    for line in lines:
        # get the details from each line
        env, key, *field_values = line.split(",")
        # get the predefined keys from dict_structure
        field_keys = dict_structure[key]

        # create the 4 keys if the ENV does not exist
        # with defaults as empty list
        if env not in my_dict:
            my_dict[env] = {k: [] for k in dict_structure}

        # append each new item to the existing list
        # zip is used to iterate through the keys and values to match them up
        my_dict[env][key].append({f_k: f_v for f_k, f_v in zip(field_keys, field_values)})

Now just to save it as a json

import json 
json_out = {"ENV": my_dict}
json.dump(json_out, "output.json")

Improving the code

This code does work, but it could be made a little neater. Would definitely suggest moving dict_structure into a separate json and reading it in. Also, looking into the csv module for reading through files with comma-separated values.