plotly 0.14.1

A plotting library powered by Plotly.js
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
//! Pie chart plot

use plotly_derive::FieldSetter;
use serde::Serialize;

use crate::private::{NumOrString, NumOrStringCollection};
use crate::{
    common::{
        Dim, Domain, Font, HoverInfo, Label, LegendGroupTitle, Marker, Orientation, PlotType,
        Position, Visible,
    },
    Trace,
};

#[derive(Debug, Clone, Serialize)]
pub enum PieDirection {
    Clockwise,
    CounterClockwise,
}

/// Construct a Pie Chart trace.
///
/// # Examples
///
/// ```
/// use plotly::Pie;
///
/// let trace = Pie::new(
///     vec![2, 3, 5]);
///
/// let expected = serde_json::json!({
///     "type": "pie",
///     "values": [2, 3, 5],
/// });
///
/// assert_eq!(serde_json::to_value(trace).unwrap(), expected);
/// ```
/// # Using only labels
///
/// Build a new Pie Chart by only assigning the labels field. The Pie chart
/// will be generated by counting the number of unique labels, see [Pie::labels]
/// field description. Note that to create a Pie chart by using this
/// function, the type parameter `P` needs to be specialized, this can be
/// done by doing
///
/// ```
/// use plotly::Pie;
///
/// let labels = ["giraffes", "giraffes", "orangutans", "monkeys"];
///
/// let trace = Pie::<u32>::from_labels(&labels);
///
/// let expected = serde_json::json!({
///     "type": "pie",
///     "labels": ["giraffes", "giraffes", "orangutans", "monkeys"],
/// });
///
/// assert_eq!(serde_json::to_value(trace).unwrap(), expected);
/// ```
#[serde_with::skip_serializing_none]
#[derive(Serialize, Clone, Debug, FieldSetter)]
#[field_setter(box_self, kind = "trace")]
pub struct Pie<P>
where
    P: Serialize + Clone,
{
    #[field_setter(default = "PlotType::Pie")]
    r#type: PlotType,
    domain: Option<Domain>,
    /// Determines whether outside text labels can push the margins.
    automargin: Option<bool>,
    /// Assigns extra data each datum. This may be useful when listening to
    /// hover, click and selection events. Note that, “scatter” traces also
    /// appends customdata items in the markers DOM elements
    #[serde(rename = "customdata")]
    custom_data: Option<NumOrStringCollection>,
    /// Specifies the direction at which succeeding sectors follow one another.
    /// The 'direction' property is an enumeration that may be specified as
    /// One of the following enumeration values: ['clockwise',
    /// 'counterclockwise']
    direction: Option<PieDirection>,
    /// Sets the label step. See label0 for more info.
    dlabel: Option<f64>,
    /// Sets the fraction of the radius to cut out of the pie. Use this to make
    /// a donut chart. The 'hole' property is a number and may be specified
    /// as a value in the interval [0, 1]
    hole: Option<f64>,
    /// Determines which trace information appear on hover. If none or skip are
    /// set, no information is displayed upon hovering. But, if none is set,
    /// click and hover events are still fired.
    #[serde(rename = "hoverinfo")]
    hover_info: Option<HoverInfo>,
    #[serde(rename = "hoverlabel")]
    hover_label: Option<Label>,
    /// Template string used for rendering the information that appear on hover
    /// box. Note that this will override hoverinfo. Variables are inserted
    /// using %{variable}, for example “y: %{y}” as well as %{xother},
    /// {%_xother}, {%_xother_}, {%xother_}. When showing info for several
    /// points, “xother” will be added to those with different x positions from
    /// the first point. An underscore before or after “(x|y)other” will add
    /// a space on that side, only when this field is shown. Numbers are
    /// formatted using d3-format’s syntax %{variable:d3-format}, for example
    /// “Price: %{y:$.2f}”.  <https://github.com/d3/d3-format/tree/v1.4.5#d3-format> for details on the formatting syntax.
    /// Dates are formatted using d3-time-format’s syntax
    /// %{variable|d3-time-format}, for example “Day: %{2019-01-01|%A}”. <https://github.com/d3/d3-time-format/tree/v2.2.3#locale_format> for
    /// details on the date formatting syntax. The variables available in
    /// hovertemplate are the ones  emitted as event data described at this link <https://plotly.com/javascript/plotlyjs-events/#event-data>.
    /// Additionally, every attributes that can be specified per-point (the
    /// ones that are arrayOk: true) are available.  Finally, the template
    /// string has access to variables label, color, value, percent and text.
    /// Anything contained in tag \<extra\> is displayed in the secondary box,
    /// for example “<extra>{fullData.name}</extra>”. To hide the secondary
    /// box completely, use an empty tag <extra></extra>.
    #[serde(rename = "hovertemplate")]
    hover_template: Option<Dim<String>>,
    /// Sets hover text elements associated with each sector. If a single
    /// string, the same string appears for all data points. If an array of
    /// string, the items are mapped in order of this trace’s sectors. To be
    /// seen, trace hoverinfo must contain a “text” flag.
    #[serde(rename = "hovertext")]
    hover_text: Option<Dim<String>>,
    /// Assigns id labels to each datum. These ids for object constancy of data
    /// points during animation. Should be an array of strings, not numbers or
    /// any other type.
    ids: Option<Vec<String>>,
    /// Sets the font used for textinfo lying inside the sector.
    #[serde(rename = "insidetextfont")]
    inside_text_font: Option<Font>,
    /// Controls the orientation of the text inside chart sectors. When set to
    /// “auto”, text may be oriented in any direction in order to be as big as
    /// possible in the middle of a sector. The “horizontal” option orients text
    /// to be parallel with the bottom of the chart, and may make text smaller
    /// in order to achieve that goal. The “radial” option orients text along
    /// the radius of the sector. The “tangential” option orients text
    /// perpendicular to the radius of the sector.
    #[serde(rename = "insidetextorientation")]
    inside_text_orientation: Option<Orientation>,
    /// Alternate to labels. Builds a numeric set of labels. Use with dlabel
    /// where label0 is the starting label and dlabel the step.
    label0: Option<f64>,
    /// Sets the sector labels. If labels entries are duplicated, we sum
    /// associated values or simply count occurrences if values is not provided.
    /// For other array attributes (including color) we use the first non-empty
    /// entry among all occurrences of the label.
    labels: Option<Vec<String>>,
    /// Sets the legend group for this trace. Traces part of the same legend
    /// group show/hide at the same time when toggling legend items.
    #[serde(rename = "legendgroup")]
    legend_group: Option<String>,
    /// Set and style the title to appear for the legend group.
    #[serde(rename = "legendgrouptitle")]
    legend_group_title: Option<LegendGroupTitle>,
    /// Sets the legend rank for this trace. Items and groups with smaller ranks
    /// are presented on top/left side while with “reversed” legend.traceorder
    /// they are on bottom/right side. The default legendrank is 1000, so that
    /// you can use ranks less than 1000 to place certain items before all
    /// unranked items, and ranks greater than 1000 to go after all unranked
    /// items. When having unranked or equal rank items shapes would be
    /// displayed after traces i.e. according to their order in data and layout.
    #[serde(rename = "legendrank")]
    legend_rank: Option<usize>,
    //
    marker: Option<Marker>,
    /// Assigns extra meta information associated with this trace that can be
    /// used in various text attributes. Attributes such as trace name, graph,
    /// axis and colorbar title.text, annotation text rangeselector,
    /// updatemenues and sliders label text all support meta. To access the
    /// trace meta values in an attribute in the same trace, simply use
    /// %{meta\[i\]} where i is the index or key of the meta item in question.
    /// To access trace meta in layout attributes, use %{data[n[.meta\[i\]}
    /// where i is the index or key of the meta and n is the trace index.
    meta: Option<NumOrString>,
    /// Sets the trace name. The trace name appears as the legend item and on
    /// hover.
    name: Option<String>,
    /// Sets the opacity of the trace.
    opacity: Option<f64>,
    /// Sets the font used for textinfo lying outside the sector.
    #[serde(rename = "outsidetextfont")]
    outside_text_font: Option<Font>,
    /// Instead of the first slice starting at 12 o’clock, rotate to some other
    /// angle. The 'rotation' property is a angle (in degrees) that may be
    /// specified as a number between -180 and 180.  Numeric values outside this
    /// range are converted to the equivalent value (e.g. 270 is converted to
    /// -90).
    rotation: Option<f64>,
    /// Determines whether or not an item corresponding to this trace is shown
    /// in the legend.
    #[serde(rename = "showlegend")]
    show_legend: Option<bool>,
    /// Determines whether or not the sectors are reordered from largest to
    /// smallest.
    sort: Option<bool>,
    /// Sets text elements associated with each sector. If trace textinfo
    /// contains a “text” flag, these elements will be seen on the chart. If
    /// trace hoverinfo contains a “text” flag and “hovertext” is not set, these
    /// elements will be seen in the hover labels.
    text: Option<Dim<String>>,
    /// Determines which trace information appear on the graph.
    #[serde(rename = "textinfo")]
    text_info: Option<String>,
    /// Sets the font used for textinfo.
    #[serde(rename = "textfont")]
    text_font: Option<Font>,
    /// Specifies the location of the textinfo.
    #[serde(rename = "textposition")]
    text_position: Option<Dim<Position>>,
    /// Template string used for rendering the information text that appear on
    /// points. Note that this will override textinfo. Variables are
    /// inserted using %{variable}, for example “y: %{y}”. Numbers are formatted
    /// using d3-format’s syntax %{variable:d3-format},  for example “Price:
    /// %{y:$.2f}”. <https://github.com/d3/d3-format/tree/v1.4.5#d3-format> for details on the formatting syntax.
    /// Dates are formatted using d3-time-format’s syntax
    /// %{variable|d3-time-format}, for example “Day: %{2019-01-01|%A}”. <https://github.com/d3/d3-time-format/tree/v2.2.3#locale_format> for details on the date formatting syntax.
    /// Every attributes that can be specified per-point (the ones that are
    /// arrayOk: true) are available. Finally, the template string has
    /// access to variables label, color, value, percent and text.
    #[serde(rename = "texttemplate")]
    text_template: Option<Dim<String>>,
    /// Controls persistence of some user-driven changes to the trace:
    /// constraintrange in parcoords traces, as well as some editable: true
    /// modifications such as name and colorbar.title. Defaults to
    /// layout.uirevision. Note that other user-driven trace attribute changes
    /// are controlled by layout attributes: trace.visible is controlled by
    /// layout.legend.uirevision, selectedpoints is controlled by
    /// layout.selectionrevision, and colorbar.(x|y) (accessible with config:
    /// {editable: true}) is controlled by layout.editrevision. Trace changes
    /// are tracked by uid, which only falls back on trace index if no uid is
    /// provided. So if your app can add/remove traces before the end of the
    /// data array, such that the same trace has a different index, you can
    /// still preserve user-driven changes if you give each trace a uid that
    /// stays with it as it moves.
    #[serde(rename = "uirevision")]
    ui_revision: Option<NumOrString>,
    /// Sets the values of the sectors. If omitted, we count occurrences of each
    /// label.
    values: Option<Vec<P>>,
    /// Determines whether or not this trace is visible. If “legendonly”, the
    /// trace is not drawn, but can appear as a legend item (provided that the
    /// legend itself is visible).
    visible: Option<Visible>,
    /// Sets the width (in px or fraction) of the legend for this trace.
    #[serde(rename = "legendwidth")]
    legend_width: Option<f64>,
    /// Sets the fraction of larger radius to pull the sectors out from the
    /// center. This can be a constant to pull all slices apart from each other
    /// equally or an array to highlight one or more slices.
    pull: Option<f64>,
    /// Sets the source reference on Chart Studio Cloud for customdata.
    #[serde(rename = "customdatasrc")]
    custom_data_src: Option<Dim<String>>,
    /// Sets the source reference on Chart Studio Cloud for hoverinfo.
    #[serde(rename = "hoverinfosrc")]
    hover_info_src: Option<Dim<String>>,
    /// Sets the source reference on Chart Studio Cloud for hovertemplate.
    #[serde(rename = "hovertemplatesrc")]
    hover_template_src: Option<Dim<String>>,
    /// Sets the source reference on Chart Studio Cloud for hovertext.
    #[serde(rename = "hovertextsrc")]
    hover_text_src: Option<Dim<String>>,
    /// Sets the source reference on Chart Studio Cloud for ids.
    #[serde(rename = "idssrc")]
    idssrc: Option<Dim<String>>,
    /// Sets the source reference on Chart Studio Cloud for labels.
    #[serde(rename = "labelssrc")]
    labelssrc: Option<Dim<String>>,
    /// metasrc – Sets the source reference on Chart Studio Cloud for meta.
    #[serde(rename = "metasrc")]
    metasrc: Option<Dim<String>>,
    /// Sets the source reference on Chart Studio Cloud for values.
    #[serde(rename = "valuessrc")]
    values_src: Option<Dim<String>>,
    /// Sets the source reference on Chart Studio Cloud for pull.
    #[serde(rename = "pullsrc")]
    pull_src: Option<Dim<String>>,
    /// Sets the source reference on Chart Studio Cloud for textposition.
    #[serde(rename = "textpositionsrc")]
    text_position_src: Option<Dim<String>>,
    /// Sets the source reference on Chart Studio Cloud for text.
    #[serde(rename = "textsrc")]
    text_src: Option<Dim<String>>,
    /// Sets the source reference on Chart Studio Cloud for texttemplate.
    #[serde(rename = "texttemplatesrc")]
    text_template_src: Option<Dim<String>>,
    /// Assign an id to this trace, Use this to provide object constancy between
    /// traces during animations and transitions.
    uid: Option<String>,
    /// If there are multiple pie charts that should be sized according to their
    /// totals, link them by providing a non-empty group id here shared by every
    /// trace in the same group.
    #[serde(rename = "scalegroup")]
    scale_group: Option<String>,
    //
    // stream – plotly.graph_objects.pie.Stream instance or dict with compatible properties
    //
    // legend – Sets the reference to a legend to show this trace in. References to these legends
    // are “legend”, “legend2”, “legend3”, etc. Settings for these legends are set in the layout,
    // under layout.legend, layout.legend2, etc.
    //
    // textinfo – Determines which trace information appear on the graph.
}

impl<P> Pie<P>
where
    P: Serialize + Clone + 'static,
{
    /// Build a new Pie Chart by only assigning the values field
    pub fn new(values: Vec<P>) -> Box<Self> {
        Box::new(Self {
            values: Some(values),
            ..Default::default()
        })
    }

    /// Same as [Pie::new()]
    pub fn from_values(values: Vec<P>) -> Box<Self> {
        Box::new(Self {
            values: Some(values),
            ..Default::default()
        })
    }

    /// Build a new Pie Chart by only assigning the labels field. The Pie chart
    /// will be generated by counting the number of unique labels, see
    /// [Pie::labels] field description. Note that to create a Pie chart by
    /// using this function, the type parameter `P` needs to be specialized,
    /// this can be done by doing
    /// ```
    /// use plotly::Pie;
    ///
    /// let labels = ["giraffes", "giraffes", "orangutans", "monkeys"];
    /// let trace = Pie::<u32>::from_labels(&labels);
    /// ```
    pub fn from_labels<T: AsRef<str> + ToString>(labels: &[T]) -> Box<Self> {
        let l = labels.iter().map(|s| s.to_string()).collect();
        Box::new(Self {
            labels: Some(l),
            ..Default::default()
        })
    }
}

impl<P> Trace for Pie<P>
where
    P: Serialize + Clone,
{
    fn to_json(&self) -> String {
        serde_json::to_string(self).unwrap()
    }
}

#[cfg(test)]
mod tests {
    use serde_json::{json, to_value};

    use super::*;

    #[test]
    fn serialize_pie() {
        let pie_trace = Pie::new(vec![45, 55])
            .name("pie")
            .automargin(true)
            .direction(PieDirection::Clockwise)
            .hole(0.2)
            .inside_text_font(Font::new().color("#ff7f0e"))
            .inside_text_orientation(Orientation::Tangential)
            .labels(vec!["a", "b"])
            .sort(true)
            .visible(Visible::True)
            .show_legend(true)
            .legend_rank(1000)
            .legend_group("legend group")
            .legend_group_title("Legend Group Title")
            .opacity(0.5)
            .ids(vec!["one"])
            .text("text")
            .text_info("label+percent")
            .text_array(vec!["text"])
            .text_template("text_template")
            .text_template_array(vec!["text_template"])
            .text_font(Font::new())
            .text_position(Position::TopCenter)
            .text_position_array(vec![Position::MiddleLeft])
            .hover_text("hover_text")
            .hover_text_array(vec!["hover_text"])
            .hover_info(HoverInfo::XAndYAndZ)
            .hover_template("hover_template")
            .hover_template_array(vec!["hover_template"])
            .meta("meta")
            .custom_data(vec!["custom_data"])
            .marker(Marker::new())
            .hover_label(Label::new())
            .ui_revision(6);
        let expected = json!({
            "values": [45, 55],
            "type": "pie",
            "name": "pie",
            "automargin": true,
            "direction" : "Clockwise",
            "hole": 0.2,
            "insidetextfont": {"color": "#ff7f0e"},
            "insidetextorientation": "t",
            "labels": ["a", "b"],
            "sort": true,
            "visible": true,
            "showlegend": true,
            "legendrank": 1000,
            "legendgroup": "legend group",
            "legendgrouptitle": {"text": "Legend Group Title"},
            "opacity": 0.5,
            "ids": ["one"],
            "text": ["text"],
            "textinfo": "label+percent",
            "textfont": {},
            "texttemplate": ["text_template"],
            "textposition": ["middle left"],
            "hovertext": ["hover_text"],
            "hoverinfo": "x+y+z",
            "hovertemplate": ["hover_template"],
            "meta": "meta",
            "customdata": ["custom_data"],
            "marker": {},
            "hoverlabel": {},
            "uirevision": 6,
        });

        assert_eq!(to_value(pie_trace).unwrap(), expected);
    }

    #[test]
    fn new_from_values() {
        let values = vec![2.2, 3.3, 4.4];
        let trace = Pie::from_values(values);

        let expected = serde_json::json!({
            "type": "pie",
            "values": [2.2, 3.3, 4.4],
        });

        assert_eq!(to_value(trace).unwrap(), expected);
    }

    #[test]
    fn new_from_labels() {
        let labels = ["giraffes", "giraffes", "orangutans", "monkeys"];

        let trace = Pie::<u32>::from_labels(&labels);

        let expected = serde_json::json!({
            "type": "pie",
            "labels": ["giraffes", "giraffes", "orangutans", "monkeys"],
        });

        assert_eq!(to_value(trace).unwrap(), expected);
    }
}