# -*- coding: utf-8 -*-
#
#    This file is part of PyNomo -
#    a program to create nomographs with Python (https://github.com/lefakkomies/pynomo)
#
#    Copyright (C) 2007-2019  Leif Roschier  <lefakkomies@users.sourceforge.net>
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

import pyx
import math
import scipy
import numpy
import random
import copy #, re, pprint
import six  # for python 2 and 3 compatibility


class Nomo_Axis:
    """
    Main class to draw axis.
    """

    def __init__(self, func_f, func_g, start, stop, turn, title, canvas, type='linear',
                 text_style='normal', title_x_shift=0, title_y_shift=0.25,
                 tick_levels=4, tick_text_levels=3,
                 text_color=pyx.color.rgb.black, axis_color=pyx.color.rgb.black,
                 manual_axis_data={}, axis_appear={}, side='left',
                 base_start=None, base_stop=None):
        self.titles = []  # holder for titles
        self.func_f = func_f
        self.func_g = func_g
        self.start = start
        self.stop = stop
        self.side = side
        self.turn = turn  # to be removed, use side
        self.title = title
        self.canvas = canvas
        self.title_x_shift = title_x_shift
        self.title_y_shift = title_y_shift
        self.text_style = text_style
        self.tick_levels = tick_levels
        self.tick_text_levels = tick_text_levels
        axis_appear_default_values = {
            'text_distance_0': 1.0,
            'text_distance_1': 1.0 / 4,
            'text_distance_2': 1.0 / 4,
            'text_distance_3': 1.0 / 4,
            'text_distance_4': 1.0 / 4,
            'text_distances': [1.0, 1.0 / 4.0, 1.0 / 4, 1.0 / 4],
            'grid_length_0': 3.0 / 4,
            'grid_length_1': 0.9 / 4,
            'grid_length_2': 0.5 / 4,
            'grid_length_3': 0.3 / 4,
            'grid_length_4': 0.2 / 4,
            'tick_lenghts': [3.0 / 4, 0.9 / 4, 0.5 / 4, 0.3 / 4, 0.2 / 4],
            'text_size_0': pyx.text.size.small,
            'text_size_1': pyx.text.size.scriptsize,
            'text_size_2': pyx.text.size.tiny,
            'text_size_3': pyx.text.size.tiny,
            'text_size_4': pyx.text.size.tiny,
            'text_sizes': [pyx.text.size.small, pyx.text.size.scriptsize,
                           pyx.text.size.tiny, pyx.text.size.tiny, pyx.text.size.tiny],
            'text_size_log_0': pyx.text.size.small,
            'text_size_log_1': pyx.text.size.tiny,
            'text_size_log_2': pyx.text.size.tiny,
            'text_size_manual': pyx.text.size.small,
            'title_distance_center': 0.5,
            'title_opposite_tick': True,
            'title_draw_center': False,
            'title_rotate_text':False,
            'title_relative_offset': (0, 0),  # relative (dx,dy)
            'title_absolute_offset': (0, 0),  # absolute (dx,dy)
            'text_format': "$%4.4g$",
            'text_format_func': None,  # can be used to define f(u) that gives out str
            'full_angle': False,
            'extra_angle': 0.0,
            'text_horizontal_align_center': False,
            'scale_max': None,  # decade for major grids
            'turn_relative': False,  # 'left' and 'right' are relative
            'angle_tick_direction': 'outer',  # for circular scales
            'arrow_size': 0.2,  # for drawing arrow scale
            'arrow_length': 1.0,
            'arrow_color': pyx.color.rgb.black,
            'axis_color': pyx.color.rgb.black,
            'text_color': pyx.color.rgb.black,
            'text_colors': None,
            'title_color': pyx.color.rgb.black,
            'title_extra_angle': 0.0,  # extra rotation
            'tick_color': pyx.color.rgb.black,
            'tick_colors': None,  # can be list of pyx.colors for each tick
            'extra_titles': [],  # list of dicts
            'base_start': None,  # drive tick scaling
            'base_stop': None,  # drive tick scaling
            'tick_distance_smart': 0.05,  # tick minimum distance for smart axes
            'text_distance_smart': 0.25,  # text minimum distance for smart axes
            'linewidth_main': pyx.style.linewidth.normal,
            'linewidth_ticks': pyx.style.linewidth.normal,
            'linewidth_ticks_thin': pyx.style.linewidth.thin,
            'tick_linewidths': [pyx.style.linewidth.normal,
                                pyx.style.linewidth.normal,
                                pyx.style.linewidth.normal,
                                pyx.style.linewidth.thin,
                                pyx.style.linewidth.thin],
            'text_formatter': None,
            # a function of format put_ddmmss_text(u,level,tick_info), see example function put_ddmmss_text implementation as template
            'ticker_func': None,
            # a function of format f(start, stop, f,g,tick_levels,distance_limit_tick, distance_limit_text, tick_info={}), see example function example_ticker implementation as template
            'tick_draw_func': None,  # see template core_tick_draw_func
            'text_draw_func': None,  # see template core_text_draw_func
            'mainline_func': None,  # for custom main-line
            'make_default_main_line': True,  # to draw normal main_line
            # 'level_text_color':None, # list of text pyx.colors for each level
            'level_text_size': None,  # list of text sizes for each level
        }
        self.axis_appear = axis_appear_default_values
        self.axis_appear.update(axis_appear)

        self.arrows = None  # only if axis is arrow axis
        # set axes ticks
        if self.axis_appear['base_start'] is not None:
            base_start_1 = self.axis_appear['base_start']
        else:
            base_start_1 = base_start
        if self.axis_appear['base_stop'] is not None:
            base_stop_1 = self.axis_appear['base_stop']
        else:
            base_stop_1 = base_stop

        if type == 'log':
            self._make_log_axis_(start=start, stop=stop, f=func_f, g=func_g, turn=turn)
            self.draw_axis(canvas)
        if type == 'linear':
            self._make_linear_axis_(start=start, stop=stop, f=func_f, g=func_g, turn=turn,
                                    base_start=base_start_1, base_stop=base_stop_1)
            self.draw_axis(canvas)
        if type == 'linear smart':
            self._make_linear_axis_smart_(start=start, stop=stop, f=func_f, g=func_g, turn=turn,
                                          base_start=base_start_1, base_stop=base_stop_1)
            self.draw_axis(canvas)
        if type == 'log smart':
            self._make_log_axis_smart_(start=start, stop=stop, f=func_f, g=func_g, turn=turn,
                                       base_start=base_start_1, base_stop=base_stop_1)
            self.draw_axis(canvas)
        if type == 'manual point':
            self._make_manual_axis_circle_(manual_axis_data)
            self.draw_axis(canvas)
        if type == 'manual line':
            self._make_manual_axis_line_(manual_axis_data)
            self.draw_axis(canvas)
        if type == 'manual arrow':
            self._make_manual_axis_arrow_(manual_axis_data)
            self.draw_axis(canvas)
        if type == 'general':
            self._make_general_axis_()
        # self.draw_axis(canvas)
        if self.axis_appear['title_draw_center']:
            self._draw_title_center_(canvas)
        else:
            if self.axis_appear['title_rotate_text']:
                self._draw_title_rotate_(canvas)
            else:
                self._draw_title_top_(canvas)
        self._draw_extra_titles_(canvas)

    def _make_general_axis_(self):
        """
        Method to make general axis, uses parameters that can be user defined
        """
        ti = self.axis_appear  # ai = axis info

        # find ticks and texts
        if ti['ticker_func'] is None:
            ticker_func = core_ticker
        else:
            ticker_func = ti['ticker_func']
        ticks, texts = ticker_func(start=self.start, stop=self.stop, f=self.func_f, g=self.func_g,
                                   tick_levels=self.tick_levels, text_levels=self.tick_text_levels,
                                   distance_limit_tick=ti['tick_distance_smart'],
                                   distance_limit_text=ti['text_distance_smart'], tick_info=ti)
        # import pprint
        # pprint.pprint(ticks)
        # pprint.pprint(texts)
        # find directions
        tick_directions = []  # (dx_unit,dy_unit,angle)
        for tick in ticks:
            dx_units, dy_units, angles = find_tick_directions(tick, self.func_f, self.func_g, self.side,
                                                              start=self.start, stop=self.stop,
                                                              full_angle=ti['full_angle'],
                                                              extra_angle=ti['extra_angle'],
                                                              turn_relative=ti['turn_relative'])
            tick_directions.append((dx_units, dy_units, angles))
        text_directions = []  # (dx_units[],dy_units[],angle[])
        for text in texts:
            dx_units, dy_units, angles = find_tick_directions(text, self.func_f, self.func_g, self.side,
                                                              start=self.start, stop=self.stop,
                                                              full_angle=ti['full_angle'],
                                                              extra_angle=ti['extra_angle'],
                                                              turn_relative=ti['turn_relative'])
            text_directions.append((dx_units, dy_units, angles))
        # import pprint
        # pprint.pprint(tick_directions)
        # pprint.pprint(text_directions)

        # make actual drawing
        # select tick draw functions
        if ti['tick_draw_func'] is None:
            tick_draw_func = core_tick_draw_func_basic  # use default
        else:
            tick_draw_func = ti['tick_draw_func']
        # select text draw functions
        if ti['text_draw_func'] is None:
            text_draw_func = core_text_draw_func_basic  # use default
        else:
            text_draw_func = ti['text_draw_func']
        # select main line draw func
        if ti['mainline_func'] is None:
            mainline_draw_func = core_main_line_draw_func_basic  # use default
        else:
            mainline_draw_func = ti['mainline_func']

        # ticks
        for i, tick in enumerate(ticks):
            dx_units, dy_units, angles = tick_directions[i]
            if len(texts) > i:
                text = texts[i]
            else:
                text = []
            tick_draw_func(tick, texts=text, level=i, f=self.func_f, g=self.func_g,
                           dx_units=dx_units, dy_units=dy_units, angles=angles,
                           tick_length=ti['tick_lenghts'][i],
                           text_distance=0,  # dummy
                           text_attr=[],  # dummy here
                           c=self.canvas, tick_info=ti)

        for i, text in enumerate(texts):
            if len(ticks) > i:
                tick = ticks[i]  # dummy
            else:
                tick = []
            dx_units, dy_units, angles = text_directions[i]
            text_attrs = _find_text_attr(text, dx_units, dy_units, angles,
                                         ti['text_sizes'][i], ti)
            text_draw_func(ticks=tick, texts=text, level=i,
                           f=self.func_f, g=self.func_g,
                           dx_units=dx_units, dy_units=dy_units, angles=angles,
                           tick_lenght=0.0,
                           text_distance=ti['text_distances'][i],
                           text_attrs=text_attrs,
                           c=self.canvas, tick_info=ti)
        # main line
        main_line_coords = calc_main_line_coords(self.start, self.stop, self.func_f, self.func_g, sections=350.0)
        if ti['make_default_main_line'] is True:
            mainline_draw_func(main_line_coords=main_line_coords,
                               func_f=self.func_f, func_g=self.func_g,
                               ticks=ticks,
                               tick_directions=tick_directions,
                               texts=texts,
                               text_directions=text_directions,
                               c=self.canvas, tick_info=ti)

    def _test_tick_(self, u, tick, scale_max):
        """ tests if it is time to put a tick
        u=value
        tick=step to put ticks
        scale_max=scale from min to max
        for example:
        u=0.2, tick=0.1 gives True
        u=0.25, tick=0.1 gives False """
        closest_number = _find_closest_tick_number_(u, tick)
        result = False
        if math.fabs(u - closest_number) < (scale_max * 1e-6):
            result = True
        return result
        # return math.fabs(math.modf(u/tick)[0]) < (scale_max*1e-5) or math.fabs((math.modf(u/tick)[0]-1)) < (scale_max*1e-8)

    #    def _find_closest_tick_number_(self,number,tick_divisor):
    #        """
    #        finds closest number with integer number of divisors from zero
    #        """
    #        n=number//tick_divisor
    #        tick_number=n*tick_divisor
    #        error=math.fabs(tick_number-number)
    #        if math.fabs(((n+1)*tick_divisor)-number)< error:
    #            tick_number=(n+1)*tick_divisor
    #            error=math.fabs(tick_number-number)
    #        if math.fabs(((n-1)*tick_divisor)-number)< error:
    #            tick_number=(n-1)*tick_divisor
    #            error=math.fabs(tick_number-number)
    #        return tick_number

    def _make_linear_axis_old_(self, start, stop, f, g, turn=1):
        """
        OBSOLETE, use _make_linear_axis_
        Makes a linear scale according to functions f(u) and g(u)
        with values u in range [start, stop].
        """
        line = pyx.path.path(pyx.path.moveto(f(start), g(start)))
        thin_line = pyx.path.path(pyx.path.moveto(f(start), g(start)))
        # for numerical derivative to find angle
        du = math.fabs(start - stop) * 1e-6
        dy = (g(start + du) - g(start))
        # self._determine_turn_()
        turn = _determine_turn_(f=self.func_f, g=self.func_g, start=self.start,
                                stop=self.stop, side=self.side)
        # turn=self.turn
        # which number to divide. how many decades there are
        ##scale_max=10.0**math.ceil(math.log10(math.fabs(start-stop)))
        scale_max = 10.0 ** round(math.log10(math.fabs(start - stop)))
        tick_min = scale_max / (500.0)
        tick_max = scale_max / 10.0
        tick_1 = scale_max / 20.0
        tick_2 = scale_max / 100.0
        start_new = _find_closest_tick_number_(start, tick_min)
        stop_new = _find_closest_tick_number_(stop, tick_min)
        # print "tick_min %f"%tick_min
        # print "start_new %f"%start_new
        # print "stop_new %f"%stop_new
        texts = list([])
        steps = round(math.fabs(start_new - stop_new) / tick_min) + 1
        for u in scipy.linspace(start_new, stop_new, steps):
            # print u
            dx = (f(u + du) - f(u)) * turn
            dy = (g(u + du) - g(u)) * turn
            dx_unit = dx / math.sqrt(dx ** 2 + dy ** 2)
            dy_unit = dy / math.sqrt(dx ** 2 + dy ** 2)
            if dy_unit != 0:
                angle = -math.atan(dx_unit / dy_unit) * 180 / math.pi
            else:
                angle = 0
            # floating arithmetic makes life difficult, that's why _test_tick_ function
            if self._test_tick_(u, tick_max, scale_max):
                text_distance = self.axis_appear['text_distance_0']
                grid_length = self.axis_appear['grid_length_0']
                if dy <= 0:
                    text_attr = [pyx.text.valign.middle, pyx.text.halign.right, pyx.text.size.small,
                                 pyx.trafo.rotate(angle)]
                else:
                    text_attr = [pyx.text.valign.middle, pyx.text.halign.left, pyx.text.size.small,
                                 pyx.trafo.rotate(angle)]
                # texts.append((`u`,f(u)+text_distance*dy_unit,g(u)-text_distance*dx_unit,text_attr))
                if self.tick_text_levels > 0:
                    texts.append(
                        (self._put_text_(u), f(u) + text_distance * dy_unit, g(u) - text_distance * dx_unit, text_attr))
                line.append(pyx.path.lineto(f(u), g(u)))
                if self.tick_levels > 0:
                    line.append(pyx.path.lineto(f(u) + grid_length * dy_unit, g(u) - grid_length * dx_unit))
                line.append(pyx.path.moveto(f(u), g(u)))
            elif self._test_tick_(u, tick_1, scale_max):
                text_distance = self.axis_appear['text_distance_1']
                grid_length = self.axis_appear['grid_length_1']
                if dy <= 0:
                    text_attr = [pyx.text.valign.middle, pyx.text.halign.right, pyx.text.size.scriptsize,
                                 pyx.trafo.rotate(angle)]
                else:
                    text_attr = [pyx.text.valign.middle, pyx.text.halign.left, pyx.text.size.scriptsize,
                                 pyx.trafo.rotate(angle)]
                if self.tick_text_levels > 1:
                    texts.append(
                        (self._put_text_(u), f(u) + text_distance * dy_unit, g(u) - text_distance * dx_unit, text_attr))
                line.append(pyx.path.lineto(f(u), g(u)))
                if self.tick_levels > 1:
                    line.append(pyx.path.lineto(f(u) + grid_length * dy_unit, g(u) - grid_length * dx_unit))
                line.append(pyx.path.moveto(f(u), g(u)))
            elif self._test_tick_(u, tick_2, scale_max):
                text_distance = self.axis_appear['text_distance_2']
                grid_length = self.axis_appear['grid_length_2']
                if dy <= 0:
                    text_attr = [pyx.text.valign.middle, pyx.text.halign.right, pyx.text.size.tiny,
                                 pyx.trafo.rotate(angle)]
                else:
                    text_attr = [pyx.text.valign.middle, pyx.text.halign.left, pyx.text.size.tiny,
                                 pyx.trafo.rotate(angle)]
                if self.tick_text_levels > 2:
                    texts.append(
                        (self._put_text_(u), f(u) + text_distance * dy_unit, g(u) - text_distance * dx_unit, text_attr))
                line.append(pyx.path.lineto(f(u), g(u)))
                if self.tick_levels > 2:
                    line.append(pyx.path.lineto(f(u) + grid_length * dy_unit, g(u) - grid_length * dx_unit))
                line.append(pyx.path.moveto(f(u), g(u)))
            else:
                grid_length = self.axis_appear['grid_length_3']
                thin_line.append(pyx.path.moveto(f(u), g(u)))
                if self.tick_levels > 3:
                    thin_line.append(pyx.path.lineto(f(u) + grid_length * dy_unit, g(u) - grid_length * dx_unit))
                thin_line.append(pyx.path.moveto(f(u), g(u)))
                line.append(pyx.path.lineto(f(u), g(u)))
        self.line = line
        self.thin_line = thin_line
        self.texts = texts

    def _make_linear_axis_(self, start, stop, f, g, turn=1, base_start=None, base_stop=None):
        """
        Makes a linear scale according to functions f(u) and g(u)
        with values u in range [start, stop].
        """
        # line lists
        main_line = pyx.path.path(pyx.path.moveto(f(start), g(start)))
        line = pyx.path.path(pyx.path.moveto(f(start), g(start)))
        thin_line = pyx.path.path(pyx.path.moveto(f(start), g(start)))
        # text list
        texts = []
        # let's find tick positions
        tick_0_list, tick_1_list, tick_2_list, tick_3_list, tick_4_list, start_ax, stop_ax = \
            find_linear_ticks(start, stop, base_start, base_stop, self.axis_appear['scale_max'])
        # let's find tick angles
        dx_units_0, dy_units_0, angles_0 = find_tick_directions(tick_0_list, f, g, self.side, start, stop,
                                                                full_angle=self.axis_appear['full_angle'],
                                                                extra_angle=self.axis_appear['extra_angle'],
                                                                turn_relative=self.axis_appear['turn_relative'])
        dx_units_1, dy_units_1, angles_1 = find_tick_directions(tick_1_list, f, g, self.side, start, stop,
                                                                full_angle=self.axis_appear['full_angle'],
                                                                extra_angle=self.axis_appear['extra_angle'],
                                                                turn_relative=self.axis_appear['turn_relative'])
        dx_units_2, dy_units_2, angles_2 = find_tick_directions(tick_2_list, f, g, self.side, start, stop,
                                                                full_angle=self.axis_appear['full_angle'],
                                                                extra_angle=self.axis_appear['extra_angle'],
                                                                turn_relative=self.axis_appear['turn_relative'])
        dx_units_3, dy_units_3, angles_3 = find_tick_directions(tick_3_list, f, g, self.side, start, stop,
                                                                full_angle=self.axis_appear['full_angle'],
                                                                extra_angle=self.axis_appear['extra_angle'],
                                                                turn_relative=self.axis_appear['turn_relative'])
        dx_units_4, dy_units_4, angles_4 = find_tick_directions(tick_4_list, f, g, self.side, start, stop,
                                                                full_angle=self.axis_appear['full_angle'],
                                                                extra_angle=self.axis_appear['extra_angle'],
                                                                turn_relative=self.axis_appear['turn_relative'])

        # tick level 0
        if self.tick_levels > 0:
            self._make_tick_lines_(tick_0_list, line, f, g, dx_units_0, dy_units_0,
                                   self.axis_appear['grid_length_0'])
        # text level 0
        if self.tick_text_levels > 0:
            self._make_texts_(tick_0_list, texts, f, g, dx_units_0, dy_units_0, angles_0,
                              self.axis_appear['text_distance_0'],
                              self.axis_appear['text_size_0'])
        # tick level 1
        if self.tick_levels > 1:
            self._make_tick_lines_(tick_1_list, line, f, g, dx_units_1, dy_units_1,
                                   self.axis_appear['grid_length_1'])
        # text level 1
        if self.tick_text_levels > 1:
            self._make_texts_(tick_1_list, texts, f, g, dx_units_1, dy_units_1, angles_1,
                              self.axis_appear['text_distance_1'],
                              self.axis_appear['text_size_1'])
        # tick level 2
        if self.tick_levels > 2:
            self._make_tick_lines_(tick_2_list, line, f, g, dx_units_2, dy_units_2,
                                   self.axis_appear['grid_length_2'])
        # text level 2
        if self.tick_text_levels > 2:
            self._make_texts_(tick_2_list, texts, f, g, dx_units_2, dy_units_2, angles_2,
                              self.axis_appear['text_distance_2'],
                              self.axis_appear['text_size_2'])
        # tick level 3
        if self.tick_levels > 3:
            self._make_tick_lines_(tick_3_list, thin_line, f, g, dx_units_3, dy_units_3,
                                   self.axis_appear['grid_length_3'])
        # text level 3
        if self.tick_text_levels > 3:
            self._make_texts_(tick_3_list, texts, f, g, dx_units_3, dy_units_3, angles_3,
                              self.axis_appear['text_distance_3'],
                              self.axis_appear['text_size_3'])
        # tick level 4
        if self.tick_levels > 4:
            self._make_tick_lines_(tick_4_list, thin_line, f, g, dx_units_4, dy_units_4,
                                   self.axis_appear['grid_length_4'])
        # text level 4
        if self.tick_text_levels > 4:
            self._make_texts_(tick_4_list, texts, f, g, dx_units_4, dy_units_4, angles_4,
                              self.axis_appear['text_distance_4'],
                              self.axis_appear['text_size_4'])
        # make main line
        self._make_main_line_(start, stop, main_line, f, g)

        self.line = line
        self.thin_line = thin_line
        self.main_line = main_line
        self.texts = texts
        self.tick_0_list = tick_0_list
        self.tick_1_list = tick_1_list
        self.tick_2_list = tick_2_list
        self.tick_3_list = tick_3_list
        self.tick_4_list = tick_4_list

        self.text_0_list = tick_0_list
        self.text_1_list = tick_1_list
        self.text_2_list = tick_2_list
        self.text_3_list = tick_3_list
        self.text_4_list = tick_4_list

    def _make_linear_axis_smart_(self, start, stop, f, g, turn=1, base_start=None, base_stop=None):
        """
        Makes a linear scale according to functions f(u) and g(u)
        with values u in range [start, stop].
        """
        # line lists
        line = pyx.path.path(pyx.path.moveto(f(start), g(start)))
        thin_line = pyx.path.path(pyx.path.moveto(f(start), g(start)))
        main_line = pyx.path.path(pyx.path.moveto(f(start), g(start)))
        # text list
        texts = []
        # let's find tick positions
        #        tick_0_list,tick_1_list,tick_2_list,tick_3_list,tick_4_list,start_ax,stop_ax=\
        #        find_linear_ticks(start,stop,base_start,base_stop,self.axis_appear['scale_max'])
        tick_0_list, tick_1_list, tick_2_list, tick_3_list, tick_4_list = \
            find_linear_ticks_smart(start, stop, f, g, turn=1, base_start=base_start,
                                    base_stop=base_stop, scale_max_0=self.axis_appear['scale_max'],
                                    distance_limit=self.axis_appear['tick_distance_smart'])
        text_0_list, text_1_list, text_2_list, text_3_list, text_4_list = \
            find_linear_ticks_smart(start, stop, f, g, turn=1, base_start=base_start,
                                    base_stop=base_stop, scale_max_0=self.axis_appear['scale_max'],
                                    distance_limit=self.axis_appear['text_distance_smart'])
        remove_text_if_not_tick(tick_0_list, text_0_list)
        remove_text_if_not_tick(tick_1_list, text_1_list)
        remove_text_if_not_tick(tick_2_list, text_2_list)
        remove_text_if_not_tick(tick_3_list, text_3_list)
        remove_text_if_not_tick(tick_4_list, text_4_list)

        #        pprint.pprint("text_list %s"%text_0_list)
        #        pprint.pprint("tick_list %s"%tick_0_list)
        # let's find tick angles
        dx_units_0, dy_units_0, angles_0 = find_tick_directions(tick_0_list, f, g, self.side, start, stop,
                                                                full_angle=self.axis_appear['full_angle'],
                                                                extra_angle=self.axis_appear['extra_angle'],
                                                                turn_relative=self.axis_appear['turn_relative'])
        dx_units_1, dy_units_1, angles_1 = find_tick_directions(tick_1_list, f, g, self.side, start, stop,
                                                                full_angle=self.axis_appear['full_angle'],
                                                                extra_angle=self.axis_appear['extra_angle'],
                                                                turn_relative=self.axis_appear['turn_relative'])
        dx_units_2, dy_units_2, angles_2 = find_tick_directions(tick_2_list, f, g, self.side, start, stop,
                                                                full_angle=self.axis_appear['full_angle'],
                                                                extra_angle=self.axis_appear['extra_angle'],
                                                                turn_relative=self.axis_appear['turn_relative'])
        dx_units_3, dy_units_3, angles_3 = find_tick_directions(tick_3_list, f, g, self.side, start, stop,
                                                                full_angle=self.axis_appear['full_angle'],
                                                                extra_angle=self.axis_appear['extra_angle'],
                                                                turn_relative=self.axis_appear['turn_relative'])
        dx_units_4, dy_units_4, angles_4 = find_tick_directions(tick_4_list, f, g, self.side, start, stop,
                                                                full_angle=self.axis_appear['full_angle'],
                                                                extra_angle=self.axis_appear['extra_angle'],
                                                                turn_relative=self.axis_appear['turn_relative'])
        # let's find text angles
        dx_units_0_text, dy_units_0_text, angles_0_text = find_tick_directions(text_0_list, f, g, self.side, start,
                                                                               stop, full_angle=self.axis_appear[
                'full_angle'], extra_angle=self.axis_appear['extra_angle'], turn_relative=self.axis_appear[
                'turn_relative'])
        dx_units_1_text, dy_units_1_text, angles_1_text = find_tick_directions(text_1_list, f, g, self.side, start,
                                                                               stop, full_angle=self.axis_appear[
                'full_angle'], extra_angle=self.axis_appear['extra_angle'], turn_relative=self.axis_appear[
                'turn_relative'])
        dx_units_2_text, dy_units_2_text, angles_2_text = find_tick_directions(text_2_list, f, g, self.side, start,
                                                                               stop, full_angle=self.axis_appear[
                'full_angle'], extra_angle=self.axis_appear['extra_angle'], turn_relative=self.axis_appear[
                'turn_relative'])
        dx_units_3_text, dy_units_3_text, angles_3_text = find_tick_directions(text_3_list, f, g, self.side, start,
                                                                               stop, full_angle=self.axis_appear[
                'full_angle'], extra_angle=self.axis_appear['extra_angle'], turn_relative=self.axis_appear[
                'turn_relative'])
        dx_units_4_text, dy_units_4_text, angles_4_text = find_tick_directions(text_4_list, f, g, self.side, start,
                                                                               stop, full_angle=self.axis_appear[
                'full_angle'], extra_angle=self.axis_appear['extra_angle'], turn_relative=self.axis_appear[
                'turn_relative'])

        # tick level 0
        if self.tick_levels > 0:
            self._make_tick_lines_(tick_0_list, line, f, g, dx_units_0, dy_units_0,
                                   self.axis_appear['grid_length_0'])
        # text level 0
        if self.tick_text_levels > 0:
            self._make_texts_(text_0_list, texts, f, g, dx_units_0_text, dy_units_0_text, angles_0_text,
                              self.axis_appear['text_distance_0'],
                              self.axis_appear['text_size_0'])
        # tick level 1
        if self.tick_levels > 1:
            self._make_tick_lines_(tick_1_list, line, f, g, dx_units_1, dy_units_1,
                                   self.axis_appear['grid_length_1'])
        # text level 1
        if self.tick_text_levels > 1:
            self._make_texts_(text_1_list, texts, f, g, dx_units_1_text, dy_units_1_text, angles_1_text,
                              self.axis_appear['text_distance_1'],
                              self.axis_appear['text_size_1'])
        # tick level 2
        if self.tick_levels > 2:
            self._make_tick_lines_(tick_2_list, line, f, g, dx_units_2, dy_units_2,
                                   self.axis_appear['grid_length_2'])
        # text level 2
        if self.tick_text_levels > 2:
            self._make_texts_(text_2_list, texts, f, g, dx_units_2_text, dy_units_2_text, angles_2_text,
                              self.axis_appear['text_distance_2'],
                              self.axis_appear['text_size_2'])
        # tick level 3
        if self.tick_levels > 3:
            self._make_tick_lines_(tick_3_list, thin_line, f, g, dx_units_3, dy_units_3,
                                   self.axis_appear['grid_length_3'])
        # text level 3
        if self.tick_text_levels > 3:
            self._make_texts_(text_3_list, texts, f, g, dx_units_3_text, dy_units_3_text, angles_3_text,
                              self.axis_appear['text_distance_3'],
                              self.axis_appear['text_size_3'])
        # tick level 4
        if self.tick_levels > 4:
            self._make_tick_lines_(tick_4_list, thin_line, f, g, dx_units_4, dy_units_4,
                                   self.axis_appear['grid_length_4'])
        # text level 4
        if self.tick_text_levels > 4:
            self._make_texts_(text_4_list, texts, f, g, dx_units_4_text, dy_units_4_text, angles_4_text,
                              self.axis_appear['text_distance_4'],
                              self.axis_appear['text_size_4'])
        # make main line
        self._make_main_line_(start, stop, main_line, f, g)

        self.line = line
        self.thin_line = thin_line
        self.main_line = main_line
        self.texts = texts
        self.tick_0_list = tick_0_list
        self.tick_1_list = tick_1_list
        self.tick_2_list = tick_2_list
        self.tick_3_list = tick_3_list
        self.tick_4_list = tick_4_list

        self.text_0_list = text_0_list
        self.text_1_list = text_1_list
        self.text_2_list = text_2_list
        self.text_3_list = text_3_list
        self.text_4_list = text_4_list

    def _make_log_axis_smart_(self, start, stop, f, g, turn=1, base_start=None, base_stop=None):
        """
        Makes a linear scale according to functions f(u) and g(u)
        with values u in range [start, stop].
        """
        # line lists
        line = pyx.path.path(pyx.path.moveto(f(start), g(start)))
        thin_line = pyx.path.path(pyx.path.moveto(f(start), g(start)))
        main_line = pyx.path.path(pyx.path.moveto(f(start), g(start)))
        # text list
        texts = []
        # let's find tick positions
        #        tick_0_list,tick_1_list,tick_2_list,tick_3_list,tick_4_list,start_ax,stop_ax=\
        #        find_linear_ticks(start,stop,base_start,base_stop,self.axis_appear['scale_max'])
        if start > stop:
            start, stop = stop, start
        if start > 0 and stop > 0:
            tick_0_list, tick_1_list, tick_2_list, tick_3_list, tick_4_list = \
                find_log_ticks_smart(start, stop, f, g, turn=1, base_start=base_start,
                                     base_stop=base_stop,
                                     distance_limit=self.axis_appear['tick_distance_smart'])
            text_0_list, text_1_list, text_2_list, text_3_list, text_4_list = \
                find_log_ticks_smart(start, stop, f, g, turn=1, base_start=base_start,
                                     base_stop=base_stop,
                                     distance_limit=self.axis_appear['text_distance_smart'])
        if start < 0 and stop < 0:
            tick_0_list, tick_1_list, tick_2_list, tick_3_list, tick_4_list = \
                find_log_ticks_negative_smart(start, stop, f, g, turn=1, base_start=base_start,
                                              base_stop=base_stop,
                                              distance_limit=self.axis_appear['tick_distance_smart'])
            text_0_list, text_1_list, text_2_list, text_3_list, text_4_list = \
                find_log_ticks_negative_smart(start, stop, f, g, turn=1, base_start=base_start,
                                              base_stop=base_stop,
                                              distance_limit=self.axis_appear['text_distance_smart'])

        if start < 0 and stop > 0:
            # negative side
            start_decade = math.floor(math.log10(-start))
            if 10 ** start_decade == -start:
                start_decate = start_decade - 1
            # initialize
            distance = 2 * self.axis_appear['text_distance_smart']
            while distance > self.axis_appear['text_distance_smart']:
                start_decade = start_decade - 1
                distance = calc_distance(f, g, -10 ** (start_decade), -10 ** (start_decade - 1))

            # positive side
            stop_decade = math.floor(math.log10(stop))
            if 10 ** start_decade == stop:
                stop_decate = stop_decade - 1
            # initialize
            distance = 2 * self.axis_appear['text_distance_smart']
            while distance > self.axis_appear['text_distance_smart']:
                stop_decade = stop_decade - 1
                distance = calc_distance(f, g, 10 ** (stop_decade), 10 ** (stop_decade - 1))
            # make the ticks
            start_decade = start_decade + 1
            stop_decade = stop_decade + 1
            print("start_decade value %f" % -10 ** start_decade)
            print("stop_decade value %f" % 10 ** stop_decade)
            tick_0_list_n, tick_1_list_n, tick_2_list_n, tick_3_list_n, tick_4_list_n = \
                find_log_ticks_negative_smart(start, -10 ** (start_decade) * 1.0001, f, g, turn=1, base_start=None,
                                              base_stop=None,
                                              distance_limit=self.axis_appear['tick_distance_smart'])
            text_0_list_n, text_1_list_n, text_2_list_n, text_3_list_n, text_4_list_n = \
                find_log_ticks_negative_smart(start, -10 ** (start_decade) * 1.0001, f, g, turn=1, base_start=None,
                                              base_stop=None,
                                              distance_limit=self.axis_appear['text_distance_smart'])

            tick_0_list_p, tick_1_list_p, tick_2_list_p, tick_3_list_p, tick_4_list_p = \
                find_log_ticks_smart(10 ** (stop_decade) * 1.0001, stop, f, g, turn=1, base_start=None,
                                     base_stop=None,
                                     distance_limit=self.axis_appear['tick_distance_smart'])
            text_0_list_p, text_1_list_p, text_2_list_p, text_3_list_p, text_4_list_p = \
                find_log_ticks_smart(10 ** (stop_decade) * 1.0001, stop, f, g, turn=1, base_start=None,
                                     base_stop=None,
                                     distance_limit=self.axis_appear['text_distance_smart'])
            # middle
            tick_0_list_mn, tick_1_list_mn, tick_2_list_mn, tick_3_list_mn, tick_4_list_mn = \
                find_linear_ticks_smart(-10 ** (start_decade), 0, f, g, turn=1, base_start=None,
                                        base_stop=None, scale_max_0=10 * 10 ** (start_decade),
                                        distance_limit=self.axis_appear['tick_distance_smart'])
            text_0_list_mn, text_1_list_mn, text_2_list_mn, text_3_list_mn, text_4_list_mn = \
                find_linear_ticks_smart(-10 ** (start_decade), 0, f, g, turn=1, base_start=None,
                                        base_stop=None, scale_max_0=10 * 10 ** (start_decade),
                                        distance_limit=self.axis_appear['text_distance_smart'])
            tick_0_list_mp, tick_1_list_mp, tick_2_list_mp, tick_3_list_mp, tick_4_list_mp = \
                find_linear_ticks_smart(0, 10 ** (stop_decade), f, g, turn=1, base_start=None,
                                        base_stop=None, scale_max_0=10 * 10 ** (stop_decade),
                                        distance_limit=self.axis_appear['tick_distance_smart'])
            text_0_list_mp, text_1_list_mp, text_2_list_mp, text_3_list_mp, text_4_list_mp = \
                find_linear_ticks_smart(0, 10 ** (stop_decade), f, g, turn=1, base_start=None,
                                        base_stop=None, scale_max_0=10 * 10 ** (stop_decade),
                                        distance_limit=self.axis_appear['text_distance_smart'])

            tick_0_list = tick_0_list_n + tick_0_list_p + tick_0_list_mn + tick_0_list_mp
            tick_1_list = tick_1_list_n + tick_1_list_p + tick_1_list_mn + tick_1_list_mp
            tick_2_list = tick_2_list_n + tick_2_list_p + tick_2_list_mn + tick_2_list_mp
            tick_3_list = tick_3_list_n + tick_3_list_p + tick_3_list_mn + tick_3_list_mp
            tick_4_list = tick_4_list_n + tick_4_list_p
            text_0_list = text_0_list_n + text_0_list_p + text_0_list_mn + text_0_list_mp
            text_1_list = text_1_list_n + text_1_list_p + text_1_list_mn + text_1_list_mp
            text_2_list = text_2_list_n + text_2_list_p + text_2_list_mn + text_2_list_mp
            text_3_list = text_3_list_n + text_3_list_p + text_3_list_mn + text_3_list_mp
            text_4_list = text_4_list_n + text_4_list_p
            remove_multiple_and_sort(tick_0_list)
            remove_multiple_and_sort(tick_1_list)
            remove_multiple_and_sort(tick_2_list)
            remove_multiple_and_sort(tick_3_list)
            remove_multiple_and_sort(tick_4_list)
            remove_multiple_and_sort(text_0_list)
            remove_multiple_and_sort(text_1_list)
            remove_multiple_and_sort(text_2_list)
            remove_multiple_and_sort(text_3_list)
            remove_multiple_and_sort(text_4_list)
            # manual removing of possible top clashes
            if max(tick_0_list) == max(tick_1_list):
                tick_1_list.remove(max(tick_1_list))
            if max(text_0_list) == max(text_1_list):
                text_1_list.remove(max(text_1_list))
            if min(tick_0_list) == min(tick_1_list):
                tick_1_list.remove(min(tick_1_list))
            if min(text_0_list) == min(text_1_list):
                text_1_list.remove(min(text_1_list))
        ##pprint.pprint("text_list %s"%text_0_list)
        ##pprint.pprint("tick_list %s"%tick_0_list)
        # let's find tick angles
        dx_units_0, dy_units_0, angles_0 = find_tick_directions(tick_0_list, f, g, self.side, start, stop,
                                                                full_angle=self.axis_appear['full_angle'],
                                                                extra_angle=self.axis_appear['extra_angle'],
                                                                turn_relative=self.axis_appear['turn_relative'])
        dx_units_1, dy_units_1, angles_1 = find_tick_directions(tick_1_list, f, g, self.side, start, stop,
                                                                full_angle=self.axis_appear['full_angle'],
                                                                extra_angle=self.axis_appear['extra_angle'],
                                                                turn_relative=self.axis_appear['turn_relative'])
        dx_units_2, dy_units_2, angles_2 = find_tick_directions(tick_2_list, f, g, self.side, start, stop,
                                                                full_angle=self.axis_appear['full_angle'],
                                                                extra_angle=self.axis_appear['extra_angle'],
                                                                turn_relative=self.axis_appear['turn_relative'])
        dx_units_3, dy_units_3, angles_3 = find_tick_directions(tick_3_list, f, g, self.side, start, stop,
                                                                full_angle=self.axis_appear['full_angle'],
                                                                extra_angle=self.axis_appear['extra_angle'],
                                                                turn_relative=self.axis_appear['turn_relative'])
        dx_units_4, dy_units_4, angles_4 = find_tick_directions(tick_4_list, f, g, self.side, start, stop,
                                                                full_angle=self.axis_appear['full_angle'],
                                                                extra_angle=self.axis_appear['extra_angle'],
                                                                turn_relative=self.axis_appear['turn_relative'])
        # let's find text angles
        dx_units_0_text, dy_units_0_text, angles_0_text = find_tick_directions(text_0_list, f, g, self.side, start,
                                                                               stop, full_angle=self.axis_appear[
                'full_angle'], extra_angle=self.axis_appear['extra_angle'], turn_relative=self.axis_appear[
                'turn_relative'])
        dx_units_1_text, dy_units_1_text, angles_1_text = find_tick_directions(text_1_list, f, g, self.side, start,
                                                                               stop, full_angle=self.axis_appear[
                'full_angle'], extra_angle=self.axis_appear['extra_angle'], turn_relative=self.axis_appear[
                'turn_relative'])
        dx_units_2_text, dy_units_2_text, angles_2_text = find_tick_directions(text_2_list, f, g, self.side, start,
                                                                               stop, full_angle=self.axis_appear[
                'full_angle'], extra_angle=self.axis_appear['extra_angle'], turn_relative=self.axis_appear[
                'turn_relative'])
        dx_units_3_text, dy_units_3_text, angles_3_text = find_tick_directions(text_3_list, f, g, self.side, start,
                                                                               stop, full_angle=self.axis_appear[
                'full_angle'], extra_angle=self.axis_appear['extra_angle'], turn_relative=self.axis_appear[
                'turn_relative'])
        dx_units_4_text, dy_units_4_text, angles_4_text = find_tick_directions(text_4_list, f, g, self.side, start,
                                                                               stop, full_angle=self.axis_appear[
                'full_angle'], extra_angle=self.axis_appear['extra_angle'], turn_relative=self.axis_appear[
                'turn_relative'])

        # let's save them
        self.dx_units_0 = dx_units_0
        self.dx_units_1 = dx_units_1
        self.dx_units_2 = dx_units_2
        self.dx_units_3 = dx_units_3
        self.dx_units_4 = dx_units_4

        self.tick_0_list = tick_0_list
        self.tick_1_list = tick_1_list
        self.tick_2_list = tick_2_list
        self.tick_3_list = tick_3_list
        self.tick_4_list = tick_4_list

        self.text_0_list = text_0_list
        self.text_1_list = text_1_list
        self.text_2_list = text_2_list
        self.text_3_list = text_3_list
        self.text_4_list = text_4_list

        # tick level 0
        if self.tick_levels > 0:
            self._make_tick_lines_(tick_0_list, line, f, g, dx_units_0, dy_units_0,
                                   self.axis_appear['grid_length_0'])
        # text level 0
        if self.tick_text_levels > 0:
            self._make_texts_(text_0_list, texts, f, g, dx_units_0_text, dy_units_0_text, angles_0_text,
                              self.axis_appear['text_distance_0'],
                              self.axis_appear['text_size_0'])
        # tick level 1
        if self.tick_levels > 1:
            self._make_tick_lines_(tick_1_list, line, f, g, dx_units_1, dy_units_1,
                                   self.axis_appear['grid_length_1'])
        # text level 1
        if self.tick_text_levels > 1:
            self._make_texts_(text_1_list, texts, f, g, dx_units_1_text, dy_units_1_text, angles_1_text,
                              self.axis_appear['text_distance_1'],
                              self.axis_appear['text_size_1'])
        # tick level 2
        if self.tick_levels > 2:
            self._make_tick_lines_(tick_2_list, line, f, g, dx_units_2, dy_units_2,
                                   self.axis_appear['grid_length_2'])
        # text level 2
        if self.tick_text_levels > 2:
            self._make_texts_(text_2_list, texts, f, g, dx_units_2_text, dy_units_2_text, angles_2_text,
                              self.axis_appear['text_distance_2'],
                              self.axis_appear['text_size_2'])
        # tick level 3
        if self.tick_levels > 3:
            self._make_tick_lines_(tick_3_list, thin_line, f, g, dx_units_3, dy_units_3,
                                   self.axis_appear['grid_length_3'])
        # text level 3
        if self.tick_text_levels > 3:
            self._make_texts_(text_3_list, texts, f, g, dx_units_3_text, dy_units_3_text, angles_3_text,
                              self.axis_appear['text_distance_3'],
                              self.axis_appear['text_size_3'])
        # tick level 4
        if self.tick_levels > 4:
            self._make_tick_lines_(tick_4_list, thin_line, f, g, dx_units_4, dy_units_4,
                                   self.axis_appear['grid_length_4'])
        # text level 4
        if self.tick_text_levels > 4:
            self._make_texts_(text_4_list, texts, f, g, dx_units_4_text, dy_units_4_text, angles_4_text,
                              self.axis_appear['text_distance_4'],
                              self.axis_appear['text_size_4'])
        # make main line
        self._make_main_line_(start, stop, main_line, f, g)

        self.line = line
        self.thin_line = thin_line
        self.main_line = main_line
        self.texts = texts

    def _make_log_axis_(self, start, stop, f, g, turn=1):
        """
        Makes a log scale
        """
        # line lists
        line = pyx.path.path(pyx.path.moveto(f(start), g(start)))
        thin_line = pyx.path.path(pyx.path.moveto(f(start), g(start)))
        main_line = pyx.path.path(pyx.path.moveto(f(start), g(start)))
        # text list
        texts = []
        # let's find tick positions
        tick_0_list, tick_1_list, tick_2_list, start_ax, stop_ax = \
            find_log_ticks(start, stop)
        # let's find tick angles
        dx_units_0, dy_units_0, angles_0 = find_tick_directions(tick_0_list, f, g, self.side, start, stop,
                                                                full_angle=self.axis_appear['full_angle'],
                                                                extra_angle=self.axis_appear['extra_angle'],
                                                                turn_relative=self.axis_appear['turn_relative'])
        dx_units_1, dy_units_1, angles_1 = find_tick_directions(tick_1_list, f, g, self.side, start, stop,
                                                                full_angle=self.axis_appear['full_angle'],
                                                                extra_angle=self.axis_appear['extra_angle'],
                                                                turn_relative=self.axis_appear['turn_relative'])
        dx_units_2, dy_units_2, angles_2 = find_tick_directions(tick_2_list, f, g, self.side, start, stop,
                                                                full_angle=self.axis_appear['full_angle'],
                                                                extra_angle=self.axis_appear['extra_angle'],
                                                                turn_relative=self.axis_appear['turn_relative'])

        # tick level 0
        if self.tick_levels > 0:
            self._make_tick_lines_(tick_0_list, line, f, g, dx_units_0, dy_units_0,
                                   self.axis_appear['grid_length_0'])
        # text level 0
        if self.tick_text_levels > 0:
            self._make_texts_(tick_0_list, texts, f, g, dx_units_0, dy_units_0, angles_0,
                              self.axis_appear['text_distance_0'],
                              self.axis_appear['text_size_log_0'])
        # tick level 1
        if self.tick_levels > 1:
            self._make_tick_lines_(tick_1_list, line, f, g, dx_units_1, dy_units_1,
                                   self.axis_appear['grid_length_1'])
        # text level 1
        if self.tick_text_levels > 1:
            self._make_texts_(tick_1_list, texts, f, g, dx_units_1, dy_units_1, angles_1,
                              self.axis_appear['text_distance_1'],
                              self.axis_appear['text_size_log_1'])  # smaller with log axis
        # tick level 2
        if self.tick_levels > 2:
            self._make_tick_lines_(tick_2_list, line, f, g, dx_units_2, dy_units_2,
                                   self.axis_appear['grid_length_2'])
        # text level 2
        if self.tick_text_levels > 2:
            self._make_texts_(tick_2_list, texts, f, g, dx_units_2, dy_units_2, angles_2,
                              self.axis_appear['text_distance_2'],
                              self.axis_appear['text_size_log_2'])

        # make main line
        self._make_main_line_(start, stop, main_line, f, g)

        self.line = line
        self.thin_line = thin_line
        self.main_line = main_line
        self.texts = texts
        self.tick_0_list = tick_0_list
        self.tick_1_list = tick_1_list
        self.tick_2_list = tick_2_list
        # self.tick_3_list=tick_3_list
        # self.tick_4_list=tick_4_list

        self.text_0_list = tick_0_list
        self.text_1_list = tick_1_list
        self.text_2_list = tick_2_list
        # self.text_3_list=tick_3_list
        # self.text_4_list=tick_4_list

    def _make_texts_(self, tick_list, text_list, f, g, dx_units, dy_units, angles,
                     text_distance, text_size, manual_texts=[]):
        """
        makes list of text definitions
        """
        for idx, u in enumerate(tick_list):
            if dy_units[idx] < 0:
                text_attr = [pyx.text.valign.middle, pyx.text.halign.right, text_size, pyx.trafo.rotate(angles[idx])]
            else:
                text_attr = [pyx.text.valign.middle, pyx.text.halign.left, text_size, pyx.trafo.rotate(angles[idx])]
            if self.axis_appear['full_angle'] == True:
                if self.axis_appear['angle_tick_direction'] == 'outer':
                    text_attr = [pyx.text.valign.middle, pyx.text.halign.left, text_size, pyx.trafo.rotate(angles[idx])]
                else:  # 'inner'
                    text_attr = [pyx.text.valign.middle, pyx.text.halign.left, text_size, pyx.trafo.rotate(angles[idx])]
            if self.axis_appear['text_horizontal_align_center'] == True:
                text_attr = [pyx.text.valign.top, pyx.text.halign.center, text_size, pyx.trafo.rotate(angles[idx])]
            if len(manual_texts) > 0:
                text_list.append((manual_texts[idx], f(u) + text_distance * dy_units[idx], \
                                  g(u) - text_distance * dx_units[idx], text_attr))
            else:  # make a number
                text_list.append((self._put_text_(u), f(u) + text_distance * dy_units[idx],
                                  g(u) - text_distance * dx_units[idx], text_attr))

    def _make_tick_lines_(self, tick_list, tick_lines, f, g, dx_units, dy_units,
                          tick_length):
        """
        appends to list tick_list lines to be tick markers
        """
        for idx, u in enumerate(tick_list):
            tick_lines.append(pyx.path.moveto(f(u), g(u)))
            tick_lines.append(pyx.path.lineto(f(u) + tick_length * dy_units[idx],
                                              g(u) - tick_length * dx_units[idx]))

    def _make_arrows_(self, tick_list, tick_lines, f, g, dx_units, dy_units,
                      arrow_length):
        """
        appends to list tick_list lines to be tick markers
        """
        for idx, u in enumerate(tick_list):
            tick_lines.append(pyx.path.line(f(u) + arrow_length * dy_units[idx],
                                            g(u) - arrow_length * dx_units[idx],
                                            f(u) + 0.02 * dy_units[idx],
                                            g(u) - 0.02 * dx_units[idx]))

    def _make_main_line_(self, start, stop, main_line, f, g, sections=350.0):
        """
        draws the major skeleton of axis
        """
        if start > stop:
            start, stop = stop, start
        du = math.fabs(stop - start) * 1e-12
        # approximate line length is found
        line_length_straigth = math.sqrt((f(start) - f(stop)) ** 2 + (g(start) - g(stop)) ** 2)
        random.seed(0.0)  # so that mistakes always the same
        for dummy in range(100):  # for case if start = stop
            first = random.uniform(start, stop)
            second = random.uniform(start, stop)
            temp = math.sqrt((f(first) - f(second)) ** 2 + (g(first) - g(second)) ** 2)
            if temp > line_length_straigth:
                line_length_straigth = temp
                # print "length: %f"%line_length_straigth
        # sections=350.0 # about number of sections
        section_length = line_length_straigth / sections
        u = start
        laskuri = 1
        main_line.append(pyx.path.moveto(f(start), g(start)))
        while True:
            if u < stop:
                main_line.append(pyx.path.lineto(f(u), g(u)))
                dx = (f(u + du) - f(u))
                dy = (g(u + du) - g(u))
                dl = math.sqrt(dx ** 2 + dy ** 2)
                if dl > 0:
                    delta_u = du * section_length / dl
                else:
                    delta_u = du
                # in order to avoid too slow derivatives
                if math.fabs(stop - start) < (delta_u * 100.0):
                    delta_u = math.fabs(stop - start) / 500.0
                u += delta_u

            else:
                main_line.append(pyx.path.lineto(f(stop), g(stop)))
                break

    def _find_center_value_(self, start, stop, f, g):
        """
        finds value of approximate centerpoint of line
        """
        if start > stop:
            start, stop = stop, start
        du = math.fabs(stop - start) * 1e-12
        # approximate line length is found
        line_length_straigth = math.sqrt((f(start) - f(stop)) ** 2 + (g(start) - g(stop)) ** 2)
        random.seed(0.0)  # so that mistakes always the same
        for dummy in range(100):  # for case if start = stop
            first = random.uniform(start, stop)
            second = random.uniform(start, stop)
            temp = math.sqrt((f(first) - f(second)) ** 2 + (g(first) - g(second)) ** 2)
            if temp > line_length_straigth:
                line_length_straigth = temp
                # print "length: %f"%line_length_straigth
        sections = 350.0  # about number of sections
        section_length = line_length_straigth / sections
        # let's start length
        u = start
        length = 0.0
        counter = 0
        while True:
            if u < stop:
                dx = (f(u + du) - f(u))
                dy = (g(u + du) - g(u))
                dl = math.sqrt(dx ** 2 + dy ** 2)
                if dl > 0:
                    delta_u = du * section_length / dl
                else:
                    delta_u = du
                length += section_length
                u += delta_u
            else:
                break
                # counter+=1
                # print counter
        # print "length %g" % length
        # let's find middlepoint
        u = start
        length_0 = 0.0
        counter = 0
        while True:
            if length_0 < (length / 2.0):
                dx = (f(u + du) - f(u))
                dy = (g(u + du) - g(u))
                dl = math.sqrt(dx ** 2 + dy ** 2)
                if dl > 0:
                    delta_u = du * section_length / dl
                else:
                    delta_u = du
                length_0 += section_length
                u += delta_u
            else:
                break
            counter += 1
            # print counter
            # print length_0
        return u

    def _make_log_axis_old(self, start, stop, f, g, turn=1):
        """
        OBSOLETE
        draw logarithmic axis
        """
        # for numerical derivative to find angle
        du = math.fabs(start - stop) * 1e-6
        # self._determine_turn_()
        turn = _determine_turn_(f=self.func_f, g=self.func_g, start=self.start,
                                stop=self.stop, side=self.side)
        # turn=self.turn
        texts = list([])
        if (start < stop):
            min = start
            max = stop
        else:
            min = stop
            max = start
        line = pyx.path.path(pyx.path.moveto(f(min), g(min)))
        thin_line = pyx.path.path(pyx.path.moveto(f(min), g(min)))
        max_decade = math.ceil(math.log10(max))
        min_decade = math.floor(math.log10(min))
        for decade in numpy.arange(min_decade, max_decade + 1, 1):
            for number in scipy.concatenate((numpy.arange(1, 2, 0.2), numpy.arange(2, 3, 0.5), numpy.arange(3, 10, 1))):
                u = number * 10.0 ** decade
                if (u - min) > 0:  # to avoid too big du values
                    du = (u - min) * 1e-6
                dx = (f(u + du) - f(u)) * turn
                dy = (g(u + du) - g(u)) * turn
                dx_unit = dx / math.sqrt(dx ** 2 + dy ** 2)
                dy_unit = dy / math.sqrt(dx ** 2 + dy ** 2)
                if dy_unit != 0:
                    angle = -math.atan(dx_unit / dy_unit) * 180 / math.pi
                else:
                    angle = 0
                if u >= min and u <= max:
                    line.append(pyx.path.lineto(f(u), g(u)))
                    if (number == 1):
                        text_distance = self.axis_appear['text_distance_0']
                        grid_length = self.axis_appear['grid_length_0']
                        if dy <= 0:
                            text_attr = [pyx.text.valign.middle, pyx.text.halign.right, pyx.text.size.small,
                                         pyx.trafo.rotate(angle)]
                        else:
                            text_attr = [pyx.text.valign.middle, pyx.text.halign.left, pyx.text.size.small,
                                         pyx.trafo.rotate(angle)]
                        if self.tick_text_levels > 0:
                            texts.append((self._put_text_(u), f(u) + text_distance * dy_unit,
                                          g(u) - text_distance * dx_unit, text_attr))
                        # line.append(pyx.path.lineto(f(u), g(u)))
                        if self.tick_levels > 0:
                            line.append(pyx.path.lineto(f(u) + grid_length * dy_unit, g(u) - grid_length * dx_unit))
                        line.append(pyx.path.moveto(f(u), g(u)))
                    else:
                        if number in [2, 3, 4, 5, 6, 7, 8, 9]:
                            text_distance = self.axis_appear['text_distance_1']
                            grid_length = self.axis_appear['grid_length_1']
                        else:
                            text_distance = self.axis_appear['text_distance_2']
                            grid_length = self.axis_appear['grid_length_2']
                        if dy <= 0:
                            text_attr = [pyx.text.valign.middle, pyx.text.halign.right, pyx.text.size.tiny,
                                         pyx.trafo.rotate(angle)]
                        else:
                            text_attr = [pyx.text.valign.middle, pyx.text.halign.left, pyx.text.size.tiny,
                                         pyx.trafo.rotate(angle)]
                        if self.tick_text_levels > 1:
                            texts.append((self._put_text_(u), f(u) + text_distance * dy_unit,
                                          g(u) - text_distance * dx_unit, text_attr))
                        # thin_line.append(pyx.path.lineto(f(u), g(u)))
                        if self.tick_levels > 1:
                            if number in [2, 3, 4, 5, 6, 7, 8, 9]:
                                line.append(pyx.path.moveto(f(u), g(u)))
                                line.append(pyx.path.lineto(f(u) + grid_length * dy_unit, g(u) - grid_length * dx_unit))
                            else:
                                thin_line.append(pyx.path.moveto(f(u), g(u)))
                                thin_line.append(
                                    pyx.path.lineto(f(u) + grid_length * dy_unit, g(u) - grid_length * dx_unit))
                            line.append(pyx.path.lineto(f(u), g(u)))
        self.line = line
        self.thin_line = thin_line
        self.texts = texts

    def _make_manual_axis_circle_(self, manual_axis_data):
        """
        draws axis with only circles and texts
        """
        f = self.func_f
        g = self.func_g
        # self._determine_turn_()
        turn = _determine_turn_(f=self.func_f, g=self.func_g, start=self.start,
                                stop=self.stop, side=self.side)
        # turn=self.turn
        texts = list([])
        line = pyx.path.path(pyx.path.moveto(f(self.start), g(self.start)))
        thin_line = pyx.path.path(pyx.path.moveto(f(self.start), g(self.start)))
        main_line = pyx.path.path(pyx.path.moveto(f(self.start), g(self.start)))
        for number, label_string in six.iteritems(manual_axis_data):
            text_distance = 1.0 / 4
            text_size = self.axis_appear['text_size_manual']
            if self.side == 'left':
                text_attr = [pyx.text.valign.middle, pyx.text.halign.right, text_size]
                texts.append((label_string, f(number) - text_distance,
                              g(number), text_attr))
            else:
                text_attr = [pyx.text.valign.middle, pyx.text.halign.left, text_size]
                texts.append((label_string, f(number) + text_distance,
                              g(number), text_attr))
            self.canvas.fill(pyx.path.circle(f(number), g(number), 0.02))
        self.line = line
        self.thin_line = thin_line
        self.main_line = main_line
        self.texts = texts

    def _make_manual_axis_arrow_(self, manual_axis_data):
        """
        Makes manual axis with arrows
        """
        f = self.func_f
        g = self.func_g
        start = self.start
        stop = self.stop
        # self._determine_turn_()
        # line lists
        line = pyx.path.path(pyx.path.moveto(f(self.start), g(self.start)))
        thin_line = pyx.path.path(pyx.path.moveto(f(self.start), g(self.start)))
        main_line = pyx.path.path(pyx.path.moveto(f(start), g(start)))
        arrows = []
        # text list
        texts = []  # pyx structure
        text_strings = []
        tick_list = []
        # let's find tick positions'
        #        manual_axis_data.sort()
        #        for number, label_string in manual_axis_data.iteritems():
        #            tick_list.append(number)
        #            text_strings.append(label_string)

        keys = manual_axis_data.keys()
        # keys.sort()
        keys = sorted(keys)  # to make work in python3
        for key in keys:
            tick_list.append(key)
            text_strings.append(manual_axis_data[key])

        # let's find tick angles
        dx_units, dy_units, angles = find_tick_directions(tick_list, f, g, self.side, start, stop,
                                                          full_angle=self.axis_appear['full_angle'],
                                                          extra_angle=self.axis_appear['extra_angle'],
                                                          turn_relative=self.axis_appear['turn_relative'])

        # ticks = arrows
        if self.tick_levels > 0:
            self._make_arrows_(tick_list, arrows, f, g, dx_units, dy_units,
                               self.axis_appear['arrow_length'])
        # texts
        if self.tick_text_levels > 0:
            self._make_texts_(tick_list, texts, f, g, dx_units, dy_units, angles,
                              self.axis_appear['arrow_length'] + 0.15,
                              self.axis_appear['text_size_0'],
                              manual_texts=text_strings)
        # make main line
        self._make_main_line_(start, stop, line, f, g)

        self.line = line
        self.thin_line = thin_line
        self.main_line = main_line
        self.texts = texts
        self.arrows = arrows

    def _make_manual_axis_line_(self, manual_axis_data):
        """
        draws axis with texts, line and ticks where texts are
        """
        # for numerical derivative to find angle
        f = self.func_f
        g = self.func_g
        # self._determine_turn_()
        turn = _determine_turn_(f=self.func_f, g=self.func_g, start=self.start,
                                stop=self.stop, side=self.side)
        # turn=self.turn
        du = math.fabs(self.start - self.stop) * 1e-6
        texts = list([])
        if (self.start < self.stop):
            min = self.start
            max = self.stop
            turn = turn * -1.0
        else:
            min = self.stop
            max = self.start
        # lets make the line
        line_length_straigth = math.sqrt((f(max) - f(min)) ** 2 + (g(max) - g(min)) ** 2)
        sections = 300.0  # about number of sections
        section_length = line_length_straigth / sections
        line = pyx.path.path(pyx.path.moveto(f(self.start), g(self.start)))
        thin_line = pyx.path.path(pyx.path.moveto(f(self.start), g(self.start)))
        main_line = pyx.path.path(pyx.path.moveto(f(min), g(min)))
        u = min
        while u < max:
            dx = (f(u + du) - f(u)) * turn
            dy = (g(u + du) - g(u)) * turn
            dl = math.sqrt(dx ** 2 + dy ** 2)
            delta_u = du * section_length / dl
            u += delta_u
            line.append(pyx.path.lineto(f(u), g(u)))
        # make lines and texts
        turn_original = turn
        for number, label_def in six.iteritems(manual_axis_data):
            turn = turn_original
            x_corr = 0.0  # shifts for labels
            y_corr = 0.0
            # if set, text pos set according to rel (dx,dy) in tick coords
            manual_relative_text_pos = None
            # if set manual line drawn
            manual_relative_line = None
            # if set, set manual text align
            manual_text_align = None
            draw_extra_line = False  # no extra line
            range_tick = False  # tick or range
            range_end = 0.0
            range_side = -1.0
            if type(label_def) is list:
                title_raw = label_def[0]
                ex_params = label_def[1]
                if 'manual_relative_text_pos' in ex_params:  # (dx,dy)
                    manual_relative_text_pos = ex_params['manual_relative_text_pos']
                if 'manual_text_align' in ex_params:  # e.g.[pyx.text.valign.middle,text.halign.right]
                    manual_text_align = ex_params['manual_text_align']
                if 'manual_relative_line' in ex_params:  # e.g. [(0,0),(1,2),(5,5)]
                    manual_relative_line = ex_params['manual_relative_line']
                if 'x_corr' in ex_params:
                    x_corr = ex_params['x_corr']
                if 'y_corr' in ex_params:
                    y_corr = ex_params['y_corr']
                if 'draw_line' in ex_params:
                    draw_extra_line = ex_params['draw_line']
                if 'change_side' in ex_params:
                    if ex_params['change_side']:  # change to opposite side
                        turn *= (-1.0)
                        range_side = 1.0
                if 'range_end' in ex_params:
                    range_end = ex_params['range_end']
                    range_tick = True
                label_string = title_raw
            else:
                label_string = label_def

            dx = (f(number + du) - f(number)) * turn
            dy = (g(number + du) - g(number)) * turn
            dx_unit = dx / math.sqrt(dx ** 2 + dy ** 2)
            dy_unit = dy / math.sqrt(dx ** 2 + dy ** 2)
            #            if dy_unit!=0:
            #                angle=-math.atan(dx_unit/dy_unit)*180/math.pi
            #            else:
            #                angle=0
            if not self.axis_appear['full_angle']:
                if dy_unit != 0:
                    angle = -math.atan(dx_unit / dy_unit) * 180 / math.pi
                else:
                    angle = 0
            if self.axis_appear['full_angle']:
                if dy_unit != 0:
                    angle = -math.atan(dx_unit / dy_unit) * 180 / math.pi
                else:
                    angle = 0
                if scipy.sign(dx_unit) < 0 and scipy.sign(dy_unit) < 0:
                    angle = angle - 180
                if scipy.sign(dy_unit) < 0 and scipy.sign(dx_unit) >= 0:
                    angle = angle + 180
            angle = angle + self.axis_appear['extra_angle']

            text_distance = self.axis_appear['text_distance_1']
            grid_length = self.axis_appear['grid_length_1']
            text_size = self.axis_appear['text_size_manual']
            # text alignment defs
            if manual_text_align != None:  # set manual values for align
                text_attr = [pyx.trafo.rotate(angle)]
                text_attr.extend(manual_text_align)
            else:  # do the default
                if dy <= 0:
                    text_attr = [pyx.text.valign.middle, pyx.text.halign.left, text_size, pyx.trafo.rotate(angle)]
                else:
                    text_attr = [pyx.text.valign.middle, pyx.text.halign.right, text_size, pyx.trafo.rotate(angle)]
                if self.axis_appear['text_horizontal_align_center'] == True:
                    text_attr = [pyx.text.valign.middle, pyx.text.halign.center, text_size, pyx.trafo.rotate(angle)]
            # normal case (not range)
            if range_tick == False:
                if manual_relative_text_pos == None:  # do default text positioning
                    texts.append((label_string, f(number) - text_distance * dy_unit + x_corr,
                                  g(number) + text_distance * dx_unit + y_corr, text_attr))
                else:  # do manual text position
                    if type(manual_relative_text_pos) is not tuple:
                        print("'manual_relative_text_pos' should be tuple (dx,dy)")
                    dx_rel = manual_relative_text_pos[0]
                    dy_rel = manual_relative_text_pos[1]
                    texts.append((label_string,
                                  f(number) - (dy_rel * dy_unit) + (dx_rel * dx_unit) + x_corr,
                                  g(number) + (dy_rel * dx_unit) + (dx_rel * dy_unit) + y_corr, text_attr))
                if manual_relative_line == None:  # default line tick drawing
                    line.append(pyx.path.moveto(f(number), g(number)))
                    line.append(pyx.path.lineto(f(number) - grid_length * dy_unit, g(number) + grid_length * dx_unit))
                else:  # manual line tick drawing
                    if type(manual_relative_line) is not list:
                        print("'manual_relative_line' should be list [(x0,y0),(x1,y1),...]")
                        print(manual_relative_line)
                    line.append(pyx.path.moveto(f(number), g(number)))
                    x_orig = f(number)
                    y_orig = g(number)
                    for coords in manual_relative_line:
                        x_curr = coords[0]  # current coordinates
                        y_curr = coords[1]
                        # coord transforms
                        x_coord = x_orig + x_curr * dx_unit - y_curr * dy_unit
                        y_coord = y_orig + y_curr * dx_unit + x_curr * dy_unit
                        # print "coords:%g,%g"%(x_coord,y_coord)                        
                        line.append(pyx.path.lineto(x_coord, y_coord))
            else:  # range_tick == True
                tick_list = [number, range_end]
                dx_units, dy_units, angles = find_tick_directions(tick_list, f, g, self.side, number, range_end,
                                                                  full_angle=self.axis_appear['full_angle'],
                                                                  extra_angle=self.axis_appear['extra_angle'],
                                                                  turn_relative=self.axis_appear['turn_relative'])
                # correction needed for some reason
                dx_units[0], dx_units[1] = range_side * dx_units[0], range_side * dx_units[1]
                dy_units[0], dy_units[1] = range_side * dy_units[0], range_side * dy_units[1]
                # first tick
                line.append(pyx.path.moveto(f(number), g(number)))
                line.append(
                    pyx.path.lineto(f(number) - grid_length * dy_units[0], g(number) + grid_length * dx_units[0]))
                # second tick
                line.append(pyx.path.moveto(f(range_end), g(range_end)))
                line.append(
                    pyx.path.lineto(f(range_end) - grid_length * dy_units[1], g(range_end) + grid_length * dx_units[1]))
                # text
                x0 = (f(number) + f(range_end)) / 2.0
                y0 = (g(number) + g(range_end)) / 2.0
                dx_unit = (dx_units[0] + dx_units[1]) / 2.0  # tick directions is average of range end directions
                dy_unit = (dy_units[0] + dy_units[1]) / 2.0
                texts.append((
                    label_string, x0 - text_distance * dy_unit + x_corr, y0 + text_distance * dx_unit + y_corr,
                    text_attr))
                self._make_main_line_(number, range_end, main_line, f, g, sections=35.0)
            if draw_extra_line:
                line.append(
                    pyx.path.lineto(f(number) - grid_length * dy_unit + x_corr,
                                    g(number) + grid_length * dx_unit + y_corr))
                # self.canvas.fill(pyx.path.circle(f(number), g(number), 0.02))
        self._make_main_line_(min, max, main_line, f, g)
        self.line = line
        self.thin_line = thin_line
        self.main_line = main_line
        self.texts = texts

    def draw_axis(self, c):
        arrow_color = self.axis_appear['arrow_color']
        text_color = self.axis_appear['text_color']
        axis_color = self.axis_appear['axis_color']
        linewidth_ticks = self.axis_appear['linewidth_ticks']
        linewidth_ticks_thin = self.axis_appear['linewidth_ticks_thin']
        linewidth_main = self.axis_appear['linewidth_main']
        # c.stroke(self.line, [pyx.style.linewidth.normal,axis_color])
        # c.stroke(self.thin_line, [pyx.style.linewidth.thin,axis_color])
        c.stroke(self.line, [linewidth_ticks, axis_color, pyx.style.linecap.butt])
        c.stroke(self.thin_line, [linewidth_ticks_thin, axis_color, pyx.style.linecap.butt])
        c.stroke(self.main_line, [linewidth_main, axis_color, pyx.style.linecap.square])
        if self.arrows is not None:
            for arrow in self.arrows:
                c.stroke(arrow,
                         [pyx.style.linewidth.thick, arrow_color,
                          pyx.deco.earrow([pyx.deco.stroked([arrow_color]),
                                       pyx.deco.filled([arrow_color])], size=self.axis_appear['arrow_size'])])
        for ttext, x, y, attr in self.texts:
            c.text(x, y, ttext, attr + [text_color])

    def _draw_title_top_(self, c):
        """
         make title to top
        """
        best_u = self.start
        y_max = self.func_g(best_u)
        if self.func_g(self.stop) > y_max:
            y_max = self.func_g(self.stop)
            best_u = self.stop
        for dummy in range(500):
            number = random.uniform(min(self.start, self.stop), max(self.start, self.stop))
            y_value = self.func_g(number)
            if y_value > y_max:
                y_max = y_value
                best_u = number
        c.text(self.func_f(best_u) + self.title_x_shift,
               self.func_g(best_u) + self.title_y_shift,
               self.title, [pyx.text.halign.center, self.axis_appear['title_color']])

        self.titles.append((self.title, self.func_f(best_u) + self.title_x_shift,
                            self.func_g(best_u) + self.title_y_shift,
                            [pyx.text.halign.center, self.axis_appear['title_color']]))

    #        # find out if start or stop has higher y-value
    #        if self.func_g(self.stop)>self.func_g(self.start):
    #            c.text(self.func_f(self.stop)+self.title_x_shift,
    #                    self.func_g(self.stop)+self.title_y_shift,
    #                    self.title,[pyx.text.halign.center])
    #        else:
    #            c.text(self.func_f(self.start)+self.title_x_shift,
    #                    self.func_g(self.start)+self.title_y_shift, self.title,
    #                    [pyx.text.halign.center])

    def _draw_title_center_(self, c):
        """
        draws axis title to the axis center
        """
        f = self.func_f
        g = self.func_g
        u_mid = self._find_center_value_(self.start, self.stop, f, g)
        # u_mid=(self.start+self.stop)/2.0
        # x_start=f(self.start)
        # x_stop=f(self.stop)
        # y_start=g(self.start)
        # y_stop=g(self.stop)
        # center_x=(x_start+x_stop)/2.0
        # center_y=(y_start+y_stop)/2.0
        center_x = f(u_mid)
        center_y = g(u_mid)

        du = math.fabs(self.start - self.stop) * 1e-6
        turn = self.turn
        if not self.axis_appear['title_opposite_tick']:
            turn = turn * (-1)
        dx = (f(u_mid + du) - f(u_mid)) * turn
        dy = (g(u_mid + du) - g(u_mid)) * turn
        dx_unit = dx / math.sqrt(dx ** 2 + dy ** 2)
        dy_unit = dy / math.sqrt(dx ** 2 + dy ** 2)
        dx_absolute = self.axis_appear['title_absolute_offset'][0]
        dy_absolute = self.axis_appear['title_absolute_offset'][1]
        dx_rel = self.axis_appear['title_relative_offset'][0]
        dy_rel = self.axis_appear['title_relative_offset'][1]
        dx_relative = -dy_rel * dy_unit + dx_rel * dx_unit
        dy_relative = dy_rel * dx_unit + dx_rel * dy_unit
        if dy_unit != 0:
            angle = -math.atan(dx_unit / dy_unit) * 180 / math.pi + 90.0
        else:
            angle = 0 - 90.0
        if self.axis_appear['full_angle'] == False:
            angle = (angle + 90) % 180 - 90
        else:
            angle = angle + 180.0
        angle += self.axis_appear['title_extra_angle']
        text_distance = self.axis_appear['title_distance_center']
        c.text(center_x - text_distance * dy_unit + dx_absolute + dx_relative,
               center_y + text_distance * dx_unit + dy_absolute + dy_relative,
               self.title, [pyx.text.halign.center, pyx.trafo.rotate(angle),
                            self.axis_appear['title_color']])
        
        self.titles.append((self.title, center_x - text_distance * dy_unit,
                            center_y + text_distance * dx_unit,
                            [pyx.text.halign.center, pyx.trafo.rotate(angle),
                             self.axis_appear['title_color']]))

        # text_attr=[pyx.text.valign.middle,text.halign.left,text.size.small,pyx.trafo.rotate(angle)]
        # texts.append((label_string,f(number)-text_distance*dy_unit,g(number)+text_distance*dx_unit,text_attr))

    def _draw_title_rotate_(self, c):
        """
        draws axis title to the top but rotate to align with axis
        """

        best_u = self.start
        y_max = self.func_g(best_u)
        if self.func_g(self.stop) > y_max:
            y_max = self.func_g(self.stop)
            best_u = self.stop
        for dummy in range(500):
            number = random.uniform(min(self.start, self.stop), max(self.start, self.stop))
            y_value = self.func_g(number)
            if y_value > y_max:
                y_max = y_value
                best_u = number
        
        f = self.func_f
        g = self.func_g
        u_mid = self._find_center_value_(self.start, self.stop, f, g)

        du = math.fabs(self.start - self.stop) * 1e-6
        turn = self.turn

        dx = (f(u_mid + du) - f(u_mid)) * turn
        dy = (g(u_mid + du) - g(u_mid)) * turn

        dx_unit = dx / math.sqrt(dx ** 2 + dy ** 2)
        dy_unit = dy / math.sqrt(dx ** 2 + dy ** 2)

        if dy_unit != 0:
            angle = -math.atan(dx_unit / dy_unit) * 180 / math.pi
        else:
            angle = -180.0

        c.text(self.func_f(best_u) + self.title_x_shift,
               self.func_g(best_u) + self.title_y_shift,
               self.title, [pyx.trafo.rotate(angle), pyx.text.halign.center, self.axis_appear['title_color']])

        self.titles.append((self.title, self.func_f(best_u) + self.title_x_shift,
                            self.func_g(best_u) + self.title_y_shift,
                            [pyx.trafo.rotate(angle),pyx.text.halign.center, self.axis_appear['title_color']]))

    def _draw_extra_titles_(self, c):
        """
        draws extra titles to top
        """
        best_u = self.start
        y_max = self.func_g(best_u)
        if self.func_g(self.stop) > y_max:
            y_max = self.func_g(self.stop)
            best_u = self.stop
        for dummy in range(500):
            number = random.uniform(min(self.start, self.stop), max(self.start, self.stop))
            y_value = self.func_g(number)
            if y_value > y_max:
                y_max = y_value
                best_u = number
                #        c.text(self.func_f(best_u)+self.title_x_shift,
                #                self.func_g(best_u)+self.title_y_shift,
                #                self.title,[pyx.text.halign.center,self.axis_appear['title_color']])

        text_default = {'dx': 0.0,
                        'dy': 0.0,
                        'text': 'no text defined...',
                        'width': 5,
                        'pyx_extra_defs': []
                        }
        if len(self.axis_appear['extra_titles']) > 0:
            for texts in self.axis_appear['extra_titles']:
                for key in text_default:
                    if key not in texts:
                        texts[key] = text_default[key]
                dx = texts['dx']
                dy = texts['dy']
                text_str = texts['text']
                width = texts['width']
                pyx_extra_defs = texts['pyx_extra_defs']
                #                c.text(x,y,text_str,[pyx.text.parbox(width)]+pyx_extra_defs)
                c.text(self.func_f(best_u) + dx,
                       self.func_g(best_u) + dy,
                       text_str, [pyx.text.parbox(width)] + pyx_extra_defs)
                self.titles.append((self.func_f(best_u) + dx,
                                    self.func_g(best_u) + dy,
                                    text_str, [pyx.text.parbox(width)] + pyx_extra_defs))

    def _put_text_(self, u):
        if self.text_style == 'oldstyle':
            return r"$\oldstylenums{%3.2f}$ " % u
        else:
            # return r"$%3.2f$ " %u
            return self.axis_appear['text_format'] % u


# def _determine_turn_(self):
#        """
#         determines if we are going upwards or downwards at start
#        """
#        g=self.func_g
#        f=self.func_f
#        start=self.start
#        stop=self.stop
#        du=(stop-start)*1e-6
#        dy=(g(start+du)-g(start))
#        if dy<=0 and self.side=='left':
#            self.turn=1.0
#        if dy>0 and self.side=='left':
#            self.turn=-1.0
#        if dy<=0 and self.side=='right':
#            self.turn=-1.0
#        if dy>0 and self.side=='right':
#            self.turn=1.0

def _determine_turn_(f, g, start, stop, side, turn_relative=False):
    """
     determines if we are going upwards or downwards at start
    _determine_turn_(f=self.func_f,g=self.func_g,start=self.start,
                     stop=self.stop,side=self.side)
     turn_0 is for overriding the calculation
    """
    du = (stop - start) * 1e-6
    dy = (g(start + du) - g(start))
    turn = 1.0  # just in case nothing found
    if dy <= 0 and side == 'left':
        turn = 1.0
    if dy > 0 and side == 'left':
        turn = -1.0
    if dy <= 0 and side == 'right':
        turn = -1.0
    if dy > 0 and side == 'right':
        turn = 1.0
    if turn_relative == True:
        if side == 'right':
            turn = 1.0
        else:  # 'left'
            turn = -1.0
    return turn


def _find_closest_tick_number_(number, tick_divisor):
    """
    finds closest number with integer number of divisors from zero
    """
    n = number // tick_divisor
    tick_number = n * tick_divisor
    error = math.fabs(tick_number - number)
    if math.fabs(((n + 1) * tick_divisor) - number) < error:
        tick_number = (n + 1) * tick_divisor
        error = math.fabs(tick_number - number)
    if math.fabs(((n - 1) * tick_divisor) - number) < error:
        tick_number = (n - 1) * tick_divisor
        error = math.fabs(tick_number - number)
    return tick_number


def _find_text_attr(tick_list, dx_units, dy_units, angles, text_size, tick_info):
    """
    helper function to generate text attributes (text_attrs) of form
    text_attrs[][vertical align, horizontal align,]
    """
    text_attrs = []
    for idx, u in enumerate(tick_list):
        if dy_units[idx] < 0:
            text_attr = [pyx.text.valign.middle, pyx.text.halign.right, text_size, pyx.trafo.rotate(angles[idx])]
        else:
            text_attr = [pyx.text.valign.middle, pyx.text.halign.left, text_size, pyx.trafo.rotate(angles[idx])]
        if tick_info['full_angle'] == True:
            if tick_info['angle_tick_direction'] == 'outer':
                text_attr = [pyx.text.valign.middle, pyx.text.halign.left, text_size, pyx.trafo.rotate(angles[idx])]
            else:  # 'inner'
                text_attr = [pyx.text.valign.middle, pyx.text.halign.left, text_size, pyx.trafo.rotate(angles[idx])]
        if tick_info['text_horizontal_align_center'] == True:
            text_attr = [pyx.text.valign.top, pyx.text.halign.center, text_size, pyx.trafo.rotate(angles[idx])]
        t_dict = {'valign': text_attr[0],
                  'halign': text_attr[1],
                  'size': text_attr[2],
                  'angle': text_attr[3],
                  'all': text_attr}
        text_attrs.append(t_dict)
    return text_attrs


def find_linear_ticks(start, stop, base_start=None, base_stop=None, scale_max_0=None):
    """
    finds tick values for linear axis
    """
    if start > stop:
        start, stop = stop, start
    if (base_start != None) and (base_stop != None):
        scale_max = 10.0 ** math.ceil(math.log10(math.fabs(base_start - base_stop)) - 0.5)
    else:
        scale_max = 10.0 ** math.ceil(math.log10(math.fabs(start - stop)) - 0.5)
    if scale_max_0 != None:
        scale_max = scale_max_0  # set range manually
    tick_0 = scale_max / 10.0
    tick_1 = scale_max / 20.0
    tick_2 = scale_max / 100.0
    tick_3 = scale_max / 500.0
    tick_4 = scale_max / 1000.0

    tick_0_list = []
    tick_1_list = []
    tick_2_list = []
    tick_3_list = []
    tick_4_list = []
    start_major = _find_closest_tick_number_(start, tick_0) - tick_0
    stop_major = _find_closest_tick_number_(stop, tick_0) + tick_0
    # print "scale_max %f"%scale_max
    # print "start %f"%start
    # print "start_major %f"%start_major
    # print "stop_major %f"%stop_major
    start_ax = None
    stop_ax = None
    steps = (stop - start_major) / tick_4 + 2
    # print "steps %i"%steps
    for step in range(0, int(steps)):  # used to be 9001
        number = start_major + step * tick_4
        if number >= start and number <= (stop * (1 + 1e-6)):  # stupid numerical correction
            if start_ax == None:
                start_ax = number
            stop_ax = number
            if step % 100 == 0:
                tick_0_list.append(number)
            if step % 50 == 0 and step % 100 != 0:
                tick_1_list.append(number)
            if step % 10 == 0 and step % 50 != 0 and step % 100 != 0:
                tick_2_list.append(number)
            if step % 5 == 0 and step % 10 != 0 and step % 50 != 0 and step % 100 != 0:
                tick_3_list.append(number)
            if step % 1 == 0 and step % 5 != 0 and step % 10 != 0 and step % 50 != 0 and step % 100 != 0:
                tick_4_list.append(number)
                #    print tick_0_list
                #    print tick_1_list
                #    print tick_2_list
                #    print tick_3_list
                #    print tick_4_list
    return tick_0_list, tick_1_list, tick_2_list, tick_3_list, tick_4_list, \
           start_ax, stop_ax


def find_log_ticks(start, stop):
    """
    finds tick values for linear axis
    """
    if (start < stop):
        min, max = start, stop
    else:
        min, max = stop, start
    # lists for ticks
    tick_0_list = []
    tick_1_list = []
    tick_2_list = []
    max_decade = math.ceil(math.log10(max))
    min_decade = math.floor(math.log10(min))
    start_ax = None
    stop_ax = None
    for decade in numpy.arange(min_decade, max_decade + 1, 1):
        # for number in scipy.concatenate((numpy.arange(1,2,0.2),numpy.arange(2,3,0.5),numpy.arange(3,10,1))):
        for number in [1, 1.2, 1.4, 1.6, 1.8, 2.0, 2.5, 3, 4, 5, 6, 7, 8, 9]:
            u = number * 10.0 ** decade
            if u >= min and u <= max:
                if start_ax == None:
                    start_ax = number
                stop_ax = number
                if number == 1:
                    tick_0_list.append(u)
                if number in [2, 3, 4, 5, 6, 7, 8, 9]:
                    tick_1_list.append(u)
                if number in [1.2, 1.4, 1.6, 1.8, 2.5]:
                    tick_2_list.append(u)
    # print tick_0_list
    # print tick_1_list
    # print tick_2_list
    return tick_0_list, tick_1_list, tick_2_list, start_ax, stop_ax


def find_log_ticks_smart(start, stop, f, g, turn=1, base_start=None,
                         base_stop=None, distance_limit=0.5):
    """
    finds tick values for linear axis
    """
    if (start < stop):
        min_value, max_value = start, stop
    else:
        min_value, max_value = stop, start
    max_decade = math.ceil(math.log10(max_value) - 0.0001)
    min_decade = math.floor(math.log10(min_value) + 0.0001)
    # resulting lists
    tick_0_list_final = []
    tick_1_list_final = []
    tick_2_list_final = []
    tick_3_list_final = []
    tick_4_list_final = []
    # initial
    tick_0_list, tick_1_list, tick_2_list, tick_3_list, tick_4_list = \
        find_linear_ticks_smart(min_value, min(10 ** (min_decade + 1), max_value), f, g, turn=1, base_start=None,
                                base_stop=None, scale_max_0=10 ** (min_decade + 1),
                                distance_limit=distance_limit)
    # added to include first min value if major decade
    if abs(10 ** min_decade - min_value) / min_value < 1e-6:
        tick_0_list_final = tick_0_list_final + [10 ** (min_decade)]
    if (10 ** (min_decade + 1)) <= max_value:
        tick_0_list_final = tick_0_list_final + [10 ** (min_decade + 1)]
    tick_1_list_final = tick_1_list_final + tick_0_list
    tick_2_list_final = tick_2_list_final + tick_1_list
    tick_3_list_final = tick_3_list_final + tick_2_list
    tick_4_list_final = tick_4_list_final + tick_3_list + tick_4_list
    for decade in numpy.arange(min_decade + 1, max_decade, 1):
        value = 10.0 ** decade
        start = value
        stop = min(value * 10.0, max_value)
        tick_0_list, tick_1_list, tick_2_list, tick_3_list, tick_4_list = \
            find_linear_ticks_smart(start, stop, f, g, turn=1, base_start=base_start,
                                    base_stop=base_stop, scale_max_0=10 ** (decade + 1),
                                    distance_limit=distance_limit)
        if 10 ** (decade + 1) <= max_value:
            tick_0_list_final = tick_0_list_final + [10 ** (decade + 1)]
        tick_1_list_final = tick_1_list_final + tick_0_list
        tick_2_list_final = tick_2_list_final + tick_1_list
        tick_3_list_final = tick_3_list_final + tick_2_list
        tick_4_list_final = tick_4_list_final + tick_3_list + tick_4_list
    # let's remove decades from list
    for decade in tick_0_list_final:
        while tick_1_list_final.count(decade) > 0:
            tick_1_list_final.remove(decade)
    tick_0_list_final.sort()
    tick_1_list_final.sort()
    tick_2_list_final.sort()
    tick_3_list_final.sort()
    tick_4_list_final.sort()
    return tick_0_list_final, tick_1_list_final, tick_2_list_final, \
           tick_3_list_final, tick_4_list_final,


def make_negative(work_list):
    for idx, number in enumerate(work_list):
        work_list[idx] = -number
    return work_list


def find_log_ticks_negative_smart(start, stop, f, g, turn=1, base_start=None,
                                  base_stop=None, distance_limit=0.5):
    """
    finds tick values negative log
    """
    tick_0_list_final, tick_1_list_final, tick_2_list_final, \
    tick_3_list_final, tick_4_list_final = find_log_ticks_smart(-stop, -start, lambda x: f(-x), lambda x: g(-x), turn=1,
                                                                base_start=None,
                                                                base_stop=None, distance_limit=distance_limit)
    tick_0_list_final = make_negative(tick_0_list_final)
    tick_0_list_final.sort()
    tick_1_list_final = make_negative(tick_1_list_final)
    tick_1_list_final.sort()
    tick_2_list_final = make_negative(tick_2_list_final)
    tick_2_list_final.sort()
    tick_3_list_final = make_negative(tick_3_list_final)
    tick_3_list_final.sort()
    tick_4_list_final = make_negative(tick_4_list_final)
    tick_4_list_final.sort()
    return tick_0_list_final, tick_1_list_final, tick_2_list_final, \
           tick_3_list_final, tick_4_list_final,


def find_tick_directions(list, f, g, side, start, stop, full_angle=False, extra_angle=0, turn_relative=False):
    """
    finds tick directions and angles
    """
    angles = []
    # following two values make unit vector
    dx_units = []
    dy_units = []
    turn = _determine_turn_(f=f, g=g, start=start, stop=stop, side=side, turn_relative=turn_relative)
    for idx, u in enumerate(list):
        if u != list[-1]:
            du = (list[idx + 1] - list[idx]) * 1e-6
        else:
            if len(list) > 1:
                du = (list[-1] - list[-2]) * 1e-6
            else:  # only one element in list
                du = abs(stop - start) * 1e-6
        # print u
        dx = (f(u + du) - f(u)) * turn
        dy = (g(u + du) - g(u)) * turn
        dx_unit = dx / math.sqrt(dx ** 2 + dy ** 2)
        dy_unit = dy / math.sqrt(dx ** 2 + dy ** 2)
        if not full_angle:
            if dy_unit != 0.0:
                angle = -math.atan(dx_unit / dy_unit) * 180.0 / math.pi
            else:
                angle = 0.0
        if full_angle:
            if dy_unit != 0.0:
                angle = -math.atan(dx_unit / dy_unit) * 180.0 / math.pi
            else:
                angle = 0.0
            if numpy.sign(dx_unit) < 0.0 and numpy.sign(dy_unit) < 0.0:
                angle = angle - 180.0
            if numpy.sign(dy_unit) < 0.0 <= numpy.sign(dx_unit):
                angle += 180.0
        angle += extra_angle
        dx_units.append(dx_unit)
        dy_units.append(dy_unit)
        angles.append(angle)
    return dx_units, dy_units, angles


def find_linear_ticks_smart(start, stop, f, g, turn=1, base_start=None,
                            base_stop=None, scale_max_0=None, distance_limit=0.5):
    """
    finds smart ticks
    """
    # first find tick scales
    if start > stop:
        start, stop = stop, start
    if (base_start != None) and (base_stop != None):
        scale_max = 10.0 ** math.ceil(math.log10(math.fabs(base_start - base_stop)) - 0.5)
    else:
        scale_max = 10.0 ** math.ceil(math.log10(math.fabs(start - stop)) - 0.5)
    if scale_max_0 != None:
        scale_max = scale_max_0  # set range manually
    tick_0 = scale_max / 10.0
    tick_1 = scale_max / 20.0
    tick_2 = scale_max / 100.0
    tick_3 = scale_max / 500.0
    tick_4 = scale_max / 1000.0
    # let's find tick positions manually
    tick_0_list, tick_1_list, tick_2_list, tick_3_list, tick_4_list, \
    start_ax, stop_ax = \
        find_linear_ticks(start, stop, base_start, base_stop, scale_max_0)
    # let's save original lists
    tick_0_list0, tick_1_list0, tick_2_list0, tick_3_list0, tick_4_list0, \
    start_ax0, stop_ax0 = \
        find_linear_ticks(start, stop, base_start, base_stop, scale_max_0)
    # let's find 0 level ticks
    distance_0 = {}
    # remove smaller distances
    while True:
        distances = []
        for idx in range(1, len(tick_0_list) - 1):
            #            # for debugging
            #            number1=tick_0_list[idx-1]
            #            number2=tick_0_list[idx]
            #            number3=tick_0_list[idx+1]
            distance1 = calc_distance(f, g, tick_0_list[idx], tick_0_list[idx - 1])
            distance2 = calc_distance(f, g, tick_0_list[idx], tick_0_list[idx + 1])
            # check if going round edge of scale
            diff_1a = tick_0_list[idx] - tick_0_list[idx - 1]
            distance1a = calc_distance(f, g, tick_0_list[idx], tick_0_list[idx - 1] + 0.01 * diff_1a)
            diff_2a = tick_0_list[idx] - tick_0_list[idx + 1]
            distance2a = calc_distance(f, g, tick_0_list[idx], tick_0_list[idx + 1] + 0.01 * diff_2a)
            value1 = 0
            value2 = 0
            if distance1 > distance1a:
                value1 = distance1
            if distance2 > distance2a:
                value2 = distance2
            # let's make zeros better
            if value1 == 0:
                value1 = value2
            if value2 == 0:
                value2 = value1
            distances.append([idx, value1, value2])
        # find minimum distance
        no_found = True
        for [idx, value1, value2] in distances:
            if value1 < distance_limit or value2 < distance_limit:
                if value1 > 0 or value2 > 0:
                    if no_found:
                        minimum_idx = idx
                        minimum_value = value1 + value2
                        no_found = False  # first found
                    else:  # something is found before
                        if minimum_value > (value1 + value2):
                            minimum_value = value1 + value2
                            minimum_idx = idx
        if no_found:
            break
        else:
            tick_0_list.pop(minimum_idx)
    # add possible middle values
    possible_values = []
    for value in tick_0_list0:
        if tick_0_list.count(value) == 0:
            possible_values.append(value)
    if len(tick_0_list) > 0:
        while True:
            distance_0 = {}
            distances = []
            tick_0_list.sort()
            for value in possible_values:
                no_distance = True
                for idx in range(0, len(tick_0_list)):
                    distance = calc_distance(f, g, value, tick_0_list[idx])
                    # let's see if turned between
                    diff = (value - tick_0_list[idx]) * 1e-3
                    distance_bigger = calc_distance(f, g, value + diff, tick_0_list[idx] - diff)
                    distance_smaller = calc_distance(f, g, value - diff, tick_0_list[idx] + diff)
                    if distance_smaller < distance_bigger:  # see if not turned
                        if no_distance:  # first round
                            min_distance = distance
                            no_distance = False
                        else:
                            if distance < min_distance:
                                min_distance = distance
                if min_distance > distance_limit:
                    distances.append(min_distance)
                    distance_0[min_distance] = value
            if len(distances) == 0:
                break
            else:
                added_value = distance_0[max(distances)]
                tick_0_list.append(added_value)
                possible_values.remove(added_value)

    tick_0_list.sort()

    tick_1_list_worked = remove_from_list_half(tick_1_list0, tick_0_list0, f, g, distance_limit=distance_limit)
    tick_2_list_worked = remove_from_list_in_four(tick_2_list0, tick_0_list0 + tick_1_list0, f, g,
                                                  distance_limit=distance_limit)
    tick_3_list_worked = remove_from_list_half(tick_3_list0, tick_0_list0 + tick_1_list0 + tick_2_list0, f, g,
                                               distance_limit=distance_limit)
    tick_4_list_worked = remove_from_list_in_four(tick_4_list0,
                                                  tick_0_list0 + tick_1_list0 + tick_2_list0 + tick_3_list0,
                                                  f, g, distance_limit=distance_limit)

    #    pprint.pprint(tick_0_list)
    #    pprint.pprint(tick_1_list_worked)
    #    pprint.pprint(tick_2_list_worked)
    #    pprint.pprint(tick_3_list_worked)
    #    pprint.pprint(tick_4_list_worked)
    return tick_0_list, tick_1_list_worked, tick_2_list_worked, tick_3_list_worked, tick_4_list_worked


def remove_from_list_in_four(work_list, upper_list, f, g, distance_limit=0.5):
    """
    Return a list where elements from work list are removed.
    Assumes that ticks are in complex of four
    """
    upper_list.sort()
    worked_list = copy.deepcopy(work_list)
    # let's check bottom
    upper_level_minimum = min(upper_list)
    numbers = [x for x in work_list if x < upper_level_minimum]
    removed_numbers = []
    for y in numbers + [upper_level_minimum]:
        for x in numbers:
            distance = calc_distance(f, g, x, y)
            if distance < distance_limit and x != y:
                if removed_numbers.count(x) == 0:
                    removed_numbers.append(x)
    if len(removed_numbers) > 0:
        for number in numbers:
            worked_list.remove(number)  # remove all
    # let's check top
    upper_level_maximum = max(upper_list)
    numbers = [x for x in work_list if x > upper_level_maximum]
    removed_numbers = []
    for y in numbers + [upper_level_maximum]:
        for x in numbers:
            distance = calc_distance(f, g, x, y)
            if distance < distance_limit and x != y:
                if removed_numbers.count(x) == 0:
                    removed_numbers.append(x)
    if len(removed_numbers) > 0:
        for number in numbers:
            worked_list.remove(number)  # remove all
    # let's check between
    worked_list_0 = copy.deepcopy(worked_list)
    upper_idx = 0
    work_idx = 0
    while len(worked_list_0) > (work_idx + 1):
        # to start in correct position
        while worked_list_0[work_idx] < min(upper_list):
            work_idx = work_idx + 1
        d = []
        if len(worked_list_0) > (work_idx) and len(upper_list) > (upper_idx):
            d.append(calc_distance(f, g, upper_list[upper_idx], worked_list_0[work_idx]))
        if len(worked_list_0) > (work_idx + 1):
            d.append(calc_distance(f, g, worked_list_0[work_idx], worked_list_0[work_idx + 1]))
        if len(worked_list_0) > (work_idx + 2):
            d.append(calc_distance(f, g, worked_list_0[work_idx + 1], worked_list_0[work_idx + 2]))
        if len(worked_list_0) > (work_idx + 3):
            d.append(calc_distance(f, g, worked_list_0[work_idx + 2], worked_list_0[work_idx + 3]))
        if len(worked_list_0) > (work_idx + 3) and len(upper_list) > (upper_idx + 1):
            d.append(calc_distance(f, g, worked_list_0[work_idx + 3], upper_list[upper_idx + 1]))
        if len(d) > 0:
            if min(d) < distance_limit:
                for idx in range(work_idx, work_idx + 4):
                    if len(worked_list_0) > idx:
                        worked_list.remove(worked_list_0[idx])
        upper_idx = upper_idx + 1
        work_idx = work_idx + 4
    return worked_list


def remove_from_list_half(work_list, upper_list, f, g, distance_limit=0.5):
    """
    removes from list half points
    """
    worked_list = copy.deepcopy(work_list)
    upper_list.sort()
    upper_idx = 0
    work_idx = 0
    if len(work_list) > 0 and len(upper_list) > 0:
        if min(work_list) < min(upper_list):
            while len(work_list) > (work_idx):
                d = []
                if len(upper_list) > (upper_idx + 1):
                    d.append(calc_distance(f, g, upper_list[upper_idx + 1], work_list[work_idx]))
                if len(upper_list) > upper_idx:
                    d.append(calc_distance(f, g, upper_list[upper_idx], work_list[work_idx]))
                if len(d) > 0:
                    if min(d) < distance_limit:
                        worked_list.remove(work_list[work_idx])
                upper_idx += 1
                work_idx += 1
        if min(work_list) > min(upper_list):
            while len(work_list) > work_idx:
                d = []
                if len(upper_list) > upper_idx:
                    d.append(calc_distance(f, g, upper_list[upper_idx], work_list[work_idx]))
                if upper_idx > 0:
                    d.append(calc_distance(f, g, upper_list[upper_idx - 1], work_list[work_idx]))
                if len(d) > 0:
                    if min(d) < distance_limit:
                        worked_list.remove(work_list[work_idx])
                upper_idx += 1
                work_idx += 1
    return worked_list


def remove_text_if_not_tick(tick_values, text_values):
    """
    removes text so that no text is in place where not ticks
    """
    for text_value in text_values:
        if tick_values.count(text_value) == 0:
            text_values.remove(text_value)


def calc_distance(f, g, u1, u2):
    """
    calculates distance between points u1 and u2
    """
    x1 = f(u1)
    x2 = f(u2)
    y1 = g(u1)
    y2 = g(u2)
    return math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)


def make_array_to_dict_for_manual_ticks(array_in, format='%3.2f'):
    array_out = {}
    for x in array_in:
        array_out[x] = format % x
    return array_out


def calc_main_line_coords(start, stop, f, g, sections=350.0):
    """
    calculate main_line coordinates
    """
    main_line = []
    if start > stop:
        start, stop = stop, start
    du = math.fabs(stop - start) * 1e-12
    # approximate line length is found
    line_length_straigth = math.sqrt((f(start) - f(stop)) ** 2 + (g(start) - g(stop)) ** 2)
    random.seed(0.0)  # so that mistakes always the same
    for dummy in range(100):  # for case if start = stop
        first = random.uniform(start, stop)
        second = random.uniform(start, stop)
        temp = math.sqrt((f(first) - f(second)) ** 2 + (g(first) - g(second)) ** 2)
        if temp > line_length_straigth:
            line_length_straigth = temp
            # print "length: %f"%line_length_straigth
    # sections=350.0 # about number of sections
    section_length = line_length_straigth / sections
    u = start
    laskuri = 1
    main_line.append((f(start), g(start)))
    while True:
        if u < stop:
            main_line.append((f(u), g(u)))
            dx = (f(u + du) - f(u))
            dy = (g(u + du) - g(u))
            dl = math.sqrt(dx ** 2 + dy ** 2)
            if dl > 0:
                delta_u = du * section_length / dl
            else:
                delta_u = du
            # in order to avoid too slow derivatives
            if math.fabs(stop - start) < (delta_u * 100.0):
                delta_u = math.fabs(stop - start) / 500.0
            u += delta_u

        else:
            main_line.append((f(stop), g(stop)))
            break
    return main_line


def remove_multiple_and_sort(work_list):
    work_list.sort()
    while work_list.count(0) > 1:
        work_list.remove(0)
        # just sort


#    copy_list=copy.deepcopy(work_list)
#    for element in copy_list:
#        if work_list.count(element)>1:
#            work_list.remove(element)
#    # remove very small differences
#    for idx1,value1 in enumerate(work_list):
#        for idx2,value2 in enumerate(work_list):
#            if idx1!=idx2:
#                if (value1-value2)<value1*1e-9:
#                    if work_list.count(value2)>0:
#                        work_list.remove(value2)

def calc_tick_coords(u, f, g, dx_unit, dy_unit, distance):
    """
    helper func to calculate tick start and stop coords
    """
    x1, y1 = f(u), g(u)
    x2 = x1 + distance * dy_unit
    y2 = y1 - distance * dx_unit
    return x1, y1, x2, y2


def core_main_line_draw_func_basic(main_line_coords, func_f, func_g, ticks, tick_directions, texts, text_directions, c,
                                   tick_info):
    """
    draws mainline
    """
    axis_color = tick_info['axis_color']
    linewidth_main = tick_info['linewidth_main']
    # c.stroke(self.line, [pyx.style.linewidth.normal,axis_color])
    # c.stroke(self.thin_line, [pyx.style.linewidth.thin,axis_color])
    main_line = pyx.path.path(pyx.path.moveto(main_line_coords[0][0], main_line_coords[0][1]))
    for x, y in main_line_coords:
        main_line.append(pyx.path.lineto(x, y))
    c.stroke(main_line, [linewidth_main, axis_color, pyx.style.linecap.square])


def core_tick_draw_func_basic(ticks, texts, level, f, g, dx_units, dy_units,
                              angles, tick_length, text_distance, text_attr, c, tick_info):
    """
    example template for drawing ticks
    ticks: list of ticks to be drawn
    texts: list of texts to be drawn (not here)
    level: drawn level
    f,g: x,y functions
    dx_units, dy_units: unity vector components
    angles: angles of ticks
    text_distance: distance where text is drawn
    text_attr: attributes (alignment, etc.) provided to the function
    c: canvas to draw
    tick_info: general hook for axis dict
    """
    n_ticks = len(ticks)
    ti = tick_info
    if len(dx_units) < n_ticks: print("too few dx_units !")
    if len(dy_units) < n_ticks: print("too few dy_units !")
    if len(angles) < n_ticks: print("too few angles !")
    for i, tick in enumerate(ticks):
        # draw actual tick
        x1, y1, x2, y2 = calc_tick_coords(tick, f, g, dx_units[i], dy_units[i], tick_length)
        # pyx.color
        tick_color = ti['tick_color']
        if ti['tick_colors'] != None:
            tick_color = ti['tick_colors'][level]
        # tick linewidth
        if level > 3:
            linewidth_tick = ti['linewidth_ticks_thin']
        else:
            linewidth_tick = ti['linewidth_ticks']
        if ti['tick_linewidths'] != None:
            linewidth_tick = ti['tick_linewidths'][level]
        # draw the tick
        c.stroke(pyx.path.line(x1, y1, x2, y2), [linewidth_tick, tick_color, pyx.style.linecap.butt])


def example_tick_draw_func(ticks, texts, level, f, g, dx_units, dy_units,
                           angles, tick_length, text_distance, text_attr, c, tick_info):
    """
    example template for drawing ticks
    ticks: list of ticks to be drawn
    texts: list of texts to be drawn (not here)
    level: drawn level
    f,g: x,y functions
    dx_units, dy_units: unity vector components
    angles: angles of ticks
    text_distance: distance where text is drawn
    text_attr: attributes (alignment, etc.) provided to the function
    c: canvas to draw
    tick_info: general hook for axis dict
    """
    n_ticks = len(ticks)
    if len(dx_units) < n_ticks: print("too few dx_units !")
    if len(dy_units) < n_ticks: print("too few dy_units !")
    if len(angles) < n_ticks: print("too few angles !")
    for i, tick in enumerate(ticks):
        # draw actual tick
        x1, y1, x2, y2 = calc_tick_coords(tick, f, g, dx_units[i], dy_units[i], tick_length)
        tick_color = tick_info['tick_colors'][level]
        linewidth_ticks = tick_info['tick_linewidths'][level]
        c.stroke(pyx.path.line(x1, y1, x2, y2), [linewidth_ticks, tick_color, pyx.style.linecap.butt])


def core_text_draw_func_basic(ticks, texts, level, f, g, dx_units, dy_units, angles,
                              tick_lenght, text_distance, text_attrs, c, tick_info):
    """
    Core basic method to draw texts
    ticks: list of tick values to be drawn (not here)
    texts: list of text values to be drawn
    level: drawn level
    f,g: x,y functions
    dx_units, dy_units: unity vector components
    angles: angles of ticks
    tick_lenght: tick lenght
    text_distance: distance where text is drawn
    text_attr: attributes (alignment, etc.) provided to the function
    c: canvas to draw
    tick_info: general hook for axis dict
    """
    ti = tick_info  # for shorthand
    n_texts = len(texts)
    if len(dx_units) < n_texts:
        print("too few dx_units !")
    if len(dy_units) < n_texts:
        print("too few dy_units !")
    if len(angles) < n_texts:
        print("too few angles !")
    for i, text_value in enumerate(texts):
        # draw actual text
        x = f(text_value) + text_distance * dy_units[i]
        y = g(text_value) - text_distance * dx_units[i]
        # print "text_distance:%g"%text_distance
        text_color = ti['text_color']
        if not ti['text_colors'] is None:
            text_color = ti['level_text_color'][level]
        text_size = ti['text_sizes'][level]
        # if ti['level_text_size']!=None:
        #    text_size=ti['level_text_size'][level]
        if ti['text_format_func'] is None:
            text = ti['text_format'] % text_value
        else:
            text = ti['text_format_func'](text_value)

        c.text(x, y, text, text_attrs[i] + [text_color, text_size])


def example_text_draw_func(ticks, texts, level, f, g, dx_units, dy_units, angles,
                           tick_lenght, text_distance, text_attrs, c, tick_info):
    """
    example template for drawing texts
    ticks: list of tick values to be drawn (not here)
    texts: list of text values to be drawn
    level: drawn level
    f,g: x,y functions
    dx_units, dy_units: unity vector components
    angles: angles of ticks
    tick_lenght: tick length
    text_distance: distance where text is drawn
    text_attr: attributes (alignment, etc.) provided to the function
    c: canvas to draw
    tick_info: general hook for axis dict
    """
    n_texts = len(texts)
    if len(dx_units) < n_texts: print("too few dx_units !")
    if len(dy_units) < n_texts: print("too few dy_units !")
    if len(angles) < n_texts: print("too few angles !")
    for i, text_value in enumerate(texts):
        # draw actual text
        x = f(text_value) + text_distance * dy_units[i]
        y = g(text_value) - text_distance * dx_units[i]
        if tick_info['text_colors'] == None:
            text_color = tick_info['text_color']
        else:
            text_color = tick_info['text_colors'][level]
        text_size = tick_info['text_sizes'][level]
        text = r"$%d ^\circ$ " % text_value
        c.text(x, y, text, text_attr + [text_color, text_size])


def example_ticker(start, stop, f, g, tick_levels, text_levels, distance_limit_tick, distance_limit_text, tick_info={}):
    """
    example function to provide tick and text values
    start, stop: scale range
    f: x function
    g: y function
    distance_limit: minimum distance between objects
    """
    # Here we use same function to make both ticks and texts

    # ticks = [tick_0_list,...,tick_N-1_list]
    # tick_M_list = values of ticks to appear in level M
    ticks = find_mmss_ticks(start, stop, f, g, tick_levels, distance_limit_tick, tick_info)
    # texts = [text_0_list,...,text_N-1,list]
    # text_M_list = numbers of texts to appear in level M
    texts = find_mmss_ticks(start, stop, f, g, text_levels, distance_limit_text, tick_info)

    # here we remove texts from list if there is no tick with same number
    for i, text_list_i in enumerate(texts):
        if len(ticks) > i:
            remove_text_if_not_tick(ticks[i], text_list_i)

    # returns lists of ticks and texts
    return ticks, texts


def core_ticker(start, stop, f, g, tick_levels, text_levels, distance_limit_tick, distance_limit_text, tick_info={}):
    """
    example function to provide tick and text values
    start, stop: scale range
    f: x function
    g: y function
    distance_limit: minimum distance between objects
    """

    # ticks = [tick_0_list,...,tick_N-1_list]
    t0, t1, t2, t3, t4 = find_linear_ticks_smart(start, stop, f, g, turn=1, base_start=tick_info['base_start'],
                                                 base_stop=tick_info['base_stop'], scale_max_0=tick_info['scale_max'],
                                                 distance_limit=tick_info['tick_distance_smart'])
    ticks = [t0, t1, t2, t3, t4]
    # texts
    te0, te1, te2, te3, te4 = find_linear_ticks_smart(start, stop, f, g, turn=1, base_start=tick_info['base_start'],
                                                      base_stop=tick_info['base_stop'],
                                                      scale_max_0=tick_info['scale_max'],
                                                      distance_limit=tick_info['text_distance_smart'])
    texts = [te0, te1, te2, te3, te4]
    # suppress levels
    print("tick_levels:%i" % tick_levels)
    print("text_levels:%i" % text_levels)
    ticks = ticks[:tick_levels]
    texts = texts[:text_levels]
    # here we remove texts from list if there is no tick with same number
    for i, text_list_i in enumerate(texts):
        if len(ticks) > i:
            remove_text_if_not_tick(ticks[i], text_list_i)

    # returns lists of ticks and texts
    return ticks, texts


## Testing
if __name__ == '__main__':
    #######
    # basic test
    def fgen_test(angle):
        return math.sin(angle / 180 * math.pi) * 3 + 17


    def ggen_test(angle):
        return math.cos(angle / 180 * math.pi) * 3 + 5


    """"
    c =pyx.canvas.canvas()
    gr1=Nomo_Axis(func_f=fgen_test,func_g=ggen_test,start=20.5,stop=300.0,turn=-1,title=r'gen test',
              canvas=c,type='general',side='left',tick_levels=3,tick_text_levels=2,
              axis_appear={})    
    c.writePDFfile("test_nomo_axis_2013")
    # end basic test
    """
    #
    # same with custom drawing
    c2 = pyx.canvas.canvas()


    def test_text_draw_func(ticks, texts, level, f, g, dx_units, dy_units, angles,
                            tick_lenght, text_distance, text_attrs, c, tick_info):
        """
        example for drawing texts
        ticks: list of tick values to be drawn in this level(not here)
        texts: list of text values to be drawn
        level: drawn level
        f,g: x,y functions
        dx_units, dy_units: unity vector components
        angles: angles of tick
        tick_lenght: tick length
        text_distance: distance where text is drawn
        text_attrs: text attributes (alignment, etc.) provided to the function
        c: canvas to draw
        tick_info: general hook for axis dict
        """
        n_texts = len(texts)
        if len(dx_units) < n_texts: print("too few dx_units !")
        if len(dy_units) < n_texts: print("too few dy_units !")
        if len(angles) < n_texts: print("too few angles !")
        for i, text_value in enumerate(texts):
            # draw actual text
            x = f(text_value) + text_distance * dy_units[i]
            y = g(text_value) - text_distance * dx_units[i]
            pyx.trafo.translate(10.0, 10.0)
            if tick_info['text_colors'] == None:  # use single pyx.color for all levels
                text_color = tick_info['text_color']
            else:
                text_color = tick_info['text_colors'][level]
            text_size = tick_info['text_sizes'][level]
            # actual text formatting
            text = r"$%d ^\circ$ " % text_value
            # c.text(x,y,text,text_attrs[i]['all']+[text_color,text_size])
            # this will draw the text to canvas c
            c.text(0, 0,  # coordinates
                   text,  # actual text
                   [text_attrs[i]['valign'],  # vertical aligenment
                    text_attrs[i]['halign'],  # horizaontal alignment
                    text_color,
                    text_size,
                    pyx.trafo.translate(x, y),  # translation
                    pyx.trafo.rotate(angles[i])  # rotation
                    ])


    def test_tick_draw_func(ticks, texts, level, f, g, dx_units, dy_units,
                            angles, tick_length, text_distance, text_attr, c, tick_info):
        """
        example template for drawing ticks
        ticks: list of ticks to be drawn
        texts: list of texts to be drawn (not here)
        level: drawn level
        f,g: x,y functions
        dx_units, dy_units: unity vector components
        angles: angles of ticks
        text_distance: distance where text is drawn
        text_attr: attributes (alignment, etc.) provided to the function
        c: canvas to draw
        tick_info: general hook for axis dict
        """
        n_ticks = len(ticks)
        if len(dx_units) < n_ticks: print("too few dx_units !")
        if len(dy_units) < n_ticks: print("too few dy_units !")
        if len(angles) < n_ticks: print("too few angles !")
        for i, tick in enumerate(ticks):
            # draw actual tick
            x1, y1, x2, y2 = calc_tick_coords(tick, f, g, dx_units[i], dy_units[i], tick_length)
            if level == 0:
                tick_color = tick_info['tick_color']
            else:
                tick_color = pyx.color.rgb.blue
            linewidth_ticks = tick_info['tick_linewidths'][level]
            c.stroke(pyx.path.line(x1, y1, x2, y2), [linewidth_ticks, tick_color, pyx.style.linecap.butt])


    gr2_axis_appear = {'text_draw_func': test_text_draw_func,
                       'tick_draw_func': test_tick_draw_func,
                       'text_colors': [pyx.color.rgb.black, pyx.color.rgb.red,
                                       pyx.color.rgb.black, pyx.color.rgb.red,
                                       pyx.color.rgb.black]}
    gr2 = Nomo_Axis(func_f=fgen_test, func_g=ggen_test, start=20.5, stop=300.0, turn=-1, title=r'gen test',
                    canvas=c2, type='general', side='left', tick_levels=4, tick_text_levels=2,
                    axis_appear=gr2_axis_appear)
    c2.writePDFfile("test_nomo_axis_2013a")


    # end
    # example 3
    def fgen_test3(angle):
        return math.cos(angle / 180 * math.pi) * 20


    def ggen_test3(angle):
        return math.sin(angle / 180 * math.pi) * 20


    c3 = pyx.canvas.canvas()


    def draw_balls(num, x1, y1, x2, y2, angle, size, c):
        """
        example function to draw balls
        """
        # make transformation
        trans = [pyx.trafo.rotate(angle), pyx.trafo.translate(x1, y1)]
        tick_color = pyx.color.rgb.black
        tick_width = pyx.style.linewidth.normal
        # c.fill(pyx.path.circle(0,0,size),trans+[tick_color,tick_width])
        while True:  # unities
            if num % 10 == 0: break
            c.fill(pyx.path.circle(-0.4, 0.04, size), trans + [tick_color, tick_width])
            if num % 10 == 1: break
            c.fill(pyx.path.circle(-0.5, 0.04, size), trans + [tick_color, tick_width])
            if num % 10 == 2: break
            c.fill(pyx.path.circle(-0.6, 0.04, size), trans + [tick_color, tick_width])
            if num % 10 == 3: break
            c.fill(pyx.path.circle(-0.7, 0.04, size), trans + [tick_color, tick_width])
            if num % 10 == 4: break
            c.fill(pyx.path.circle(-0.4, -0.04, size), trans + [tick_color, tick_width])
            if num % 10 == 5: break
            c.fill(pyx.path.circle(-0.5, -0.04, size), trans + [tick_color, tick_width])
            if num % 10 == 6: break
            c.fill(pyx.path.circle(-0.6, -0.04, size), trans + [tick_color, tick_width])
            if num % 10 == 7: break
            c.fill(pyx.path.circle(-0.7, -0.04, size), trans + [tick_color, tick_width])
            if num % 10 == 8: break
            c.fill(pyx.path.circle(-0.8, 0.0, size), trans + [tick_color, tick_width])
            if num % 10 == 9: break
            break
        while True:  # tens
            num = int(num / 10)
            if num % 10 == 0: break
            c.stroke(pyx.path.circle(0.4 - 0.3, 0.04, size), trans + [tick_color, tick_width])
            if num % 10 == 1: break
            c.stroke(pyx.path.circle(0.5 - 0.3, 0.04, size), trans + [tick_color, tick_width])
            if num % 10 == 2: break
            c.stroke(pyx.path.circle(0.6 - 0.3, 0.04, size), trans + [tick_color, tick_width])
            if num % 10 == 3: break
            c.stroke(pyx.path.circle(0.7 - 0.3, 0.04, size), trans + [tick_color, tick_width])
            if num % 10 == 4: break
            c.stroke(pyx.path.circle(0.4 - 0.3, -0.04, size), trans + [tick_color, tick_width])
            if num % 10 == 5: break
            c.stroke(pyx.path.circle(0.5 - 0.3, -0.04, size), trans + [tick_color, tick_width])
            if num % 10 == 6: break
            c.stroke(pyx.path.circle(0.6 - 0.3, -0.04, size), trans + [tick_color, tick_width])
            if num % 10 == 7: break
            c.stroke(pyx.path.circle(0.7 - 0.3, -0.04, size), trans + [tick_color, tick_width])
            if num % 10 == 8: break
            c.stroke(pyx.path.circle(0.8 - 0.3, 0.0, size), trans + [tick_color, tick_width])
            if num % 10 == 9: break
            break
        c.stroke(pyx.path.line(0, 0, 0.4, 0), trans + [tick_color, tick_width])
        # print "stroking"


    def test_tick_draw_func_balls(ticks, texts, level, f, g, dx_units, dy_units,
                                  angles, tick_length, text_distance, text_attr, c, tick_info):
        """
        example template for drawing ticks
        ticks: list of ticks to be drawn
        texts: list of texts to be drawn (not here)
        level: drawn level     
        f,g: x,y functions
        dx_units, dy_units: unity vector components
        angles: angles of ticks
        text_distance: distance where text is drawn
        text_attr: attributes (alignment, etc.) provided to the function
        c: canvas to draw
        tick_info: general hook for axis dict
        """
        n_ticks = len(ticks)
        if len(dx_units) < n_ticks: print("too few dx_units !")
        if len(dy_units) < n_ticks: print("too few dy_units !")
        if len(angles) < n_ticks: print("too few angles !")
        for i, tick in enumerate(ticks):
            # draw actual tick
            x1, y1, x2, y2 = calc_tick_coords(tick, f, g, dx_units[i], dy_units[i], tick_length)
            if level == 0:
                tick_color = tick_info['tick_color']
            else:
                tick_color = pyx.color.rgb.blue
            linewidth_ticks = tick_info['tick_linewidths'][level]
            c.stroke(pyx.path.line(x1, y1, x2, y2), [linewidth_ticks, tick_color, pyx.style.linecap.butt])
            # if 1:
            if level == 0:
                draw_balls(tick, x1, y1, x2, y2, angles[i], 0.02, c)
                # print "draw_balls"


    gr3_axis_appear = {'text_draw_func': test_text_draw_func,
                       'tick_draw_func': test_tick_draw_func_balls,
                       'text_colors': [pyx.color.rgb.black, pyx.color.rgb.red,
                                       pyx.color.rgb.black, pyx.color.rgb.red,
                                       pyx.color.rgb.black]}
    gr3 = Nomo_Axis(func_f=fgen_test3, func_g=ggen_test3, start=0.0, stop=20.0, turn=-1, title=r'gen test11',
                    canvas=c3, type='general', side='left', tick_levels=3, tick_text_levels=2,
                    axis_appear=gr3_axis_appear)
    c3.writePDFfile("test_nomo_axis_2013b")

if False:
    # find_log_ticks(990.0,999.0)
    # find_log_ticks(-33,52)
    find_log_ticks(0.12, 10.0)


    def f1(L):
        return 2 * (L * L - 8 * L - 5) / (3 * L * L + 2 * L + 7)


    def g1(L):
        return 10 * (8 * L * L + 12 * L - 8) / (3 * L * L + 2 * L + 7)


    def f1a(L):
        return 5


    def g1a(L):
        return 3 * math.log10(L)


    def f1b(L):
        return 1.5


    def g1b(L):
        return L * 1.3


    def f1c(L):
        return 10 + L / 10.0


    def g1c(L):
        return L


    def f1d(angle):
        return math.sin(angle / 180 * math.pi) * 3 + 17


    def g1d(angle):
        return math.cos(angle / 180 * math.pi) * 5 + 5


    manual_axis_data = {1.0: 'first',
                        2.0: 'second',
                        3.0: 'third',
                        3.1415: r'$\pi$',
                        4.0: 'fourth',
                        5.0: 'fifth',
                        6.0: 'sixth',
                        7.0: 'seventh',
                        8.0: 'eigth',
                        9.0: 'nineth',
                        10.0: 'tenth'}

    c = pyx.canvas.canvas()
    # gg3=Nomo_Axis(func_f=f3,func_g=g3,start=1.0,stop=0.5,turn=-1,title='func 1',canvas=c,type='linear')
    gr1 = Nomo_Axis(func_f=f1, func_g=g1, start=0.5, stop=1.0, turn=-1, title='func 1',
                    canvas=c, type='linear', side='left')
    gr11 = Nomo_Axis(func_f=f1, func_g=g1, start=0.5, stop=1.0, turn=-1, title='func 1',
                     canvas=c, type='linear', side='right')
    gr2 = Nomo_Axis(func_f=f1a, func_g=g1a, start=1.0, stop=1e4, turn=-1, title='func 2',
                    canvas=c, type='log', side='left')
    gr22 = Nomo_Axis(func_f=f1a, func_g=g1a, start=1.0, stop=1e4, turn=-1, title='func 2',
                     canvas=c, type='log', side='right')
    gr3 = Nomo_Axis(func_f=f1b, func_g=g1b, start=1.0, stop=10, turn=-1, title='func 3',
                    canvas=c, type='manual point',
                    manual_axis_data=manual_axis_data, side='left')
    gr33 = Nomo_Axis(func_f=f1b, func_g=g1b, start=1.0, stop=10, turn=-1, title='func 3',
                     canvas=c, type='manual point',
                     manual_axis_data=manual_axis_data, side='right')

    gr4 = Nomo_Axis(func_f=f1c, func_g=g1c, start=1.0, stop=10, turn=-1, title='func 4',
                    canvas=c, type='manual arrow',
                    manual_axis_data=manual_axis_data, side='right',
                    axis_appear={'extra_angle': 0,
                                 'text_horizontal_align_center': False,
                                 'arrow_color': pyx.color.rgb.blue,
                                 'text_color': pyx.color.rgb.red})
    gr44 = Nomo_Axis(func_f=f1c, func_g=g1c, start=1.0, stop=10, turn=-1, title='func 4',
                     canvas=c, type='manual line',
                     manual_axis_data=manual_axis_data, side='left')

    # for some reason, this does not work when stop is 359 ??
    gr5 = Nomo_Axis(func_f=f1d, func_g=g1d, start=0.0, stop=360.0, turn=-1, title='func 1',
                    canvas=c, type='linear', side='left',
                    axis_appear={'extra_angle': 0,
                                 'text_horizontal_align_center': False,
                                 'axis_color': pyx.color.rgb.blue,
                                 'text_color': pyx.color.cmyk.Orange})

    gr10 = Nomo_Axis(func_f=lambda u: 20.0, func_g=lambda x: (x + 12.5) / 2.0, start=-17.1757381043, stop=19.5610135785,
                     turn=-1, title='test neg.',
                     canvas=c, type='linear', side='right')

    gr11 = Nomo_Axis(func_f=lambda u: 25.0, func_g=lambda x: (x + 12.5) / 5.0, start=-40.0, stop=120.0, turn=-1,
                     title='test neg.',
                     canvas=c, type='linear', side='right')
    # gg4=Nomo_Axis(func_f=f4,func_g=g4,start=0.5,stop=1.0,turn=-1,title='func 3',canvas=c,type='linear')
    c.writePDFfile("test_nomo_axis")

    cc = pyx.canvas.canvas()
    axis_appear = {'full_angle': True,
                   'extra_angle': -90.0,
                   'text_format': "$%3.0f$",
                   'text_horizontal_align_center': True}
    circ = Nomo_Axis(func_f=lambda u: -5 * math.sin(u / 180 * math.pi),
                     func_g=lambda u: 5 * math.cos(u / 180 * math.pi), start=0.0, stop=360.0, turn=-1, title='circ',
                     canvas=cc, type='linear', side='left', axis_appear=axis_appear)
    cc.writePDFfile("test_nomo_axis_circ")

    manual_axis_data_1 = {10.0: '10',
                          20.0: '20',
                          30.0: '30',
                          31.415: r'$\pi \times 10$',
                          40.0: '40',
                          50.0: '50',
                          60.0: '60',
                          70.0: '70',
                          80.0: '80',
                          90.0: '90',
                          100.0: '100'}
    ccc = pyx.canvas.canvas()
    axis_appear = {'full_angle': True,
                   'extra_angle': -90.0,
                   'text_format': "$%3.0f$",
                   'text_horizontal_align_center': True,
                   'grid_length_1': 0.5 / 4}
    circ = Nomo_Axis(func_f=lambda u: -5 * math.sin(u / 180 * math.pi),
                     func_g=lambda u: 5 * math.cos(u / 180 * math.pi), start=10.0, stop=100.0, turn=-1, title='circ',
                     canvas=ccc, type='manual line', manual_axis_data=manual_axis_data_1,
                     side='right', axis_appear=axis_appear)
    ccc.writePDFfile("test_nomo_axis_circ_manual")
