Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).

## Unreleased

### Added
- Add `px.scatter_smith` for plotting complex values (`real` and `imag`) on Smith charts, and support the `"smith"` subplot type in `make_subplots` [[#5824](https://github.com/plotly/plotly.py/pull/5824)], with thanks to @ybai08 for the contribution!

### Fixed
- Fix `mpl_to_plotly` tick marker mirroring, axis positioning, and trace visibility for twinned and overlaid subplots (such as `twinx` and `twiny`) [[#5310](https://github.com/plotly/plotly.py/pull/5310)], with thanks to @robertoffmoura for the contribution!
- Fix `mpl_to_plotly` losing matplotlib axis line colors by exporting the color of each axis's displayed spine to the plotly x and y axis `linecolor` [[#5311](https://github.com/plotly/plotly.py/pull/5311)], with thanks to @robertoffmoura for the contribution!
Expand Down
1 change: 1 addition & 0 deletions doc/apidoc/plotly.express.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ plotly's high-level API for rapid figure generation. ::
scatter_3d
scatter_polar
scatter_ternary
scatter_smith
scatter_map
scatter_geo
line
Expand Down
18 changes: 18 additions & 0 deletions doc/python/smith-charts.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,24 @@ jupyter:
A [Smith Chart](https://en.wikipedia.org/wiki/Smith_chart) is a specialized chart for visualizing [complex numbers](https://en.wikipedia.org/wiki/Complex_number): numbers with both a real and imaginary part.


### Smith Charts with Plotly Express

[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/). With `px.scatter_smith`, each row of the DataFrame is represented as a marker on the Smith chart, with `real` and `imag` giving the real and imaginary parts of its normalized impedance.

```python
import plotly.express as px
import pandas as pd

df = pd.DataFrame({
"real": [0.2, 0.5, 1.0, 2.0, 0.2, 0.5, 1.0, 2.0],
"imag": [0.5, 1.0, 0.5, -1.0, -0.5, -1.0, 2.0, 0.0],
"antenna": ["A", "A", "A", "A", "B", "B", "B", "B"],
})

fig = px.scatter_smith(df, real="real", imag="imag", color="antenna")
fig.show()
```

### Smith Charts with Plotly Graph Objects

```python
Expand Down
5 changes: 3 additions & 2 deletions plotly/_subplots.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# little differently.
import collections

_single_subplot_types = {"scene", "geo", "polar", "ternary", "map"}
_single_subplot_types = {"scene", "geo", "polar", "ternary", "map", "smith"}
_subplot_types = set.union(_single_subplot_types, {"xy", "domain"})

# For most subplot types, a trace is associated with a particular subplot
Expand All @@ -20,7 +20,7 @@
# the trace property is just named `subplot`. For example setting
# the `scatterpolar.subplot` property to `polar3` associates the scatterpolar
# trace with the third polar subplot in the figure
_subplot_prop_named_subplot = {"polar", "ternary", "map"}
_subplot_prop_named_subplot = {"polar", "ternary", "map", "smith"}


# Named tuple to hold an xaxis/yaxis pair that represent a single subplot
Expand Down Expand Up @@ -152,6 +152,7 @@ def make_subplots(
- 'polar': Polar subplot for scatterpolar, barpolar, etc.
- 'ternary': Ternary subplot for scatterternary
- 'map': Map subplot for scattermap, choroplethmap and densitymap
- 'smith': Smith chart subplot for scattersmith
- 'domain': Subplot type for traces that are individually
positioned. pie, parcoords, parcats, etc.
- trace type: A trace type which will be used to determine
Expand Down
1 change: 1 addition & 0 deletions plotly/basedatatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2428,6 +2428,7 @@ def get_subplot(self, row, col, secondary_y=False):
* plotly.graph_objs.layout.Polar: if subplot type is 'polar'
* plotly.graph_objs.layout.Ternary: if subplot type is 'ternary'
* plotly.graph_objs.layout.Map: if subplot type is 'map'
* plotly.graph_objs.layout.Smith: if subplot type is 'smith'
* SubplotDomain namedtuple with `x` and `y` fields:
if subplot type is 'domain'.
- x: length 2 list of the subplot start and stop width
Expand Down
2 changes: 2 additions & 0 deletions plotly/express/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
scatter_3d,
scatter_polar,
scatter_ternary,
scatter_smith,
scatter_map,
scatter_geo,
line,
Expand Down Expand Up @@ -79,6 +80,7 @@
"scatter_3d",
"scatter_polar",
"scatter_ternary",
"scatter_smith",
"scatter_map",
"scatter_geo",
"scatter_matrix",
Expand Down
41 changes: 41 additions & 0 deletions plotly/express/_chart_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,47 @@ def line_ternary(
line_ternary.__doc__ = make_docstring(line_ternary)


def scatter_smith(
data_frame=None,
real=None,
imag=None,
color=None,
symbol=None,
size=None,
text=None,
hover_name=None,
hover_data=None,
custom_data=None,
animation_frame=None,
animation_group=None,
category_orders=None,
labels=None,
color_discrete_sequence=None,
color_discrete_map=None,
color_continuous_scale=None,
range_color=None,
color_continuous_midpoint=None,
symbol_sequence=None,
symbol_map=None,
opacity=None,
size_max=None,
title=None,
subtitle=None,
template=None,
width=None,
height=None,
) -> go.Figure:
"""
In a Smith chart scatter plot, each row of `data_frame` is represented by
a symbol mark in Smith chart coordinates, positioned by its normalized
impedance (`real` + `imag` * j).
"""
return make_figure(args=locals(), constructor=go.Scattersmith)


scatter_smith.__doc__ = make_docstring(scatter_smith)


def scatter_polar(
data_frame=None,
r=None,
Expand Down
10 changes: 5 additions & 5 deletions plotly/express/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@

# Declare all supported attributes, across all plot types
direct_attrables = (
["base", "x", "y", "z", "a", "b", "c", "r", "theta", "size", "x_start", "x_end"]
+ ["hover_name", "text", "names", "values", "parents", "wide_cross"]
+ ["ids", "error_x", "error_x_minus", "error_y", "error_y_minus", "error_z"]
+ ["error_z_minus", "lat", "lon", "locations", "animation_group"]
["base", "x", "y", "z", "a", "b", "c", "r", "theta", "real", "imag", "size"]
+ ["x_start", "x_end", "hover_name", "text", "names", "values", "parents"]
+ ["wide_cross", "ids", "error_x", "error_x_minus", "error_y", "error_y_minus"]
+ ["error_z", "error_z_minus", "lat", "lon", "locations", "animation_group"]
)
array_attrables = ["dimensions", "custom_data", "hover_data", "path", "wide_variable"]
group_attrables = ["animation_frame", "facet_row", "facet_col", "line_group"]
Expand Down Expand Up @@ -2893,7 +2893,7 @@ def init_figure(args, subplot_type, frame_list, nrows, ncols, col_labels, row_la
horizontal_spacing = args.get("facet_col_spacing") or 0.02
else:
# Other subplot types:
# 'scene', 'geo', 'polar', 'ternary', 'map', 'domain', None
# 'scene', 'geo', 'polar', 'ternary', 'map', 'smith', 'domain', None
#
# We can customize subplot spacing per type once we enable faceting
# for all plot types
Expand Down
10 changes: 10 additions & 0 deletions plotly/express/_doc.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@
colref_desc,
"Values from this column or array_like are used to position marks along the angular axis in polar coordinates.",
],
real=[
colref_type,
colref_desc,
"Values from this column or array_like are used as the real part of the normalized impedance of marks in Smith chart coordinates.",
],
imag=[
colref_type,
colref_desc,
"Values from this column or array_like are used as the imaginary part of the normalized impedance of marks in Smith chart coordinates.",
],
values=[
colref_type,
colref_desc,
Expand Down
1 change: 1 addition & 0 deletions plotly/subplots.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ def make_subplots(
- 'polar': Polar subplot for scatterpolar, barpolar, etc.
- 'ternary': Ternary subplot for scatterternary
- 'map': Map subplot for scattermap
- 'smith': Smith chart subplot for scattersmith
- 'domain': Subplot type for traces that are individually
positioned. pie, parcoords, parcats, etc.
- trace type: A trace type which will be used to determine
Expand Down
20 changes: 20 additions & 0 deletions tests/test_core/test_subplots/test_get_subplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,26 @@ def test_get_subplot(self):
domain = fig.data[-1].domain
self.assertEqual(subplot, SubplotDomain(x=domain.x, y=domain.y))

def test_get_subplot_smith(self):
# "smith" and the "scattersmith" trace type both create smith subplots
fig = subplots.make_subplots(
rows=1, cols=2, specs=[[{"type": "smith"}, {"type": "scattersmith"}]]
)
fig.add_trace(go.Scattersmith(real=[0.5, 1], imag=[1, 2]), row=1, col=1)
fig.add_trace(go.Scattersmith(real=[2, 3], imag=[-1, 0]), row=1, col=2)

self.assertEqual(fig.layout.smith.domain.x, (0.0, 0.45))
self.assertEqual(fig.layout.smith2.domain.x, (0.55, 1.0))
self.assertEqual(fig.data[0].subplot, "smith")
self.assertEqual(fig.data[1].subplot, "smith2")

self.assertEqual(fig.get_subplot(1, 1), fig.layout.smith)
self.assertEqual(fig.get_subplot(1, 2), fig.layout.smith2)

fig.update_traces(marker_color="red", row=1, col=2)
self.assertIsNone(fig.data[0].marker.color)
self.assertEqual(fig.data[1].marker.color, "red")

def test_get_subplot_out_of_bounds(self):
fig = subplots.make_subplots(rows=4, cols=2)

Expand Down
34 changes: 34 additions & 0 deletions tests/test_optional/test_px/test_px_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -688,3 +688,37 @@ def test_empty_histogram():
fig = px.histogram()
assert len(fig.data) == 1
assert fig.data[0].type == "histogram"


def test_scatter_smith_px():
real = np.array([0.5, 1.0, 2.0])
imag = np.array([1.0, -0.5, 0.0])
go_trace = go.Scattersmith(real=real, imag=imag, mode="markers")
fig = px.scatter_smith(real=real, imag=imag)
_compare_figures(go_trace, fig)
assert fig.data[0].subplot == "smith"
assert fig.layout.smith.domain.x == (0.0, 1.0)


def test_scatter_smith(constructor):
data = {
"r": [0.5, 1.0, 2.0, 0.2],
"x": [1.0, -0.5, 0.0, 3.0],
"band": ["low", "low", "high", "high"],
"f": [1, 2, 3, 4],
}
df = constructor(data)
fig = px.scatter_smith(
df, real="r", imag="x", color="band", text="f", hover_data=["f"]
)

assert [t.type for t in fig.data] == ["scattersmith", "scattersmith"]
assert [t.name for t in fig.data] == ["low", "high"]
assert_array_equal(fig.data[0].real, [0.5, 1.0])
assert_array_equal(fig.data[0].imag, [1.0, -0.5])
assert_array_equal(fig.data[1].real, [2.0, 0.2])
assert_array_equal(fig.data[1].imag, [0.0, 3.0])
assert fig.data[0].mode == "markers+text"
assert fig.data[0].hovertemplate == (
"band=low<br>r=%{real}<br>x=%{imag}<br>f=%{customdata[0]}<extra></extra>"
)