diff --git a/CHANGELOG.md b/CHANGELOG.md index b14a7d6802..74782fa341 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,16 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -## Unreleased +## [6.2.0] - 2025-06-26 +### Added +- Add SRI (Subresource Integrity) hash support for CDN script tags when using `include_plotlyjs='cdn'`. This enhances security by ensuring browser verification of CDN-served plotly.js files [[#5165](https://github.com/plotly/plotly.py/pull/5165)] (with thanks to @ddworken) + +### Fixed +- Allow setting Plotly.js path via `pio.defaults` [[#5207](https://github.com/plotly/plotly.py/pull/5207)] + +### Changed +- Refactor validation code to reduce bundle size [[#5214](https://github.com/plotly/plotly.py/pull/5214)] (with thanks to @bmaranville) - Add deprecation warnings when using Kaleido v0 or deprecated image export features [[#5177](https://github.com/plotly/plotly.py/pull/5236)] ## [6.1.2] - 2025-05-27 @@ -24,9 +32,6 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Add support for Kaleido>=v1.0.0 for image generation [[#5062](https://github.com/plotly/plotly.py/pull/5062), [#5177](https://github.com/plotly/plotly.py/pull/5177)] - Reduce package bundle size by 18-24% via changes to code generation [[#4978](https://github.com/plotly/plotly.py/pull/4978)] -### Added -- Add SRI (Subresource Integrity) hash support for CDN script tags when using `include_plotlyjs='cdn'`. This enhances security by ensuring browser verification of CDN-served plotly.js files [[#PENDING](https://github.com/plotly/plotly.py/pull/PENDING)] - ### Fixed - Fix third-party widget display issues in v6 [[#5102](https://github.com/plotly/plotly.py/pull/5102)] - Add handling for case where `jupyterlab` or `notebook` is not installed [[#5104](https://github.com/plotly/plotly.py/pull/5104/files)] diff --git a/doc/apidoc/conf.py b/doc/apidoc/conf.py index 3b71a156e5..02317ef0ee 100644 --- a/doc/apidoc/conf.py +++ b/doc/apidoc/conf.py @@ -24,7 +24,7 @@ # The short X.Y version version = "" # The full version, including alpha/beta/rc tags -release = "6.0.1" +release = "6.2.0" # -- General configuration --------------------------------------------------- diff --git a/doc/python/bar-charts.md b/doc/python/bar-charts.md index 543b1563e3..3e28be0dfe 100644 --- a/doc/python/bar-charts.md +++ b/doc/python/bar-charts.md @@ -589,6 +589,108 @@ fig.update_layout( ) ``` +### Using a scatterplot to wrap long bars into multiple columns + +This bar-style pictogram allows readers to focus on the relative sizes of smaller entities by wrapping the bar for largest entries into multiple columns. You could make it even more of a pictogram by using fontawesome to replace the square markers we use below with icons like mortar boards for students. + +```python +import plotly.graph_objects as go +import pandas as pd +def pictogram_bar(data, title, icon_size, max_icons_per_column=10, units_per_icon=1, unit_description="", inter_group_spacing=.8,icon_vertical_spacing=0.005): + + fig = go.Figure() + x_start = 1 + tick_locations = [] + #loop through each group and create a trace with its icons + for i, (category, value) in enumerate(data.items()): + # compute the number of icons to use to represent this category. Depending on your use case, you might replace round with floor or ceiling. + icon_count = round(value / units_per_icon) + # compute the number of columns in which to arrange the icons for this category + # using a double negative sign to convert a floor(division) operation into a ceiling(division) operation + num_columns = -(-icon_count // max_icons_per_column) + + #create and populate lists of icon coordinates + x_coordinates, y_coordinates = [], [] + for col in range(num_columns): + # the number of icons in this column is the lesser of the column height or + # the number of icons remaining to place + column_icons = min(max_icons_per_column, icon_count - col * max_icons_per_column) + + # Create a one item list containing the x-coordinate of this column. + # Then add column_icons copies of that coordinate to the list of icon x coordinates using list multiplication. + # Normalizing the width of each within-category column to 1 simplifies the code. + # We can adjust the visible space between columns by adjusting the total width below. + x_coordinates.extend([x_start + col] * column_icons) + # Create a list of sequentially increasing y-coordinates for icons. + y_coordinates.extend([y + icon_vertical_spacing * y for y in range(1, column_icons + 1)]) + # Add scatter plot for the category + fig.add_trace(go.Scatter( + x=x_coordinates, + y=y_coordinates, + mode='markers', + marker=dict(size=icon_size, symbol="square", color= i), + name=category, + # Suppress the x and y coordinates in the hover text, since they are irrelevant implementation details. + hoverinfo="text", + text=[f"{category}: {value}" for _ in range(len(x_coordinates))] + )) + + # Add an annotation above the center of each category showing its value + fig.add_trace(go.Scatter( + x=[x_start + (num_columns - 1) / 2], # Compute the location of the center + y=[max_icons_per_column* (1+icon_vertical_spacing) + 1.15], + mode="text", + text=[f"{value}"], + textfont=dict(size=14, color="black"), + showlegend=False + )) + # Track locations where we will put the text labeling each category + tick_locations.append(x_start + (num_columns - 1) / 2) + #compute the left edge of the next category + x_start += num_columns + inter_group_spacing + + fig.update_layout( + title=title, + xaxis=dict( + tickvals=tick_locations, + # Label ecah category + ticktext=list(data.keys()), + tickangle=-45, + showgrid=False, + title="Categories" + ), + yaxis=dict( + title=f"Each icon represents {units_per_icon:,g} {unit_description}", + # The y-axis goes above the top icon to make room for the annotations. + # We set tick values so the axis labeling does not go above the top icon. + # If you choose a value of max_icons_per_column that is not a multiple of 5, consider changing this. + tickvals=list(range(0,max_icons_per_column+1,5)), + showgrid=False, + zeroline=False, + ), + # We have already got all the labeling we need so we suppress the legend. + showlegend=False, + height=700, + # The x-coordinates scale to fill available space, so adjusting the width of the image is a good way to adjust spacing between columns. + width=(len(data) * 150 + 50) + ) + fig.show() + +df = pd.DataFrame({ + 'School': ["Haverford College", "University of Mary Washington", "Brown University", "Arizona State University"], + 'Enrollment': [1421, 3611, 7226, 65174] +}) + +pictogram_bar( + data={row['School']: row['Enrollment'] for _, row in df.iterrows()}, + title="Undergraduate Enrollment at Participating Schools", + units_per_icon=1000, + unit_description = "students", + icon_size=27, + icon_vertical_spacing=0.05 +) +``` + ### Customizing Individual Bar Base ```python diff --git a/doc/python/static-image-export.md b/doc/python/static-image-export.md index 7ac4beb56f..6ccd1af2c0 100644 --- a/doc/python/static-image-export.md +++ b/doc/python/static-image-export.md @@ -269,7 +269,7 @@ The following settings are available. `default_scale`: The default image scale factor applied on image export. -`default_format`: The default image format used on export. One of "png", "jpeg", "webp", "svg", or "pdf". ("eps" support is deprecated and available with Kaleido v0 only) +`default_format`: The default image format used on export. One of "png", "jpeg", "webp", "svg", or "pdf". ("eps" support is available with Kaleido v0 only) `mathjax`: Location of the MathJax bundle needed to render LaTeX characters. Defaults to a CDN location. If fully offline export is required, set this to a local MathJax bundle. diff --git a/doc/requirements.txt b/doc/requirements.txt index 85e870636a..a874f2f022 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -1,4 +1,4 @@ -plotly==6.0.1 +plotly==6.2.0 anywidget cufflinks==0.17.3 dash-bio diff --git a/doc/what_about_dash.md b/doc/what_about_dash.md index 696aa93a63..5a0b192f4e 100644 --- a/doc/what_about_dash.md +++ b/doc/what_about_dash.md @@ -22,6 +22,6 @@ app.layout = html.Div([ dcc.Graph(figure=fig) ]) -app.run_server(debug=True, use_reloader=False) # Turn off reloader if inside Jupyter +app.run(debug=True, use_reloader=False) # Turn off reloader if inside Jupyter ``` diff --git a/plotly/basedatatypes.py b/plotly/basedatatypes.py index 72f4cd25ca..1384e08d54 100644 --- a/plotly/basedatatypes.py +++ b/plotly/basedatatypes.py @@ -3404,8 +3404,8 @@ def show(self, *args, **kwargs): plot is. The default is set in plotly.js. height: int or float - An integer or float that determines the number of pixels wide the - plot is. The default is set in plotly.js. + An integer or float specifying the height of the plot in pixels. + The default is set in plotly.js. config: dict A dict of parameters to configure the figure. The defaults are set diff --git a/pyproject.toml b/pyproject.toml index cfd15eb1ca..49a821cfb2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,7 @@ classifiers = [ ] requires-python = ">=3.8" license = {file="LICENSE.txt"} -version = "6.1.2" +version = "6.2.0" dependencies = [ "narwhals>=1.15.1", "packaging" diff --git a/tests/test_io/test_to_from_plotly_json.py b/tests/test_io/test_to_from_plotly_json.py index 1c0440b033..f8c5a71ee4 100644 --- a/tests/test_io/test_to_from_plotly_json.py +++ b/tests/test_io/test_to_from_plotly_json.py @@ -109,7 +109,7 @@ def numpy_unicode_array(request): params=[ datetime.datetime(2003, 7, 12, 8, 34, 22), datetime.datetime.now(), - np.datetime64(datetime.datetime.utcnow()), + np.datetime64(datetime.datetime.now(datetime.timezone.utc)), pd.Timestamp(datetime.datetime.now()), eastern.localize(datetime.datetime(2003, 7, 12, 8, 34, 22)), eastern.localize(datetime.datetime.now()), diff --git a/uv.lock b/uv.lock index 0f3318f370..e882459b0f 100644 --- a/uv.lock +++ b/uv.lock @@ -4276,7 +4276,7 @@ wheels = [ [[package]] name = "plotly" -version = "6.1.2" +version = "6.2.0" source = { editable = "." } dependencies = [ { name = "narwhals" },
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: