lets-plot 4.6.1__cp310-cp310-macosx_11_0_arm64.whl → 4.7.0rc1__cp310-cp310-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of lets-plot might be problematic. Click here for more details.
- lets_plot/_global_settings.py +5 -0
- lets_plot/_kbridge.py +7 -0
- lets_plot/_type_utils.py +29 -6
- lets_plot/_version.py +1 -1
- lets_plot/bistro/im.py +2 -2
- lets_plot/bistro/waterfall.py +93 -12
- lets_plot/export/ggsave_.py +23 -15
- lets_plot/frontend_context/_configuration.py +8 -1
- lets_plot/geo_data/__init__.py +2 -1
- lets_plot/package_data/lets-plot.min.js +2 -1
- lets_plot/plot/annotation.py +75 -18
- lets_plot/plot/core.py +147 -30
- lets_plot/plot/geom.py +730 -89
- lets_plot/plot/geom_function_.py +1 -1
- lets_plot/plot/geom_imshow_.py +42 -51
- lets_plot/plot/geom_livemap_.py +2 -22
- lets_plot/plot/ggtb_.py +0 -1
- lets_plot/plot/pos.py +13 -44
- lets_plot/plot/scale_position.py +9 -3
- lets_plot/plot/series_meta.py +179 -105
- lets_plot/plot/stat.py +4 -4
- lets_plot/plot/subplots.py +4 -4
- lets_plot/plot/theme_.py +55 -52
- lets_plot/plot/util.py +15 -4
- lets_plot/tilesets.py +69 -4
- {lets_plot-4.6.1.dist-info → lets_plot-4.7.0rc1.dist-info}/METADATA +28 -20
- {lets_plot-4.6.1.dist-info → lets_plot-4.7.0rc1.dist-info}/RECORD +35 -31
- {lets_plot-4.6.1.dist-info → lets_plot-4.7.0rc1.dist-info}/WHEEL +1 -1
- lets_plot-4.7.0rc1.dist-info/licenses/licenses/LICENSE.FreeType +166 -0
- lets_plot-4.7.0rc1.dist-info/licenses/licenses/LICENSE.ImageMagick +106 -0
- lets_plot-4.7.0rc1.dist-info/licenses/licenses/LICENSE.expat +21 -0
- lets_plot-4.7.0rc1.dist-info/licenses/licenses/LICENSE.fontconfig +200 -0
- lets_plot_kotlin_bridge.cpython-310-darwin.so +0 -0
- {lets_plot-4.6.1.dist-info → lets_plot-4.7.0rc1.dist-info/licenses}/LICENSE +0 -0
- {lets_plot-4.6.1.dist-info → lets_plot-4.7.0rc1.dist-info}/top_level.txt +0 -0
lets_plot/plot/annotation.py
CHANGED
|
@@ -14,7 +14,24 @@ __all__ = ['layer_labels']
|
|
|
14
14
|
|
|
15
15
|
class layer_labels(FeatureSpec):
|
|
16
16
|
"""
|
|
17
|
-
Configure annotations
|
|
17
|
+
Configure annotations for geometry layers.
|
|
18
|
+
|
|
19
|
+
Annotations are currently supported for bar, pie, and crossbar geometry
|
|
20
|
+
layers. This class provides methods to customize the appearance and
|
|
21
|
+
content of text labels displayed on these geometries.
|
|
22
|
+
|
|
23
|
+
Notes
|
|
24
|
+
-----
|
|
25
|
+
By default, annotation text color is automatically selected for optimal
|
|
26
|
+
contrast: white text appears on darker filled geometries, and black text
|
|
27
|
+
appears on lighter filled geometries.
|
|
28
|
+
|
|
29
|
+
The text color can be manually specified using:
|
|
30
|
+
``theme(label_text=element_text(color=...))``
|
|
31
|
+
|
|
32
|
+
Alternatively, the ``inherit_color()`` method can be used to override both
|
|
33
|
+
automatic and manual color settings, making the annotation text use the
|
|
34
|
+
geometry's ``color`` aesthetic instead.
|
|
18
35
|
|
|
19
36
|
Examples
|
|
20
37
|
--------
|
|
@@ -24,9 +41,9 @@ class layer_labels(FeatureSpec):
|
|
|
24
41
|
|
|
25
42
|
from lets_plot import *
|
|
26
43
|
LetsPlot.setup_html()
|
|
27
|
-
data = {'name': ['a', 'b', 'c', 'd', 'b'], 'value': [40, 90, 10, 50, 20 ]
|
|
44
|
+
data = {'name': ['a', 'b', 'c', 'd', 'b'], 'value': [40, 90, 10, 50, 20 ]}
|
|
28
45
|
ggplot(data) + geom_pie(aes(slice='value', fill='name'), size=15, hole=0.4, \\
|
|
29
|
-
stat='identity', tooltips
|
|
46
|
+
stat='identity', tooltips='none', \\
|
|
30
47
|
labels=layer_labels().line('@value'))
|
|
31
48
|
|
|
32
49
|
"""
|
|
@@ -46,11 +63,12 @@ class layer_labels(FeatureSpec):
|
|
|
46
63
|
self._lines: List = None
|
|
47
64
|
self._variables = variables
|
|
48
65
|
self._size = None
|
|
66
|
+
self._useLayerColor = None
|
|
49
67
|
super().__init__('labels', name=None)
|
|
50
68
|
|
|
51
69
|
def as_dict(self):
|
|
52
70
|
"""
|
|
53
|
-
Return
|
|
71
|
+
Return a dictionary of all properties of the object.
|
|
54
72
|
|
|
55
73
|
Returns
|
|
56
74
|
-------
|
|
@@ -76,6 +94,7 @@ class layer_labels(FeatureSpec):
|
|
|
76
94
|
d['lines'] = self._lines
|
|
77
95
|
d['variables'] = self._variables
|
|
78
96
|
d['annotation_size'] = self._size
|
|
97
|
+
d['use_layer_color'] = self._useLayerColor
|
|
79
98
|
return _filter_none(d)
|
|
80
99
|
|
|
81
100
|
def format(self, field=None, format=None):
|
|
@@ -113,7 +132,7 @@ class layer_labels(FeatureSpec):
|
|
|
113
132
|
|
|
114
133
|
from lets_plot import *
|
|
115
134
|
LetsPlot.setup_html()
|
|
116
|
-
data = {'name': ['a', 'b', 'c', 'd', 'b'], 'value': [40, 90, 10, 50, 20 ]
|
|
135
|
+
data = {'name': ['a', 'b', 'c', 'd', 'b'], 'value': [40, 90, 10, 50, 20 ]}
|
|
117
136
|
ggplot(data) + geom_pie(aes(fill=as_discrete('name', order_by='..count..'), weight='value'), \\
|
|
118
137
|
size=15, tooltips='none', \\
|
|
119
138
|
labels=layer_labels(['..proppct..']) \\
|
|
@@ -127,7 +146,7 @@ class layer_labels(FeatureSpec):
|
|
|
127
146
|
|
|
128
147
|
from lets_plot import *
|
|
129
148
|
LetsPlot.setup_html()
|
|
130
|
-
data = {'name': ['a', 'b', 'c', 'd', 'b'], 'value': [40, 90, 10, 50, 20 ]
|
|
149
|
+
data = {'name': ['a', 'b', 'c', 'd', 'b'], 'value': [40, 90, 10, 50, 20 ]}
|
|
131
150
|
ggplot(data) + geom_pie(aes(fill=as_discrete('name', order_by='..count..', order=1), weight='value'), \\
|
|
132
151
|
size=15, tooltips='none', \\
|
|
133
152
|
labels=layer_labels() \\
|
|
@@ -146,12 +165,17 @@ class layer_labels(FeatureSpec):
|
|
|
146
165
|
|
|
147
166
|
def line(self, value):
|
|
148
167
|
"""
|
|
149
|
-
|
|
168
|
+
Add a line of text to the multiline label annotation.
|
|
169
|
+
|
|
170
|
+
This method configures one line of text that will be displayed in a
|
|
171
|
+
multiline label. Multiple calls to this method can be chained to build
|
|
172
|
+
up a complete multiline annotation.
|
|
150
173
|
|
|
151
174
|
Parameters
|
|
152
175
|
----------
|
|
153
176
|
value : str
|
|
154
|
-
|
|
177
|
+
The text content for this line of the annotation. Can include
|
|
178
|
+
variable and aesthetic references.
|
|
155
179
|
|
|
156
180
|
Returns
|
|
157
181
|
-------
|
|
@@ -162,17 +186,16 @@ class layer_labels(FeatureSpec):
|
|
|
162
186
|
-----
|
|
163
187
|
Variables and aesthetics can be accessed via special syntax:
|
|
164
188
|
|
|
165
|
-
- ^color for
|
|
189
|
+
- ^color for aesthetics,
|
|
166
190
|
- @x for variable,
|
|
167
191
|
- @{x + 1} for variable with spaces in the name,
|
|
168
192
|
- @{x^2 + 1} for variable with spaces and '^' symbol in the name,
|
|
169
193
|
- @x^2 for variable with '^' symbol in its name.
|
|
170
194
|
|
|
171
|
-
|
|
172
|
-
in the literal text - by doubling:
|
|
195
|
+
Special characters can be escaped:
|
|
173
196
|
|
|
174
|
-
- 'x\\\\^2' -> "x^2"
|
|
175
|
-
- '{{x}}' -> "{x}"
|
|
197
|
+
- 'x\\\\^2' -> "x^2" (escape ^ with backslash)
|
|
198
|
+
- '{{x}}' -> "{x}" (escape braces by doubling)
|
|
176
199
|
|
|
177
200
|
Examples
|
|
178
201
|
--------
|
|
@@ -182,7 +205,7 @@ class layer_labels(FeatureSpec):
|
|
|
182
205
|
|
|
183
206
|
from lets_plot import *
|
|
184
207
|
LetsPlot.setup_html()
|
|
185
|
-
data = {'name': ['a', 'b', 'c', 'd', 'b'], 'value': [40, 90, 10, 50, 20 ]
|
|
208
|
+
data = {'name': ['a', 'b', 'c', 'd', 'b'], 'value': [40, 90, 10, 50, 20 ]}
|
|
186
209
|
ggplot(data) + geom_pie(aes(fill='name', weight='value'), size=15, \\
|
|
187
210
|
tooltips='none', \\
|
|
188
211
|
labels=layer_labels()\\
|
|
@@ -200,12 +223,12 @@ class layer_labels(FeatureSpec):
|
|
|
200
223
|
|
|
201
224
|
def size(self, value):
|
|
202
225
|
"""
|
|
203
|
-
|
|
226
|
+
Set the text size for the annotation.
|
|
204
227
|
|
|
205
228
|
Parameters
|
|
206
229
|
----------
|
|
207
230
|
value : float
|
|
208
|
-
|
|
231
|
+
The text size value for the annotation.
|
|
209
232
|
|
|
210
233
|
Returns
|
|
211
234
|
-------
|
|
@@ -221,9 +244,9 @@ class layer_labels(FeatureSpec):
|
|
|
221
244
|
|
|
222
245
|
from lets_plot import *
|
|
223
246
|
LetsPlot.setup_html()
|
|
224
|
-
data = {'name': ['a', 'b', 'c', 'd', 'b'], 'value': [40, 90, 10, 50, 20 ]
|
|
247
|
+
data = {'name': ['a', 'b', 'c', 'd', 'b'], 'value': [40, 90, 10, 50, 20 ]}
|
|
225
248
|
ggplot(data) + geom_pie(aes(slice='value', fill='name'), size=15, hole=0.4, \\
|
|
226
|
-
stat='identity', tooltips
|
|
249
|
+
stat='identity', tooltips='none', \\
|
|
227
250
|
labels=layer_labels().line('@value')
|
|
228
251
|
.size(25))
|
|
229
252
|
|
|
@@ -231,3 +254,37 @@ class layer_labels(FeatureSpec):
|
|
|
231
254
|
|
|
232
255
|
self._size = value
|
|
233
256
|
return self
|
|
257
|
+
|
|
258
|
+
def inherit_color(self):
|
|
259
|
+
"""
|
|
260
|
+
Use the layer's color for the annotation text.
|
|
261
|
+
|
|
262
|
+
When enabled, the annotation text will inherit the color from the
|
|
263
|
+
layer it's associated with, rather than using a default or
|
|
264
|
+
explicitly set color.
|
|
265
|
+
|
|
266
|
+
Returns
|
|
267
|
+
-------
|
|
268
|
+
`layer_labels`
|
|
269
|
+
Annotations specification.
|
|
270
|
+
|
|
271
|
+
Examples
|
|
272
|
+
--------
|
|
273
|
+
|
|
274
|
+
.. jupyter-execute::
|
|
275
|
+
:linenos:
|
|
276
|
+
:emphasize-lines: 8
|
|
277
|
+
|
|
278
|
+
from lets_plot import *
|
|
279
|
+
LetsPlot.setup_html()
|
|
280
|
+
data = {'name': ['a', 'b', 'c', 'd', 'b'], 'value': [40, 90, 10, 50, 20 ]}
|
|
281
|
+
ggplot(data) + geom_pie(aes(slice='value', color='name'), alpha=0, size=15, hole=0.4, \\
|
|
282
|
+
stroke=5, spacer_color='pen', \\
|
|
283
|
+
stat='identity', tooltips='none', \\
|
|
284
|
+
labels=layer_labels().line('@value')
|
|
285
|
+
.inherit_color())
|
|
286
|
+
|
|
287
|
+
"""
|
|
288
|
+
|
|
289
|
+
self._useLayerColor = True
|
|
290
|
+
return self
|
lets_plot/plot/core.py
CHANGED
|
@@ -9,7 +9,7 @@ from typing import Union
|
|
|
9
9
|
|
|
10
10
|
__all__ = ['aes', 'layer']
|
|
11
11
|
|
|
12
|
-
from lets_plot._global_settings import get_global_bool, has_global_value, FRAGMENTS_ENABLED
|
|
12
|
+
from lets_plot._global_settings import get_global_bool, has_global_value, FRAGMENTS_ENABLED, MAGICK_EXPORT
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
def aes(x=None, y=None, **kwargs):
|
|
@@ -96,7 +96,7 @@ def layer(geom=None, stat=None, data=None, mapping=None, position=None, **kwargs
|
|
|
96
96
|
mapped to plot "aesthetics".
|
|
97
97
|
position : str or `FeatureSpec`
|
|
98
98
|
Position adjustment.
|
|
99
|
-
Either a position adjustment name: 'dodge', '
|
|
99
|
+
Either a position adjustment name: 'dodge', 'jitter', 'nudge', 'jitterdodge', 'fill',
|
|
100
100
|
'stack' or 'identity', or the result of calling a position adjustment function (e.g., `position_dodge()` etc.).
|
|
101
101
|
kwargs:
|
|
102
102
|
Other arguments passed on to layer. These are often aesthetics settings, used to set an aesthetic to a fixed
|
|
@@ -566,10 +566,10 @@ class PlotSpec(FeatureSpec):
|
|
|
566
566
|
h : float, default=None
|
|
567
567
|
Height of the output image in units.
|
|
568
568
|
Only applicable when exporting to PNG or PDF.
|
|
569
|
-
unit : {'in', 'cm', 'mm'}, default=
|
|
569
|
+
unit : {'in', 'cm', 'mm'}, default='in'
|
|
570
570
|
Unit of the output image. One of: 'in', 'cm', 'mm'.
|
|
571
571
|
Only applicable when exporting to PNG or PDF.
|
|
572
|
-
dpi : int, default=
|
|
572
|
+
dpi : int, default=300
|
|
573
573
|
Resolution in dots per inch.
|
|
574
574
|
Only applicable when exporting to PNG or PDF.
|
|
575
575
|
|
|
@@ -580,9 +580,27 @@ class PlotSpec(FeatureSpec):
|
|
|
580
580
|
|
|
581
581
|
Notes
|
|
582
582
|
-----
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
583
|
+
- If `w`, `h`, `unit`, and `dpi` are all specified:
|
|
584
|
+
|
|
585
|
+
- The plot's pixel size (default or set by `ggsize()`) is ignored.
|
|
586
|
+
- The output size is calculated using the specified `w`, `h`, `unit`, and `dpi`.
|
|
587
|
+
|
|
588
|
+
- The plot is resized to fit the specified `w` x `h` area, which may affect the layout, tick labels, and other elements.
|
|
589
|
+
|
|
590
|
+
- If only `dpi` is specified:
|
|
591
|
+
|
|
592
|
+
- The plot's pixel size (default or set by `ggsize()`) is converted to inches using the standard display PPI of 96.
|
|
593
|
+
- The output size is then calculated based on the specified DPI.
|
|
594
|
+
|
|
595
|
+
- The plot maintains its aspect ratio, preserving layout, tick labels, and other visual elements.
|
|
596
|
+
- Useful for printing - the plot will appear nearly the same size as on screen.
|
|
597
|
+
|
|
598
|
+
- If `w`, `h` are not specified:
|
|
599
|
+
|
|
600
|
+
- The `scale` parameter is used to determine the output size.
|
|
601
|
+
|
|
602
|
+
- The plot maintains its aspect ratio, preserving layout, tick labels, and other visual elements.
|
|
603
|
+
- Useful for generating high-resolution images suitable for publication.
|
|
586
604
|
|
|
587
605
|
Examples
|
|
588
606
|
--------
|
|
@@ -600,6 +618,7 @@ class PlotSpec(FeatureSpec):
|
|
|
600
618
|
file_like = io.BytesIO()
|
|
601
619
|
p.to_png(file_like)
|
|
602
620
|
display.Image(file_like.getvalue())
|
|
621
|
+
|
|
603
622
|
"""
|
|
604
623
|
return _export_as_raster(self, path, scale, 'png', w=w, h=h, unit=unit, dpi=dpi)
|
|
605
624
|
|
|
@@ -623,10 +642,10 @@ class PlotSpec(FeatureSpec):
|
|
|
623
642
|
h : float, default=None
|
|
624
643
|
Height of the output image in units.
|
|
625
644
|
Only applicable when exporting to PNG or PDF.
|
|
626
|
-
unit : {'in', 'cm', 'mm'}, default=
|
|
645
|
+
unit : {'in', 'cm', 'mm'}, default='in'
|
|
627
646
|
Unit of the output image. One of: 'in', 'cm', 'mm'.
|
|
628
647
|
Only applicable when exporting to PNG or PDF.
|
|
629
|
-
dpi : int, default=
|
|
648
|
+
dpi : int, default=300
|
|
630
649
|
Resolution in dots per inch.
|
|
631
650
|
Only applicable when exporting to PNG or PDF.
|
|
632
651
|
|
|
@@ -637,9 +656,27 @@ class PlotSpec(FeatureSpec):
|
|
|
637
656
|
|
|
638
657
|
Notes
|
|
639
658
|
-----
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
659
|
+
- If `w`, `h`, `unit`, and `dpi` are all specified:
|
|
660
|
+
|
|
661
|
+
- The plot's pixel size (default or set by `ggsize()`) is ignored.
|
|
662
|
+
- The output size is calculated using the specified `w`, `h`, `unit`, and `dpi`.
|
|
663
|
+
|
|
664
|
+
- The plot is resized to fit the specified `w` x `h` area, which may affect the layout, tick labels, and other elements.
|
|
665
|
+
|
|
666
|
+
- If only `dpi` is specified:
|
|
667
|
+
|
|
668
|
+
- The plot's pixel size (default or set by `ggsize()`) is converted to inches using the standard display PPI of 96.
|
|
669
|
+
- The output size is then calculated based on the specified DPI.
|
|
670
|
+
|
|
671
|
+
- The plot maintains its aspect ratio, preserving layout, tick labels, and other visual elements.
|
|
672
|
+
- Useful for printing - the plot will appear nearly the same size as on screen.
|
|
673
|
+
|
|
674
|
+
- If `w`, `h` are not specified:
|
|
675
|
+
|
|
676
|
+
- The `scale` parameter is used to determine the output size.
|
|
677
|
+
|
|
678
|
+
- The plot maintains its aspect ratio, preserving layout, tick labels, and other visual elements.
|
|
679
|
+
- Useful for generating high-resolution images suitable for publication.
|
|
643
680
|
|
|
644
681
|
Examples
|
|
645
682
|
--------
|
|
@@ -660,6 +697,7 @@ class PlotSpec(FeatureSpec):
|
|
|
660
697
|
p = ggplot({'x': x, 'y': y}, aes(x='x', y='y')) + geom_jitter()
|
|
661
698
|
file_like = io.BytesIO()
|
|
662
699
|
p.to_pdf(file_like)
|
|
700
|
+
|
|
663
701
|
"""
|
|
664
702
|
return _export_as_raster(self, path, scale, 'pdf', w=w, h=h, unit=unit, dpi=dpi)
|
|
665
703
|
|
|
@@ -875,29 +913,108 @@ def _to_html(spec, path, iframe: bool) -> Union[str, None]:
|
|
|
875
913
|
return None
|
|
876
914
|
|
|
877
915
|
|
|
878
|
-
def _export_as_raster(spec, path, scale: float, export_format: str, w=None, h=None, unit=None, dpi=None) -> Union[
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
return
|
|
916
|
+
def _export_as_raster(spec, path, scale: float, export_format: str, w=None, h=None, unit=None, dpi=None) -> Union[str, None]:
|
|
917
|
+
if get_global_bool(MAGICK_EXPORT):
|
|
918
|
+
if w is None and h is None and unit is None and dpi is None:
|
|
919
|
+
def_scale = 2.0
|
|
920
|
+
def_dpi = -1
|
|
921
|
+
def_unit = ""
|
|
922
|
+
else:
|
|
923
|
+
def_scale = 1.0
|
|
924
|
+
def_dpi = 300
|
|
925
|
+
def_unit = 'in'
|
|
926
|
+
|
|
927
|
+
return _export_with_magick(
|
|
928
|
+
spec,
|
|
929
|
+
path,
|
|
930
|
+
scale if scale is not None else def_scale,
|
|
931
|
+
export_format,
|
|
932
|
+
w if w is not None else -1,
|
|
933
|
+
h if h is not None else -1,
|
|
934
|
+
unit if unit is not None else def_unit,
|
|
935
|
+
dpi if dpi is not None else def_dpi
|
|
936
|
+
)
|
|
937
|
+
else:
|
|
938
|
+
return _export_with_cairo(spec, path, scale, export_format, w, h, unit, dpi)
|
|
939
|
+
|
|
940
|
+
|
|
941
|
+
def _export_with_magick(spec, path, scale: float, export_format: str, w, h, unit, dpi) -> Union[str, None]:
|
|
942
|
+
import base64
|
|
943
|
+
from .. import _kbridge
|
|
944
|
+
|
|
945
|
+
if isinstance(path, str):
|
|
946
|
+
file_path = _makedirs(path)
|
|
947
|
+
file_like_object = None
|
|
948
|
+
else:
|
|
949
|
+
file_like_object = path
|
|
950
|
+
file_path = None
|
|
951
|
+
|
|
952
|
+
png_base64 = _kbridge._export_png(spec.as_dict(), float(w), float(h), unit, int(dpi), float(scale))
|
|
953
|
+
png = base64.b64decode(png_base64)
|
|
890
954
|
|
|
891
955
|
if export_format.lower() == 'png':
|
|
892
|
-
|
|
956
|
+
if file_path is not None:
|
|
957
|
+
with open(file_path, 'wb') as f:
|
|
958
|
+
f.write(png)
|
|
959
|
+
return file_path
|
|
960
|
+
else:
|
|
961
|
+
file_like_object.write(png)
|
|
962
|
+
return None
|
|
893
963
|
elif export_format.lower() == 'pdf':
|
|
894
|
-
|
|
964
|
+
try:
|
|
965
|
+
from PIL import Image
|
|
966
|
+
except ImportError:
|
|
967
|
+
import sys
|
|
968
|
+
print("\n"
|
|
969
|
+
"To export Lets-Plot figure to a PDF file please install pillow library"
|
|
970
|
+
"to your Python environment.\n"
|
|
971
|
+
"Pillow is free and distributed under the MIT-CMU license.\n"
|
|
972
|
+
"For more details visit: https://python-pillow.github.io/\n", file=sys.stderr)
|
|
973
|
+
return None
|
|
974
|
+
|
|
975
|
+
|
|
976
|
+
with Image.open(io.BytesIO(png)) as img:
|
|
977
|
+
if img.mode == 'RGBA':
|
|
978
|
+
img = img.convert('RGB')
|
|
979
|
+
|
|
980
|
+
dpi = dpi if dpi is not None else 96 # Default DPI if not specified
|
|
981
|
+
if file_path is not None:
|
|
982
|
+
img.save(file_path, "PDF", dpi=(dpi, dpi))
|
|
983
|
+
return file_path
|
|
984
|
+
else:
|
|
985
|
+
img.save(file_like_object, "PDF", dpi=(dpi, dpi))
|
|
986
|
+
return None
|
|
895
987
|
else:
|
|
896
988
|
raise ValueError("Unknown export format: {}".format(export_format))
|
|
897
989
|
|
|
990
|
+
|
|
991
|
+
def _export_with_cairo(spec, path, scale: float, export_format: str, w=None, h=None, unit=None, dpi=None) -> Union[str, None]:
|
|
898
992
|
from .. import _kbridge
|
|
899
|
-
|
|
900
|
-
|
|
993
|
+
|
|
994
|
+
input = None
|
|
995
|
+
export_function = None
|
|
996
|
+
|
|
997
|
+
if export_format.lower() == 'png' or export_format.lower() == 'pdf':
|
|
998
|
+
try:
|
|
999
|
+
import cairosvg
|
|
1000
|
+
except ImportError:
|
|
1001
|
+
import sys
|
|
1002
|
+
print("\n"
|
|
1003
|
+
"To export Lets-Plot figure to a PNG or PDF file please install CairoSVG library"
|
|
1004
|
+
"to your Python environment.\n"
|
|
1005
|
+
"CairoSVG is free and distributed under the LGPL-3.0 license.\n"
|
|
1006
|
+
"For more details visit: https://cairosvg.org/documentation/\n", file=sys.stderr)
|
|
1007
|
+
return None
|
|
1008
|
+
|
|
1009
|
+
if export_format.lower() == 'png':
|
|
1010
|
+
export_function = cairosvg.svg2png
|
|
1011
|
+
elif export_format.lower() == 'pdf':
|
|
1012
|
+
export_function = cairosvg.svg2pdf
|
|
1013
|
+
|
|
1014
|
+
# Use SVG image-rendering style as Cairo doesn't support CSS image-rendering style,
|
|
1015
|
+
input = _kbridge._generate_svg(spec.as_dict(), use_css_pixelated_image_rendering=False)
|
|
1016
|
+
else:
|
|
1017
|
+
raise ValueError("Unknown export format: {}".format(export_format))
|
|
901
1018
|
|
|
902
1019
|
if isinstance(path, str):
|
|
903
1020
|
abspath = _makedirs(path)
|
|
@@ -910,10 +1027,10 @@ def _export_as_raster(spec, path, scale: float, export_format: str, w=None, h=No
|
|
|
910
1027
|
raise ValueError("w, h, unit, and dpi must all be specified")
|
|
911
1028
|
|
|
912
1029
|
w, h = _to_inches(w, unit) * dpi, _to_inches(h, unit) * dpi
|
|
913
|
-
export_function(bytestring=
|
|
1030
|
+
export_function(bytestring=input, write_to=path, dpi=dpi, output_width=w, output_height=h)
|
|
914
1031
|
else:
|
|
915
1032
|
scale = scale if scale is not None else 2.0
|
|
916
|
-
export_function(bytestring=
|
|
1033
|
+
export_function(bytestring=input, write_to=path, scale=scale)
|
|
917
1034
|
|
|
918
1035
|
return result
|
|
919
1036
|
|