Skip to content

Commit d2b7d9f

Browse files
committed
updated docs and tests
1 parent c881251 commit d2b7d9f

18 files changed

Lines changed: 6562 additions & 44 deletions

CLAUDE.md

Lines changed: 74 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,15 @@ ggplotly/
4242
│ ├── ggplot.py # Core ggplot class
4343
│ ├── aes.py # Aesthetic mappings
4444
│ ├── layer.py # Layer abstraction
45-
│ ├── geoms/ # 44+ geometric objects
45+
│ ├── geoms/ # 46 geometric objects
4646
│ ├── stats/ # 13 statistical transformations
47-
│ ├── scales/ # 17+ scales
48-
│ ├── coords/ # Coordinate systems
47+
│ ├── scales/ # 19 scales
48+
│ ├── coords/ # 5 coordinate systems
4949
│ ├── themes.py # 9 built-in themes
5050
│ ├── facets.py # facet_wrap, facet_grid
51-
│ └── data/ # Built-in datasets (CSV)
51+
│ └── data/ # 16 built-in datasets (CSV)
5252
├── pytest/ # Test suite (39 files)
53-
├── examples/ # Jupyter notebooks (43)
53+
├── examples/ # Jupyter notebooks
5454
└── docs/ # MkDocs documentation
5555
```
5656

@@ -107,11 +107,11 @@ Optional:
107107

108108
| Component | Count | Location |
109109
|-----------|-------|----------|
110-
| Geoms | 44+ | `ggplotly/geoms/` |
110+
| Geoms | 46 | `ggplotly/geoms/` |
111111
| Stats | 13 | `ggplotly/stats/` |
112-
| Scales | 17+ | `ggplotly/scales/` |
112+
| Scales | 19 | `ggplotly/scales/` |
113113
| Themes | 9 | `ggplotly/themes.py` |
114-
| Coords | 4 | `ggplotly/coords/` |
114+
| Coords | 5 | `ggplotly/coords/` |
115115
| Datasets | 16 | `ggplotly/data/` |
116116

117117
## Testing Patterns
@@ -254,6 +254,7 @@ aes(y=after_stat('count / count.sum()')) # Proportions
254254
|------|----------|
255255
| `geom_point()` | Scatter plots |
256256
| `geom_line()` | Line charts |
257+
| `geom_path()` | Connect points in data order |
257258
| `geom_bar()` | Bar charts (stat='count' default) |
258259
| `geom_col()` | Bar charts (stat='identity') |
259260
| `geom_histogram()` | Histograms |
@@ -262,20 +263,38 @@ aes(y=after_stat('count / count.sum()')) # Proportions
262263
| `geom_density()` | Density curves |
263264
| `geom_smooth()` | Trend lines with CI |
264265
| `geom_area()` | Area charts |
266+
| `geom_ribbon()` | Confidence bands (ymin/ymax) |
265267
| `geom_tile()` | Heatmaps |
268+
| `geom_rect()` | Rectangles (highlight regions) |
266269
| `geom_text()` | Text labels |
270+
| `geom_label()` | Text with background |
267271
| `geom_errorbar()` | Error bars |
272+
| `geom_segment()` | Line segments (with optional arrows) |
268273
| `geom_vline()`, `geom_hline()` | Reference lines |
274+
| `geom_abline()` | Slope/intercept lines |
275+
| `geom_jitter()` | Jittered points |
276+
| `geom_rug()` | Marginal tick marks |
277+
| `geom_qq()`, `geom_qq_line()` | Q-Q plots |
278+
| `geom_contour()` | Contour lines |
269279
| `geom_candlestick()` | Financial OHLC |
280+
| `geom_waterfall()` | Waterfall charts |
270281
| `geom_map()` | Choropleth maps |
271282

272283
## Built-in Datasets
273284

274285
```python
275-
from ggplotly import diamonds, mpg, iris, mtcars, economics, msleep, faithfuld
286+
from ggplotly import data
287+
288+
# List all datasets
289+
data()
290+
291+
# Load a specific dataset
292+
mpg = data('mpg')
293+
diamonds = data('diamonds')
294+
iris = data('iris')
276295
```
277296

278-
Available: diamonds, mpg, iris, mtcars, economics, msleep, faithfuld, seals, txhousing, midwest, and more in `ggplotly/data/`
297+
Available: diamonds, mpg, iris, mtcars, economics, economics_long, msleep, faithfuld, seals, txhousing, midwest, presidential, commodity_prices, luv_colours, us_flights (network data)
279298

280299
## Themes
281300

@@ -285,9 +304,9 @@ theme_minimal() # Clean, minimal
285304
theme_classic() # Classic ggplot2 style
286305
theme_dark() # Dark background
287306
theme_ggplot2() # R ggplot2 style
288-
theme_bw() # Black and white
289307
theme_nytimes() # NYT style
290308
theme_bbc() # BBC News style
309+
theme_custom() # Custom theme builder
291310
```
292311

293312
## Position Adjustments
@@ -304,6 +323,7 @@ position_nudge() # Shift by fixed amount
304323

305324
```python
306325
coord_cartesian(xlim=(0, 10)) # Zoom without clipping data
326+
coord_fixed(ratio=1) # Fixed aspect ratio (1:1 scaling)
307327
coord_flip() # Swap x and y axes
308328
coord_polar() # Polar coordinates (pie charts)
309329
coord_sf() # Geographic projections
@@ -340,6 +360,9 @@ facet_wrap('category', scales='free') # 'free_x', 'free_y'
340360
```python
341361
# Axis transforms
342362
scale_x_log10() # Log scale
363+
scale_y_log10() # Log scale (y-axis)
364+
scale_x_reverse() # Reversed x-axis
365+
scale_y_reverse() # Reversed y-axis
343366
scale_x_continuous(limits=(0,100)) # Set range
344367
scale_x_date(date_labels='%Y-%m') # Date formatting
345368

@@ -369,11 +392,14 @@ scale_x_rangeselector() # Add range buttons
369392
| `stat_bin` | Bin data | `geom_histogram` |
370393
| `stat_density` | Kernel density | `geom_density` |
371394
| `stat_smooth` | Smoothed line + CI | `geom_smooth` |
372-
| `stat_boxplot` | Boxplot stats | `geom_boxplot` |
373395
| `stat_ecdf` | Empirical CDF | - |
374396
| `stat_summary` | Summary statistics | - |
375397
| `stat_function` | Apply function | - |
376398
| `stat_qq` | Q-Q plot points | `geom_qq` |
399+
| `stat_qq_line` | Q-Q reference line | `geom_qq_line` |
400+
| `stat_contour` | Contour computation | `geom_contour` |
401+
| `stat_stl` | STL decomposition | `geom_stl` |
402+
| `stat_fanchart` | Fan chart percentiles | `geom_fanchart` |
377403

378404
## Specialized Features
379405

@@ -405,6 +431,42 @@ geom_edgebundle() # Edge bundling
405431
geom_sankey() # Sankey diagrams
406432
```
407433

434+
### Time Series Analysis
435+
```python
436+
geom_stl() # STL decomposition (trend, seasonal, residual)
437+
geom_acf() # Autocorrelation function
438+
geom_pacf() # Partial autocorrelation function
439+
geom_fanchart() # Fan charts for uncertainty
440+
geom_range() # Historical range plots (5-year range)
441+
```
442+
443+
### Recent Feature Additions
444+
445+
#### New Geoms
446+
- `geom_rect` - Draw rectangles (highlight regions, backgrounds)
447+
- `geom_label` - Text labels with background boxes
448+
449+
#### New Scales
450+
```python
451+
scale_x_reverse() # Reversed x-axis
452+
scale_y_reverse() # Reversed y-axis
453+
```
454+
455+
#### New Parameters
456+
| Geom | Parameter | Description |
457+
|------|-----------|-------------|
458+
| `geom_point` | `stroke` | Marker border width |
459+
| `geom_segment` | `arrow`, `arrow_size` | Add arrows to segments |
460+
| `geom_errorbar` | `width` | Error bar cap width |
461+
| `geom_text` | `parse` | Enable LaTeX/MathJax rendering |
462+
| `geom_col` | `width` | Bar width control |
463+
| `geom_smooth` | `fullrange` | Extend line to full x-axis |
464+
| `geom_area` | `position` | Stacking support |
465+
466+
#### Parameter Aliases (ggplot2 compatibility)
467+
- `linewidth``size` (ggplot2 3.4+)
468+
- `colour``color` (British spelling)
469+
408470
## Adding New Features
409471

410472
### New Geom

ROADMAP.md

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -102,20 +102,29 @@
102102

103103
| Item | Type | Description | Status |
104104
|------|------|-------------|--------|
105+
| `geom_pointrange` | Geom | Point with error bars | TODO |
106+
| `geom_linerange` | Geom | Vertical line ranges | TODO |
107+
| `geom_raster` | Geom | High-performance rectangular tiles | TODO |
105108
| `geom_polygon` | Geom | Arbitrary polygons | TODO |
106109
| `geom_dotplot` | Geom | Dot plots | TODO |
107110
| `geom_freqpoly` | Geom | Frequency polygons | TODO |
108111
| `geom_spoke` | Geom | Line segments by angle | TODO |
109112
| `geom_curve` | Geom | Curved line segments | TODO |
113+
| `stat_spoke` | Stat | Spoke statistics | TODO |
114+
| `stat_bin_2d` | Stat | 2D binning | TODO |
115+
| `stat_boxplot` | Stat | Boxplot statistics | TODO |
116+
| `stat_unique` | Stat | Remove duplicates | TODO |
110117
| `scale_alpha` | Scale | Alpha/transparency scaling | TODO |
111118
| `scale_linetype` | Scale | Linetype scaling | TODO |
112119
| `scale_x_sqrt` | Scale | Square root x-axis | TODO |
113120
| `scale_y_sqrt` | Scale | Square root y-axis | TODO |
114121
| `scale_color_viridis_c` | Scale | Viridis for color aesthetic | TODO |
122+
| `scale_fill_viridis_d` | Scale | Viridis discrete for fill | TODO |
115123
| `scale_color_distiller` | Scale | ColorBrewer continuous for color | TODO |
124+
| `theme_bw` | Theme | Black and white theme | TODO |
125+
| `theme_void` | Theme | Empty theme | TODO |
126+
| `xlab` / `ylab` | Label | Axis label shortcuts | TODO |
116127
| `coord_trans` | Coord | Transformed coordinates | TODO |
117-
| `stat_boxplot` | Stat | Boxplot statistics | TODO |
118-
| `stat_unique` | Stat | Remove duplicates | TODO |
119128

120129
---
121130

@@ -149,27 +158,29 @@
149158

150159
## Completed Features
151160

152-
### Geoms (46+)
153-
- Basic: `geom_point`, `geom_line`, `geom_path`, `geom_bar`, `geom_col`, `geom_area`, `geom_ribbon`
154-
- Distribution: `geom_histogram`, `geom_density`, `geom_boxplot`, `geom_violin`, `geom_qq`
155-
- Statistical: `geom_smooth`, `geom_errorbar`, `geom_pointrange`, `geom_linerange`
161+
### Geoms (46)
162+
- Basic: `geom_point`, `geom_line`, `geom_lines`, `geom_path`, `geom_bar`, `geom_col`, `geom_area`, `geom_ribbon`
163+
- Distribution: `geom_histogram`, `geom_density`, `geom_boxplot`, `geom_violin`, `geom_qq`, `geom_qq_line`, `geom_norm`
164+
- Statistical: `geom_smooth`, `geom_errorbar`
156165
- Annotation: `geom_text`, `geom_label`, `geom_rect`, `geom_hline`, `geom_vline`, `geom_abline`, `geom_segment`
157-
- Specialized: `geom_tile`, `geom_raster`, `geom_contour`, `geom_contour_filled`
158-
- Financial: `geom_candlestick`, `geom_ohlc`, `geom_waterfall`
166+
- Specialized: `geom_tile`, `geom_contour`, `geom_contour_filled`
167+
- Financial: `geom_candlestick`, `geom_ohlc`, `geom_waterfall`, `geom_fanchart`
168+
- Time Series: `geom_stl`, `geom_acf`, `geom_pacf`, `geom_range`
159169
- 3D: `geom_point_3d`, `geom_surface`, `geom_wireframe`
160170
- Geographic: `geom_map`, `geom_sf`, `geom_searoute`
161171
- Network: `geom_edgebundle`, `geom_sankey`
162-
- Other: `geom_step`, `geom_jitter`, `geom_rug`, `geom_range`
172+
- Other: `geom_step`, `geom_jitter`, `geom_rug`
163173

164174
### Stats (13)
165-
`stat_identity`, `stat_count`, `stat_bin`, `stat_density`, `stat_smooth`, `stat_summary`, `stat_ecdf`, `stat_function`, `stat_qq`, `stat_stl`, `stat_spoke`, `stat_bin_2d`, `stat_contour`
175+
`stat_identity`, `stat_count`, `stat_bin`, `stat_density`, `stat_smooth`, `stat_summary`, `stat_ecdf`, `stat_function`, `stat_qq`, `stat_qq_line`, `stat_stl`, `stat_fanchart`, `stat_contour`
166176

167-
### Scales (19+)
177+
### Scales (19)
168178
- Continuous: `scale_x_continuous`, `scale_y_continuous`, `scale_x_log10`, `scale_y_log10`
169179
- Reversed: `scale_x_reverse`, `scale_y_reverse`
170180
- Date/Time: `scale_x_date`, `scale_x_datetime`
171-
- Color: `scale_color_manual`, `scale_color_gradient`, `scale_color_brewer`, `scale_fill_*` variants
172-
- Viridis: `scale_fill_viridis_c`, `scale_fill_viridis_d`
181+
- Color: `scale_color_manual`, `scale_color_gradient`, `scale_color_brewer`
182+
- Fill: `scale_fill_manual`, `scale_fill_gradient`, `scale_fill_brewer`, `scale_fill_viridis_c`
183+
- Other: `scale_shape_manual`, `scale_size`
173184
- Interactive: `scale_x_rangeslider`, `scale_x_rangeselector`
174185

175186
### Coords (5)
@@ -179,14 +190,15 @@
179190
`position_identity`, `position_dodge`, `position_dodge2`, `position_stack`, `position_fill`, `position_jitter`, `position_nudge`
180191

181192
### Themes (9)
182-
`theme_default`, `theme_minimal`, `theme_classic`, `theme_dark`, `theme_ggplot2`, `theme_bw`, `theme_void`, `theme_bbc`, `theme_nytimes`
193+
`theme_default`, `theme_minimal`, `theme_classic`, `theme_dark`, `theme_ggplot2`, `theme_bbc`, `theme_nytimes`, `theme_custom`, `theme`
183194

184195
### Other
185-
- Faceting: `facet_wrap`, `facet_grid` with labellers
196+
- Faceting: `facet_wrap`, `facet_grid` with labellers (`label_both`, `label_value`)
186197
- Guides: `guides`, `guide_legend`, `guide_colorbar`
187-
- Labels: `labs`, `ggtitle`, `xlab`, `ylab`
188-
- Utilities: `ggsave`, `ggsize`, `annotate`
189-
- 16 built-in datasets
198+
- Labels: `labs`, `ggtitle`, `annotate`
199+
- Limits: `xlim`, `ylim`, `lims`
200+
- Utilities: `ggsave`, `ggsize`
201+
- Data: `data` (16 built-in datasets), `map_data`, `aes`, `after_stat`, `layer`
190202

191203
---
192204

docs/gallery/basic.ipynb

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,104 @@
573573
"metadata": {},
574574
"outputs": [],
575575
"source": "df = pd.DataFrame({'x': np.random.randn(100), 'y': np.random.randn(100)})\n\n(ggplot(df, aes(x='x', y='y'))\n + geom_point(alpha=0.5)\n + geom_rug(sides='bl', alpha=0.3)\n + labs(title='Scatter with Marginal Rugs'))"
576+
},
577+
{
578+
"cell_type": "markdown",
579+
"id": "uh0z6ntbh6",
580+
"source": "## Point Borders (stroke)\n\nAdd borders to points with the `stroke` parameter:",
581+
"metadata": {}
582+
},
583+
{
584+
"cell_type": "code",
585+
"id": "xarrrstguxr",
586+
"source": "df = pd.DataFrame({\n 'x': [1, 2, 3, 4, 5],\n 'y': [2, 4, 3, 5, 4],\n 'category': ['A', 'B', 'A', 'B', 'A']\n})\n\n# Points with colored borders\n(ggplot(df, aes(x='x', y='y', color='category'))\n + geom_point(size=15, stroke=2)\n + labs(title='Points with Borders (stroke=2)'))",
587+
"metadata": {},
588+
"execution_count": null,
589+
"outputs": []
590+
},
591+
{
592+
"cell_type": "markdown",
593+
"id": "yutsck4pyx",
594+
"source": "## Rectangles (geom_rect)\n\nHighlight regions with rectangles:",
595+
"metadata": {}
596+
},
597+
{
598+
"cell_type": "code",
599+
"id": "039wi1wceyx3",
600+
"source": "# Data for scatter plot\nscatter_df = pd.DataFrame({\n 'x': np.random.randn(100),\n 'y': np.random.randn(100)\n})\n\n# Rectangle to highlight a region\nrect_df = pd.DataFrame({\n 'xmin': [-1], 'xmax': [1],\n 'ymin': [-1], 'ymax': [1]\n})\n\n(ggplot(scatter_df, aes(x='x', y='y'))\n + geom_rect(data=rect_df, mapping=aes(xmin='xmin', xmax='xmax', ymin='ymin', ymax='ymax'),\n fill='yellow', alpha=0.3)\n + geom_point(alpha=0.6)\n + labs(title='Scatter with Highlighted Region'))",
601+
"metadata": {},
602+
"execution_count": null,
603+
"outputs": []
604+
},
605+
{
606+
"cell_type": "markdown",
607+
"id": "4r48c8bsylr",
608+
"source": "## Labels with Background (geom_label)\n\nText labels with a background box for better readability:",
609+
"metadata": {}
610+
},
611+
{
612+
"cell_type": "code",
613+
"id": "26pg8mh4j6u",
614+
"source": "df = pd.DataFrame({\n 'x': [1, 2, 3, 4],\n 'y': [2, 4, 3, 5],\n 'label': ['Alpha', 'Beta', 'Gamma', 'Delta']\n})\n\n(ggplot(df, aes(x='x', y='y'))\n + geom_point(size=10, color='steelblue')\n + geom_label(aes(label='label'), fill='white', alpha=0.8)\n + labs(title='Points with Background Labels'))",
615+
"metadata": {},
616+
"execution_count": null,
617+
"outputs": []
618+
},
619+
{
620+
"cell_type": "markdown",
621+
"id": "j63h040isd",
622+
"source": "## Segments with Arrows\n\nAdd arrows to line segments:",
623+
"metadata": {}
624+
},
625+
{
626+
"cell_type": "code",
627+
"id": "bo5o2bppuri",
628+
"source": "df = pd.DataFrame({\n 'x': [1, 2, 3],\n 'y': [1, 2, 1],\n 'xend': [2, 3, 4],\n 'yend': [2, 1, 2]\n})\n\n(ggplot(df, aes(x='x', y='y', xend='xend', yend='yend'))\n + geom_segment(arrow=True, arrow_size=15, color='steelblue', size=2)\n + labs(title='Segments with Arrows'))",
629+
"metadata": {},
630+
"execution_count": null,
631+
"outputs": []
632+
},
633+
{
634+
"cell_type": "markdown",
635+
"id": "ghbwtfx9hh7",
636+
"source": "## Fixed Aspect Ratio (coord_fixed)\n\nEnsure equal scaling on both axes:",
637+
"metadata": {}
638+
},
639+
{
640+
"cell_type": "code",
641+
"id": "24b4cl86b18",
642+
"source": "# Circle should appear as a circle, not an ellipse\ntheta = np.linspace(0, 2*np.pi, 100)\ncircle = pd.DataFrame({\n 'x': np.cos(theta),\n 'y': np.sin(theta)\n})\n\n(ggplot(circle, aes(x='x', y='y'))\n + geom_path(size=2)\n + coord_fixed(ratio=1)\n + labs(title='Circle with coord_fixed(ratio=1)'))",
643+
"metadata": {},
644+
"execution_count": null,
645+
"outputs": []
646+
},
647+
{
648+
"cell_type": "markdown",
649+
"id": "xu783fl74ge",
650+
"source": "## Reversed Axes\n\nFlip axis direction with `scale_x_reverse()` or `scale_y_reverse()`:",
651+
"metadata": {}
652+
},
653+
{
654+
"cell_type": "code",
655+
"id": "998i04rrr5n",
656+
"source": "df = pd.DataFrame({'x': range(1, 6), 'y': [2, 4, 3, 5, 4]})\n\n# Reversed y-axis (useful for rankings, depth charts)\n(ggplot(df, aes(x='x', y='y'))\n + geom_line(size=2)\n + geom_point(size=10)\n + scale_y_reverse()\n + labs(title='Reversed Y-Axis', y='Rank (1 = best)'))",
657+
"metadata": {},
658+
"execution_count": null,
659+
"outputs": []
660+
},
661+
{
662+
"cell_type": "markdown",
663+
"id": "muf3lcw2nz",
664+
"source": "## LaTeX Labels (parse)\n\nRender mathematical notation with `parse=True`:",
665+
"metadata": {}
666+
},
667+
{
668+
"cell_type": "code",
669+
"id": "2bkjxs2t6v5",
670+
"source": "df = pd.DataFrame({\n 'x': [1, 2, 3],\n 'y': [1, 4, 9],\n 'label': [r'$x^2$', r'$\\sqrt{x}$', r'$\\frac{1}{x}$']\n})\n\n(ggplot(df, aes(x='x', y='y'))\n + geom_point(size=15)\n + geom_text(aes(label='label'), parse=True, vjust=-1.5, size=14)\n + labs(title='Mathematical Labels with LaTeX'))",
671+
"metadata": {},
672+
"execution_count": null,
673+
"outputs": []
576674
}
577675
],
578676
"metadata": {

0 commit comments

Comments
 (0)