plot3 0.4.0__tar.gz → 0.4.1__tar.gz

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.
Files changed (81) hide show
  1. {plot3-0.4.0 → plot3-0.4.1}/PKG-INFO +22 -5
  2. {plot3-0.4.0 → plot3-0.4.1}/README.md +21 -4
  3. plot3-0.4.1/plot3/__version__.py +1 -0
  4. {plot3-0.4.0 → plot3-0.4.1}/plot3/ggplot.py +8 -1
  5. {plot3-0.4.0 → plot3-0.4.1}/plot3.egg-info/PKG-INFO +22 -5
  6. {plot3-0.4.0 → plot3-0.4.1}/tests/test_payload_display.py +26 -0
  7. plot3-0.4.0/plot3/__version__.py +0 -1
  8. {plot3-0.4.0 → plot3-0.4.1}/LICENSE +0 -0
  9. {plot3-0.4.0 → plot3-0.4.1}/plot3/__init__.py +0 -0
  10. {plot3-0.4.0 → plot3-0.4.1}/plot3/aesexpr.py +0 -0
  11. {plot3-0.4.0 → plot3-0.4.1}/plot3/build.py +0 -0
  12. {plot3-0.4.0 → plot3-0.4.1}/plot3/calculus.py +0 -0
  13. {plot3-0.4.0 → plot3-0.4.1}/plot3/compose.py +0 -0
  14. {plot3-0.4.0 → plot3-0.4.1}/plot3/contour.py +0 -0
  15. {plot3-0.4.0 → plot3-0.4.1}/plot3/craft.py +0 -0
  16. {plot3-0.4.0 → plot3-0.4.1}/plot3/encode.py +0 -0
  17. {plot3-0.4.0 → plot3-0.4.1}/plot3/expr.py +0 -0
  18. {plot3-0.4.0 → plot3-0.4.1}/plot3/flip.py +0 -0
  19. {plot3-0.4.0 → plot3-0.4.1}/plot3/function.py +0 -0
  20. {plot3-0.4.0 → plot3-0.4.1}/plot3/geoms.py +0 -0
  21. {plot3-0.4.0 → plot3-0.4.1}/plot3/io.py +0 -0
  22. {plot3-0.4.0 → plot3-0.4.1}/plot3/jupyter.py +0 -0
  23. {plot3-0.4.0 → plot3-0.4.1}/plot3/latexin.py +0 -0
  24. {plot3-0.4.0 → plot3-0.4.1}/plot3/masking.py +0 -0
  25. {plot3-0.4.0 → plot3-0.4.1}/plot3/mathtext.py +0 -0
  26. {plot3-0.4.0 → plot3-0.4.1}/plot3/payload.py +0 -0
  27. {plot3-0.4.0 → plot3-0.4.1}/plot3/remote.py +0 -0
  28. {plot3-0.4.0 → plot3-0.4.1}/plot3/scales.py +0 -0
  29. {plot3-0.4.0 → plot3-0.4.1}/plot3/scaling.py +0 -0
  30. {plot3-0.4.0 → plot3-0.4.1}/plot3/special.py +0 -0
  31. {plot3-0.4.0 → plot3-0.4.1}/plot3/stat2d.py +0 -0
  32. {plot3-0.4.0 → plot3-0.4.1}/plot3/static.py +0 -0
  33. {plot3-0.4.0 → plot3-0.4.1}/plot3/stats3d.py +0 -0
  34. {plot3-0.4.0 → plot3-0.4.1}/plot3/table.py +0 -0
  35. {plot3-0.4.0 → plot3-0.4.1}/plot3/themes.py +0 -0
  36. {plot3-0.4.0 → plot3-0.4.1}/plot3/viewer.py +0 -0
  37. {plot3-0.4.0 → plot3-0.4.1}/plot3.egg-info/SOURCES.txt +0 -0
  38. {plot3-0.4.0 → plot3-0.4.1}/plot3.egg-info/dependency_links.txt +0 -0
  39. {plot3-0.4.0 → plot3-0.4.1}/plot3.egg-info/requires.txt +0 -0
  40. {plot3-0.4.0 → plot3-0.4.1}/plot3.egg-info/top_level.txt +0 -0
  41. {plot3-0.4.0 → plot3-0.4.1}/pyproject.toml +0 -0
  42. {plot3-0.4.0 → plot3-0.4.1}/setup.cfg +0 -0
  43. {plot3-0.4.0 → plot3-0.4.1}/tests/test_2d_density.py +0 -0
  44. {plot3-0.4.0 → plot3-0.4.1}/tests/test_3d.py +0 -0
  45. {plot3-0.4.0 → plot3-0.4.1}/tests/test_animation.py +0 -0
  46. {plot3-0.4.0 → plot3-0.4.1}/tests/test_annotate.py +0 -0
  47. {plot3-0.4.0 → plot3-0.4.1}/tests/test_api_public.py +0 -0
  48. {plot3-0.4.0 → plot3-0.4.1}/tests/test_array_backend.py +0 -0
  49. {plot3-0.4.0 → plot3-0.4.1}/tests/test_arrow.py +0 -0
  50. {plot3-0.4.0 → plot3-0.4.1}/tests/test_build_contract.py +0 -0
  51. {plot3-0.4.0 → plot3-0.4.1}/tests/test_contour.py +0 -0
  52. {plot3-0.4.0 → plot3-0.4.1}/tests/test_everyday_ggplot2.py +0 -0
  53. {plot3-0.4.0 → plot3-0.4.1}/tests/test_expr.py +0 -0
  54. {plot3-0.4.0 → plot3-0.4.1}/tests/test_facets_compose.py +0 -0
  55. {plot3-0.4.0 → plot3-0.4.1}/tests/test_geom_function.py +0 -0
  56. {plot3-0.4.0 → plot3-0.4.1}/tests/test_geoms_ds.py +0 -0
  57. {plot3-0.4.0 → plot3-0.4.1}/tests/test_ggplot2_extras2.py +0 -0
  58. {plot3-0.4.0 → plot3-0.4.1}/tests/test_ggplot2_parity.py +0 -0
  59. {plot3-0.4.0 → plot3-0.4.1}/tests/test_ggplot_extras.py +0 -0
  60. {plot3-0.4.0 → plot3-0.4.1}/tests/test_grammar.py +0 -0
  61. {plot3-0.4.0 → plot3-0.4.1}/tests/test_latex_input.py +0 -0
  62. {plot3-0.4.0 → plot3-0.4.1}/tests/test_lidar_scene.py +0 -0
  63. {plot3-0.4.0 → plot3-0.4.1}/tests/test_masking.py +0 -0
  64. {plot3-0.4.0 → plot3-0.4.1}/tests/test_math_layers.py +0 -0
  65. {plot3-0.4.0 → plot3-0.4.1}/tests/test_mathtext.py +0 -0
  66. {plot3-0.4.0 → plot3-0.4.1}/tests/test_payload.py +0 -0
  67. {plot3-0.4.0 → plot3-0.4.1}/tests/test_point_cloud.py +0 -0
  68. {plot3-0.4.0 → plot3-0.4.1}/tests/test_r_oracle_parity.py +0 -0
  69. {plot3-0.4.0 → plot3-0.4.1}/tests/test_readme.py +0 -0
  70. {plot3-0.4.0 → plot3-0.4.1}/tests/test_remote_bridge.py +0 -0
  71. {plot3-0.4.0 → plot3-0.4.1}/tests/test_review_fixes.py +0 -0
  72. {plot3-0.4.0 → plot3-0.4.1}/tests/test_save_menu.py +0 -0
  73. {plot3-0.4.0 → plot3-0.4.1}/tests/test_scales_api.py +0 -0
  74. {plot3-0.4.0 → plot3-0.4.1}/tests/test_scales_themes.py +0 -0
  75. {plot3-0.4.0 → plot3-0.4.1}/tests/test_special.py +0 -0
  76. {plot3-0.4.0 → plot3-0.4.1}/tests/test_stat2d.py +0 -0
  77. {plot3-0.4.0 → plot3-0.4.1}/tests/test_static_save.py +0 -0
  78. {plot3-0.4.0 → plot3-0.4.1}/tests/test_stats_semantic.py +0 -0
  79. {plot3-0.4.0 → plot3-0.4.1}/tests/test_step3_geoms.py +0 -0
  80. {plot3-0.4.0 → plot3-0.4.1}/tests/test_table_backends.py +0 -0
  81. {plot3-0.4.0 → plot3-0.4.1}/tests/test_titles_theme.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plot3
3
- Version: 0.4.0
3
+ Version: 0.4.1
4
4
  Summary: ggplot2 grammar of graphics for Python: interactive WebGL figures and journal-ready PNG, SVG, and PDF
5
5
  Author: Rigoberto Leyva Salmeron
6
6
  License-Expression: MIT
@@ -376,13 +376,28 @@ ggplot() + geom_function("y = sin(x - t)") + transition_time(t=(0, 6.28)) # tr
376
376
  ggplot() + geom_function("y = dbeta(x, a, b)") + slider(a=(0.5, 5), b=(0.5, 5))
377
377
  ```
378
378
 
379
- Data animations follow `gganimate`:
379
+ Data animations follow `gganimate`. With a table shaped like gapminder
380
+ (made-up numbers here; the real data is
381
+ `pl.read_csv("https://raw.githubusercontent.com/kirenz/datasets/master/gapminder.csv")`):
380
382
 
381
- ```python notest
382
- (ggplot(gapminder, aes(x="gdp", y="life", size="pop", colour="continent", group="country"))
383
+ ```python
384
+ countries = {"Brazil": "Americas", "China": "Asia", "Egypt": "Africa",
385
+ "France": "Europe", "India": "Asia", "Mexico": "Americas"}
386
+ gapminder = pd.DataFrame([
387
+ {"country": country, "continent": continent, "year": year,
388
+ "gdpPercap": 800 * (1.03 + 0.01 * i) ** (year - 1952),
389
+ "lifeExp": 45 + 0.35 * (year - 1952) + 2 * i,
390
+ "pop": 2e7 * (1.02 + 0.002 * i) ** (year - 1952)}
391
+ for i, (country, continent) in enumerate(countries.items())
392
+ for year in range(1952, 2008, 5)
393
+ ])
394
+
395
+ (ggplot(gapminder, aes(x="gdpPercap", y="lifeExp", size="pop", colour="continent", group="country"))
383
396
  + geom_point() + scale_x_log10() + transition_time("year") + labs(title="{frame_time}"))
384
397
  ```
385
398
 
399
+ `{frame_time}` in a title shows the current year as the animation plays.
400
+
386
401
  The viewer interpolates between frames in the browser, with play, pause,
387
402
  scrubbing, speed, and video recording.
388
403
 
@@ -437,7 +452,9 @@ tree) is shortened to twice its width so it does not become a thin column;
437
452
  - **SolveIt** draws figures inline and hides their HTML from the model's
438
453
  context (`autohide(False)` to opt out).
439
454
  - **VS Code notebooks** block WebGL in output cells, so plot3 opens figures
440
- in your browser (`PLOT3_DISPLAY=browser|iframe` to force a mode).
455
+ in your browser (`PLOT3_DISPLAY=browser|iframe` to force a mode). The page
456
+ is written to `.plot3_preview/latest.html` in the notebook's folder, or to
457
+ the system temp folder when that folder is read-only.
441
458
  - **CRAFT / `%gpu`**: the same `ggplot(...)` code runs on the remote kernel;
442
459
  stats run where the data lives and only a compact payload comes back.
443
460
 
@@ -343,13 +343,28 @@ ggplot() + geom_function("y = sin(x - t)") + transition_time(t=(0, 6.28)) # tr
343
343
  ggplot() + geom_function("y = dbeta(x, a, b)") + slider(a=(0.5, 5), b=(0.5, 5))
344
344
  ```
345
345
 
346
- Data animations follow `gganimate`:
346
+ Data animations follow `gganimate`. With a table shaped like gapminder
347
+ (made-up numbers here; the real data is
348
+ `pl.read_csv("https://raw.githubusercontent.com/kirenz/datasets/master/gapminder.csv")`):
347
349
 
348
- ```python notest
349
- (ggplot(gapminder, aes(x="gdp", y="life", size="pop", colour="continent", group="country"))
350
+ ```python
351
+ countries = {"Brazil": "Americas", "China": "Asia", "Egypt": "Africa",
352
+ "France": "Europe", "India": "Asia", "Mexico": "Americas"}
353
+ gapminder = pd.DataFrame([
354
+ {"country": country, "continent": continent, "year": year,
355
+ "gdpPercap": 800 * (1.03 + 0.01 * i) ** (year - 1952),
356
+ "lifeExp": 45 + 0.35 * (year - 1952) + 2 * i,
357
+ "pop": 2e7 * (1.02 + 0.002 * i) ** (year - 1952)}
358
+ for i, (country, continent) in enumerate(countries.items())
359
+ for year in range(1952, 2008, 5)
360
+ ])
361
+
362
+ (ggplot(gapminder, aes(x="gdpPercap", y="lifeExp", size="pop", colour="continent", group="country"))
350
363
  + geom_point() + scale_x_log10() + transition_time("year") + labs(title="{frame_time}"))
351
364
  ```
352
365
 
366
+ `{frame_time}` in a title shows the current year as the animation plays.
367
+
353
368
  The viewer interpolates between frames in the browser, with play, pause,
354
369
  scrubbing, speed, and video recording.
355
370
 
@@ -404,7 +419,9 @@ tree) is shortened to twice its width so it does not become a thin column;
404
419
  - **SolveIt** draws figures inline and hides their HTML from the model's
405
420
  context (`autohide(False)` to opt out).
406
421
  - **VS Code notebooks** block WebGL in output cells, so plot3 opens figures
407
- in your browser (`PLOT3_DISPLAY=browser|iframe` to force a mode).
422
+ in your browser (`PLOT3_DISPLAY=browser|iframe` to force a mode). The page
423
+ is written to `.plot3_preview/latest.html` in the notebook's folder, or to
424
+ the system temp folder when that folder is read-only.
408
425
  - **CRAFT / `%gpu`**: the same `ggplot(...)` code runs on the remote kernel;
409
426
  stats run where the data lives and only a compact payload comes back.
410
427
 
@@ -0,0 +1 @@
1
+ __version__ = "0.4.1"
@@ -8,6 +8,7 @@ from plot3 import scaling as _scaling
8
8
  import html as _htmlesc
9
9
  import os
10
10
  import sys
11
+ import tempfile
11
12
  import webbrowser
12
13
  from pathlib import Path
13
14
 
@@ -545,7 +546,13 @@ class ggplot:
545
546
  ) -> Path:
546
547
  if path is None:
547
548
  out_dir = Path.cwd() / ".plot3_preview"
548
- out_dir.mkdir(parents=True, exist_ok=True)
549
+ try:
550
+ out_dir.mkdir(parents=True, exist_ok=True)
551
+ except OSError:
552
+ # A kernel started in "/" or another read-only folder (VS
553
+ # Code does this for notebooks outside a workspace).
554
+ out_dir = Path(tempfile.gettempdir()) / "plot3_preview"
555
+ out_dir.mkdir(parents=True, exist_ok=True)
549
556
  path = out_dir / "latest.html"
550
557
  else:
551
558
  path = Path(path)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plot3
3
- Version: 0.4.0
3
+ Version: 0.4.1
4
4
  Summary: ggplot2 grammar of graphics for Python: interactive WebGL figures and journal-ready PNG, SVG, and PDF
5
5
  Author: Rigoberto Leyva Salmeron
6
6
  License-Expression: MIT
@@ -376,13 +376,28 @@ ggplot() + geom_function("y = sin(x - t)") + transition_time(t=(0, 6.28)) # tr
376
376
  ggplot() + geom_function("y = dbeta(x, a, b)") + slider(a=(0.5, 5), b=(0.5, 5))
377
377
  ```
378
378
 
379
- Data animations follow `gganimate`:
379
+ Data animations follow `gganimate`. With a table shaped like gapminder
380
+ (made-up numbers here; the real data is
381
+ `pl.read_csv("https://raw.githubusercontent.com/kirenz/datasets/master/gapminder.csv")`):
380
382
 
381
- ```python notest
382
- (ggplot(gapminder, aes(x="gdp", y="life", size="pop", colour="continent", group="country"))
383
+ ```python
384
+ countries = {"Brazil": "Americas", "China": "Asia", "Egypt": "Africa",
385
+ "France": "Europe", "India": "Asia", "Mexico": "Americas"}
386
+ gapminder = pd.DataFrame([
387
+ {"country": country, "continent": continent, "year": year,
388
+ "gdpPercap": 800 * (1.03 + 0.01 * i) ** (year - 1952),
389
+ "lifeExp": 45 + 0.35 * (year - 1952) + 2 * i,
390
+ "pop": 2e7 * (1.02 + 0.002 * i) ** (year - 1952)}
391
+ for i, (country, continent) in enumerate(countries.items())
392
+ for year in range(1952, 2008, 5)
393
+ ])
394
+
395
+ (ggplot(gapminder, aes(x="gdpPercap", y="lifeExp", size="pop", colour="continent", group="country"))
383
396
  + geom_point() + scale_x_log10() + transition_time("year") + labs(title="{frame_time}"))
384
397
  ```
385
398
 
399
+ `{frame_time}` in a title shows the current year as the animation plays.
400
+
386
401
  The viewer interpolates between frames in the browser, with play, pause,
387
402
  scrubbing, speed, and video recording.
388
403
 
@@ -437,7 +452,9 @@ tree) is shortened to twice its width so it does not become a thin column;
437
452
  - **SolveIt** draws figures inline and hides their HTML from the model's
438
453
  context (`autohide(False)` to opt out).
439
454
  - **VS Code notebooks** block WebGL in output cells, so plot3 opens figures
440
- in your browser (`PLOT3_DISPLAY=browser|iframe` to force a mode).
455
+ in your browser (`PLOT3_DISPLAY=browser|iframe` to force a mode). The page
456
+ is written to `.plot3_preview/latest.html` in the notebook's folder, or to
457
+ the system temp folder when that folder is read-only.
441
458
  - **CRAFT / `%gpu`**: the same `ggplot(...)` code runs on the remote kernel;
442
459
  stats run where the data lives and only a compact payload comes back.
443
460
 
@@ -114,3 +114,29 @@ def test_freeze_faceted_raises(cars):
114
114
  fig = ggplot(cars, aes(x="wt", y="mpg")) + geom_point() + facet_wrap("cyl")
115
115
  with pytest.raises(ValueError, match="facet"):
116
116
  fig.freeze()
117
+
118
+
119
+ def test_browser_preview_falls_back_when_the_folder_is_read_only(tmp_path, monkeypatch):
120
+ """A kernel started in a read-only folder ("/" in VS Code) still shows plots."""
121
+ import importlib
122
+ import os
123
+ import tempfile
124
+
125
+ gg = importlib.import_module("plot3.ggplot")
126
+
127
+ if os.name == "nt" or os.geteuid() == 0:
128
+ pytest.skip("needs a folder the test user cannot write to")
129
+ locked = tmp_path / "locked"
130
+ locked.mkdir()
131
+ locked.chmod(0o555)
132
+ monkeypatch.chdir(locked)
133
+ monkeypatch.setattr(gg.webbrowser, "open", lambda *_a, **_k: None)
134
+ monkeypatch.setattr(tempfile, "tempdir", str(tmp_path / "tmp"))
135
+ (tmp_path / "tmp").mkdir()
136
+ fig = ggplot({"x": [1, 2], "y": [3, 4]}, aes(x="x", y="y")) + geom_point()
137
+ try:
138
+ out = fig.show(browser=True)
139
+ finally:
140
+ locked.chmod(0o755)
141
+ assert out == (tmp_path / "tmp" / "plot3_preview" / "latest.html").resolve()
142
+ assert out.read_text(encoding="utf-8").startswith("<!")
@@ -1 +0,0 @@
1
- __version__ = "0.4.0"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes