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

docinfosci / canvasxpress-python / 5f9854e2-3ace-4db8-8620-070e901a70eb

04 Apr 2025 03:41AM UTC coverage: 80.946% (+6.1%) from 74.814%
5f9854e2-3ace-4db8-8620-070e901a70eb

push

circleci

web-flow
JS local sources; Better Jupyter; Top level configs; R/JS attribute mapping

1.  Support local / custom CanvasXpress JS and CSS sources.
2.  Support top-level configuration declarations.
3.  Support mapping R/JS configuration key names to Pythonic editions.  For example, renderTo --> render_to.
4.  Improved Jupyter Notebook detection and pre-loading of CanvasXpress JS and CSS.

93 of 117 new or added lines in 10 files covered. (79.49%)

7 existing lines in 3 files now uncovered.

1933 of 2388 relevant lines covered (80.95%)

0.81 hits per line

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

19.18
/canvasxpress/render/popup.py
1
import os
1✔
2
import tempfile
1✔
3
import uuid
1✔
4
import webbrowser
1✔
5
from copy import deepcopy
1✔
6
from time import sleep
1✔
7
from typing import Any, Union, List
1✔
8

9
from canvasxpress.canvas import CanvasXpress
1✔
10
from canvasxpress.render.base import CXRenderable
1✔
11

12
_cx_fx_template = """
1✔
13
<script type="text/javascript">
14
    @code@
15
</script>
16
"""
17

18
_cx_html_template = """
1✔
19
<html>
20
    <head>
21
        <meta charset="UTF-8">
22
        <title>CanvasXpress</title>
23

24
        <!-- 1. Include the CanvasXpress library -->
25
        @canvasxpress_license@
26
        <link 
27
                href='@css_url@' 
28
                rel='stylesheet' 
29
                type='text/css'
30
                referrerpolicy='origin-when-cross-origin'
31
        />
32
        <script 
33
                src='@js_url@' 
34
                type='text/javascript'>
35
                referrerpolicy='origin-when-cross-origin'
36
        </script>
37
    </head>
38
    <body>
39
        <!-- 3. DOM element where the visualization will be displayed -->
40
        @canvases@
41
        <!-- 2. Include script to initialize object -->
42
        @js_functions@
43
     </body>
44
</html>
45
"""
46

47

48
class CXBrowserPopup(CXRenderable):
1✔
49
    """
50
    CXBrowserPopup is a `CXRenderable` that renders `CanvasXpress` objects into
51
    a Web page that is displayed in a pop-up browser window.
52
    """
53

54
    def __init__(self, *cx: Union[List[CanvasXpress], CanvasXpress, None]):
1✔
55
        """
56
        Initializes a new `CXBrowserPopup` object.
57
        :praram cx: `Union[List[CanvasXpress], CanvasXpress, None], ...`
58
            The `CanvasXpress` object(s) to be tracked.  See the `canvas`
59
            property, except that on initialization cx can be `None`.
60
            Multiple CanvasXpress objects are supported provided that
61
            they have distinct `render_to` targets.
62
        """
63
        super().__init__(*cx)
×
64

65
    def render(self, **kwargs: Any):
1✔
66
        """
67
        Renders the associated CanvasXpress object appropriate for display in
68
        a pop-up browser window.  Charts cannot have the same name,
69
        so render_to will be updated with a uuid for each conflicting chart.
70
        :param kwargs: `Any`
71
            Supports `columns` for any positive `int` of `1` or greater, with a
72
            default value of `1`.  Values less that `1` are ignored.  `columns`
73
            indicates how many charts should be rendered horizontally in the
74
            browser if more than one chart is being tracked.
75
        """
76
        render_targets = list()
×
77

78
        if self.canvas is None:
×
79
            pass
×
80

81
        elif isinstance(self.canvas, CanvasXpress):
×
82
            render_targets.append(deepcopy(self.canvas))
×
83

84
        else:
85
            for chart in self.canvas:
×
86
                render_targets.append(deepcopy(chart))
×
87

88
        used_render_targets = list()
×
89
        for target in render_targets:
×
90
            original_render_target = target.render_to
×
91
            if original_render_target in used_render_targets:
×
92
                target.render_to = (
×
93
                    original_render_target + "_" + str(uuid.uuid4()).replace("-", "_")
94
                )
95

96
            used_render_targets.append(target.render_to)
×
97

98
        render_targets.reverse()
×
99

100
        html_parts = [target.render_to_html_parts() for target in render_targets]
×
101

102
        canvases = [part["cx_canvas"] for part in html_parts]
×
103

104
        functions = [part["cx_js"] for part in html_parts]
×
105

106
        cx_license = ""
×
107
        for part in html_parts:
×
108
            if part.get("cx_license"):
×
109
                cx_license = part["cx_license"]
×
110
                break
×
111

112
        columns_arg = int(kwargs.get("columns", 1))
×
113
        columns = columns_arg if columns_arg > 0 else 1
×
114
        if len(canvases) < columns:
×
115
            columns = len(canvases)
×
116

117
        page_width = 0
×
118
        page_height = 0
×
119
        chart_count = len(canvases)
×
120
        canvas_table = '<table style="width:100%">'
×
121

122
        while chart_count > 0:
×
123
            candidate_width = 0
×
124
            candidate_height = 0
×
125

126
            canvas_table += "<tr>"
×
127
            for c in range(columns):
×
128
                canvas_table += "<td>"
×
129
                if chart_count > 0:
×
130
                    canvas_table += canvases[chart_count - 1]
×
131

132
                    candidate_width += render_targets[chart_count - 1].width
×
133
                    if render_targets[chart_count - 1].height > candidate_height:
×
134
                        candidate_height = render_targets[chart_count - 1].height
×
135

136
                canvas_table += "</td>"
×
137
                chart_count = chart_count - 1
×
138

139
            canvas_table += "</tr>"
×
140

141
            if candidate_width > page_width:
×
142
                page_width = candidate_width
×
143
            page_height += candidate_height
×
144

145
        js_functions = "\n".join(
×
146
            [_cx_fx_template.replace("@code@", fx) for fx in functions]
147
        )
148

NEW
149
        css_url = CanvasXpress.css_library_url()
×
NEW
150
        js_url = CanvasXpress.js_library_url()
×
151

152
        html = (
×
153
            _cx_html_template.replace("@canvases@", canvas_table)
154
            .replace("@canvasxpress_license@", cx_license)
155
            .replace("@js_functions@", js_functions)
156
            .replace("@css_url@", css_url)
157
            .replace("@js_url@", js_url)
158
        )
159

160
        tempdir = tempfile.TemporaryDirectory()
×
161

162
        temp_filename = os.path.join(tempdir.name, f"{str(uuid.uuid4())}.html")
×
163
        with open(temp_filename, "w") as temp_file:
×
164
            temp_file.write(html)
×
165

166
        webbrowser.open("file://" + temp_filename, new=1)
×
167

168
        sleep(2)
×
169
        tempdir.cleanup()
×
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

© 2025 Coveralls, Inc