Skip to content

Commit 3809561

Browse files
authored
Merge branch 'plotters-rs:master' into fix/hslcolor-hue-wrap
2 parents 398328e + 48b01c4 commit 3809561

19 files changed

Lines changed: 179 additions & 127 deletions

File tree

plotters-backend/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
features, you need to play with `ensure_prepared` and `present` method. The following figure illustrates how Plotters operates a drawing backend.
2727
2828
- `ensure_prepared` - Called before each time when plotters want to draw. This function should initialize the backend for current frame, if the backend is already prepared
29-
for a frame, this function should simply do nothing.
29+
for a frame, this function should simply do nothing.
3030
- `present` - Called when plotters want to finish current frame drawing
3131
3232

plotters-backend/src/text.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ pub trait BackendTextStyle {
217217
text_anchor::Pos::default()
218218
}
219219

220-
fn family(&self) -> FontFamily;
220+
fn family(&self) -> FontFamily<'_>;
221221

222222
#[allow(clippy::type_complexity)]
223223
fn layout_box(&self, text: &str) -> Result<((i32, i32), (i32, i32)), Self::FontError>;

plotters-bitmap/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ readme = "README.md"
1212
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1313

1414
[dependencies]
15-
gif = { version = "0.12.0", optional = true }
15+
gif = { version = "0.14.0", optional = true }
1616

1717
[dependencies.plotters-backend]
1818
version = "0.3.6"
1919
path = "../plotters-backend"
2020

2121
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.image]
22-
version = "0.24.3"
22+
version = "0.25.9"
2323
optional = true
2424
default-features = false
2525
features = ["jpeg", "png", "bmp"]
@@ -35,7 +35,7 @@ features = ["ttf", "line_series", "bitmap_backend"]
3535
path = "../plotters"
3636

3737
[dev-dependencies]
38-
criterion = "0.5.1"
38+
criterion = "0.8.1"
3939
rayon = "1.5.1"
4040

4141
[[bench]]

plotters-bitmap/src/bitmap.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ impl<'a, P: PixelFormat> BitMapBackend<'a, P> {
142142
///
143143
/// - `area_size`: The size of the area
144144
/// - **returns**: The split backends that can be rendered in parallel
145-
pub fn split(&mut self, area_size: &[u32]) -> Vec<BitMapBackend<P>> {
145+
pub fn split(&mut self, area_size: &[u32]) -> Vec<BitMapBackend<'_, P>> {
146146
let (w, h) = self.get_size();
147147
let buf = self.get_raw_pixel_buffer();
148148

plotters-bitmap/src/bitmap_pixel/bgrx.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ impl PixelFormat for BGRXPixel {
193193
// TODO: Consider using AVX instructions when possible
194194
let ptr = p as *mut [u8; 8] as *mut u64;
195195
unsafe {
196-
let d: u64 = std::mem::transmute([
196+
let d: u64 = u64::from_ne_bytes([
197197
b, g, r, 0, b, g, r, 0, // QW1
198198
]);
199199
ptr.write_unaligned(d);

plotters-svg/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ version = "0.3.6"
1616
path = "../plotters-backend"
1717

1818
[dependencies.image]
19-
version = "0.24.2"
19+
version = "0.25.9"
2020
optional = true
2121
default-features = false
2222
features = ["jpeg", "png", "bmp"]

plotters/Cargo.toml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ optional = true
3838
path = "../plotters-svg"
3939

4040
[target.'cfg(not(all(target_arch = "wasm32", not(target_os = "wasi"))))'.dependencies]
41-
ttf-parser = { version = "0.20.0", optional = true }
41+
ttf-parser = { version = "0.25.1", optional = true }
4242
lazy_static = { version = "1.4.0", optional = true }
4343
pathfinder_geometry = { version = "0.5.1", optional = true }
4444
font-kit = { version = "0.14.2", optional = true }
@@ -47,7 +47,7 @@ once_cell = { version = "1.8.0", optional = true }
4747

4848

4949
[target.'cfg(not(all(target_arch = "wasm32", not(target_os = "wasi"))))'.dependencies.image]
50-
version = "0.24.3"
50+
version = "0.25.9"
5151
optional = true
5252
default-features = false
5353
features = ["jpeg", "png", "bmp"]
@@ -120,17 +120,17 @@ evcxr_bitmap = ["evcxr", "bitmap_backend", "plotters-svg/bitmap_encoder"]
120120
deprecated_items = [] # Keep some of the deprecated items for backward compatibility
121121

122122
[dev-dependencies]
123-
itertools = "0.10.0"
124-
criterion = "0.5.1"
123+
itertools = "0.14.0"
124+
criterion = "0.8.1"
125125
rayon = "1.5.1"
126126
serde_json = "1.0.82"
127127
serde_derive = "1.0.140"
128128
plotters = { path = ".", features = ["serialization"] }
129129

130130
[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
131-
rand = "0.8.3"
132-
rand_distr = "0.4.0"
133-
rand_xorshift = "0.3.0"
131+
rand = "0.9.2"
132+
rand_distr = "0.5.1"
133+
rand_xorshift = "0.4.0"
134134

135135
[target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi")))'.dev-dependencies]
136136
wasm-bindgen-test = "0.3.39"

plotters/src/chart/context/cartesian2d/draw_impl.rs

Lines changed: 111 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,8 @@ impl<'a, DB: DrawingBackend, X: Ranged, Y: Ranged> ChartContext<'a, DB, Cartesia
153153

154154
/* Draw the axis and get the axis range so that we can do further label
155155
* and tick mark drawing */
156-
let axis_range = self.draw_axis(area, axis_style, orientation, tick_size < 0)?;
156+
// Always draw axis on the outer edge (pass false for inward_labels)
157+
let axis_range = self.draw_axis(area, axis_style, orientation, false)?;
157158

158159
/* To make the right label area looks nice, it's a little bit tricky, since for a that is
159160
* very long, we actually prefer left alignment instead of right alignment.
@@ -162,14 +163,14 @@ impl<'a, DB: DrawingBackend, X: Ranged, Y: Ranged> ChartContext<'a, DB, Cartesia
162163
let label_width: Vec<_> = labels
163164
.iter()
164165
.map(|(_, text)| {
165-
if orientation.0 > 0 && orientation.1 == 0 && tick_size >= 0 {
166+
if orientation.0 > 0 && orientation.1 == 0 {
166167
self.drawing_area
167168
.estimate_text_size(text, label_style)
168169
.map(|(w, _)| w)
169170
.unwrap_or(0) as i32
170171
} else {
171-
// Don't ever do the layout estimationfor the drawing area that is either not
172-
// the right one or the tick mark is inward.
172+
// Don't ever do the layout estimation for the drawing area that is either not
173+
// the right one.
173174
0
174175
}
175176
})
@@ -194,51 +195,32 @@ impl<'a, DB: DrawingBackend, X: Ranged, Y: Ranged> ChartContext<'a, DB, Cartesia
194195
continue;
195196
}
196197

197-
let (cx, cy, h_pos, v_pos) = if tick_size >= 0 {
198-
match orientation {
199-
// Right
200-
(dx, dy) if dx > 0 && dy == 0 => {
201-
if w >= right_align_width {
202-
(label_dist, *p - y0, HPos::Left, VPos::Center)
203-
} else {
204-
(
205-
label_dist + right_align_width,
206-
*p - y0,
207-
HPos::Right,
208-
VPos::Center,
209-
)
210-
}
211-
}
212-
// Left
213-
(dx, dy) if dx < 0 && dy == 0 => {
214-
(tw as i32 - label_dist, *p - y0, HPos::Right, VPos::Center)
215-
}
216-
// Bottom
217-
(dx, dy) if dx == 0 && dy > 0 => (*p - x0, label_dist, HPos::Center, VPos::Top),
218-
// Top
219-
(dx, dy) if dx == 0 && dy < 0 => {
220-
(*p - x0, th as i32 - label_dist, HPos::Center, VPos::Bottom)
221-
}
222-
_ => panic!("Bug: Invalid orientation specification"),
223-
}
224-
} else {
225-
match orientation {
226-
// Right
227-
(dx, dy) if dx > 0 && dy == 0 => {
228-
(tw as i32 - label_dist, *p - y0, HPos::Right, VPos::Center)
229-
}
230-
// Left
231-
(dx, dy) if dx < 0 && dy == 0 => {
198+
// Always position labels on the outside
199+
let (cx, cy, h_pos, v_pos) = match orientation {
200+
// Right
201+
(dx, dy) if dx > 0 && dy == 0 => {
202+
if w >= right_align_width {
232203
(label_dist, *p - y0, HPos::Left, VPos::Center)
204+
} else {
205+
(
206+
label_dist + right_align_width,
207+
*p - y0,
208+
HPos::Right,
209+
VPos::Center,
210+
)
233211
}
234-
// Bottom
235-
(dx, dy) if dx == 0 && dy > 0 => {
236-
(*p - x0, th as i32 - label_dist, HPos::Center, VPos::Bottom)
237-
}
238-
// Top
239-
(dx, dy) if dx == 0 && dy < 0 => (*p - x0, label_dist, HPos::Center, VPos::Top),
240-
_ => panic!("Bug: Invalid orientation specification"),
241212
}
213+
// Left
214+
(dx, dy) if dx < 0 && dy == 0 => {
215+
(tw as i32 - label_dist, *p - y0, HPos::Right, VPos::Center)
216+
}
217+
// Bottom
218+
(dx, dy) if dx == 0 && dy > 0 => (*p - x0, label_dist, HPos::Center, VPos::Top),
219+
// Top
220+
(dx, dy) if dx == 0 && dy < 0 => {
221+
(*p - x0, th as i32 - label_dist, HPos::Center, VPos::Bottom)
222+
}
223+
_ => panic!("Bug: Invalid orientation specification"),
242224
};
243225

244226
let (text_x, text_y) = if orientation.0 == 0 {
@@ -250,34 +232,22 @@ impl<'a, DB: DrawingBackend, X: Ranged, Y: Ranged> ChartContext<'a, DB, Cartesia
250232
let label_style = &label_style.pos(Pos::new(h_pos, v_pos));
251233
area.draw_text(t, label_style, (text_x, text_y))?;
252234

253-
if tick_size != 0 {
235+
// Only draw outward tick marks here (tick_size > 0)
236+
// Inward tick marks are drawn separately in draw_mesh
237+
if tick_size > 0 {
254238
if let Some(style) = axis_style {
255239
let xmax = tw as i32 - 1;
256240
let ymax = th as i32 - 1;
257-
let (kx0, ky0, kx1, ky1) = if tick_size > 0 {
258-
match orientation {
259-
(dx, dy) if dx > 0 && dy == 0 => (0, *p - y0, tick_size, *p - y0),
260-
(dx, dy) if dx < 0 && dy == 0 => {
261-
(xmax - tick_size, *p - y0, xmax, *p - y0)
262-
}
263-
(dx, dy) if dx == 0 && dy > 0 => (*p - x0, 0, *p - x0, tick_size),
264-
(dx, dy) if dx == 0 && dy < 0 => {
265-
(*p - x0, ymax - tick_size, *p - x0, ymax)
266-
}
267-
_ => panic!("Bug: Invalid orientation specification"),
241+
let (kx0, ky0, kx1, ky1) = match orientation {
242+
(dx, dy) if dx > 0 && dy == 0 => (0, *p - y0, tick_size, *p - y0),
243+
(dx, dy) if dx < 0 && dy == 0 => {
244+
(xmax - tick_size, *p - y0, xmax, *p - y0)
268245
}
269-
} else {
270-
match orientation {
271-
(dx, dy) if dx > 0 && dy == 0 => {
272-
(xmax, *p - y0, xmax + tick_size, *p - y0)
273-
}
274-
(dx, dy) if dx < 0 && dy == 0 => (0, *p - y0, -tick_size, *p - y0),
275-
(dx, dy) if dx == 0 && dy > 0 => {
276-
(*p - x0, ymax, *p - x0, ymax + tick_size)
277-
}
278-
(dx, dy) if dx == 0 && dy < 0 => (*p - x0, 0, *p - x0, -tick_size),
279-
_ => panic!("Bug: Invalid orientation specification"),
246+
(dx, dy) if dx == 0 && dy > 0 => (*p - x0, 0, *p - x0, tick_size),
247+
(dx, dy) if dx == 0 && dy < 0 => {
248+
(*p - x0, ymax - tick_size, *p - x0, ymax)
280249
}
250+
_ => panic!("Bug: Invalid orientation specification"),
281251
};
282252
let line = PathElement::new(vec![(kx0, ky0), (kx1, ky1)], *style);
283253
area.draw(&line)?;
@@ -364,6 +334,77 @@ impl<'a, DB: DrawingBackend, X: Ranged, Y: Ranged> ChartContext<'a, DB, Cartesia
364334
)?;
365335
}
366336

337+
// Draw inward tick marks on the plot area
338+
let plot_area = self.drawing_area.strip_coord_spec();
339+
let (x0, y0) = self.drawing_area.get_base_pixel();
340+
let (dw, dh) = self.drawing_area.dim_in_pixel();
341+
let dw = dw as i32;
342+
let dh = dh as i32;
343+
344+
if x_axis {
345+
// Top inward ticks (x_tick_size[0] is for top label area)
346+
if x_tick_size[0] < 0 {
347+
let abs_tick = x_tick_size[0].abs();
348+
for (px, _) in &x_labels {
349+
let x = *px - x0;
350+
if x >= 0 && x < dw {
351+
let line = PathElement::new(
352+
vec![(x, 0), (x, abs_tick)],
353+
*axis_style,
354+
);
355+
plot_area.draw(&line)?;
356+
}
357+
}
358+
}
359+
360+
// Bottom inward ticks (x_tick_size[1] is for bottom label area)
361+
if x_tick_size[1] < 0 {
362+
let abs_tick = x_tick_size[1].abs();
363+
for (px, _) in &x_labels {
364+
let x = *px - x0;
365+
if x >= 0 && x < dw {
366+
let line = PathElement::new(
367+
vec![(x, dh - 1 - abs_tick), (x, dh - 1)],
368+
*axis_style,
369+
);
370+
plot_area.draw(&line)?;
371+
}
372+
}
373+
}
374+
}
375+
376+
if y_axis {
377+
// Left inward ticks (y_tick_size[0] is for left label area)
378+
if y_tick_size[0] < 0 {
379+
let abs_tick = y_tick_size[0].abs();
380+
for (py, _) in &y_labels {
381+
let y = *py - y0;
382+
if y >= 0 && y < dh {
383+
let line = PathElement::new(
384+
vec![(0, y), (abs_tick, y)],
385+
*axis_style,
386+
);
387+
plot_area.draw(&line)?;
388+
}
389+
}
390+
}
391+
392+
// Right inward ticks (y_tick_size[1] is for right label area)
393+
if y_tick_size[1] < 0 {
394+
let abs_tick = y_tick_size[1].abs();
395+
for (py, _) in &y_labels {
396+
let y = *py - y0;
397+
if y >= 0 && y < dh {
398+
let line = PathElement::new(
399+
vec![(dw - 1 - abs_tick, y), (dw - 1, y)],
400+
*axis_style,
401+
);
402+
plot_area.draw(&line)?;
403+
}
404+
}
405+
}
406+
}
407+
367408
Ok(())
368409
}
369-
}
410+
}

plotters/src/chart/context/cartesian3d/draw_impl.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ where
114114
}
115115
Ok(())
116116
}
117+
118+
#[allow(clippy::needless_range_loop)]
117119
#[allow(clippy::type_complexity)]
118120
pub(crate) fn draw_axis(
119121
&mut self,

plotters/src/coord/ranged1d/combinators/group_by.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ impl<T: AsRangedCoord + Sized> ToGroupByRange for T where T::CoordDescType: Disc
4545

4646
impl<T: DiscreteRanged> DiscreteRanged for GroupBy<T> {
4747
fn size(&self) -> usize {
48-
(self.0.size() + self.1 - 1) / self.1
48+
self.0.size().div_ceil(self.1)
4949
}
5050
fn index_of(&self, value: &Self::ValueType) -> Option<usize> {
5151
self.0.index_of(value).map(|idx| idx / self.1)
@@ -75,8 +75,9 @@ impl<T: DiscreteRanged> Ranged for GroupBy<T> {
7575
let range = 0..(self.0.size() + self.1) / self.1;
7676
//let logic_range: RangedCoordusize = range.into();
7777

78-
let interval =
79-
((range.end - range.start + hint.bold_points() - 1) / hint.bold_points()).max(1);
78+
let interval = (range.end - range.start)
79+
.div_ceil(hint.bold_points())
80+
.max(1);
8081
let count = (range.end - range.start) / interval;
8182

8283
let idx_iter = (0..hint.bold_points()).map(|x| x * interval);
@@ -85,7 +86,7 @@ impl<T: DiscreteRanged> Ranged for GroupBy<T> {
8586
let outer_ticks = idx_iter;
8687
let outer_tick_size = interval * self.1;
8788
let inner_ticks_per_group = hint.max_num_points() / outer_ticks.len();
88-
let inner_ticks = (outer_tick_size + inner_ticks_per_group - 1) / inner_ticks_per_group;
89+
let inner_ticks = outer_tick_size.div_ceil(inner_ticks_per_group);
8990
let inner_ticks: Vec<_> = (0..(outer_tick_size / inner_ticks))
9091
.map(move |x| x * inner_ticks)
9192
.collect();

0 commit comments

Comments
 (0)