• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

sandialabs / toyplot / 9912662049

12 Jul 2024 06:45PM UTC coverage: 94.497% (-0.1%) from 94.629%
9912662049

Pull #214

github

web-flow
Merge cce091bb5 into 93ab5d60c
Pull Request #214: add as_float, change repr(x) -> str(x)

70 of 87 new or added lines in 10 files covered. (80.46%)

31 existing lines in 2 files now uncovered.

5409 of 5724 relevant lines covered (94.5%)

8.5 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

74.75
/toyplot/marker.py
1
# Copyright 2014, Sandia Corporation. Under the terms of Contract
2
# DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain
3
# rights in this software.
4

5
"""Functionality for managing markers (shapes used to highlight datums in plots and text).
6
"""
7

8

9
import copy
9✔
10
import xml.sax.saxutils
9✔
11

12
import numpy
9✔
13

14
import toyplot.style
9✔
15
from toyplot.require import as_float
9✔
16

17

18
class Marker(object):
9✔
19
    """Represents the complete specification of a marker's appearance."""
20
    def __init__(self, shape, mstyle, size, angle, label, lstyle):
9✔
21
        self._shape = shape
9✔
22
        self._mstyle = mstyle
9✔
23
        self._size = size
9✔
24
        self._angle = angle
9✔
25
        self._label = label
9✔
26
        self._lstyle = lstyle
9✔
27

28
    @property
9✔
29
    def shape(self):
9✔
30
        return self._shape
9✔
31

32
    @property
9✔
33
    def mstyle(self):
9✔
34
        return self._mstyle
9✔
35

36
    @property
9✔
37
    def size(self):
9✔
38
        return self._size
9✔
39

40
    @property
9✔
41
    def angle(self):
9✔
42
        return self._angle
9✔
43

44
    @property
9✔
45
    def label(self):
9✔
46
        return self._label
9✔
47

48
    @property
9✔
49
    def lstyle(self):
9✔
50
        return self._lstyle
9✔
51

52
    def __add__(self, other):
9✔
53
        if isinstance(other, str):
9✔
54
            return self.to_html() + other
9✔
55
        elif isinstance(other, toyplot.marker.Marker):
9✔
56
            result = copy.deepcopy(self)
9✔
57
            if other._shape is not None:
9✔
58
                result._shape = other._shape
9✔
59
            result._mstyle = toyplot.style.combine(result.mstyle, other._mstyle)
9✔
60
            if other._size is not None:
9✔
61
                result._size = other._size
×
62
            if other._angle is not None:
9✔
63
                result._angle = other._angle
9✔
64
            if other._label is not None:
9✔
65
                result._label = other._label
9✔
66
            result._lstyle = toyplot.style.combine(result.lstyle, other._lstyle)
9✔
67
            return result
9✔
68
        else:
69
            raise ValueError("Can't add toyplot.marker.Marker and %r" % other) # pragma: no cover
70

71
    def __eq__(self, other):
9✔
72
        return self._shape == other._shape and self._mstyle == other._mstyle and self._shape == other._shape and self._angle == other._angle and self._label == other._label and self._lstyle == other._lstyle
×
73

74
    def __hash__(self):
9✔
75
        return hash((self._shape, self._mstyle, self._size, self._angle, self._label, self._lstyle))
×
76

77
    def __radd__(self, other):
9✔
78
        return other + self.to_html()
9✔
79

80
    def __repr__(self):
9✔
81
        return self.to_html()
×
82

83
    def __format__(self, format_spec):
9✔
84
        return self.to_html()
×
85

86
    def to_html(self):
9✔
87
        """Convert a marker specification to HTML markup that can be embedded in rich text."""
88
        return """<marker%s%s%s%s%s%s/>""" % (
9✔
89
            " shape='%s'"% xml.sax.saxutils.escape(self._shape) if self._shape else "",
90
            " mstyle='%s'" % toyplot.style.to_css(self._mstyle) if self._mstyle else "",
91
            " size='%s'"% self._size if self._size else "",
92
            " angle='%s'" % self._angle if self._angle else "",
93
            " label='%s'" % xml.sax.saxutils.escape(self._label) if self._label else "",
94
            " lstyle='%s'" % toyplot.style.to_css(self._lstyle) if self._lstyle else "",
95
            )
96

97
    def intersect(self, p):
9✔
98
        """Compute the intersection between this marker's border and a line segment.
99

100
        Parameters
101
        ----------
102
        p: :class:`numpy.ndarray` with shape (2), required
103
            Relative coordinates of a line segment originating at the center of this marker.
104

105
        Returns
106
        -------
107
        dp: :class:`numpy.ndarray` with shape (2)
108
            Relative coordinates of the intersection with this marker's border.
109
        """
110
        if self._size:
9✔
111
            if self._shape in ["o", "oo", "o|", "o/", "o-", "o\\", "o+", "ox", "o*"]:
9✔
112
                p /= numpy.linalg.norm(p)
9✔
113
                p *= self._size / 2
9✔
114
                return p
9✔
115
            if self._shape in ["s"]:
×
116
                u = numpy.max(numpy.abs(p))
×
117
                p /= u
×
118
                p *= self._size / 2
×
119
                return p
×
120
            if self._shape and self._shape[0] == "r":
×
121
                width, height = self._shape[1:].split("x")
×
NEW
122
                width = as_float(width)
×
NEW
123
                height = as_float(height)
×
124

125
                ap = numpy.abs(p)
×
126
                if ap[1]:
×
127
                    if ap[0] / ap[1] > width / height:
×
128
                        p = p / ap[0] * self._size * width / 2
×
129
                    else:
130
                        p = p / ap[1] * self._size * height / 2
×
131
                else:
132
                    p = p / ap[0] * self._size * width / 2
×
133
                return p
×
134

135
        return numpy.zeros((2,))
×
136

137

138
def create(shape=None, mstyle=None, size=None, angle=None, label=None, lstyle=None):
9✔
139
    """Factory function for creating instances of :class:`toyplot.marker.Marker`."""
140
    return Marker(shape=shape, mstyle=mstyle, size=size, angle=angle, label=label, lstyle=lstyle)
9✔
141

142

143
def convert(value):
9✔
144
    """Construct an instance of :class:`toyplot.marker.Marker` from alternative representations."""
145
    if value is None:
9✔
146
        return value
×
147
    if isinstance(value, Marker):
9✔
148
        return value
9✔
149
    if isinstance(value, str):
9✔
150
        return Marker(shape=value, mstyle=None, size=None, angle=None, label=None, lstyle=None)
9✔
151
    raise ValueError("Can't convert %r to toyplot.marker.Marker." % value) # pragma: no cover
152

153

154
def from_html(html):
9✔
155
    """Convert a parsed xml.etree.ElementTree representation of a marker to a :class:`toyplot.marker.Marker` object."""
156
    size = html.get("size", None)
9✔
157
    if size is not None:
9✔
NEW
158
        size = as_float(size)
×
159

160
    angle = html.get("angle", None)
9✔
161
    if angle is not None:
9✔
NEW
162
        angle = as_float(angle)
×
163

164
    return Marker(
9✔
165
        shape=html.get("shape", None),
166
        mstyle=toyplot.style.parse(html.get("mstyle", "")),
167
        size=size,
168
        angle=angle,
169
        label=html.get("label", None),
170
        lstyle=toyplot.style.parse(html.get("lstyle", "")),
171
        )
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc