|
| 1 | +--- |
| 2 | +jupyter: |
| 3 | + jupytext: |
| 4 | + notebook_metadata_filter: all |
| 5 | + text_representation: |
| 6 | + extension: .md |
| 7 | + format_name: markdown |
| 8 | + format_version: '1.2' |
| 9 | + jupytext_version: 1.4.2 |
| 10 | + kernelspec: |
| 11 | + display_name: Python 3 |
| 12 | + language: python |
| 13 | + name: python3 |
| 14 | + language_info: |
| 15 | + codemirror_mode: |
| 16 | + name: ipython |
| 17 | + version: 3 |
| 18 | + file_extension: .py |
| 19 | + mimetype: text/x-python |
| 20 | + name: python |
| 21 | + nbconvert_exporter: python |
| 22 | + pygments_lexer: ipython3 |
| 23 | + version: 3.7.7 |
| 24 | + plotly: |
| 25 | + description: How to use categorical axes in Python with Plotly. |
| 26 | + display_as: basic |
| 27 | + language: python |
| 28 | + layout: base |
| 29 | + name: Categorical Axes |
| 30 | + order: 16 |
| 31 | + page_type: example_index |
| 32 | + permalink: python/categorical-axes/ |
| 33 | + thumbnail: thumbnail/bar.jpg |
| 34 | +--- |
| 35 | + |
| 36 | + |
| 37 | +This page shows examples of how to configure [2-dimensional Cartesian axes](/python/figure-structure/#2d-cartesian-trace-types-and-subplots) to visualize categorical (i.e. qualitative, nominal or ordinal data as opposed to continuous numerical data). Such axes are a natural fit for bar charts, waterfall charts, funnel charts, heatmaps, violin charts and box plots, but can also be used with scatter plots and line charts. [Configuring gridlines, ticks, tick labels and axis titles](/python/axes/) on logarithmic axes is done the same was as with [linear axes](/python/axes/). |
| 38 | + |
| 39 | +### 2-D Cartesian Axis Type and Auto-Detection |
| 40 | + |
| 41 | +The different types of Cartesian axes are configured via the `xaxis.type` or `yaxis.type` attribute, which can take on the following values: |
| 42 | + |
| 43 | +- `'linear'` (see the [linear axes tutoria](/python/axes/)) |
| 44 | +- `'log'` (see the [log plot tutorial](/python/log-plots/)) |
| 45 | +- `'date'` (see the [tutorial on timeseries](/python/time-series/)) |
| 46 | +- `'category'` see below |
| 47 | +- `'multicategory'` see below |
| 48 | + |
| 49 | +The axis type is auto-detected by looking at data from the first [trace](/python/figure-structure/) linked to this axis: |
| 50 | + |
| 51 | +* First check for `multicategory`, then `date`, then `category`, else default to `linear` (`log` is never automatically selected) |
| 52 | +* `multicategory` is just a shape test: is the array nested? |
| 53 | +* `date` and `category`: require **more than twice as many distinct date or category strings** as distinct numbers or numeric strings in order to choose that axis type. |
| 54 | + * Both of these test an evenly-spaced sample of at most 1000 values |
| 55 | + * Small detail: the `category` test sorts every value into either number or category, whereas for dates, 2- and 4-digit integers count as both dates and numbers. |
| 56 | + |
| 57 | + |
| 58 | +### Forcing an axis to be categorical |
| 59 | + |
| 60 | +If you pass string values for the `x` or `y` parameter, plotly will automatically set the corresponding axis type to `category`, *except if enough of these strings contain numbers* as detailed above, in which case the axis is automatically set to `linear`. It is however possible to force the axis type by setting explicitely `xaxis_type` to be `category`. |
| 61 | + |
| 62 | +```python |
| 63 | +import plotly.express as px |
| 64 | +fig = px.bar(x=[1, 2, 4, 10], y =[8, 6, 11, 5]) |
| 65 | +fig.update_xaxes(type='category') |
| 66 | +fig.show() |
| 67 | +``` |
| 68 | + |
| 69 | +### Controlling the Category Order with Plotly Express |
| 70 | + |
| 71 | +[Plotly Express](/python/plotly-express/) is the easy-to-use, high-level interface to Plotly, which [operates on a variety of types of data](/python/px-arguments/) and produces [easy-to-style figures](/python/styling-plotly-express/). |
| 72 | + |
| 73 | +By default, Plotly Express lays out categorical data in the order in which it appears in the underlying data. Every 2-d cartesian Plotly Express function also includes a `category_orders` keyword argument which can be used to control the order in which categorical axes are drawn, but beyond that can also control [the order in which discrete colors appear in the legend](/python/discrete-color/), and [the order in which facets are laid out](/python/facet-plots/). |
| 74 | + |
| 75 | +```python |
| 76 | +import plotly.express as px |
| 77 | +df = px.data.tips() |
| 78 | +fig = px.bar(df, x="day", y="total_bill", color="smoker", barmode="group", facet_col="sex", |
| 79 | + category_orders={"day": ["Thur", "Fri", "Sat", "Sun"], |
| 80 | + "smoker": ["Yes", "No"], |
| 81 | + "sex": ["Male", "Female"]}) |
| 82 | +fig.show() |
| 83 | +``` |
| 84 | + |
| 85 | +### Automatically Sorting Categories by Name or Total Value |
| 86 | + |
| 87 | +Whether using Plotly Express or not, categories can be sorted alphabetically or by value using the `categoryorder` attribute: |
| 88 | + |
| 89 | +Set `categoryorder` to `"category ascending"` or `"category descending"` for the alphanumerical order of the category names or `"total ascending"` or `"total descending"` for numerical order of values. [categoryorder](https://plotly.com/python/reference/layout/xaxis/#layout-xaxis-categoryorder) for more information. Note that sorting the bars by a particular trace isn't possible right now - it's only possible to sort by the total values. Of course, you can always sort your data _before_ plotting it if you need more customization. |
| 90 | + |
| 91 | +This example orders the categories **alphabetically** with `categoryorder: 'category ascending'` |
| 92 | + |
| 93 | +```python |
| 94 | +import plotly.graph_objects as go |
| 95 | + |
| 96 | +x=['b', 'a', 'c', 'd'] |
| 97 | +fig = go.Figure(go.Bar(x=x, y=[2,5,1,9], name='Montreal')) |
| 98 | +fig.add_trace(go.Bar(x=x, y=[1, 4, 9, 16], name='Ottawa')) |
| 99 | +fig.add_trace(go.Bar(x=x, y=[6, 8, 4.5, 8], name='Toronto')) |
| 100 | + |
| 101 | +fig.update_layout(barmode='stack') |
| 102 | +fig.update_xaxes(categoryorder='category ascending') |
| 103 | +fig.show() |
| 104 | +``` |
| 105 | + |
| 106 | +This example orders the categories **by total value** with `categoryorder: 'total descending'` |
| 107 | + |
| 108 | +```python |
| 109 | +import plotly.graph_objects as go |
| 110 | + |
| 111 | +x=['b', 'a', 'c', 'd'] |
| 112 | +fig = go.Figure(go.Bar(x=x, y=[2,5,1,9], name='Montreal')) |
| 113 | +fig.add_trace(go.Bar(x=x, y=[1, 4, 9, 16], name='Ottawa')) |
| 114 | +fig.add_trace(go.Bar(x=x, y=[6, 8, 4.5, 8], name='Toronto')) |
| 115 | + |
| 116 | +fig.update_layout(barmode='stack') |
| 117 | +fig.update_xaxes(categoryorder='total ascending') |
| 118 | +fig.show() |
| 119 | +``` |
| 120 | + |
| 121 | +This example shows how to control category order when using `plotly.graph_objects` by defining `categoryorder` to "array" to derive the ordering from the attribute `categoryarray`. |
| 122 | + |
| 123 | +```python |
| 124 | +import plotly.graph_objects as go |
| 125 | + |
| 126 | +x=['b', 'a', 'c', 'd'] |
| 127 | +fig = go.Figure(go.Bar(x=x, y=[2,5,1,9], name='Montreal')) |
| 128 | +fig.add_trace(go.Bar(x=x, y=[1, 4, 9, 16], name='Ottawa')) |
| 129 | +fig.add_trace(go.Bar(x=x, y=[6, 8, 4.5, 8], name='Toronto')) |
| 130 | + |
| 131 | +fig.update_layout(barmode='stack') |
| 132 | +fig.update_xaxes(categoryorder='array', categoryarray= ['d','a','c','b']) |
| 133 | +fig.show() |
| 134 | +``` |
| 135 | +### Gridlines, Ticks and Tick Labels |
| 136 | + |
| 137 | + |
| 138 | +By default, gridlines and ticks are not shown on categorical axes but they can be activated: |
| 139 | + |
| 140 | +```python |
| 141 | +import plotly.express as px |
| 142 | + |
| 143 | +fig = px.bar(x=["A","B","C"], y=[1,3,2]) |
| 144 | +fig.update_xaxes(showgrid=True, ticks="outside") |
| 145 | +fig.show() |
| 146 | +``` |
| 147 | + |
| 148 | +By default, ticks and gridlines appear on the categories but the `tickson` attribute can be used to move them to the category boundaries: |
| 149 | + |
| 150 | +```python |
| 151 | +import plotly.express as px |
| 152 | + |
| 153 | +fig = px.bar(x=["A","B","C"], y=[1,3,2]) |
| 154 | +fig.update_xaxes(showgrid=True, ticks="outside", tickson="boundaries") |
| 155 | +fig.show() |
| 156 | +``` |
| 157 | + |
| 158 | +### Multi-categorical Axes |
| 159 | + |
| 160 | +A two-level categorical axis (also known as grouped or hierarchical categories, or sub-categories) can be created by specifying a trace's `x` or `y` property as a 2-dimensional lists. The first sublist represents the outer categorical value while the second sublist represents the inner categorical value. This is only possible with `plotly.graph_objects` at the moment, and not Plotly Express. |
| 161 | + |
| 162 | +Passing in a two-dimensional list as the `x` or `y` value of a trace causes [the `type` of the corresponding axis](/python/axes/) to be set to `multicategory`. |
| 163 | + |
| 164 | +Here is an example that creates a figure with 2 `bar` traces with a 2-level categorical x-axis. |
| 165 | + |
| 166 | +```python |
| 167 | +import plotly.graph_objects as go |
| 168 | + |
| 169 | +fig = go.Figure() |
| 170 | + |
| 171 | +fig.add_trace(go.Bar( |
| 172 | + x = [['First', 'First', 'Second', 'Second'], |
| 173 | + ["A", "B", "A", "B"]], |
| 174 | + y = [2, 3, 1, 5], |
| 175 | + name = "Adults", |
| 176 | +)) |
| 177 | + |
| 178 | +fig.add_trace(go.Bar( |
| 179 | + x = [['First', 'First', 'Second', 'Second'], |
| 180 | + ["A", "B", "A", "B"]], |
| 181 | + y = [8, 3, 6, 5], |
| 182 | + name = "Children", |
| 183 | +)) |
| 184 | + |
| 185 | +fig.update_layout(title_text="Multi-category axis") |
| 186 | + |
| 187 | +fig.show() |
| 188 | +``` |
| 189 | +### Reference |
| 190 | + |
| 191 | +See https://plotly.com/python/reference/layout/xaxis/ for more information and chart attribute options! |
0 commit comments