create a column with multiple if conditions - python

I have 3 columns: balls, black, white. balls is all entries in the df. black is boolean (1 for black and 0 for not), and white is also boolean (1 and 0).
I would like to create a column using:
if Black then B
if white then W
else B

I think this might answer your question:
import random
import numpy as np
import pandas as pd
# create balls
balls = []
N = 100 # user to edit
for i in range(N):
colour = ''
if np.random.random() > 0.5:
colour = 'B'
else:
colour = 'W'
balls.append(colour)
# create dataframe
df = pd.DataFrame({'balls': balls})
# add black column
df['black'] = df['balls'].apply(lambda x: 1 if x == 'B' else 0)
# add white column
df['white'] = df['balls'].apply(lambda x: 1 if x == 'W' else 0)
This results in a dataframe with 3 columns - 'balls' containing the colour, 'black' containing 1 if the ball is black otherwise 0, and 'white' which is 1 if the ball is white otherwise 0

Related

How to apply conditional color styling to a column in a Multi-index pandas dataframe

I already had a question answered for conditionally applying color with a normal Dataframe. Link
The question I have is how do I do that with a multi-index data-frame? The dataframe in the previous question was
Value Limit Actual
Issues < 33 0
Rating > 4 4.2
Complaints < 15 18
Time 30 - 45 41
Tip -- -
The new dataframe is the same dataframe but with header like below
df.columns =pd.MultiIndex.from_product([['summary'], df.columns])
df
So the new dataframe is like so
Summary
Value Limit Actual
Issues < 33 0
Rating > 4 4.2
Complaints < 15 18
Time 30 - 45 41
Tip -- -
The out put expected is like the previous question itself but with a additional header row at the top.
I tried replacing row['Limit'] with x.loc[:,idx[:,'Limit']] where idx is pd.IndexSlice but it did not work
import re
def highlight(row):
numbers = re.findall('[0-9]+', row['Limit'])
if row['Value'] in ('Issues','Rating','Complaints'):
if '>' in row['Limit'] and row['Actual'] > numbers[0]:
color = 'green'
elif row['Actual'] < numbers[0]:
color = 'green'
else:
color = 'red'
else:
if len(numbers) == 0:
color = 'yellow'
elif row['Actual'] > numbers[0] and row['Actual'] < numbers[1]:
color = 'green'
else:
color = 'red'
return f"background-color: {color}"
You need change:
row['Limit']
to:
row[('summary', 'Limit')]
for select by MultiIndex in columns.
EDIT:
If use:
row[(slice(None),'Limit')]
row[idx[:,'Actual']]
output is one element Series.
So need select first value in this methods for scalar:
row[(slice(None),'Limit')].iat[0]
row[idx[:,'Actual']].iat[0]

Correct way to assign a value to a cell in a for loop in pandas

The code works by cycling through every row and calling an 'is_color' function. The function checks values in the ith row and assigns a color, 'blue' for example, if the condition is met
import numpy as np
import pandas as pd
def is_color(df):
df['color'] = np.nan
def blue(i):
is_blue = True # some more complex condition
if is_blue:
#df['color'].iloc[i] = 'blue'
df.set_value(i, 'color', 'blue')
for i in range(len(df)):
blue(i)
# not included i this example
#green(i)
#orange(i)
#purple(i)
#yellow(i)
return df
I was originally doing df['color'].iloc[i] = 'blue' which worked but threw a SettingWithCopyWarning I need to make it production ready, I tried df.set_value(i, 'color', 'blue') however that throws a ValueError: could not convert string to float: blue i need to do it like this i think:
import numpy as np
import pandas as pd
def is_color(df):
df['color'] = np.nan
def blue(i, df):
is_blue = True # some more complex condition
if is_blue:
#df['color'].iloc[i] = 'blue'
return df.set_value(i, 'color', 'blue')
return df
for i in range(len(df)):
df = blue(i, df)
# not included i this example
#df = green(i, df)
#df = orange(i, df)
return df
I feel like my original code was cleaner though, is there a prettier way to do this ?
If many conditions is possible use apply with custom function with if, elif and else:
Sample:
df = pd.DataFrame({'A':[10,20,31],
'B':[4,5,6]})
print (df)
def is_color(x):
if x < 15:
x = 'blue'
elif (x > 15) and (x < 25):
x = 'green'
else:
x = 'nothing'
return (x)
df['color'] = df['A'].apply(is_color)
print (df)
A B color
0 10 4 blue
1 20 5 green
2 31 6 nothing
Similar solution:
def is_color(x):
a = 'nothing'
if x < 15:
a = 'blue'
if (x > 15) and (x < 25):
a = 'green'
return (a)
df['color'] = df['A'].apply(is_color)
print (df)
A B color
0 10 4 blue
1 20 5 green
2 31 6 nothing

Can't get fractal image to work

So I'm working on a homework assignment regarding using image objects in python. I'm using python 3.4.1 for this assignment. I feel like I have everything done, but it doesn't want to work correctly. Basically, I'm trying to get it to look like the picture that I've attached, but it only shows as 1 red line across, and 1 red line top to bottom on a white background.
Any help would be much appreciated.
The attached image:
http://imgur.com/TMho41w
import cImage as image
width = 500
height = 500
img = image.EmptyImage(width, height)
win = image.ImageWin("Exercise 3", width, height)
img.draw(win)
for row in range(height):
for col in range(width):
p = img.getPixel(col, row)
if row == 0 or col == 0:
p = image.Pixel(255, 0, 0)
else:
Sum = 0
temppixel = img.getPixel(col-1, row)
if temppixel.getRed() == 255:
Sum = Sum + 1
elif temppixel.getBlue() == 255:
Sum = Sum + 2
temppixel = img.getPixel(col-1, row-1)
if temppixel.getRed() == 255:
Sum = Sum + 1
elif temppixel.getBlue() == 255:
Sum = Sum + 2
temppixel = img.getPixel(col, row-1)
if temppixel.getRed() == 255:
Sum = Sum + 1
elif temppixel.getBlue() == 255:
Sum = Sum + 2
if Sum % 3 == 1:
p = image.Pixel(255, 0, 0)
elif Sum % 3 == 2:
p = image.Pixel(0, 0, 255)
else:
p = image.Pixel(255, 255, 255)
img.setPixel(col, row, p)
img.draw(win)
img.draw(win)
# uncomment this to save the image as a file
#img.saveTk("gradient.gif")
win.exitonclick()
Unfortunately, your code does exactly what you have written it to do. Let's name the three first if ... elif condition1, 2 and 3 :
The first pixel is set to red
Then we progress through the first line, so row = 0 which means condition 2 and 3 are using invalid coordinates (because of row-1). So there's only condition at play here, and it will always increment by 1 sum which means it'll add a new red pixel.
So you have now your first red line.
For the first column, starting from the second line : conditions 1 & 2 are using invalid coordinates. Condition 3 will always return sum = 1 which means a new red pixel. And you have your red line from top to bottom
And then from row = 1 and col = 1, all neighbors are red, which leads to a new white pixel. Unfortunately, white does contain some red, so it'll always be the sames conditions that are met, and you have your white background.
I haven't been able to find the complete algorithm for this method to build a Sierpinski carpet, so I can't really correct it. But you should be extra careful with these edges situations : what should be the three neighbors if you are on the first line or first row ?

Python program to detect intersection of one-dimensional line segments

I have line segments of four colors—pink, green, orange, red—as in the figure below.
As an example, the first pink segment has start and end position (5258,5422).
The coordinates are stored in this dictionary of tuples:
mycoord = { 'pink' :[(5258,5422), (5479,5864)],
'green' :[(5425,5450)],
'orange':[(5266,5770)],
'red' :[(5258,5864)] }
What I want to do is to get all the possible intersections' start and end values as shown in this figure:
Thus, the desired answer would be:
sect1/pink-red : 5258,5266
sect2/pink-orange-red : 5266,5422
sect3/orange-red : 5422,5425
sect4/green-orange-red: 5425,5450
sect5/orange-red : 5450,5479
sect6/pink-orange-red : 5479,5770
sect7/pink-red : 5770,5864
Note that I want to preserve the color indicator for each intersection (e.g., pink-red). How can I achieve this with Python?
I suggest that you proceed as follows.
Sort the endpoints, remembering each one's color and whether it's a left (opening) or right (closing) endpoint.
Iterate over the endpoints, keeping track of open spans with a hash that maps each color to the number of open spans of that color. Increment when you open a span of a given color, decrement when you close a span. Remove colors when their count reaches zero. For each distinct endpoint, put the colors of all open spans at that point into a set.
Iterate over consecutive pairs of distinct endpoints. These form the left and right endpoints of the spans that interest you. For each endpoint, you know the colors that are active at that point. The set of colors that are active during the span is the set intersection of the colors that are active at the left end and the colors that are active at the right end.
Note: If the intersection of colors between two endpoints is empty, you've found a gap between spans, so you know that it should be skipped. You might also like to skip spans with only one color. The implementation below does not. You can easily change it to skip single-color spans by modifying this line:
if len(colors) > 0:
so that it reads:
if len(colors) > 1:
If you're interested in seeing the gaps between spans, you can change the threshold to -1 or remove the condition altogether.
Implementation:
mycoord = { 'pink' :[(5258,5422), (5479,5864)],
'green' :[(5425,5450)],
'orange':[(5266,5770)],
'red' :[(5258,5864)] }
# Sort the endpoints. Remember their color and whether they open or close.
points = []
for color, spans in mycoord.items():
for open, close in spans:
points.append((open, 'open', color))
points.append((close, 'close', color))
points.sort()
# Iterate over the endpoints. Keep track of open spans. Mark intersections.
active_spans = {}
intersections = []
for point, kind, color in points:
if len(intersections) != 0 and intersections[-1][0] == point:
intersections[-1][1].add(color)
else:
color_set = set([color] + list(active_spans.keys()))
intersections.append((point, color_set))
if kind == 'close':
active_spans[color] -= 1
if active_spans[color] == 0:
del active_spans[color]
else:
active_spans[color] = active_spans.setdefault(color, 0) + 1
# Iterate over consecutive pairs of unique intersections. Intersect the color sets.
tab_width = sum(map(len, mycoord)) + len(mycoord)
count = 0
for i in range(1, len(intersections)):
a, b = intersections[i - 1], intersections[i]
colors = sorted(a[1] & b[1])
if len(colors) > 0:
count += 1
print('sect{0}/{1:<{2}}: {3},{4}'.format(count, '-'.join(colors), tab_width,
a[0], b[0]))
Result:
sect1/pink-red : 5258,5266
sect2/orange-pink-red : 5266,5422
sect3/orange-red : 5422,5425
sect4/green-orange-red : 5425,5450
sect5/orange-red : 5450,5479
sect6/orange-pink-red : 5479,5770
sect7/pink-red : 5770,5864
Using the brace open/close idea of Michael Laszlo above:
>>> mycoord = { 'pink' :[(5258,5422), (5479,5864)],
'green' :[(5425,5450)],
'orange':[(5266,5770)],
'red' :[(5258,5864)] }
>>> labeled_values=[]
# make tuples of (value, brace status (open/close), color)
>>> for color,color_ranges in mycoord.items():
for color_range in color_ranges:
labeled_values.append((color_range[0],True,color))
labeled_values.append((color_range[1],False,color))
# labeled_values are now like (5258, True, 'pink'), (5422, False, 'pink') ...
>>> sects = []
# traverse the sorted values and maintain a color-set
>>> color_set_so_far=set()
>>> range_start = -1
>>> for value,range_open,color in sorted(labeled_values):
if not range_open or range_start != value:
sects.append(("-".join(color_set_so_far), range_start, value))
if range_open:
color_set_so_far.add(color)
else:
color_set_so_far.remove(color)
range_start = value
>>> sects = [s for s in sects if s[0] and s[1]!=s[2]] # filter out empty ranges
>>> sects
# [('pink-red', 5258, 5266), ('pink-orange-red', 5266, 5422), ('orange-red', 5422, 5425), ('orange-green-red', 5425, 5450), ('orange-red', 5450, 5479), ('pink-orange-red', 5479, 5770), ('pink-red', 5770, 5864)]

detect a single ball out of two (Python)

So i've got an image in input an i transformed it into an array. There is two ball, and i want to remove one ball.
My idea is to run through a loop, and detect line by line if there is a red pixel. And if in this array at an i, and there is not red pixel in i+1 it erase the entire rest of the line.
for i in range(0, len(data)):
h = h + 1
#print("0"),
if (i>1) and (((data[i - 1])[1] > 40 and (data[i - 1])[2] > 40 ) and ((data[i + 1])[1] > 40 and (data[i+1])[2])):
print("_"),
elif (data[i])[1] < 40 and (data[i])[2] < 40 and (data[i])[0] > 50 :
j = j + 1
print "#" ,
else :
print("."),
#else :
# print data[i],
if h == 64 :
h = 0
test = True
print("\n")
What is wrong with my code and how can i erase a ball through my method ?
If you just want to delete anything on the left side:
data[:,:data.shape[1]/2] = 0
or right side:
data[:,data.shape[1]/2:] = 0
If your problem is that you have balls (red, green and blue) in an array (numpy) and there's no background or noise. For simplicity, if the color of red = 1, green = 2 and blue = 3 then:
data[np.where(data == 1)] = 0
will remove the red ball. For more sophisticated detection-needs you can use below...
You can use label from scipy.ndimage given that your data is an np-array by simply saying (of course if your balls get too overlapped they may not be separated):
from scipy.ndimage import label
labled_data, labels = label(data)
#If you want to remove the first ball
labled_data[np.where(labled_data == 1)] = 0
#Then your second ball will be where the labled data is 2
#Else if you just temporary want to know where the second ball is:
labled_data == 2
#Will be true for those places

Categories