Различия между версиями 10 и 12 (по 2 версиям)
Версия 10 от 2018-11-28 15:06:33
Размер: 10944
Редактор: FrBrGeorge
Комментарий:
Версия 12 от 2018-11-28 22:44:35
Размер: 11251
Редактор: FrBrGeorge
Комментарий:
Удаления помечены так. Добавления помечены так.
Строка 174: Строка 174:
 1.#0 Внезапно — ничего из учебника, '''TODO''' про масштабирование и графики-ломаные — где?
  * Про черепашку
В домашнем задании используются приёмы непосредственно из лекции. Фактически, это ''одна'' задача, так что не пугайтесь, что она состоит из нескольких пунктов.

 1.#0 Прощёлкать этот конспект, добиться того, чтобы последняя кривая получилась
Строка 177: Строка 178:
 1. <<EJCMC(114, IntervalDots, Забор и щели)>>

Построение графика функции

Разбор Д/З

Про графики

Базовая статья: FrBrGeorge/PythonScaleAndRotate

  • Что такое график?
    • Отображение точек x:f(x)
    • ⇒ f(x) должно ∃
    • Ограничения по началу и концу (не бесконечный, а от A до B)

    • Количество точек в графике? Бесконечно много!
      • ⇒ отрезки, а не непрерывная кривая
      • ⇒ ломаная (N точек, N-1 отрезок)
  • Черепашка и график синуса
    • Повторение: циклический конструктор списка:
        [ выражение for имя in последователоьность ]
          или
        [ выражение for имя, имя in последователоьность_пар]
          и т. п.
        Например, [i*2+1 for i in range(6)]
    • Подготовим черепашье поле
         1 >>> from math import *
         2 >>> from turtle import *
         3 >>> reset()
      
    • Точки — это пары координат (x, y)
    • График — это последовательность таких пар, например
         1 >>> graph = [(-200, -119), (-160, -100), (-120, -57), (-80, 0), (-40, 57), (0, 100), (40, 119), (80, 109), (120, 71), (160, 16), (200, -42)]
         2 >>> def drawgraph(gr):
         3   penup() # Сначала перейдём на начало графика
         4   for x,y in gr:
         5     goto(x,y)
         6     pendown()
         7 
         8 >>> drawgraph(graph)
      
    • Попробуем нарисовать график синуса:
         1 >>> reset()
         2 >>> graph = [(i,sin(i)) for i in range(-100,100)]
         3 >>> drawgraph(graph)
      
      • Фигня какая-то: волняшки слишком частые, но слишком невысокие
    • Масштаб по X и Y:
         1 >>> reset()
         2 >>> graph = [(i,sin(i/20)*60) for i in range(-100,100)]
         3 >>> drawgraph(graph)
      
      • Но это уже непонятно чего график. В каких границах?

Попробуем разобраться

В следующих примерах окно python3 не надо закрывать, иначе придётся заново импортировать math, turtle и определять функции drawgraph() и scale()

Ну, или положить код в файл :)

  • График как список координат
    • В заборе 10 досок, значит, в нём 9 щелей!
    • Количество замеров: график функции f(x) на интервале [a,b]

      • — это ломаная, которая начинается в точке (a,f(a)), а заканчивается в точке (b, f(b)).

      • Если в ней N вершин, то отрезков в ней N-1.

      • Абсциссы вершин находятся на равном расстоянии друг от друга, т. е. на расстоянии (b-a)/(N-1)

    • Допустим, вершин у нас 10, значит, отрезков 9; допусти также, что a=-6, b=3

      • Расстояние между абсциссами (3-(-6))/9 == 1

      • абсцисса 0-й вершины — начало интервала, a, т. е. -6

      • абсцисса 1-й вершины — начало отрезка + первый отрезок, т. е a+(b-a)/(N-1), т. е. -6+1*1 == -5

      • абсцисса 2-й вершины — начало отрезка + первых два отрезка, т. е a+2*(b-a)/(N-1), т. е. -6+2*1 == -4

      • абсцисса 8-й (№ N-2) вершины — a+(N-2)*(b-a)/(N-1), т. е. -6+8*1 == 2

      • абсцисса 9-й (№ N-1) вершины — a+(N-1)*(b-a)/(N-1), т. е. -6+9*1 == 2 (т. е. b)

           1 >>> a, b = -6, 3
           2 >>> N=10
           3 >>> X = [a+i*(b-a)/(N-1) for i in range(N)]
           4 >>> X
           5 [-6.0, -5.0, -4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0]
           6 
        

        Соответственно, значения функции f(x) в этих точках (предположим, f — это sin):

           1 >>> from math import *
           2 >>> f=sin
           3 >>> Y = [f(x) for x in X]
           4 >>> Y
           5 [0.27941549819892586, 0.9589242746631385, 0.7568024953079282, -0.1411200080598672, -0.9092974268256817, -0.8414709848078965, 0.0, 0.8414709848078965, 0.9092974268256817, 0.1411200080598672]
           6 
        
  • Функция масштабирования+переноса (да, это аффинные преобразования, только никому не говорите, а то испугаются).
    • (см. статью) Чтобы превратить точку x0 из диапазона a0,b0 в точку x1 из диапазона a1,b1, надо:

    • составить пропорцию x0 делит отрезок a0,b0 в той же пропорции, что и x1 делит отрезок a1,b1

    • т. е. (x0-a0)/(b0-a0) = (x1-a1)/(b1-a1)

    • и x1 = (x0-a0)/(b0-a0)*(b1-a1)+a1

      • prop.png

    • Напишем функцию scale(), которая это вычисляет:

         1 >>> def scale(x, a0, b0, a1, b1):
         2     """превратить точку x из диапазона a0,b0 в точку x1 из диапазона a1,b1"""
         3     return (x-a0)/(b0-a0)*(b1-a1)+a1
         4 
         5 >>> scale(10,-100,100,-10,10)
         6 1.0
         7 
      
    • То есть список из N штук x-координат точек графика можно представить как scale() счётчика i из диапазона 0,N-1 в диапазон a,b:

         1 >>> N=10
         2 >>> a,b = -6, 3
         3 >>> X = [a+i*(b-a)/(N-1) for i in range(N)]
         4 >>> X
         5 [-6.0, -5.0, -4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0]
         6 >>> X = [scale(i, 0, N-1, a, b) for i in range(N)]
         7 >>> X
         8 [-6.0, -5.0, -4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0]
         9 
      
  • Координаты исходного графика vs координаты на экране
    • Таким образом, в исходном графике функции f(x) x-коорднаты меняются в заданном интервале, а x-координаты — в пределах области значений функции f(x) на этом интервале. Диапазон по x мы задаём, а вот диапазон по y, он же f(x) придётся поискать среди значений функции в точках графика

         1 >>> a, b = -6,3
         2 >>> n = 100
         3 >>> X = [scale(i,0,n-1,a,b) for i in range(n)]
         4 >>> X[0]
         5 -6.0
         6 >>> X[-1]
         7 3.0
         8 >>> f=sin
         9 >>> Y = [f(x) for x in X]
        10 >>> ymin, ymax = min(Y), max(Y)
        11 >>> ymin, ymax
        12 (-0.9996789142433975, 0.9998892390840102)
        13 
      
      • Обратите внимание на то, что диапазон оказался близок, но не равен диапазону «настоящего» синуса (-1 … 1; а почему не равен?)
    • Что касается координат на экране, то они совсем другие. Они зависят от размеров окна (минус размер рамки)
      •    1 >>> reset()
           2 >>> window_width()
           3 800
           4 >>> window_height()
           5 900
           6 >>> Border = 20 # Отступ от края окна
           7 >>> Left, Right = -window_width()/2+Border, window_width()/2-Border
           8 >>> Bottom, Top = -window_height()/2+Border, window_height()/2-Border
           9 >>> Left, Right, Bottom, Top
          10 (-380.0, 380.0, -430.0, 430.0)
          11 >>> for x in Left, Right:
          12 >>>     for y in Bottom, Top:
          13 >>>             goto(x,y)
        
    • Всё готово. Нам нужно нарисовать на экране, координаты которого меняются от Left до Right по x и от Bottom до Top по y, график функции f(x) на n точках в диапазоне от a до b, зная, что f(x) на этом диапазоне принимает значения от miny дол maxy.

      • вычислим координаты точек на экране и нарисуем график!
           1 >>> graphX = [scale(x, a, b, Left, Right) for x in X]
           2 >>> graphY = [scale(y, ymin, ymax, Bottom, Top) for y in Y]
           3 >>> for i in range(len(graphX)):
           4 >>>     goto(graphX[i],graphY[i])
        

        roughsin.png

    • Замечание: надо было сначала переместиться на нулевую точку графика в режиме penup()

    • Замечание: Использование конструкции range(len(graphX)) наводит на мысль, что так можно было не делать. Действительно, можно было воспользоваться zip():

      •    1 >>> for x,y  in zip(graphX, graphY):
           2 >>>    goto(x,y)
        
  • Теперь можно рисовать график любой функции! Вводим строку (в которой есть x), а вместо f(x) обрабатываем эту строку eval():

       1 >>> sf = input()
       2 x/(sin(x)+2)
       3 >>> Y = [eval(sf) for x in X]
       4 >>> # вычисляем и строим график заново …
    
    • formula.png

Д/З

В домашнем задании используются приёмы непосредственно из лекции. Фактически, это одна задача, так что не пугайтесь, что она состоит из нескольких пунктов.

  1. Прощёлкать этот конспект, добиться того, чтобы последняя кривая получилась
  2. TODO

  3. EJudge: IntervalDots 'Забор и щели'

    Ввести (через запятую) три числа: вещественные A и B — границы отрезка по X, и целое N — количество равноудалённых точек на нём. Вывести (через пробел) положение этих точек (их X-координаты).

    Input:

    -3,4,15
    Output:

    -3.0 -2.5 -2.0 -1.5 -1.0 -0.5 0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0
  4. Ввести отрезок, количество точек и ширину экрана, вывести абсциссы точек на экране
  5. Ввести отрезок, количество точек, а также строку — функцию от x (например, x*sin(x**2)), вывести координаты исходных точек графика

  6. Ввести отрезок, количество точек, ширину и высоту экрана, а также строку — функцию от x (например, x*sin(x**2)), вывести координаты точек графика на экране

  7. Нарисовать всё это черепашкой
    • Нарисовать оси координат
    • Что делать, если оси координат лежат в стороне от графика, а рисовать их надо?

Python/PsyPython2018/12_FunctionGraph (последним исправлял пользователь FrBrGeorge 2018-11-29 17:38:32)