NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

exoplanetsgraph.py (34963B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\projectdiscovery\client\projects\exoplanets\graphs\exoplanetsgraph.py
      2 from __future__ import absolute_import
      3 from carbonui.graphs.axis import AutoTicksAxis
      4 from carbonui.graphs.graph import GraphArea
      5 from carbonui.graphs.grid import Grid
      6 from carbonui.graphs.minimap import MiniMap
      7 from carbonui.graphs.pointgraph import PointGraph
      8 from carbonui.primitives.container import Container
      9 from eve.client.script.ui.control.eveLoadingWheel import LoadingWheel
     10 from evegraphics import settings as gfxsettings
     11 from projectdiscovery.client.projects.exoplanets.graphs.consensusgraph import ConsensusGraph
     12 from projectdiscovery.client.projects.exoplanets.graphs.exoplanetsminigraph import ExoPlanetsMiniGraph
     13 from projectdiscovery.client.projects.exoplanets.graphs.exoplanetsbasegraph import ExoPlanetsGraphContainer
     14 from carbonui.primitives.line import Line
     15 from carbonui.uianimations import animations as uianimations
     16 from itertools import izip
     17 from projectdiscovery.client import const
     18 from projectdiscovery.client.projects.exoplanets.exoplanetsutil import calibration, binning, result, zoom
     19 from projectdiscovery.client.projects.exoplanets.graphs.resulticongraph import ResultIconGraph
     20 from projectdiscovery.client.projects.exoplanets.graphtools.magnifyingglasstool import MagnifyingGlassTool, MagnifyingGlassScalingOrientation
     21 from projectdiscovery.client.projects.exoplanets.transitinformationcontainer import TransitInformationContainer
     22 import carbonui.const as uiconst
     23 import carbonui.graphs.axis as axis
     24 import carbonui.graphs.axislabels as axislabels
     25 from . import animations
     26 import trinity
     27 import geo2
     28 import blue
     29 import math
     30 import localization
     31 FOLD_ANIMATION_MAX_TIME = 0.5
     32 
     33 class ExoPlanetsGraph(ExoPlanetsGraphContainer):
     34     __notifyevents__ = ExoPlanetsGraphContainer.__notifyevents__ + ['OnProjectDiscoveryResultBackButtonPressed']
     35     default_mini_map_color = (1.0,
     36      1.0,
     37      1.0,
     38      0.09)
     39 
     40     def ApplyAttributes(self, attributes):
     41         self._audio_service = sm.GetService('audio')
     42         self.setup_binning_fidelity()
     43         self._mini_graph = None
     44         self._mini_map = None
     45         self._mini_map_area = None
     46         self._loading_wheel = None
     47         self._is_time_axis_dirty = False
     48         self._is_mini_map_hidden = False
     49         self._desired_animation_zoom = None
     50         self._m_update_progression = 0
     51         self._is_zoom_animation = False
     52         self._is_update_animation = False
     53         self._is_calibration_animation = False
     54         self._is_fold_animation = False
     55         self._m_calibration_progression = 0
     56         self._calibration_marking_start_points = []
     57         self._calibration_marking_end_points = []
     58         self._calibration_marking_color = (1, 1, 1, 1)
     59         self._calibration_axis = None
     60         self._calibration_graph = None
     61         self._start_animation_data = []
     62         self._end_animation_data = []
     63         self._consensus_vertical_axis = None
     64         self._consensus_time_axis = None
     65         self._consensus_graph = None
     66         self._interval_mapping = {}
     67         self._is_result_shown = False
     68         self._correct_horizontal_axis = None
     69         self._missed_horizontal_axis = None
     70         self._incorrect_horizontal_axis = None
     71         self._correct_graph = None
     72         self._missed_graph = None
     73         self._incorrect_graph = None
     74         self._fold_result_state = None
     75         self._fold_result_points_indices = []
     76         self._correct_point_indices = []
     77         self._missed_point_indices = []
     78         self._incorrect_point_indices = []
     79         self._result_icon_graphs = []
     80         self._correct_intervals = []
     81         self._incorrect_intervals = []
     82         self._missed_intervals = []
     83         self._last_scroll_time = 0
     84         self._scroll_reset_time = 1
     85         self._is_scroll_reset = True
     86         super(ExoPlanetsGraph, self).ApplyAttributes(attributes)
     87         self.pickState = uiconst.TR2_SPS_ON
     88         self._setup_layout()
     89 
     90     def setup_binning_fidelity(self):
     91         shader_quality = gfxsettings.Get(gfxsettings.GFX_SHADER_QUALITY)
     92         self.animation_binning_fidelity = 15 if shader_quality == 1 else 1
     93         self.binning_fidelity = 1
     94 
     95     def graph_update(self):
     96         while not self.destroyed:
     97             current_time = trinity.device.animationTime
     98             if self.is_mouse_moved:
     99                 self.is_mouse_moved = False
    100                 self.on_mouse_move()
    101             if self.is_wheel_scrolled:
    102                 self.is_wheel_scrolled = False
    103                 self.on_mouse_wheel(self.scroll_amount)
    104             if self._is_time_axis_dirty:
    105                 self.on_time_axis_changed()
    106             if not self._is_scroll_reset and current_time >= self._last_scroll_time + self._scroll_reset_time:
    107                 self._is_scroll_reset = True
    108                 if not self.is_animation_running():
    109                     self.on_graph_movement_stopped()
    110             blue.synchro.Yield()
    111             self.unlock_graph_updates()
    112 
    113     def disable_point_graph(self):
    114         if self._main_graph:
    115             self._main_graph.set_show_status_of_point_graph(False)
    116 
    117     def enable_point_graph(self):
    118         if self._main_graph:
    119             self._main_graph.set_show_status_of_point_graph(True)
    120             if not self.is_animation_running() and self._is_scroll_reset:
    121                 self._main_graph.show_point_graph()
    122 
    123     def on_mouse_wheel(self, amount):
    124         if self.is_folding():
    125             self._scroll_fade()
    126         super(ExoPlanetsGraph, self).on_mouse_wheel(amount)
    127 
    128     def _scroll_fade(self, *args, **kwargs):
    129         self._is_scroll_reset = False
    130         self._last_scroll_time = trinity.device.animationTime
    131         self.on_graph_movement()
    132 
    133     def _setup_layout(self):
    134         self._graph_container = None
    135         if self._loading_wheel:
    136             self._loading_wheel.Close()
    137             self._loading_wheel = None
    138         if self._graph_data:
    139             self.SetState(uiconst.UI_NORMAL)
    140             self.setup_graph()
    141             sm.ScatterEvent('OnEnableDetrend')
    142         else:
    143             self.SetState(uiconst.UI_DISABLED)
    144             self._setup_waiting_screen()
    145 
    146     def setup_graph(self):
    147         self._audio_service.SendUIEvent(const.Sounds.MainImageLoadStop)
    148         self._graph_container = Container(name='graphContainer', parent=self, align=uiconst.TOALL)
    149         self._consensus_vertical_axis = AutoTicksAxis(dataRange=(0, 1.6), tickCount=10, tickFilter=consensus_tick_filter, labelFormat=consensus_label_format)
    150         self._flux_axis = self._flux_axis_type(self.get_range_of_flux(), tickCount=4, margins=(0.01, 0.01))
    151         self._time_axis = self._time_axis_type(self.get_time_values(self._graph_data), margins=(0.01, 0.01))
    152         self._category_axes.append(self._time_axis)
    153         Line(parent=self._graph_container, align=uiconst.TOBOTTOM, opacity=0.2)
    154         self._setup_mini_map_area()
    155         Line(parent=self._graph_container, align=uiconst.TOBOTTOM, opacity=0.2)
    156         self._time_labels = axislabels.AxisLabels(name='ExoPlanetsTimeLabels', parent=self._graph_container, align=uiconst.TOBOTTOM, height=30, axis=self._time_axis, orientation=axis.AxisOrientation.HORIZONTAL, minFactor=0, maxFactor=1, textAlignment=uiconst.CENTER)
    157         Line(parent=self._graph_container, align=uiconst.TOBOTTOM, opacity=0.05)
    158         self._tooltip_area = Container(name='TooltipArea', parent=self._graph_container, align=uiconst.TOALL)
    159         if self._tool:
    160             self.set_tool(self._tool)
    161         self._consensus_graph_area = GraphArea(name='ConsensusGraphArea', parent=self._graph_container, align=uiconst.TOALL, clipChildren=False, state=uiconst.UI_PICKCHILDREN, opacity=0)
    162         self._graph_area = GraphArea(name='GraphArea', parent=self._graph_container, align=uiconst.TOALL, state=uiconst.UI_PICKCHILDREN)
    163         self._transit_info_container = TransitInformationContainer(name='TransitInfoContainer', parent=self._graph_area, align=uiconst.CENTERRIGHT, height=60, width=500, top=30, padRight=10, buttonFunc=None)
    164         self._flux_labels = axislabels.AxisLabels(name='ExoPlanetsFluxLabels', parent=self._graph_area, align=uiconst.TOLEFT_NOPUSH, width=100, axis=self._flux_axis, orientation=axis.AxisOrientation.VERTICAL, minFactor=1, maxFactor=0, textAlignment=uiconst.CENTERLEFT)
    165         self._consensus_labels = axislabels.AxisLabels(name='ConsensusLabels', parent=self._consensus_graph_area, align=uiconst.TORIGHT_NOPUSH, width=100, axis=self._consensus_vertical_axis, orientation=axis.AxisOrientation.VERTICAL, minFactor=1, maxFactor=0, textAlignment=uiconst.CENTERRIGHT)
    166         self.set_fux_display_state(FluxDisplayState.RELATIVE)
    167         self._graph_area.AddAxis(orientation=axis.AxisOrientation.VERTICAL, axis=self._flux_axis, minFactor=1.0, maxFactor=0.0)
    168         self._graph_area.AddAxis(orientation=axis.AxisOrientation.HORIZONTAL, axis=self._time_axis)
    169         self._create_graph_from_data(self._graph_data)
    170         self.horizontalLines = Grid(parent=self._graph_area, axis=self._flux_axis, orientation=axis.AxisOrientation.VERTICAL, color=(1, 1, 1, 0.05), minFactor=1.0, maxFactor=0.0)
    171         self._consensus_lines = Grid(parent=self._consensus_graph_area, axis=self._consensus_vertical_axis, orientation=axis.AxisOrientation.VERTICAL, color=(1, 1, 1, 0.05), minFactor=1.0, maxFactor=0.0)
    172 
    173     def _setup_waiting_screen(self):
    174         self._audio_service.SendUIEvent(const.Sounds.MainImageLoadPlay)
    175         self._loading_wheel = LoadingWheel(name='LoadingWheel', parent=self, align=uiconst.CENTER)
    176 
    177     def _setup_mini_map_area(self):
    178         self._mini_map_area = Container(name='MiniMapArea', parent=self._graph_container, align=uiconst.TOBOTTOM, height=80)
    179         self._mini_map_area.pickState = uiconst.TR2_SPS_ON
    180         self._setup_zoom_mini_map()
    181 
    182     def _setup_zoom_mini_map(self):
    183         self._control_axis = self._time_axis_type(self.get_time_values(self._graph_data)[:1], dataRange=(self._time_axis.get_min_value(), self._time_axis.get_max_value()))
    184         self._category_axes.append(self._control_axis)
    185         self._control_axis.onChange.connect(self._set_time_axis_dirty)
    186         self._mini_map = MiniMap(name='MiniMap', parent=self._mini_map_area, align=uiconst.TOALL, controlAxis=self._control_axis, state=uiconst.UI_PICKCHILDREN)
    187         self._mini_map.slider.name = 'ExoPlanetsZoomSlider'
    188         self._mini_map.slider.beforeAxisUpdate.connect(self.lock_graph_updates)
    189         self._mini_map.slider.onSliderStart.connect(self.on_graph_movement)
    190         self._mini_map.slider.onSliderReleased.connect(self.on_graph_movement_stopped)
    191         self._mini_map.slider.onSliderWheel.connect(self._scroll_fade)
    192         self._mini_map.slider.pickState = uiconst.TR2_SPS_ON
    193         self._mini_graph = ExoPlanetsMiniGraph(name='MiniGraph', parent=self._mini_map_area, align=uiconst.TOALL, opacity=1, state=uiconst.UI_NORMAL)
    194         self._mini_graph.set_data(self._graph_data)
    195         self._mini_graph.set_tool(MagnifyingGlassTool(scaling_orientation=MagnifyingGlassScalingOrientation.HORIZONTAL, adjust_flux_zoom=False, on_click=lambda t1, t2, f1, f2: (self.zoom(t1, t2) if not self.is_folding() else None)))
    196         self.zoom(*self._control_axis.get_visible_range())
    197 
    198     def Close(self):
    199         if self._mini_map:
    200             self._control_axis.onChange.disconnect(self._set_time_axis_dirty)
    201             self._mini_map.slider.beforeAxisUpdate.disconnect(self.lock_graph_updates)
    202             self._mini_map.slider.onSliderStart.disconnect(self.on_graph_movement)
    203             self._mini_map.slider.onSliderReleased.disconnect(self.on_graph_movement_stopped)
    204             self._mini_map.slider.onSliderWheel.disconnect(self._scroll_fade)
    205         super(ExoPlanetsGraph, self).Close()
    206 
    207     def setup_result_graph(self, correct_intervals, missed_intervals, incorrect_intervals, interval_mapping):
    208         self._interval_mapping = interval_mapping
    209         self._correct_intervals = correct_intervals
    210         self._missed_intervals = missed_intervals
    211         self._incorrect_intervals = incorrect_intervals
    212         self._correct_point_indices, self._missed_point_indices, self._incorrect_point_indices = result.categorize_point_indices_to_result(self._graph_data, correct_intervals, missed_intervals, incorrect_intervals)
    213         self._show_result_graph()
    214         self._show_result_icon_graphs(correct_intervals, missed_intervals, incorrect_intervals)
    215 
    216     def _show_result_graph(self):
    217         self.clear_result_graph()
    218         if self.is_folding():
    219             points = [ self._graph_data[i] for i in self._fold_result_points_indices ]
    220             color = const.Colors.GREEN if self._fold_result_state == result.ResultStates.CORRECT else const.Colors.YELLOW
    221             self._correct_horizontal_axis, self._correct_graph = self._create_result_graph_components(points, color, points_size=3)
    222             uianimations.BlinkIn(self._correct_graph)
    223             return
    224         correct_points = [ self._graph_data[i] for i in self._correct_point_indices ]
    225         missed_points = [ self._graph_data[i] for i in self._missed_point_indices ]
    226         incorrect_points = [ self._graph_data[i] for i in self._incorrect_point_indices ]
    227         self._correct_horizontal_axis, self._correct_graph = self._create_result_graph_components(correct_points, const.Colors.GREEN)
    228         self._missed_horizontal_axis, self._missed_graph = self._create_result_graph_components(missed_points, const.Colors.YELLOW)
    229         self._incorrect_horizontal_axis, self._incorrect_graph = self._create_result_graph_components(incorrect_points, const.Colors.RED)
    230         self._is_result_shown = True
    231         uianimations.BlinkIn(self._correct_graph)
    232         uianimations.BlinkIn(self._missed_graph)
    233         uianimations.BlinkIn(self._incorrect_graph)
    234 
    235     def clear_result_graph(self):
    236         if self._correct_graph:
    237             self._correct_graph.Close()
    238         if self._missed_graph:
    239             self._missed_graph.Close()
    240         if self._incorrect_graph:
    241             self._incorrect_graph.Close()
    242         self._correct_horizontal_axis = None
    243         self._missed_horizontal_axis = None
    244         self._incorrect_horizontal_axis = None
    245         self._correct_graph = None
    246         self._missed_graph = None
    247         self._incorrect_graph = None
    248 
    249     def _create_result_graph_components(self, points, color, points_size = 4):
    250         time_values = self.get_time_values(points)
    251         flux_values = self.get_flux_values(points)
    252         category_axis = self._time_axis_type(time_values, dataRange=(self._time_axis.get_min_value(), self._time_axis.get_max_value()))
    253         category_axis.set_zoom(*self._control_axis.get_visible_range())
    254         if self.is_folding():
    255             category_axis.fold(self._fold_center, self._period_length)
    256         self._category_axes.append(category_axis)
    257         self._graph_area.AddAxis(orientation=axis.AxisOrientation.HORIZONTAL, axis=category_axis)
    258         graph = PointGraph(name='ResultGraph', parent=self._graph_area, categoryAxis=category_axis, valueAxis=self._flux_axis, values=flux_values, pointColor=color, pointSize=points_size, state=uiconst.UI_DISABLED, idx=0)
    259         return (category_axis, graph)
    260 
    261     def _show_result_icon_graphs(self, correct_intervals, missed_intervals, incorrect_intervals):
    262         axis1, graph1 = self._create_result_icon_graph_components(correct_intervals, 'res:/UI/Texture/classes/ProjectDiscovery/result_success.png', const.Colors.GREEN, localization.GetByLabel('UI/ProjectDiscovery/exoplanets/CorrectClickForInfo'))
    263         axis2, graph2 = self._create_result_icon_graph_components(missed_intervals, 'res:/UI/Texture/classes/ProjectDiscovery/result_missed.png', const.Colors.YELLOW, localization.GetByLabel('UI/ProjectDiscovery/exoplanets/MissedClickForInfo'))
    264         axis3, graph3 = self._create_result_icon_graph_components(incorrect_intervals, 'res:/UI/Texture/classes/ProjectDiscovery/result_fail.png', const.Colors.RED, localization.GetByLabel('UI/ProjectDiscovery/exoplanets/IncorrectClickForInfo'))
    265         self._result_icon_graphs = [graph1, graph2, graph3]
    266 
    267     def _get_intervals_centers(self, intervals):
    268         return [ interval[0] * 0.5 + interval[1] * 0.5 for interval in intervals ]
    269 
    270     def _create_result_icon_graph_components(self, intervals, icon_path, color, tooltip):
    271         interval_centers = self._get_intervals_centers(intervals)
    272         category_axis = self._time_axis_type(interval_centers, dataRange=(self._time_axis.get_min_value(), self._time_axis.get_max_value()))
    273         self._category_axes.append(category_axis)
    274         self._graph_area.AddAxis(orientation=axis.AxisOrientation.HORIZONTAL, axis=category_axis)
    275         graph = ResultIconGraph(name='ResultIconGraph', parent=self._graph_area, categoryAxis=category_axis, color=color, iconPath=icon_path, tooltipMessage=tooltip, transitIntervals=intervals, onClick=self._on_result_click, intervalMapping=self._interval_mapping)
    276         return (category_axis, graph)
    277 
    278     def _hide_icon_graphs(self, is_hidden = True):
    279         for graph in self._result_icon_graphs:
    280             graph.state = uiconst.UI_DISABLED if is_hidden else uiconst.UI_PICKCHILDREN
    281             animation = uianimations.BlinkOut if is_hidden else uianimations.BlinkIn
    282             animation(graph)
    283 
    284     def _on_result_click(self, minimum, maximum):
    285         self._hide_icon_graphs()
    286 
    287         def calibrate_in():
    288             self.clear_result_graph()
    289             self.calibrate_to_folded_mode(marker.get_center(), marker.get_period_length(), callback=lambda : self._show_result_graph() or sm.ScatterEvent('OnEnableDetrend') or sm.ScatterEvent('OnShowProjectDiscoveryResultBackButton'))
    290 
    291         self.hide_mini_map_zoom(True, duration=0.5)
    292         if (minimum, maximum) in self._interval_mapping:
    293             marker = self._interval_mapping[minimum, maximum]
    294             self._fold_result_points_indices, self._fold_result_state = result.get_intervals_points_indices_of_same_state(self._correct_intervals, self._missed_intervals, self._incorrect_intervals, (minimum, maximum), self._interval_mapping, self._graph_data)
    295             sm.ScatterEvent('OnDisplayTransitInformation', marker, state=self._fold_result_state)
    296             if len(marker.get_centers()) > 1:
    297                 sm.ScatterEvent('OnDisableDetrend')
    298                 self.reset_zoom(callback=calibrate_in)
    299                 return
    300         else:
    301             sm.ScatterEvent('OnDisplayTransitInformation', None, epoch=round(0.5 * minimum + 0.5 * maximum - self._graph_data[0][0], 3))
    302         sm.ScatterEvent('OnShowProjectDiscoveryResultBackButton')
    303         self.zoom_animated(minimum - (maximum - minimum) * 2, maximum + (maximum - minimum) * 2, max_duration=0.5)
    304 
    305     def OnProjectDiscoveryResultBackButtonPressed(self, *args, **kwargs):
    306         self._hide_icon_graphs(False)
    307         if self.is_folding():
    308             self.calibrate_to_unfolded_mode(callback=lambda : self.show_mini_map_zoom(True, 0.5) or sm.ScatterEvent('OnDisplayTransitMarkers'))
    309         else:
    310             self.reset_zoom()
    311             self.show_mini_map_zoom(True, 0.5)
    312         sm.ScatterEvent('OnHideTransitInformation')
    313 
    314     def setup_consensus_graph(self, consensus_data, transit_markers):
    315         if not consensus_data:
    316             return
    317         time_values = []
    318         for min_time, max_time, value in consensus_data:
    319             time_values.append(min_time)
    320             time_values.append(max_time)
    321 
    322         uianimations.BlinkOut(self.horizontalLines, startVal=0.05, endVal=0.0)
    323         uianimations.BlinkIn(self._consensus_graph_area)
    324         self._consensus_time_axis = self._time_axis_type(time_values)
    325         self._consensus_graph_area.AddAxis(orientation=axis.AxisOrientation.VERTICAL, axis=self._consensus_vertical_axis, minFactor=1.0, maxFactor=0.0)
    326         self._consensus_graph_area.AddAxis(orientation=axis.AxisOrientation.HORIZONTAL, axis=self._consensus_time_axis)
    327         self._category_axes.append(self._consensus_time_axis)
    328         self._consensus_graph = ConsensusGraph(name='ConsensusGraph', parent=self._consensus_graph_area, categoryAxis=self._consensus_time_axis, valueAxis=self._consensus_vertical_axis, values=[ point[2] for point in consensus_data ], transitMarkers=transit_markers, onClick=lambda minimum, maximum: self.zoom_animated(minimum - (maximum - minimum) * 2, maximum + (maximum - minimum) * 2, max_duration=0.5))
    329         self._consensus_graph_area.opacity = 0
    330         uianimations.FadeIn(self._consensus_graph_area)
    331         self._consensus_graph.Animate(animations.AnimationType.GROW, animations.AnimationDynamics.RANDOM, 1.0)
    332         uianimations.FadeTo(self._graph_area, startVal=self._graph_area.opacity, endVal=0.5)
    333 
    334     def get_time_visible_range(self):
    335         return self._control_axis.get_visible_range()
    336 
    337     def reset_zoom(self, callback = None):
    338         if not self.is_zoom():
    339             invoke_callback(callback)
    340         else:
    341             self.zoom_animated(self._time_axis.get_min_value(), self._time_axis.get_max_value(), callback=callback)
    342 
    343     def zoom_animated(self, minimum_time, maximum_time, max_duration = 1.0, callback = None):
    344         minimum_time = min(max(minimum_time, self._graph_data[0][0]), self._graph_data[-1][0])
    345         maximum_time = min(max(maximum_time, self._graph_data[0][0]), self._graph_data[-1][0])
    346         start_zoom = self.get_time_visible_range()
    347         end_zoom = (minimum_time, maximum_time)
    348         if start_zoom == end_zoom:
    349             invoke_callback(callback)
    350             return
    351         self._desired_animation_zoom = (minimum_time, maximum_time)
    352         self._zoom_animation_callback = callback
    353         duration = zoom.get_zoom_animation_duration(start_zoom, end_zoom, max_duration=max_duration)
    354         self._is_zoom_animation = True
    355         self.state = uiconst.UI_DISABLED
    356         self._on_animation()
    357         uianimations.MorphVector2(self, '_zoom', self._zoom, end_zoom, duration, callback=self._after_zoom_animation)
    358 
    359     def _after_zoom_animation(self):
    360         self._is_zoom_animation = False
    361         min_time, max_time = self._desired_animation_zoom[0], self._desired_animation_zoom[1]
    362         self._desired_animation_zoom = None
    363         self.zoom(min_time, max_time)
    364         self.state = uiconst.UI_NORMAL
    365         self._on_animation_stopped()
    366         invoke_callback(self._zoom_animation_callback)
    367         self._zoom_animation_callback = None
    368 
    369     def _point_graph_toggle(self, *args):
    370         if self._main_graph:
    371             self._is_point_graph = not self._main_graph.get_show_status_of_point_graph()
    372             self._main_graph.set_show_status_of_point_graph(self._is_point_graph)
    373             self._main_graph.hide_point_graph() if not self._is_point_graph else self._main_graph.show_point_graph()
    374 
    375     def update_data(self, data, new_zoomed_range = None, adjust_zoom = True):
    376         super(ExoPlanetsGraph, self).update_data(data, new_zoomed_range, adjust_zoom)
    377         if not self._is_mini_map_hidden and not self.is_animation_running():
    378             self._mini_graph.update_data(data)
    379 
    380     def update_animated(self, data, callback = None):
    381 
    382         def update_callback():
    383             self._is_update_animation = False
    384             self.update_data(self._original_data)
    385             self._on_animation_stopped()
    386             invoke_callback(callback)
    387 
    388         self.lock_graph_updates()
    389         self._is_update_animation = True
    390         self._on_animation()
    391         self._original_data = data
    392         self._start_animation_data = binning.bin(self.get_graph_data(), self.animation_binning_fidelity)
    393         self._end_animation_data = binning.bin(data, self.animation_binning_fidelity)
    394         uianimations.MorphScalar(self, '_update_progression', 0, 1, 0.5, callback=update_callback)
    395 
    396     def clean_container(self):
    397         if self._tool:
    398             self._tooltip.SetParent(None)
    399         super(ExoPlanetsGraph, self).clean_container()
    400         self._consensus_graph = None
    401         self._consensus_graph_area = None
    402         self._consensus_time_axis = None
    403         self._consensus_vertical_axis = None
    404         self._is_result_shown = False
    405         self.clear_result_graph()
    406 
    407     def _set_time_axis_dirty(self, *args):
    408         self._is_time_axis_dirty = True
    409 
    410     def on_time_axis_changed(self, *args):
    411         self.lock_graph_updates()
    412         min_value, max_value = self.get_time_visible_range()
    413         self.zoom(min_value, max_value)
    414         self._is_time_axis_dirty = False
    415 
    416     def hide_mini_map_zoom(self, is_animate = False, duration = 1.0, callback = None):
    417 
    418         def animation_callback():
    419             self._mini_map.state = uiconst.UI_HIDDEN
    420             invoke_callback(callback)
    421 
    422         if is_animate:
    423             uianimations.FadeOut(self._mini_map, duration=duration, callback=animation_callback)
    424         else:
    425             animation_callback()
    426 
    427     def show_mini_map_zoom(self, is_animate = False, duration = 1.0, callback = None):
    428 
    429         def animation_callback():
    430             invoke_callback(callback)
    431 
    432         self._mini_map.SetState(uiconst.UI_NORMAL)
    433         self._mini_map.pickState = uiconst.TR2_SPS_CHILDREN
    434         if is_animate:
    435             uianimations.FadeIn(self._mini_map, duration=duration, callback=animation_callback)
    436         else:
    437             animation_callback()
    438 
    439     def fold_animated(self, center, period):
    440 
    441         def animation_callback():
    442             self._is_fold_animation = False
    443             self.state = uiconst.UI_NORMAL
    444             self.fold(center, period)
    445             self._on_animation_stopped()
    446 
    447         if self._is_folding:
    448             animated_center = self._reverse_engineer_center_fix(center, period)
    449         else:
    450             time_values = [ time for time, flux in self._graph_data ]
    451             min_time, max_time = time_values[0], time_values[-1]
    452             self._period_length = max_time - min_time
    453             self._fold_center = min_time + self._period_length / 2.0
    454             animated_center = self._fold_center
    455         if (self._fold_center, self._period_length) == (center, period):
    456             return
    457         self._is_fold_animation = True
    458         self._on_animation()
    459         self.state = uiconst.UI_DISABLED
    460         duration = self.get_fold_animation_time(animated_center)
    461         uianimations.MorphVector2(self, '_fold_variables', (self._fold_center, self._period_length), (animated_center, period), duration, callback=animation_callback)
    462 
    463     def get_fold_animation_time(self, fold_center):
    464         max_length = (self._time_axis.get_max_value() - self._time_axis.get_min_value()) / 2.0
    465         diff_center = math.fabs(fold_center - self._fold_center)
    466         return diff_center / max_length * FOLD_ANIMATION_MAX_TIME
    467 
    468     def calibrate_to_folded_mode(self, calibration_center, calibration_period, transit_selection = None, duration = 1.0, callback = None):
    469 
    470         def animation_callback():
    471             self._on_calibration_animation_ended(True, transit_selection, calibration_center, calibration_period, callback)
    472 
    473         if self.is_folding():
    474             invoke_callback(callback)
    475             return
    476         self._remove_transit_selections_not_in_list([transit_selection])
    477         if transit_selection and transit_selection.get_period_length():
    478             self._calibration_axis = self._transit_selection_graphs[0].category_axis
    479             self._calibration_marking_start_points = transit_selection.get_centers()
    480             self._calibration_marking_end_points = calibration.get_end_time_values(start_time_values=self._calibration_marking_start_points, center=calibration_center, period=calibration_period, min_time=min(self.get_time_values(self._graph_data)), max_time=max(self.get_time_values(self._graph_data)))
    481         self.state = uiconst.UI_DISABLED
    482         self._is_calibration_animation = True
    483         self._on_animation()
    484         self._original_data = self.get_graph_data()
    485         self._start_animation_data = binning.bin(self.get_graph_data(), self.animation_binning_fidelity)
    486         self._end_animation_data = calibration.get_end_data(self._start_animation_data, calibration_center, calibration_period)
    487         uianimations.MorphScalar(self, '_calibration_progression', 0, 1, duration=duration, callback=animation_callback)
    488 
    489     def calibrate_to_unfolded_mode(self, transit_selection = None, duration = 1.0, callback = None):
    490 
    491         def animation_callback():
    492             self._on_calibration_animation_ended(False, transit_selection, callback=callback)
    493 
    494         if not self.is_folding():
    495             invoke_callback(callback)
    496             return
    497         self.state = uiconst.UI_DISABLED
    498         self._is_calibration_animation = True
    499         self._on_animation()
    500         self._original_data = self.get_graph_data()
    501         self._end_animation_data = binning.bin(self.get_graph_data(), self.animation_binning_fidelity)
    502         self._start_animation_data = calibration.get_end_data(self._end_animation_data, self._fold_center, self._period_length)
    503         self._remove_transit_selections_not_in_list([transit_selection])
    504         if transit_selection and transit_selection.get_period_length():
    505             self._calibration_axis = self._transit_selection_graphs[0].category_axis
    506             self._calibration_marking_end_points = transit_selection.get_centers()
    507             self._calibration_marking_start_points = calibration.get_end_time_values(start_time_values=self._calibration_marking_end_points, center=transit_selection.get_center(), period=transit_selection.get_period_length(), min_time=min(self.get_time_values(self._graph_data)), max_time=max(self.get_time_values(self._graph_data)))
    508         self.unfold()
    509         self.update_data(self._start_animation_data)
    510         uianimations.MorphScalar(self, '_calibration_progression', 0, 1, duration=duration, callback=animation_callback)
    511 
    512     def _on_calibration_animation_ended(self, is_folding, transit_selection, center = None, period = None, callback = None):
    513         if transit_selection:
    514             points = self._calibration_marking_start_points if is_folding else self._calibration_marking_end_points
    515             self._calibration_axis.set_data_points(points)
    516             self._calibration_axis = None
    517             self._calibration_marking_start_points = []
    518             self._calibration_marking_end_points = []
    519         self._is_calibration_animation = False
    520         self.update_data(self._original_data)
    521         if is_folding:
    522             self.fold(center, period)
    523         self.state = uiconst.UI_NORMAL
    524         self._on_animation_stopped()
    525         invoke_callback(callback)
    526 
    527     def _on_animation(self):
    528         self._hide_graph_labels()
    529         self.on_graph_movement()
    530         if self._is_result_shown:
    531             self.clear_result_graph()
    532 
    533     def _on_animation_stopped(self):
    534         if not self.is_animation_running():
    535             self._show_graph_labels()
    536             self.on_graph_movement_stopped()
    537             if self._is_result_shown:
    538                 self._show_result_graph()
    539 
    540     def _hide_graph_labels(self):
    541         uianimations.FadeOut(self._flux_labels, duration=0.1)
    542         uianimations.FadeOut(self._time_labels, duration=0.1)
    543 
    544     def _show_graph_labels(self):
    545         uianimations.FadeIn(self._flux_labels, duration=0.1)
    546         uianimations.FadeIn(self._time_labels, duration=0.1)
    547 
    548     def _reverse_engineer_center_fix(self, next_center, period_length):
    549         min_visible, max_visible = self._time_axis.get_visible_range()
    550         time_values = self.get_time_values(self._graph_data)
    551         min_time, max_time = min(time_values), max(time_values)
    552         if next_center < min_visible:
    553             while next_center < max_time:
    554                 next_center += period_length
    555 
    556         elif next_center > max_visible:
    557             while next_center > min_time:
    558                 next_center -= period_length
    559 
    560         return next_center
    561 
    562     def set_fux_display_state(self, state):
    563         self._flux_labels.Clear()
    564         if self._flux_axis:
    565             if state == FluxDisplayState.RELATIVE:
    566                 flux_values = self.get_flux_values(self._graph_data)
    567                 self._flux_axis.set_relative_flux_active(flux_values)
    568             else:
    569                 self._flux_axis.set_actual_flux_active()
    570 
    571     def display_transit_markers(self, transit_selections, mini_map_transit_markers = None):
    572         super(ExoPlanetsGraph, self).display_transit_markers(transit_selections)
    573         if not mini_map_transit_markers:
    574             mini_map_transit_markers = []
    575         if self._mini_graph:
    576             self._mini_graph.display_transit_markers(mini_map_transit_markers)
    577 
    578     def is_animation_running(self):
    579         is_other_animation_running = self._is_calibration_animation or self._is_fold_animation or self._is_update_animation or self._is_zoom_animation
    580         return is_other_animation_running
    581 
    582     def unlock_graph_updates(self):
    583         super(ExoPlanetsGraph, self).unlock_graph_updates()
    584         if self._mini_graph:
    585             self._mini_graph.unlock_graph_updates()
    586 
    587     def zoom(self, *args, **kwargs):
    588         if self._desired_animation_zoom and self._zoom_replicate_count > 5:
    589             self.StopAnimations()
    590             invoke_callback(self._after_zoom_animation)
    591             return
    592         super(ExoPlanetsGraph, self).zoom(*args, **kwargs)
    593 
    594     @property
    595     def _calibration_progression(self):
    596         return self._m_calibration_progression
    597 
    598     @_calibration_progression.setter
    599     def _calibration_progression(self, value):
    600         self.lock_graph_updates()
    601         self._m_calibration_progression = value
    602         data = linearly_interpolate_data(self._start_animation_data, self._end_animation_data, value)
    603         self.update_data(data)
    604         if self._calibration_marking_start_points:
    605             marking = [ (1 - value) * start_time + value * end_time for start_time, end_time in izip(self._calibration_marking_start_points, self._calibration_marking_end_points) ]
    606             self._calibration_axis.set_data_points(marking)
    607 
    608     @property
    609     def _zoom(self):
    610         return self._zoomed_range
    611 
    612     @_zoom.setter
    613     def _zoom(self, zoom_range):
    614         self.zoom(*zoom_range)
    615 
    616     @property
    617     def _fold_variables(self):
    618         return (self._fold_center, self._period_length)
    619 
    620     @_fold_variables.setter
    621     def _fold_variables(self, _center_and_period):
    622         self.fold(*_center_and_period)
    623 
    624     @property
    625     def _update_progression(self):
    626         return self._m_update_progression
    627 
    628     @_update_progression.setter
    629     def _update_progression(self, t):
    630         self._m_update_progression = t
    631         data = linearly_interpolate_data(self._start_animation_data, self._end_animation_data, t)
    632         self.update_data(data)
    633 
    634 
    635 class FluxDisplayState(object):
    636     RELATIVE = 0
    637     ACTUAL = 1
    638 
    639 
    640 def invoke_callback(callback, *args, **kwargs):
    641     if callable(callback):
    642         callback(*args, **kwargs)
    643 
    644 
    645 def linearly_interpolate_data(start_data, end_data, t):
    646     return [ geo2.Lerp(start, end, t) for start, end in izip(start_data, end_data) ]
    647 
    648 
    649 def consensus_tick_filter(tick):
    650     return tick <= 1.0
    651 
    652 
    653 def consensus_label_format(tick):
    654     return '%s%%' % int(tick * 100)