diff --git a/en/graphing-functions/coordinate_systems.png b/en/graphing-functions/coordinate_systems.png new file mode 100644 index 0000000..2b983c3 Binary files /dev/null and b/en/graphing-functions/coordinate_systems.png differ diff --git a/en/graphing-functions/cos.png b/en/graphing-functions/cos.png new file mode 100644 index 0000000..01e6ba0 Binary files /dev/null and b/en/graphing-functions/cos.png differ diff --git a/en/graphing-functions/cube.png b/en/graphing-functions/cube.png new file mode 100644 index 0000000..a4c12b8 Binary files /dev/null and b/en/graphing-functions/cube.png differ diff --git a/en/graphing-functions/index.html b/en/graphing-functions/index.html new file mode 100644 index 0000000..26ab23e --- /dev/null +++ b/en/graphing-functions/index.html @@ -0,0 +1,421 @@ + +
Problem written by Moussa Doumbouya
++ In this exercice, you are going to write a program that creates the graphical representation of a function of your choice. Like the followings: +
+ ++
+ This is done by findng the pixels that correspond to (x, y) points of the plotted function, and setting the color of those pixels to green. + The axes are also drawn in a similar fashion. +
+ + + ++
x_to_pixel_x()
and y_to_pixel_y()
functions for this purpose. The starter code also contains
+ "doctests" to help you check your implementation. You may run the test cases as follow: python -m doctests your_file.py+
+ A starter code is provided below. This contains useful constants and a suggested high level decomposition of the problem. +
+ ++from simpleimage import SimpleImage +import math + +# Domain of the plot +X_MIN = -10 +X_MAX = 10 + +# Range of the plot +Y_MIN = -10 +Y_MAX = 10 + +# Size of the plot in pixels +PLOT_WIDTH = 400 +PLOT_HEIGHT = 400 + +# Color of the axes +AXIS_COLOR_R = 200 +AXIS_COLOR_G = 0 +AXIS_COLOR_B = 0 + +# Color of the plot +PLOT_COLOR_R = 0 +PLOT_COLOR_G = 200 +PLOT_COLOR_B = 0 + +# x and y step sizes +DELTA_X = 0.01 +DELTA_Y = 0.01 + + +def main(): + """ + Make a blank plot, draw the x and y axis, plot the + function defined by plotted_function and show the plot. + """ + plot = make_blank_plot() + plot = draw_axes(plot) + plot = plot_function(plot) + plot.show() + + +def ploted_function(x): + """ + Compute the y value of the ploted function for the given :param:x value. + Implement a function of your choice + """ + return math.cos(x) + + +def x_to_pixel_x(x): + """ + Compute the horizontal pixel position for horizontal + position :param:x in the plotted coordinate system. + + Test Cases: + + x = 0 should correspond to middle of the plot + >>> x_to_pixel_x(0) + 200 + + x = -10 should correspond to far left of the plot + >>> x_to_pixel_x(-10) + 0 + + x = 10 should correspond to far right of the plot + Note: x=10 is outside of the plotting area + >>> x_to_pixel_x(10) + 400 + """ + + # TODO: Your code here + # calculate the pixel x position and store it in px + + return int(px) + + +def y_to_pixel_y(y): + """ + Compute the horizontal pixel position for vertical + position :param:y in the plotted coordinate system + + Test Cases: + + y = 0 should correspond to the middle of the plot + >>> y_to_pixel_y(0) + 200 + + y=10 should correspond to the top of the plot. + >>> y_to_pixel_y(10) + 0 + + y=-10 should correspond to the bottom of the plot + Note y=-10 is actually outside of the plotting area + >>> y_to_pixel_y(-10) + 400 + """ + + # TODO: your code here + # Calculate the pixel y position and store it in py + + return int(py) + +if __name__ == '__main__': + main() ++ + + + +
from simpleimage import SimpleImage +import math + +# Domain of the plot +X_MIN = -10 +X_MAX = 10 + +# Range of the plot +Y_MIN = -10 +Y_MAX = 10 + +# Size of the plot in pixels +PLOT_WIDTH = 400 +PLOT_HEIGHT = 400 + +# Color of the axes +AXIS_COLOR_R = 200 +AXIS_COLOR_G = 0 +AXIS_COLOR_B = 0 + +# Color of the plot +PLOT_COLOR_R = 0 +PLOT_COLOR_G = 200 +PLOT_COLOR_B = 0 + +# x and y step sizes +DELTA_X = 0.01 +DELTA_Y = 0.01 + + +def main(): + """ + Make a blank plot, draw the x and y axis, plot the + function defined by plotted_function and show the plot. + """ + plot = make_blank_plot() + plot = draw_axes(plot) + plot = plot_function(plot) + plot.show() + + +def ploted_function(x): + """ + Compute the ploted function at point :param:x + """ + # return math.cos(x) + # return math.tanh(x) + # return x**3 + return x ** 2 + + +def make_blank_plot(): + """ + Create an image with all pixel colors set to black + """ + plot = SimpleImage.blank(PLOT_WIDTH, PLOT_HEIGHT) + for px in plot: + px.red = 0 + px.green = 0 + px.blue = 0 + return plot + + +def x_to_pixel_x(x): + """ + Compute the horizontal pixel position for horizontal + position :param:x in the plotted coordinate system. + + Test Cases: + + x = 0 should correspond to middle of the plot + >>> x_to_pixel_x(0) + 200 + + x = -10 should correspond to far left of the plot + >>> x_to_pixel_x(-10) + 0 + + x = 10 should correspond to far right of the plot + Note: x=10 is outside of the plotting area + >>> x_to_pixel_x(10) + 400 + """ + h_pixel_per_point = PLOT_WIDTH / (X_MAX - X_MIN) + px = x * h_pixel_per_point + PLOT_WIDTH/2 + return int(px) + + +def y_to_pixel_y(y): + """ + Compute the horizontal pixel position for vertical + position :param:y in the plotted coordinate system + + Test Cases: + + y = 0 should correspond to the middle of the plot + >>> y_to_pixel_y(0) + 200 + + y=10 should correspond to the top of the plot. + >>> y_to_pixel_y(10) + 0 + + y=-10 should correspond to the bottom of the plot + Note y=-10 is actually outside of the plotting area + >>> y_to_pixel_y(-10) + 400 + """ + v_pixel_per_point = PLOT_HEIGHT / (Y_MAX - Y_MIN) + py = PLOT_HEIGHT/2 - y * v_pixel_per_point + return int(py) + + +def draw_axes(plot): + """ + Draw the horizontal and vertical axes + """ + draw_x_axis(plot) + draw_y_axis(plot) + return plot + + +def draw_x_axis(plot): + """ + Draw the horizontal axis + Set of points for which (x, 0) where x in [X_MIN, XMAX[ (x-max not included) + """ + x = X_MIN + while x<X_MAX: + px = x_to_pixel_x(x) + py = y_to_pixel_y(0) + pixel = plot.get_pixel(px, py) + pixel.red = AXIS_COLOR_R + pixel.green = AXIS_COLOR_G + pixel.blue = AXIS_COLOR_B + x+=DELTA_X + return plot + + +def draw_y_axis(plot): + """ + Draw the vertical axis + Set of points for which (0, y) where x in ]Y_MIN, Y_MAX] (Y_MIN not included) + """ + y = Y_MIN + DELTA_Y + while y<Y_MAX: + px = x_to_pixel_x(0) + py = y_to_pixel_y(y) + pixel = plot.get_pixel(px, py) + pixel.red = AXIS_COLOR_R + pixel.green = AXIS_COLOR_G + pixel.blue = AXIS_COLOR_B + y += DELTA_Y + return plot + + +def plot_function(plot): + """ + Draw the points of the function defined by plotted_function() + that are in range + """ + x = X_MIN + while x < X_MAX: + y = ploted_function(x) + if y > Y_MIN and y <= Y_MAX: + px = x_to_pixel_x(x) + py = y_to_pixel_y(y) + pixel = plot.get_pixel(px, py) + pixel.red = PLOT_COLOR_R + pixel.green = PLOT_COLOR_G + pixel.blue = PLOT_COLOR_B + + x += DELTA_X + return plot + + +if __name__ == '__main__': + main()+
+ In this exercice, you are going to write a program that creates the graphical representation of a function of your choice. Like the followings: +
+ ++
+ This is done by findng the pixels that correspond to (x, y) points of the plotted function, and setting the color of those pixels to green. + The axes are also drawn in a similar fashion. +
+ + + ++
x_to_pixel_x()
and y_to_pixel_y()
functions for this purpose. The starter code also contains
+ "doctests" to help you check your implementation. You may run the test cases as follow: python -m doctests your_file.py+
+ A starter code is provided below. This contains useful constants and a suggested high level decomposition of the problem. +
+ ++from simpleimage import SimpleImage +import math + +# Domain of the plot +X_MIN = -10 +X_MAX = 10 + +# Range of the plot +Y_MIN = -10 +Y_MAX = 10 + +# Size of the plot in pixels +PLOT_WIDTH = 400 +PLOT_HEIGHT = 400 + +# Color of the axes +AXIS_COLOR_R = 200 +AXIS_COLOR_G = 0 +AXIS_COLOR_B = 0 + +# Color of the plot +PLOT_COLOR_R = 0 +PLOT_COLOR_G = 200 +PLOT_COLOR_B = 0 + +# x and y step sizes +DELTA_X = 0.01 +DELTA_Y = 0.01 + + +def main(): + """ + Make a blank plot, draw the x and y axis, plot the + function defined by plotted_function and show the plot. + """ + plot = make_blank_plot() + plot = draw_axes(plot) + plot = plot_function(plot) + plot.show() + + +def ploted_function(x): + """ + Compute the y value of the ploted function for the given :param:x value. + Implement a function of your choice + """ + return math.cos(x) + + +def x_to_pixel_x(x): + """ + Compute the horizontal pixel position for horizontal + position :param:x in the plotted coordinate system. + + Test Cases: + + x = 0 should correspond to middle of the plot + >>> x_to_pixel_x(0) + 200 + + x = -10 should correspond to far left of the plot + >>> x_to_pixel_x(-10) + 0 + + x = 10 should correspond to far right of the plot + Note: x=10 is outside of the plotting area + >>> x_to_pixel_x(10) + 400 + """ + + # TODO: Your code here + # calculate the pixel x position and store it in px + + return int(px) + + +def y_to_pixel_y(y): + """ + Compute the horizontal pixel position for vertical + position :param:y in the plotted coordinate system + + Test Cases: + + y = 0 should correspond to the middle of the plot + >>> y_to_pixel_y(0) + 200 + + y=10 should correspond to the top of the plot. + >>> y_to_pixel_y(10) + 0 + + y=-10 should correspond to the bottom of the plot + Note y=-10 is actually outside of the plotting area + >>> y_to_pixel_y(-10) + 400 + """ + + # TODO: your code here + # Calculate the pixel y position and store it in py + + return int(py) + +if __name__ == '__main__': + main() ++ + + diff --git a/examples/graphing-functions/inv.png b/examples/graphing-functions/inv.png new file mode 100644 index 0000000..4f041a4 Binary files /dev/null and b/examples/graphing-functions/inv.png differ diff --git a/examples/graphing-functions/neg_square.png b/examples/graphing-functions/neg_square.png new file mode 100644 index 0000000..7f5396a Binary files /dev/null and b/examples/graphing-functions/neg_square.png differ diff --git a/examples/graphing-functions/simpleimage.py b/examples/graphing-functions/simpleimage.py new file mode 100644 index 0000000..5038794 --- /dev/null +++ b/examples/graphing-functions/simpleimage.py @@ -0,0 +1,264 @@ +#!/usr/bin/env python3 + +""" +Stanford CS106AP SimpleImage + +Written by Nick Parlante, Sonja Johnson-Yu, and Nick Bowman. + -7/2019 version, has file reading, pix, foreach, hidden get/setpix + +SimpleImage Features: +Create image: + image = SimpleImage.blank(400, 200) # create new image of size + image = SimpleImage('foo.jpg') # create from file + +Access size + image.width, image.height + +Get pixel at x,y + pix = image.get_pixel(x, y) + # pix is RGB tuple like (100, 200, 0) + +Set pixel at x,y + image.set_pixel(x, y, pix) # set data by tuple also + +Get Pixel object at x,y + pixel = image.get_pixel(x, y) + pixel.red = 0 + pixel.blue = 255 + +Show image on screen + image.show() + +The main() function below demonstrates the above functions as a test. +""" + +import sys +# If the following line fails, "Pillow" needs to be installed +from PIL import Image + + +def clamp(num): + """ + Return a "clamped" version of the given num, + converted to be an int limited to the range 0..255 for 1 byte. + """ + num = int(num) + if num < 0: + return 0 + if num >= 256: + return 255 + return num + + +class Pixel(object): + """ + A pixel at an x,y in a SimpleImage. + Supports set/get .red .green .blue + and get .x .y + """ + def __init__(self, image, x, y): + self.image = image + self._x = x + self._y = y + + def __str__(self): + return 'r:' + str(self.red) + ' g:' + str(self.green) + ' b:' + str(self.blue) + + # Pillow image stores each pixel color as a (red, green, blue) tuple. + # So the functions below have to unpack/repack the tuple to change anything. + + @property + def red(self): + return self.image.px[self._x, self._y][0] + + @red.setter + def red(self, value): + rgb = self.image.px[self._x, self._y] + self.image.px[self._x, self._y] = (clamp(value), rgb[1], rgb[2]) + + @property + def green(self): + return self.image.px[self._x, self._y][1] + + @green.setter + def green(self, value): + rgb = self.image.px[self._x, self._y] + self.image.px[self._x, self._y] = (rgb[0], clamp(value), rgb[2]) + + @property + def blue(self): + return self.image.px[self._x, self._y][2] + + @blue.setter + def blue(self, value): + rgb = self.image.px[self._x, self._y] + self.image.px[self._x, self._y] = (rgb[0], rgb[1], clamp(value)) + + @property + def x(self): + return self._x + + @property + def y(self): + return self._y + + +# color tuples for background color names 'red' 'white' etc. +BACK_COLORS = { + 'white': (255, 255, 255), + 'black': (0, 0, 0), + 'red': (255, 0, 0), + 'green': (0, 255, 0), + 'blue': (0, 0, 255), +} + + +class SimpleImage(object): + def __init__(self, filename, width=0, height=0, back_color=None): + """ + Create a new image. This case works: SimpleImage('foo.jpg') + To create a blank image use SimpleImage.blank(500, 300) + The other parameters here are for internal/experimental use. + """ + # Create pil_image either from file, or making blank + if filename: + self.pil_image = Image.open(filename).convert("RGB") + if self.pil_image.mode != 'RGB': + raise Exception('Image file is not RGB') + self._filename = filename # hold onto + else: + if not back_color: + back_color = 'white' + color_tuple = BACK_COLORS[back_color] + if width == 0 or height == 0: + raise Exception('Creating blank image requires width/height but got {} {}' + .format(width, height)) + self.pil_image = Image.new('RGB', (width, height), color_tuple) + self.px = self.pil_image.load() + size = self.pil_image.size + self._width = size[0] + self._height = size[1] + self.curr_x = 0 + self.curr_y = 0 + + def __iter__(self): + return self + + def __next__(self): + if self.curr_x < self.width and self.curr_y < self.height: + x = self.curr_x + y = self.curr_y + self.increment_curr_counters() + return Pixel(self, x, y) + else: + self.curr_x = 0 + self.curr_y = 0 + raise StopIteration() + + def increment_curr_counters(self): + self.curr_x += 1 + if self.curr_x == self.width: + self.curr_x = 0 + self.curr_y += 1 + + @classmethod + def blank(cls, width, height, back_color=None): + """Create a new blank image of the given width and height, optional back_color.""" + return SimpleImage('', width, height, back_color=back_color) + + @classmethod + def file(cls, filename): + """Create a new image based on a file, alternative to raw constructor.""" + return SimpleImage(filename) + + @property + def width(self): + """Width of image in pixels.""" + return self._width + + @property + def height(self): + """Height of image in pixels.""" + return self._height + + def get_pixel(self, x, y): + """ + Returns a Pixel at the given x,y, suitable for getting/setting + .red .green .blue values. + """ + if x < 0 or x >= self._width or y < 0 or y >= self.height: + e = Exception('get_pixel bad coordinate x %d y %d (vs. image width %d height %d)' % + (x, y, self._width, self.height)) + raise e + return Pixel(self, x, y) + + def set_pixel(self, x, y, pixel): + if x < 0 or x >= self._width or y < 0 or y >= self.height: + e = Exception('set_pixel bad coordinate x %d y %d (vs. image width %d height %d)' % + (x, y, self._width, self.height)) + raise e + self.px[x, y] = (pixel.red, pixel.green, pixel.blue) + + def set_rgb(self, x, y, red, green, blue): + """ + Set the pixel at the given x,y to have + the given red/green/blue values without + requiring a separate pixel object. + """ + self.px[x, y] = (red, green, blue) + + def _get_pix_(self, x, y): + """Get pix RGB tuple (200, 100, 50) for the given x,y.""" + return self.px[x, y] + + def _set_pix_(self, x, y, pix): + """Set the given pix RGB tuple into the image at the given x,y.""" + self.px[x, y] = pix + + def show(self): + """Displays the image using an external utility.""" + self.pil_image.show() + + def make_as_big_as(self, image): + """Resizes image to the shape of the given image""" + self.pil_image = self.pil_image.resize((image.width, image.height)) + self.px = self.pil_image.load() + size = self.pil_image.size + self._width = size[0] + self._height = size[1] + + +def main(): + """ + main() exercises the features as a test. + 1. With 1 arg like flowers.jpg - opens it + 2. With 0 args, creates a yellow square with + a green stripe at the right edge. + """ + args = sys.argv[1:] + if len(args) == 1: + image = SimpleImage.file(args[0]) + image.show() + return + + # Create yellow rectangle, using foreach iterator + image = SimpleImage.blank(400, 200) + for pixel in image: + pixel.red = 255 + pixel.green = 255 + pixel.blue = 0 + + # for pixel in image: + # print(pixel) + + # Set green stripe using pix access. + pix = image._get_pix_(0, 0) + green = (0, pix[1], 0) + for x in range(image.width - 10, image.width): + for y in range(image.height): + image._set_pix_(x, y, green) + image.show() + + +if __name__ == '__main__': + main() diff --git a/examples/graphing-functions/soln.py b/examples/graphing-functions/soln.py new file mode 100644 index 0000000..a2ea603 --- /dev/null +++ b/examples/graphing-functions/soln.py @@ -0,0 +1,178 @@ +from simpleimage import SimpleImage +import math + +# Domain of the plot +X_MIN = -10 +X_MAX = 10 + +# Range of the plot +Y_MIN = -10 +Y_MAX = 10 + +# Size of the plot in pixels +PLOT_WIDTH = 400 +PLOT_HEIGHT = 400 + +# Color of the axes +AXIS_COLOR_R = 200 +AXIS_COLOR_G = 0 +AXIS_COLOR_B = 0 + +# Color of the plot +PLOT_COLOR_R = 0 +PLOT_COLOR_G = 200 +PLOT_COLOR_B = 0 + +# x and y step sizes +DELTA_X = 0.01 +DELTA_Y = 0.01 + + +def main(): + """ + Make a blank plot, draw the x and y axis, plot the + function defined by plotted_function and show the plot. + """ + plot = make_blank_plot() + plot = draw_axes(plot) + plot = plot_function(plot) + plot.show() + + +def ploted_function(x): + """ + Compute the ploted function at point :param:x + """ + # return math.cos(x) + # return math.tanh(x) + # return x**3 + return x ** 2 + + +def make_blank_plot(): + """ + Create an image with all pixel colors set to black + """ + plot = SimpleImage.blank(PLOT_WIDTH, PLOT_HEIGHT) + for px in plot: + px.red = 0 + px.green = 0 + px.blue = 0 + return plot + + +def x_to_pixel_x(x): + """ + Compute the horizontal pixel position for horizontal + position :param:x in the plotted coordinate system. + + Test Cases: + + x = 0 should correspond to middle of the plot + >>> x_to_pixel_x(0) + 200 + + x = -10 should correspond to far left of the plot + >>> x_to_pixel_x(-10) + 0 + + x = 10 should correspond to far right of the plot + Note: x=10 is outside of the plotting area + >>> x_to_pixel_x(10) + 400 + """ + h_pixel_per_point = PLOT_WIDTH / (X_MAX - X_MIN) + px = x * h_pixel_per_point + PLOT_WIDTH/2 + return int(px) + + +def y_to_pixel_y(y): + """ + Compute the horizontal pixel position for vertical + position :param:y in the plotted coordinate system + + Test Cases: + + y = 0 should correspond to the middle of the plot + >>> y_to_pixel_y(0) + 200 + + y=10 should correspond to the top of the plot. + >>> y_to_pixel_y(10) + 0 + + y=-10 should correspond to the bottom of the plot + Note y=-10 is actually outside of the plotting area + >>> y_to_pixel_y(-10) + 400 + """ + v_pixel_per_point = PLOT_HEIGHT / (Y_MAX - Y_MIN) + py = PLOT_HEIGHT/2 - y * v_pixel_per_point + return int(py) + + +def draw_axes(plot): + """ + Draw the horizontal and vertical axes + """ + draw_x_axis(plot) + draw_y_axis(plot) + return plot + + +def draw_x_axis(plot): + """ + Draw the horizontal axis + Set of points for which (x, 0) where x in [X_MIN, XMAX[ (x-max not included) + """ + x = X_MIN + while x