or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

aesthetic-mappings.mdcoordinate-systems.mdcore-plotting.mdfaceting.mdgeometric-objects.mdguides-and-legends.mdindex.mdlabels-and-annotations.mdposition-adjustments.mdsample-datasets.mdscales-and-axes.mdstatistical-transformations.mdthemes-and-styling.mdwatermarks.md

position-adjustments.mddocs/

0

# Position Adjustments

1

2

Position adjustments modify the position of geometric objects to handle overlapping data points, create specialized layouts, and improve plot readability. They are essential for bar charts, box plots, and other visualizations where multiple data points share the same coordinate space.

3

4

## Capabilities

5

6

### Basic Position Adjustments

7

8

Core position adjustment functions for handling overlapping and grouped data.

9

10

```python { .api }

11

def position_identity():

12

"""

13

No position adjustment (default for most geoms).

14

15

Objects are plotted at their exact data coordinates without any adjustment.

16

Use when you want precise positioning or when overlapping is desired.

17

"""

18

19

def position_dodge(width=None):

20

"""

21

Dodge overlapping objects side-by-side.

22

23

Places overlapping objects next to each other horizontally. Essential

24

for grouped bar charts, box plots, and other grouped visualizations.

25

26

Parameters:

27

- width: float, width of dodging in data units. Default uses 80% of

28

the resolution of the data (0.8 * smallest difference between values)

29

30

Usage: Grouped bar charts, side-by-side box plots, grouped points

31

"""

32

33

def position_dodge2(width=None, preserve='total', padding=0.1, reverse=False):

34

"""

35

Enhanced dodging with additional control options.

36

37

Improved version of position_dodge with better handling of different

38

group sizes and more control over positioning behavior.

39

40

Parameters:

41

- width: float, dodging width

42

- preserve: str, what to preserve when dodging ('total' or 'single')

43

- padding: float, padding between groups

44

- reverse: bool, whether to reverse the order of groups

45

"""

46

47

def position_stack():

48

"""

49

Stack overlapping objects on top of each other.

50

51

Cumulative positioning where each object is placed on top of the previous one.

52

Standard for stacked bar charts and area plots.

53

54

Usage: Stacked bar charts, stacked area plots, cumulative histograms

55

"""

56

57

def position_fill():

58

"""

59

Stack objects and normalize to 100%.

60

61

Like position_stack, but normalizes the total height to 1.0 (100%),

62

showing proportions rather than absolute values.

63

64

Usage: Proportional stacked bar charts, percentage area plots

65

"""

66

```

67

68

### Jittering and Random Adjustments

69

70

Position adjustments that add controlled randomness to reduce overplotting.

71

72

```python { .api }

73

def position_jitter(width=None, height=None, seed=None):

74

"""

75

Add random noise to positions to reduce overplotting.

76

77

Adds small random offsets to point positions to reveal overlapping

78

data points. Essential for discrete variables with many observations.

79

80

Parameters:

81

- width: float, amount of horizontal jittering (data units)

82

- height: float, amount of vertical jittering (data units)

83

- seed: int, random seed for reproducible jittering

84

85

Default widths/heights are 40% of the resolution of the data.

86

87

Usage: Scatter plots with discrete variables, strip charts

88

"""

89

90

def position_jitterdodge(jitter_width=None, jitter_height=None, dodge_width=None,

91

seed=None):

92

"""

93

Combine dodging and jittering.

94

95

First dodges groups side-by-side, then adds jittering within each group.

96

Useful for grouped data with many overlapping points.

97

98

Parameters:

99

- jitter_width: float, width of jittering within groups

100

- jitter_height: float, height of jittering

101

- dodge_width: float, width of dodging between groups

102

- seed: int, random seed

103

104

Usage: Grouped scatter plots, grouped strip charts

105

"""

106

```

107

108

### Nudging and Manual Adjustments

109

110

Functions for making small manual adjustments to object positions.

111

112

```python { .api }

113

def position_nudge(x=0, y=0):

114

"""

115

Nudge objects by constant offsets.

116

117

Applies fixed offsets to object positions. Useful for fine-tuning

118

placement of labels, annotations, or separating overlapping elements.

119

120

Parameters:

121

- x: float, horizontal offset in data units

122

- y: float, vertical offset in data units

123

124

Usage: Label positioning, annotation adjustments, creating separation

125

"""

126

```

127

128

## Usage Patterns

129

130

### Bar Chart Position Adjustments

131

```python

132

# Default stacked bar chart

133

ggplot(data, aes(x='category', y='value', fill='group')) + \

134

geom_col(position='stack') # or position_stack()

135

136

# Side-by-side grouped bars

137

ggplot(data, aes(x='category', y='value', fill='group')) + \

138

geom_col(position='dodge') # or position_dodge()

139

140

# Proportional stacked bars (100% stacked)

141

ggplot(data, aes(x='category', y='value', fill='group')) + \

142

geom_col(position='fill') # or position_fill()

143

144

# Custom dodge width

145

ggplot(data, aes(x='category', y='value', fill='group')) + \

146

geom_col(position=position_dodge(width=0.7))

147

```

148

149

### Handling Overplotting with Jitter

150

```python

151

# Basic jittered scatter plot

152

ggplot(data, aes(x='group', y='value')) + \

153

geom_point(position='jitter') # or position_jitter()

154

155

# Custom jitter amounts

156

ggplot(data, aes(x='treatment', y='response')) + \

157

geom_point(position=position_jitter(width=0.2, height=0))

158

159

# Reproducible jittering

160

ggplot(data, aes(x='category', y='measurement')) + \

161

geom_point(position=position_jitter(seed=123))

162

163

# Box plot with jittered points

164

ggplot(data, aes(x='group', y='value')) + \

165

geom_boxplot() + \

166

geom_point(position=position_jitter(width=0.2), alpha=0.6)

167

```

168

169

### Grouped Visualizations

170

```python

171

# Grouped box plots

172

ggplot(data, aes(x='treatment', y='response', fill='gender')) + \

173

geom_boxplot(position='dodge')

174

175

# Grouped points with dodging and jittering

176

ggplot(data, aes(x='category', y='value', color='group')) + \

177

geom_point(position=position_jitterdodge(dodge_width=0.8, jitter_width=0.2))

178

179

# Enhanced dodging for uneven groups

180

ggplot(data, aes(x='category', y='value', fill='treatment')) + \

181

geom_col(position=position_dodge2(preserve='single'))

182

```

183

184

### Label and Annotation Positioning

185

```python

186

# Nudge labels away from points

187

ggplot(data, aes(x='x', y='y', label='name')) + \

188

geom_point() + \

189

geom_text(position=position_nudge(y=0.1))

190

191

# Nudge in both directions

192

ggplot(data, aes(x='score1', y='score2', label='student')) + \

193

geom_point() + \

194

geom_text(position=position_nudge(x=0.5, y=-0.2))

195

196

# Different nudging for different groups

197

ggplot(data, aes(x='x', y='y', label='text', color='group')) + \

198

geom_point() + \

199

geom_text(data=data.query('group == "A"'),

200

position=position_nudge(y=0.1)) + \

201

geom_text(data=data.query('group == "B"'),

202

position=position_nudge(y=-0.1))

203

```

204

205

### Advanced Position Combinations

206

```python

207

# Stacked bars with error bars

208

summary_data = data.groupby(['category', 'group']).agg({

209

'value': ['mean', 'std']

210

}).reset_index()

211

212

ggplot(summary_data, aes(x='category', y='value_mean', fill='group')) + \

213

geom_col(position='stack') + \

214

geom_errorbar(aes(ymin='value_mean - value_std',

215

ymax='value_mean + value_std'),

216

position=position_dodge(width=0.9), width=0.2)

217

218

# Multiple position adjustments in layers

219

ggplot(data, aes(x='treatment', y='response', fill='gender')) + \

220

geom_boxplot(position='dodge', alpha=0.7) + \

221

geom_point(position=position_jitterdodge(), alpha=0.3) + \

222

stat_summary(fun='mean', geom='point',

223

position=position_dodge(width=0.75),

224

color='red', size=3)

225

```

226

227

### Histogram and Density Position Adjustments

228

```python

229

# Stacked histogram

230

ggplot(data, aes(x='value', fill='group')) + \

231

geom_histogram(position='stack', bins=20)

232

233

# Side-by-side histogram (dodged)

234

ggplot(data, aes(x='value', fill='group')) + \

235

geom_histogram(position='dodge', bins=20)

236

237

# Identity position for overlapping histograms

238

ggplot(data, aes(x='value', fill='group')) + \

239

geom_histogram(position='identity', alpha=0.6, bins=20)

240

241

# Fill position for proportional histogram

242

ggplot(data, aes(x='value', fill='group')) + \

243

geom_histogram(position='fill', bins=20)

244

```

245

246

### Time Series and Line Plots

247

```python

248

# Dodged points in time series

249

ggplot(time_data, aes(x='date', y='value', color='series')) + \

250

geom_point(position=position_dodge(width=1)) + \

251

geom_line(aes(group='series'))

252

253

# Jittered time points to reduce overlap

254

ggplot(events_data, aes(x='timestamp', y='category', color='type')) + \

255

geom_point(position=position_jitter(height=0.1))

256

```

257

258

### Statistical Plots with Position Adjustments

259

```python

260

# Mean and error bars with dodging

261

ggplot(data, aes(x='treatment', y='response', fill='gender')) + \

262

stat_summary(fun='mean', geom='col', position='dodge') + \

263

stat_summary(fun_data='mean_se', geom='errorbar',

264

position=position_dodge(width=0.9), width=0.2)

265

266

# Violin plots with dodging

267

ggplot(data, aes(x='group', y='measurement', fill='condition')) + \

268

geom_violin(position='dodge') + \

269

geom_boxplot(position=position_dodge(width=0.9), width=0.1)

270

```

271

272

### Customizing Position Parameters

273

```python

274

# Fine-tune dodging width

275

ggplot(data, aes(x='category', y='value', fill='group')) + \

276

geom_col(position=position_dodge(width=0.8)) + \

277

geom_text(aes(label='value'),

278

position=position_dodge(width=0.8), vjust=-0.5)

279

280

# Control jitter seed for reproducibility

281

set.seed(123) # For consistent jittering across runs

282

ggplot(data, aes(x='treatment', y='response')) + \

283

geom_boxplot() + \

284

geom_point(position=position_jitter(width=0.3, seed=123), alpha=0.6)

285

286

# Combine multiple position adjustments

287

ggplot(data, aes(x='category', y='value', color='group')) + \

288

geom_point(position=position_jitterdodge(

289

jitter_width=0.2, jitter_height=0.1, dodge_width=0.8

290

), alpha=0.7) + \

291

stat_summary(fun='mean', geom='point', size=3,

292

position=position_dodge(width=0.8))

293

```

294

295

## Position Adjustment Best Practices

296

297

### Choosing the Right Position Adjustment

298

```python

299

# For categorical x with continuous y and groups:

300

# - position_dodge: Compare groups side-by-side

301

# - position_stack: Show totals and contributions

302

# - position_fill: Show proportions

303

304

# For overplotting:

305

# - position_jitter: Discrete variables

306

# - position_identity with alpha: Continuous variables

307

308

# For labels:

309

# - position_nudge: Small manual adjustments

310

# - position_dodge: Align with dodged geoms

311

```

312

313

### Consistent Position Parameters

314

```python

315

# Use same dodge width across layers

316

dodge_width = 0.8

317

318

ggplot(data, aes(x='group', y='value', fill='treatment')) + \

319

geom_col(position=position_dodge(width=dodge_width)) + \

320

geom_errorbar(aes(ymin='value - se', ymax='value + se'),

321

position=position_dodge(width=dodge_width), width=0.2) + \

322

geom_text(aes(label='label'),

323

position=position_dodge(width=dodge_width), vjust=-0.5)

324

```