Esempio n. 1
0
class OrbitPlotter3D(_BaseOrbitPlotter):
    """OrbitPlotter3D class.
    """

    def __init__(self):
        super().__init__()
        self._layout = Layout(
            autosize=True,
            scene=dict(
                xaxis=dict(
                    title="x (km)",
                ),
                yaxis=dict(
                    title="y (km)",
                ),
                zaxis=dict(
                    title="z (km)",
                ),
                aspectmode="data",  # Important!
            ),
        )

    def _plot_sphere(self, radius, color, name, center=[0, 0, 0] * u.km):
        xx, yy, zz = _generate_sphere(radius, center)
        sphere = Surface(
            x=xx.to(u.km).value, y=yy.to(u.km).value, z=zz.to(u.km).value,
            name=name,
            colorscale=[[0, color], [1, color]],
            cauto=False, cmin=1, cmax=1, showscale=False,  # Boilerplate
        )
        return sphere

    @u.quantity_input(elev=u.rad, azim=u.rad, distance=u.km)
    def set_view(self, elev, azim, distance=5 * u.km):
        x = distance * np.cos(elev) * np.cos(azim)
        y = distance * np.cos(elev) * np.sin(azim)
        z = distance * np.sin(elev)

        self._layout.update({
            "scene": {
                "camera": {
                    "eye": {
                        "x": x.to(u.km).value, "y": y.to(u.km).value, "z": z.to(u.km).value
                    }
                }
            }
        })

    def _plot_trajectory(self, trajectory, label, color, dashed):
        trace = Scatter3d(
            x=trajectory.x.to(u.km).value, y=trajectory.y.to(u.km).value, z=trajectory.z.to(u.km).value,
            name=label,
            line=dict(
                color=color,
                width=5,
                dash='dash' if dashed else 'solid',
            ),
            mode="lines",  # Boilerplate
        )
        self._data.append(trace)
Esempio n. 2
0
class OrbitPlotter3D(_BaseOrbitPlotter):
    """OrbitPlotter3D class.
    """

    def __init__(self):
        super().__init__()
        self._layout = Layout(
            autosize=True,
            scene=dict(
                xaxis=dict(
                    title="x (km)",
                ),
                yaxis=dict(
                    title="y (km)",
                ),
                zaxis=dict(
                    title="z (km)",
                ),
                aspectmode="data",  # Important!
            ),
        )

    def _plot_sphere(self, radius, color, name, center=[0, 0, 0] * u.km):
        xx, yy, zz = _generate_sphere(radius, center)
        sphere = Surface(
            x=xx.to(u.km).value, y=yy.to(u.km).value, z=zz.to(u.km).value,
            name=name,
            colorscale=[[0, color], [1, color]],
            cauto=False, cmin=1, cmax=1, showscale=False,  # Boilerplate
        )
        return sphere

    @u.quantity_input(elev=u.rad, azim=u.rad, distance=u.km)
    def set_view(self, elev, azim, distance=5 * u.km):
        x = distance * np.cos(elev) * np.cos(azim)
        y = distance * np.cos(elev) * np.sin(azim)
        z = distance * np.sin(elev)

        self._layout.update({
            "scene": {
                "camera": {
                    "eye": {
                        "x": x.to(u.km).value, "y": y.to(u.km).value, "z": z.to(u.km).value
                    }
                }
            }
        })

    def _plot_trajectory(self, trajectory, label, color, dashed):
        trace = Scatter3d(
            x=trajectory.x.to(u.km).value, y=trajectory.y.to(u.km).value, z=trajectory.z.to(u.km).value,
            name=label,
            line=dict(
                color=color,
                width=5,
                dash='dash' if dashed else 'solid',
            ),
            mode="lines",  # Boilerplate
        )
        self._data.append(trace)
Esempio n. 3
0
class OrbitPlotter2D(_BaseOrbitPlotter):
    """OrbitPlotter2D class.

    .. versionadded:: 0.9.0
    """

    def __init__(self):
        super().__init__()
        self._layout = Layout(
            autosize=True,
            xaxis=dict(
                title="x (km)",
                constrain="domain",
            ),
            yaxis=dict(
                title="y (km)",
                scaleanchor="x",
            ),
        )
        self._layout.update({
            "shapes": []
        })

    def _plot_sphere(self, radius, color, name, center=[0, 0, 0] * u.km):
        xx, yy = _generate_circle(radius, center)
        x_center, y_center, z_center = center
        trace = Scatter(x=xx.to(u.km).value, y=yy.to(u.km).value, mode='markers', line=dict(color=color, width=5,
                                                                                            dash='dash',), name=name)
        self._layout["shapes"] += (
            {
                'type': 'circle',
                'xref': 'x',
                'yref': 'y',
                'x0': (x_center - radius).to(u.km).value,
                'y0': (y_center - radius).to(u.km).value,
                'x1': (x_center + radius).to(u.km).value,
                'y1': (y_center + radius).to(u.km).value,
                'opacity': 1,
                'fillcolor': color,
                'line': {
                    'color': color,
                },
            },

        )
        return trace

    def _plot_trajectory(self, trajectory, label, color, dashed):
        trace = Scatter(
            x=trajectory.x.to(u.km).value, y=trajectory.y.to(u.km).value,
            name=label,
            line=dict(
                color=color,
                width=2,
                dash='dash' if dashed else 'solid',
            ),
            mode="lines",  # Boilerplate
        )
        self._data.append(trace)
Esempio n. 4
0
class OrbitPlotter2D(_BaseOrbitPlotter):
    """OrbitPlotter2D class.

    .. versionadded:: 0.9.0
    """

    def __init__(self):
        super().__init__()
        self._layout = Layout(
            autosize=True,
            xaxis=dict(
                title="x (km)",
                constrain="domain",
            ),
            yaxis=dict(
                title="y (km)",
                scaleanchor="x",
            ),
        )
        self._layout.update({
            "shapes": []
        })

    def _plot_sphere(self, radius, color, name, center=[0, 0, 0] * u.km):
        xx, yy = _generate_circle(radius, center)
        x_center, y_center, z_center = center
        trace = Scatter(x=xx.to(u.km).value, y=yy.to(u.km).value, mode='markers', line=dict(color=color, width=5,
                                                                                            dash='dash',), name=name)
        self._layout["shapes"] += (
            {
                'type': 'circle',
                'xref': 'x',
                'yref': 'y',
                'x0': (x_center - radius).to(u.km).value,
                'y0': (y_center - radius).to(u.km).value,
                'x1': (x_center + radius).to(u.km).value,
                'y1': (y_center + radius).to(u.km).value,
                'opacity': 1,
                'fillcolor': color,
                'line': {
                    'color': color,
                },
            },

        )
        return trace

    def _plot_trajectory(self, trajectory, label, color, dashed):
        trace = Scatter(
            x=trajectory.x.to(u.km).value, y=trajectory.y.to(u.km).value,
            name=label,
            line=dict(
                color=color,
                width=2,
                dash='dash' if dashed else 'solid',
            ),
            mode="lines",  # Boilerplate
        )
        self._data.append(trace)
Esempio n. 5
0
class OrbitPlotter3D(BaseOrbitPlotter):
    """OrbitPlotter3D class.

    """

    def __init__(self, figure=None, dark=False):
        super().__init__(figure)
        self._layout = Layout(
            autosize=True,
            scene=dict(
                xaxis=dict(title="x (km)"),
                yaxis=dict(title="y (km)"),
                zaxis=dict(title="z (km)"),
                aspectmode="data",  # Important!
            ),
        )
        if dark:
            self._layout.template = "plotly_dark"

    def _plot_point(self, radius, color, name, center=[0, 0, 0] * u.km):
        # We use _plot_sphere here because it's not easy to specify the size of a marker
        # in data units instead of pixels, see
        # https://stackoverflow.com/q/47086547
        return self._plot_sphere(radius, color, name, center)

    def _plot_sphere(self, radius, color, name, center=[0, 0, 0] * u.km):
        xx, yy, zz = generate_sphere(radius, center)
        sphere = Surface(
            x=xx.to(u.km).value,
            y=yy.to(u.km).value,
            z=zz.to(u.km).value,
            name=name,
            colorscale=[[0, color], [1, color]],
            cauto=False,
            cmin=1,
            cmax=1,
            showscale=False,
        )
        self._figure.add_trace(sphere)

        return sphere

    def _plot_trajectory(self, trajectory, label, color, dashed):
        trace = Scatter3d(
            x=trajectory.x.to(u.km).value,
            y=trajectory.y.to(u.km).value,
            z=trajectory.z.to(u.km).value,
            name=label,
            line=dict(color=color, width=5, dash="dash" if dashed else "solid"),
            mode="lines",  # Boilerplate
        )
        self._figure.add_trace(trace)

        return trace

    @u.quantity_input(elev=u.rad, azim=u.rad, distance=u.km)
    def set_view(self, elev, azim, distance=5 * u.km):
        x = distance * np.cos(elev) * np.cos(azim)
        y = distance * np.cos(elev) * np.sin(azim)
        z = distance * np.sin(elev)

        self._layout.update(
            {
                "scene": {
                    "camera": {
                        "eye": {
                            "x": x.to(u.km).value,
                            "y": y.to(u.km).value,
                            "z": z.to(u.km).value,
                        }
                    }
                }
            }
        )

        if not self._figure._in_batch_mode:
            return self.show()
Esempio n. 6
0
class OrbitPlotter3D:
    """OrbitPlotter3D class.
    """
    def __init__(self):
        self._layout = Layout(
            autosize=True,
            scene=dict(
                xaxis=dict(title="x (km)", ),
                yaxis=dict(title="y (km)", ),
                zaxis=dict(title="z (km)", ),
                aspectmode="data",  # Important!
            ),
        )
        self._data = []  # type: List[dict]

        # TODO: Refactor?
        self._attractor = None
        self._attractor_data = {}  # type: dict
        self._attractor_radius = np.inf * u.km

        self._color_cycle = cycle(plotly.colors.DEFAULT_PLOTLY_COLORS)

    @property
    def figure(self):
        return dict(
            data=self._data + [self._attractor_data],
            layout=self._layout,
        )

    def _redraw_attractor(self, min_radius=0 * u.km):
        # Select a sensible value for the radius: realistic for low orbits,
        # visible for high and very high orbits
        radius = max(self._attractor.R.to(u.km), min_radius.to(u.km))

        # If the resulting radius is smaller than the current one, redraw it
        if radius < self._attractor_radius:
            sphere = _plot_sphere(
                radius, BODY_COLORS.get(self._attractor.name, "#999999"),
                self._attractor.name)

            # Overwrite stored properties
            self._attractor_radius = radius
            self._attractor_data = sphere

    def _plot_trajectory(self, trajectory, label, color, dashed):
        trace = Scatter3d(
            x=trajectory.x.to(u.km).value,
            y=trajectory.y.to(u.km).value,
            z=trajectory.z.to(u.km).value,
            name=label,
            line=dict(
                color=color,
                width=5,
                dash='dash' if dashed else 'solid',
            ),
            mode="lines",  # Boilerplate
        )
        self._data.append(trace)

    def set_attractor(self, attractor):
        """Sets plotting attractor.
        Parameters
        ----------
        attractor : ~poliastro.bodies.Body
            Central body.
        """
        if self._attractor is None:
            self._attractor = attractor

        elif attractor is not self._attractor:
            raise NotImplementedError(
                "Attractor has already been set to {}.".format(
                    self._attractor.name))

    @u.quantity_input(elev=u.rad, azim=u.rad)
    def set_view(self, elev, azim, distance=5):
        x = distance * np.cos(elev) * np.cos(azim)
        y = distance * np.cos(elev) * np.sin(azim)
        z = distance * np.sin(elev)

        self._layout.update({
            "scene": {
                "camera": {
                    "eye": {
                        "x": x.to(u.km).value,
                        "y": y.to(u.km).value,
                        "z": z.to(u.km).value
                    }
                }
            }
        })

    def plot(self, orbit, *, label=None, color=None):
        """Plots state and osculating orbit in their plane.
        """
        if color is None:
            color = next(self._color_cycle)

        self.set_attractor(orbit.attractor)

        self._redraw_attractor(orbit.r_p * 0.15)  # Arbitrary threshold

        label = _generate_label(orbit, label)
        trajectory = orbit.sample()

        self._plot_trajectory(trajectory, label, color, True)

        # Plot sphere in the position of the body
        radius = min(self._attractor_radius * 0.5,
                     (norm(orbit.r) - orbit.attractor.R) *
                     0.3)  # Arbitrary thresholds
        sphere = _plot_sphere(radius, color, label, center=orbit.r)

        self._data.append(sphere)

    def plot_trajectory(self, trajectory, *, label=None, color=None):
        """Plots a precomputed trajectory.
        An attractor must be set first.
        Parameters
        ----------
        trajectory : ~astropy.coordinates.CartesianRepresentation
            Trajectory to plot.
        """
        if self._attractor is None:
            raise ValueError("An attractor must be set up first, please use "
                             "set_attractor(Major_Body).")
        else:
            self._redraw_attractor(trajectory.norm().min() *
                                   0.15)  # Arbitrary threshold

        self._plot_trajectory(trajectory, str(label), color, False)

    def _prepare_plot(self, **layout_kwargs):
        # If there are no orbits, draw only the attractor
        if not self._data:
            self._redraw_attractor()

        if layout_kwargs:
            self._layout.update(layout_kwargs)

    def show(self, **layout_kwargs):
        self._prepare_plot(**layout_kwargs)

        plot(self.figure)

    def savefig(self, filename, **layout_kwargs):
        self._prepare_plot(**layout_kwargs)

        basename, ext = os.path.splitext(filename)
        export(
            self.figure,
            image=ext[1:],
            image_filename=basename,
            show_link=False,  # Boilerplate
        )
Esempio n. 7
0
class PlotlyGraph:
    def __init__(self,
                 graph_title: object,
                 random_colors: object = False,
                 y_type: object = None) -> object:
        self.random_colors = random_colors
        self.default_colors = chain([
            'rgb(47, 117, 181)', 'rgb(84, 130, 53)', 'rgb(198, 89, 17)',
            'rgb(51, 63, 79)', 'rgb(110, 65, 143)', 'rgb(165, 27, 27)'
        ])  # TODO possible crash if there are more then 6 scatters

        self.data = []
        self.layout = Layout(title=graph_title, separators=', ')
        # self.layout = Layout(title=graph_title, separators=', ', width=1000, height=900) # TODO: resolution for PNG
        # self.layout.update(titlefont=dict(size=36))
        # self.layout.update(width=900, height=500)
        # self.layout.update(font=dict(family='Courier New, monospace', size=25, color='#7f7f7f'))
        # self.layout()

        self.layout.update(xaxis=dict(title='x_axis',
                                      showline=True,
                                      showticklabels=True,
                                      ticks='outside',
                                      separatethousands=True))
        if y_type == 'log':
            self.layout.update(yaxis=dict(title='y_axis',
                                          showline=True,
                                          anchor='x',
                                          side='left',
                                          showticklabels=True,
                                          ticks='outside',
                                          separatethousands=True,
                                          exponentformat='none',
                                          type='log',
                                          autorange=True))
        else:
            self.layout.update(yaxis=dict(title='y_axis',
                                          showline=True,
                                          anchor='x',
                                          side='left',
                                          showticklabels=True,
                                          ticks='outside',
                                          separatethousands=True,
                                          exponentformat='none'))
        self.layout.update(yaxis2=dict(title='y2_axis'))

        self.layout.update(
            legend=dict(orientation='h', xanchor='center', y=-0.3))

        self.shapes = []

        self.max_x = 0
        self.max_y = 0
        self.max_y2 = 0

    @staticmethod
    def _moving_average(interval, window_size):
        window = numpy.ones(int(window_size)) / float(window_size)
        return numpy.convolve(interval, window, 'same')

    @staticmethod
    def _random_color():
        return 'rgb({r}, {g}, {b})'.format(r=randint(0, 255),
                                           g=randint(0, 255),
                                           b=randint(0, 255))

    def append_data(self,
                    name: str,
                    x: list,
                    y: list = [],
                    y2: bool = False,
                    sma: bool = False,
                    sma_interval: int = 5,
                    line_color: list = {},
                    line_type: str = 'line'):
        if line_color == {}:
            if self.random_colors:
                line_color = self._random_color()
            else:
                line_color = next(self.default_colors)

        if line_type == 'line':
            if len(x) is 0 or len(y) is 0:
                raise ValueError('"x" or "y" must not be empty')
            if len(x) != len(y):
                raise ValueError('"x" and "y" must be the same length')

            self.max_x = max([self.max_x, max(x)])

            if y2:
                self.max_y2 = max(
                    [self.max_y2,
                     max(n for n in y if n is not None)])
                self.layout.update(
                    yaxis2=dict(title=self.layout['yaxis2']['title'],
                                showline=True,
                                anchor='x',
                                overlaying='y',
                                side='right',
                                showticklabels=True,
                                ticks='outside',
                                showgrid=False,
                                separatethousands=True,
                                range=[0, self.max_y2]))
            else:
                self.max_y = max(
                    [self.max_y,
                     max(n for n in y if n is not None)])
                self.layout.update(yaxis=dict(range=[0, self.max_y]))

            scatter_params = dict()
            scatter_params['x'] = x
            scatter_params['y'] = y
            if sma:
                scatter_params['opacity'] = 0.5
            scatter_params['line'] = plotly.graph_objs.scatter.Line(
                width=2, color=line_color)
            scatter_params['name'] = name
            if y2:
                scatter_params['yaxis'] = 'y2'
            self.data.append(Scatter(**scatter_params))

            if sma:

                # filtering None values
                sma_x = [
                    x[offset] for offset, value in enumerate(y)
                    if value is not None
                ]
                sma_y = [value for value in y if value is not None]

                ma = self._moving_average(sma_y, sma_interval)
                ma_scatter_params = dict()
                ma_scatter_params['x'] = sma_x[sma_interval:1 - sma_interval]
                ma_scatter_params['y'] = ma[sma_interval:1 - sma_interval]
                ma_scatter_params['line'] = plotly.graph_objs.scatter.Line(
                    width=2, color=line_color)
                ma_scatter_params['name'] = name + ' (sma)'
                if y2:
                    ma_scatter_params['yaxis'] = 'y2'
                self.data.append(Scatter(**ma_scatter_params))
        elif line_type == 'histogramm':
            scatter_params = dict()
            scatter_params['x'] = x
            if len(y) > 0:
                scatter_params['y'] = y
                scatter_params['histfunc'] = 'sum'
            scatter_params['name'] = name
            scatter_params['type'] = 'histogram'
            scatter_params['marker'] = dict(color=line_color)
            self.data.append(scatter_params)

    def config_axes(self,
                    x_sign: str = False,
                    y_sign: str = False,
                    y2_sign: str = False,
                    x_max=False,
                    y_max=False,
                    y2_max=False):
        self.sign_axes(x_sign=x_sign, y_sign=y_sign, y2_sign=y2_sign)
        if x_max:
            self.layout.update(xaxis=dict(range=[0, x_max]))
        if y_max:
            self.layout.update(yaxis=dict(range=[0, y_max]))
        if y2_max:
            self.layout.update(yaxis2=dict(range=[0, y2_max]))

    def sign_axes(self,
                  x_sign: str = False,
                  y_sign: str = False,
                  y2_sign: str = False):
        if x_sign:
            self.layout.update(xaxis=dict(title=x_sign))
        if y_sign:
            self.layout.update(yaxis=dict(title=y_sign))
        if y2_sign:
            self.layout.update(yaxis2=dict(title=y2_sign))

    # to-do: исправить следующее поведение
    # add_vertical_line/add_horizontal_line в случае использивания имен
    # должны вызываться после добавления всех линий на график
    # в противном случае они будут идти не через весь график

    def add_vertical_line(self,
                          x,
                          color='rgb(55, 128, 191)',
                          width=3,
                          name=None):
        if name != None:
            scatter_params = dict()
            scatter_params['x'] = [x, x]
            scatter_params['y'] = [0, self.max_y]
            scatter_params['line'] = Line(width=width, color=color)
            scatter_params['name'] = name
            self.data.append(Scatter(**scatter_params))
        else:
            self.shapes.append(
                dict(type='line',
                     x0=x,
                     y0=0,
                     x1=x,
                     y1=None,
                     line=dict(color=color, width=width)))

    def add_horizontal_line(self,
                            y,
                            color='rgb(55, 128, 191)',
                            width=3,
                            name=None):
        if name != None:
            scatter_params = dict()
            scatter_params['x'] = [0, self.max_x]
            scatter_params['y'] = [y, y]
            scatter_params['line'] = Line(width=width, color=color)
            scatter_params['name'] = name
            self.data.append(Scatter(**scatter_params))
        else:
            self.shapes.append(
                dict(type='line',
                     x0=0,
                     y0=y,
                     x1=None,
                     y1=y,
                     line=dict(color=color, width=width)))

    def add_redline(self, x):
        self.add_vertical_line(x=x, color='red', width=3)

    def plot(self, file_name):
        if len(self.data) == 0:
            print('No data to plot')
            return 1

        if len(self.shapes) > 0:
            for shape in self.shapes:
                if shape['x1'] is None:
                    shape['x1'] = self.max_x
                elif shape['y1'] is None:
                    shape['y1'] = self.max_y
            self.layout.update(shapes=self.shapes)

        plotly.offline.plot(
            dict(layout=self.layout, data=self.data),
            filename=file_name,
            auto_open=False,
            # image='png', image_filename='io',
            image_width=700,
            image_height=450,
            show_link=False)
Esempio n. 8
0
class OrbitPlotter3D(BaseOrbitPlotter):
    """OrbitPlotter3D class.

    """
    def __init__(self, figure=None, dark=False):
        super().__init__(figure)
        self._layout = Layout(
            autosize=True,
            scene=dict(
                xaxis=dict(title="x (km)"),
                yaxis=dict(title="y (km)"),
                zaxis=dict(title="z (km)"),
                aspectmode="data",  # Important!
            ),
        )
        if dark:
            self._layout.template = "plotly_dark"

    def _plot_point(self, radius, color, name, center=[0, 0, 0] * u.km):
        # We use _plot_sphere here because it's not easy to specify the size of a marker
        # in data units instead of pixels, see
        # https://stackoverflow.com/q/47086547
        return self._plot_sphere(radius, color, name, center)

    def _plot_sphere(self, radius, color, name, center=[0, 0, 0] * u.km):
        xx, yy, zz = generate_sphere(radius, center)
        sphere = Surface(
            x=xx.to(u.km).value,
            y=yy.to(u.km).value,
            z=zz.to(u.km).value,
            name=name,
            colorscale=[[0, color], [1, color]],
            cauto=False,
            cmin=1,
            cmax=1,
            showscale=False,
        )
        self._figure.add_trace(sphere)

        return sphere

    def _plot_trajectory(self, trajectory, label, color, dashed):
        trace = Scatter3d(
            x=trajectory.x.to(u.km).value,
            y=trajectory.y.to(u.km).value,
            z=trajectory.z.to(u.km).value,
            name=label,
            line=dict(color=color, width=5,
                      dash="dash" if dashed else "solid"),
            mode="lines",  # Boilerplate
        )
        self._figure.add_trace(trace)

        return trace

    @u.quantity_input(elev=u.rad, azim=u.rad, distance=u.km)
    def set_view(self, elev, azim, distance=5 * u.km):
        x = distance * np.cos(elev) * np.cos(azim)
        y = distance * np.cos(elev) * np.sin(azim)
        z = distance * np.sin(elev)

        self._layout.update({
            "scene": {
                "camera": {
                    "eye": {
                        "x": x.to(u.km).value,
                        "y": y.to(u.km).value,
                        "z": z.to(u.km).value,
                    }
                }
            }
        })

        return self.show()
Esempio n. 9
0
class PlotlyGraph:
    def __init__(self, graph_title, random_colors: bool = False):
        self.random_colors = random_colors
        self.default_colors = chain([
            'rgb(47, 117, 181)', 'rgb(84, 130, 53)', 'rgb(198, 89, 17)',
            'rgb(51, 63, 79)', 'rgb(110, 65, 143)', 'rgb(165, 27, 27)'
        ])

        self.data = []
        self.layout = Layout(title=graph_title, separators=', ')
        # self.layout = Layout(title=graph_title, separators=', ', width=1000, height=900) # TODO: resolution for PNG
        # self.layout.update(titlefont=dict(size=36))
        # self.layout.update(width=900, height=500)
        # self.layout.update(font=dict(family='Courier New, monospace', size=25, color='#7f7f7f'))
        # self.layout()

        self.layout.update(xaxis=dict(title='x_axis',
                                      showline=True,
                                      showticklabels=True,
                                      ticks='outside',
                                      separatethousands=True))
        self.layout.update(yaxis=dict(title='y_axis',
                                      showline=True,
                                      anchor='x',
                                      side='left',
                                      showticklabels=True,
                                      ticks='outside',
                                      separatethousands=True,
                                      exponentformat='none'))
        self.layout.update(
            legend=dict(orientation='h', xanchor='middle', y=-0.3))

        self.shapes = []

        self.max_x = 0
        self.max_y = 0
        self.max_y2 = 0

    @staticmethod
    def _moving_average(interval, window_size):
        window = numpy.ones(int(window_size)) / float(window_size)
        return numpy.convolve(interval, window, 'same')

    @staticmethod
    def _random_color():
        return 'rgb({r}, {g}, {b})'.format(r=randint(0, 255),
                                           g=randint(0, 255),
                                           b=randint(0, 255))

    def append_data(self,
                    name: str,
                    x: list,
                    y: list,
                    y2: bool = False,
                    sma: bool = False,
                    sma_interval: int = 5):
        if len(x) is 0 or len(y) is 0:
            raise ValueError('"x" or "y" must not be empty')
        if len(x) != len(y):
            raise ValueError('"x" and "y" must be the same length')

        if self.random_colors:
            line_color = self._random_color()
        else:
            line_color = next(self.default_colors)

        self.max_x = max([self.max_x, max(x)])

        if y2:
            self.max_y2 = max(
                [self.max_y2, max(n for n in y if n is not None)])
            self.layout.update(yaxis2=dict(title='y2_axis',
                                           showline=True,
                                           anchor='x',
                                           overlaying='y',
                                           side='right',
                                           showticklabels=True,
                                           ticks='outside',
                                           showgrid=False,
                                           separatethousands=True,
                                           range=[0, self.max_y2]))
        else:
            self.max_y = max([self.max_y, max(n for n in y if n is not None)])
            self.layout.update(yaxis=dict(range=[0, self.max_y]))

        scatter_params = dict()
        scatter_params['x'] = x
        scatter_params['y'] = y
        if sma:
            scatter_params['opacity'] = '0.5'
        scatter_params['line'] = Line(width=2, color=line_color)
        scatter_params['name'] = name
        if y2:
            scatter_params['yaxis'] = 'y2'
        self.data.append(Scatter(**scatter_params))

        if sma:

            # filtering None values
            sma_x = [
                x[offset] for offset, value in enumerate(y)
                if value is not None
            ]
            sma_y = [value for value in y if value is not None]

            ma = self._moving_average(sma_y, sma_interval)
            ma_scatter_params = dict()
            ma_scatter_params['x'] = sma_x[sma_interval:1 - sma_interval]
            ma_scatter_params['y'] = ma[sma_interval:1 - sma_interval]
            ma_scatter_params['line'] = Line(width=2, color=line_color)
            ma_scatter_params['name'] = name + ' (sma)'
            if y2:
                ma_scatter_params['yaxis'] = 'y2'
            self.data.append(Scatter(**ma_scatter_params))

    def config_axes(self,
                    x_sign: str = False,
                    y_sign: str = False,
                    y2_sign: str = False,
                    x_max=False,
                    y_max=False,
                    y2_max=False):
        self.sign_axes(x_sign=x_sign, y_sign=y_sign, y2_sign=y2_sign)
        if x_max:
            self.layout.update(xaxis=dict(range=[0, x_max]))
        if y_max:
            self.layout.update(yaxis=dict(range=[0, y_max]))
        if y2_max:
            self.layout.update(yaxis2=dict(range=[0, y2_max]))

    def sign_axes(self,
                  x_sign: str = False,
                  y_sign: str = False,
                  y2_sign: str = False):
        if x_sign:
            self.layout.update(xaxis=dict(title=x_sign))
        if y_sign:
            self.layout.update(yaxis=dict(title=y_sign))
        if y2_sign:
            self.layout.update(yaxis2=dict(title=y2_sign))

    def add_vertical_line(self, x, color='rgb(55, 128, 191)', width=3):
        self.shapes.append(
            dict(type='line',
                 x0=x,
                 y0=0,
                 x1=x,
                 y1=None,
                 line=dict(color=color, width=width)))

    def add_horizontal_line(self, y, color='rgb(55, 128, 191)', width=3):
        self.shapes.append(
            dict(type='line',
                 x0=0,
                 y0=y,
                 x1=None,
                 y1=y,
                 line=dict(color=color, width=width)))

    def add_redline(self, x):
        self.add_vertical_line(x=x, color='red', width=3)

    def plot(self, file_name):
        if len(self.data) == 0:
            print('No data to plot')
            return 1

        if len(self.shapes) > 0:
            for shape in self.shapes:
                if shape['x1'] is None:
                    shape['x1'] = self.max_x
                elif shape['y1'] is None:
                    shape['y1'] = self.max_y
            self.layout.update(shapes=self.shapes)

        plotly.offline.plot(
            dict(layout=self.layout, data=self.data),
            filename=file_name,
            auto_open=False,
            # image='png', image_filename='io',
            image_width=700,
            image_height=450,
            show_link=False)
Esempio n. 10
0
class OrbitPlotter2D:
    """OrbitPlotter2D class.

    .. versionadded:: 0.9.0

    Experimental alternative to :py:class:`OrbitPlotter`
    that uses Plotly instead of matplotlib.
    Some visualization issues pending, use with care.

    """

    def __init__(self):
        self._layout = Layout(
            autosize=True,
            xaxis=dict(
                title="x (km)",
                constrain="domain",
            ),
            yaxis=dict(
                title="y (km)",
                scaleanchor="x",
            ),
        )
        self._layout.update({
            "shapes": []
        })
        self._data = []  # type: List[dict]
        self._attractor = None
        self._attractor_data = {}  # type: dict
        self._attractor_radius = np.inf * u.km

        self._color_cycle = cycle(plotly.colors.DEFAULT_PLOTLY_COLORS)

    @property
    def figure(self):
        return dict(
            data=self._data + [self._attractor_data],
            layout=self._layout,
        )

    def _plot_circle(self, radius, color, name, center=[0, 0, 0] * u.km):
        xx, yy = _generate_circle(radius, center)
        x_center, y_center, z_center = center
        trace = Scatter(x=xx.to(u.km).value, y=yy.to(u.km).value, mode='markers', line=dict(color=color, width=5,
                                                                                            dash='dash',), name=name)
        self._layout["shapes"].append(
            {
                'type': 'circle',
                'xref': 'x',
                'yref': 'y',
                'x0': (x_center - radius).to(u.km).value,
                'y0': (y_center - radius).to(u.km).value,
                'x1': (x_center + radius).to(u.km).value,
                'y1': (y_center + radius).to(u.km).value,
                'opacity': 1,
                'fillcolor': color,
                'line': {
                    'color': color,
                },
            },

        )
        return trace

    def _redraw_attractor(self, min_radius=0 * u.km):
        # Select a sensible value for the radius: realistic for low orbits,
        # visible for high and very high orbits
        radius = max(self._attractor.R.to(u.km), min_radius.to(u.km))

        # If the resulting radius is smaller than the current one, redraw it
        if radius < self._attractor_radius:
            circle = self._plot_circle(
                radius, BODY_COLORS.get(self._attractor.name, "#999999"), self._attractor.name)

            # Overwrite stored properties
            self._attractor_radius = radius
            self._attractor_data = circle

    def _plot_trajectory(self, trajectory, label, color, dashed):
        trace = Scatter(
            x=trajectory.x.to(u.km).value, y=trajectory.y.to(u.km).value,
            name=label,
            line=dict(
                color=color,
                width=2,
                dash='dash' if dashed else 'solid',
            ),
            mode="lines",  # Boilerplate
        )
        self._data.append(trace)

    def set_attractor(self, attractor):
        """Sets plotting attractor.

        Parameters
        ----------
        attractor : ~poliastro.bodies.Body
            Central body.
        """
        if self._attractor is None:
            self._attractor = attractor

        elif attractor is not self._attractor:
            raise NotImplementedError("Attractor has already been set to {}.".format(self._attractor.name))

    def plot(self, orbit, *, label=None, color=None):
        """Plots state and osculating orbit in their plane.

        Parameters
        ----------
        orbit : ~poliastro.twobody.orbit.Orbit
        label : string, optional
        color : string, optional
        """
        if color is None:
            color = next(self._color_cycle)

        self.set_attractor(orbit.attractor)

        self._redraw_attractor(orbit.r_p * 0.15)  # Arbitrary threshold

        label = _generate_label(orbit, label)
        _, trajectory = orbit.sample()

        self._plot_trajectory(trajectory, label, color, True)

        # Plot sphere in the position of the body
        radius = min(self._attractor_radius * 0.5, (norm(orbit.r) - orbit.attractor.R) * 0.3)  # Arbitrary thresholds
        circle = self._plot_circle(
            radius, color, label, center=orbit.r)

        self._data.append(circle)

    def plot_trajectory(self, trajectory, *, label=None, color=None):
        """Plots a precomputed trajectory.

        An attractor must be set first.

        Parameters
        ----------
        trajectory : ~astropy.coordinates.CartesianRepresentation
            Trajectory to plot.
        label : string, optional
        color : string, optional

        """
        if self._attractor is None:
            raise ValueError("An attractor must be set up first, please use "
                             "set_attractor(Major_Body).")
        else:
            self._redraw_attractor(trajectory.norm().min() * 0.15)  # Arbitrary threshold

        self._plot_trajectory(trajectory, str(label), color, False)

    def _prepare_plot(self, **layout_kwargs):
        # If there are no orbits, draw only the attractor
        if not self._data:
            self._redraw_attractor()

        if layout_kwargs:
            self._layout.update(layout_kwargs)

    def show(self, **layout_kwargs):
        """Shows the plot in the Notebook.
        """
        self._prepare_plot(**layout_kwargs)

        iplot(self.figure)

    def savefig(self, filename, **layout_kwargs):
        """Function for saving the plot locally.

        Parameters
        ----------
        filename : string, format = "anyname.anyformat"
                    anyformat can only be jpeg, png, svg, webp
        """
        self._prepare_plot(**layout_kwargs)

        basename, ext = os.path.splitext(filename)
        export(
            self.figure,
            image=ext[1:], image_filename=basename,
            show_link=False,  # Boilerplate
        )
Esempio n. 11
0
# Finally, we create the plotly graph by creating a separate subplot for each channel

# In[15]:

step = 1. / n_channels
kwargs = dict(domain=[1 - step, 1], showticklabels=False, zeroline=False, showgrid=False)

# create objects for layout and traces
layout = Layout(yaxis=YAxis(kwargs), showlegend=False)
traces = [Scatter(x=times, y=data.T[:, 0])]

# loop over the channels
for ii in range(1, n_channels):
        kwargs.update(domain=[1 - (ii + 1) * step, 1 - ii * step])
        layout.update({'yaxis%d' % (ii + 1): YAxis(kwargs), 'showlegend': False})
        traces.append(Scatter(x=times, y=data.T[:, ii], yaxis='y%d' % (ii + 1)))

# add channel names using Annotations
annotations = Annotations([Annotation(x=-0.06, y=0, xref='paper', yref='y%d' % (ii + 1),
                                      text=ch_name, font=Font(size=9), showarrow=False)
                          for ii, ch_name in enumerate(ch_names)])
layout.update(annotations=annotations)

# set the size of the figure and plot it
layout.update(autosize=False, width=1000, height=600)
fig = Figure(data=Data(traces), layout=layout)
py.iplot(fig, filename='shared xaxis')


# We can look at the list of bad channels from the ``info`` dictionary