JuliaPy / PyCall.jl

Package to call Python functions from the Julia language
MIT License
1.47k stars 189 forks source link

Slice indexing of python objects? #563

Open galenlynch opened 6 years ago

galenlynch commented 6 years ago

I'm trying to use GridSpec in matplotlib with PyCall, and ran into this error:

julia> using PyCall, PyPlot

# Make a GridSpec object
julia> gs_main = PyPlot.matplotlib[:gridspec][:GridSpec](1, 2)
PyObject <matplotlib.gridspec.GridSpec object at 0x7f3161b08828>

# In python, you can use slice indexing on a GridSpec object to make subplots
# However, the naive way of going about this doesn't work:
julia> gs_main[1:2]
ERROR: MethodError: no method matching getindex(::PyObject, ::UnitRange{Int64})
Closest candidates are:
  getindex(::PyObject, ::Symbol) at /home/glynch/.julia/packages/PyCall/rUul9/src/PyCall.jl:294
  getindex(::PyObject, ::AbstractString) at /home/glynch/.julia/packages/PyCall/rUul9/src/PyCall.jl:283
  getindex(::PyObject, ::Integer) at /home/glynch/.julia/packages/PyCall/rUul9/src/PyCall.jl:755
  ...
Stacktrace:
 [1] top-level scope at none:0

# Manually indexing with slice objects does work, however
julia> gs_main[:__getitem__](pybuiltin(:slice)(0, 2))
PyObject <matplotlib.gridspec.SubplotSpec object at 0x7f31636fe8d0>

Is there a more straight-forward way of accomplishing this?

stevengj commented 5 years ago

One possibility would be for getindex to call slice automatically when it is passed a range. Will have to wait until #629 though, since we need to first change the getindex api so that it no longers subtracts 1 from indices automatically.

rharper2 commented 3 years ago

I realise this is rather old now and PyCall is vastly different, but for GridSpec in particular the method I use is just to wrap it in a py call e.g taking one of the GridSpec examples:

using PyPlot
using PyCall
fig3 = plt.figure(constrained_layout=true)
gs = fig3.add_gridspec(3, 3)

f3_ax3 = fig3.add_subplot(py"$(gs)[1:, -1]")
f3_ax3.set_title("gs[1:, -1]")
f3_ax4 = fig3.add_subplot(py"$(gs)[-1, 0]")
f3_ax4.set_title("gs[-1, 0]")
f3_ax5 = fig3.add_subplot(py"$(gs)[-1, -2]")
f3_ax5.set_title("gs[-1, -2]")
f3_ax1 = fig3.add_subplot(py"$(gs)[0, :]")
f3_ax1.set_title("gs[0, :]")
f3_ax2 = fig3.add_subplot(py"$(gs)[1, :-1]")
f3_ax2.set_title("gs[1, :-1]")
f3_ax3 = fig3.add_subplot(py"$(gs)[1:, -1]")
f3_ax3.set_title("gs[1:, -1]")
f3_ax4 = fig3.add_subplot(py"$(gs)[-1, 0]")
f3_ax4.set_title("gs[-1, 0]")
f3_ax5 = fig3.add_subplot(py"$(gs)[-1, -2]")
f3_ax5.set_title("gs[-1, -2]")

Which seems to work fine.