JuliaPy / JuliaPy/PyPlot.jl

julia PyPlot support missing data

Open
#593 2 comments 0 reactions 0 assignees View on GitHub
Dominant language
Julia
Stars
488
Forks
90
PR merge metrics
No merged PRs in 30d

Description

Passing a value of `missing`, a first class type in Julia Base, to matplotlib should simply not the plot `missing` data. It should handle `missing` just like it presently does NaN.

However, passing a `missing` to matplotlib results in long and unhelpful errors from PyPlot and matplotlib:
```
plot([0,missing,2])

ERROR: PyError ($(Expr(:escape, :(ccall(#= ~/.julia/packages/PyCall/1gn3u/src/pyfncall.jl:43 =# @pysym(:PyObject_Call), PyPtr, (PyPtr, PyPtr, PyPtr), o, pyargsptr, kw)))))
TypeError("float() argument must be a string or a real number, not 'PyCall.jlwrap'")
File "mypath/python3.12/site-packages/matplotlib/pyplot.py", line 3794, in plot
return gca().plot(
^^^^^^^^^^^
File "/mypath/python3.12/site-packages/matplotlib/axes/_axes.py", line 1781, in plot
self.add_line(line)
File "/mypath/python3.12/site-packages/matplotlib/axes/_base.py", line 2339, in add_line
self._update_line_limits(line)
File "/mypath/python3.12/site-packages/matplotlib/axes/_base.py", line 2362, in _update_line_limits
path = line.get_path()
^^^^^^^^^^^^^^^
File "/mypath/python3.12/site-packages/matplotlib/lines.py", line 1037, in get_path
self.recache()
File "/mypath/python3.12/site-packages/matplotlib/lines.py", line 679, in recache
y = _to_unmasked_float_array(yconv).ravel()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mypath/python3.12/site-packages/matplotlib/cbook.py", line 1398, in _to_unmasked_float_array
return np.asarray(x, float)
^^^^^^^^^^^^^^^^^^^^

Stacktrace:
[1] pyerr_check
@ ~/.julia/packages/PyCall/1gn3u/src/exception.jl:75 [inlined]
[2] pyerr_check
@ ~/.julia/packages/PyCall/1gn3u/src/exception.jl:79 [inlined]
[3] _handle_error(msg::String)
@ PyCall ~/.julia/packages/PyCall/1gn3u/src/exception.jl:96
[4] macro expansion
@ ~/.julia/packages/PyCall/1gn3u/src/exception.jl:110 [inlined]
[5] #107
@ ~/.julia/packages/PyCall/1gn3u/src/pyfncall.jl:43 [inlined]
[6] disable_sigint
@ ./c.jl:473 [inlined]
[7] __pycall!
@ ~/.julia/packages/PyCall/1gn3u/src/pyfncall.jl:42 [inlined]
[8] _pycall!(ret::PyObject, o::PyObject, args::Tuple{Vector{Union{Missing, Int64}}}, nargs::Int64, kw::Ptr{Nothing})
@ PyCall ~/.julia/packages/PyCall/1gn3u/src/pyfncall.jl:29
[9] _pycall!
@ ~/.julia/packages/PyCall/1gn3u/src/pyfncall.jl:11 [inlined]
[10] pycall
@ ~/.julia/packages/PyCall/1gn3u/src/pyfncall.jl:83 [inlined]
[11] plot(args::Vector{Union{Missing, Int64}}; kws::@Kwargs{})
@ PyPlot ~/.julia/packages/PyPlot/rWSdf/src/PyPlot.jl:194
[12] plot(args::Vector{Union{Missing, Int64}})
@ PyPlot ~/.julia/packages/PyPlot/rWSdf/src/PyPlot.jl:190
[13] top-level scope
@ REPL[56]:1
```

For years I have wrapped my inputs to matplotlib in the helper function
```
m2n(x) = ismissing(x) ? NaN : x
```
It is awkward.

I propose then, that
1. `missing` values are simply (not) plotted, just like NaNs.
2. a brief warning catch and warn the user of `missing`s in the data.

The proposed change will make PyPlot more compatible with Julia and Plots.jl, cf.
https://github.com/JuliaPlots/Plots.jl/issues/1706

I expect this will not break most cases, because `missing` is just a newer use pattern than NaN for missing data.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.