3D scatterplot using custom imageMatplotlib: 3D Scatter Plot with Images as AnnotationsProper way to declare custom exceptions in modern Python?Preview an image before it is uploadedSave plot to image file instead of displaying it using MatplotlibAssigning individual high and low fill values using geom_tile() & facet_wrap()Plot large data using ggplot2 and shiny with navigation sliderHow to use .ico images in plots programmatically with/without conversionR: Is it possible to combine a lattice xy plot with a ggplot?Browser crash when trying to convert HTML+ SVG content to scaled image using html2canvasCreate an image filled chart in R using ggplotScatterplot colors lost when converting to plotly in R

Make some Prime Squares!

Can an isometry leave entropy invariant?

BOOM! Perfect Clear for Mr. T

Building a list of products from the elements in another list

Using a microphone from the 1930s

Answer "Justification for travel support" in conference registration form

Would Hubble Space Telescope improve black hole image observed by EHT if it joined array of telesopes?

How can I support myself financially as a 17 year old with a loan?

How adjust and align properly different equations

how to ban all connection to .se and .ru in the hosts.deny-file

What was the design of the Macintosh II's MMU replacement?

On which topic did Indiana Jones write his doctoral thesis?

Is it possible to know which is the correct temperature range and speed for any model?

Why do money exchangers give different rates to different bills?

How can I get a job without pushing my family's income into a higher tax bracket?

Using field size much larger than necessary

Why are prions in animal diets not destroyed by the digestive system?

Verb "geeitet" in an old scientific text

Did we get closer to another plane than we were supposed to, or was the pilot just protecting our delicate sensibilities?

Understanding trademark infringements in a world where many dictionary words are trademarks?

Manager is threatening to grade me poorly if I don't complete the project

Why is "Vayechulu" said 3 times on Leil Shabbat?

Position of past participle and extent of the Verbklammer

What does this colon mean? It is not labeling, it is not ternary operator



3D scatterplot using custom image


Matplotlib: 3D Scatter Plot with Images as AnnotationsProper way to declare custom exceptions in modern Python?Preview an image before it is uploadedSave plot to image file instead of displaying it using MatplotlibAssigning individual high and low fill values using geom_tile() & facet_wrap()Plot large data using ggplot2 and shiny with navigation sliderHow to use .ico images in plots programmatically with/without conversionR: Is it possible to combine a lattice xy plot with a ggplot?Browser crash when trying to convert HTML+ SVG content to scaled image using html2canvasCreate an image filled chart in R using ggplotScatterplot colors lost when converting to plotly in R






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;








11















I am trying to use ggplot and ggimage to create a 3D scatterplot with a custom image. It works fine in 2D:



library(ggplot2)
library(ggimage)
library(rsvg)

set.seed(2017-02-21)
d <- data.frame(x = rnorm(10), y = rnorm(10), z=1:10,
image = 'https://image.flaticon.com/icons/svg/31/31082.svg'
)

ggplot(d, aes(x, y)) +
geom_image(aes(image=image, color=z)) +
scale_color_gradient(low='burlywood1', high='burlywood4')


enter image description here



I've tried two ways to create a 3D chart:



  1. plotly - This currently does not work with geom_image, though it is queued as a future request.


  2. gg3D - This is an R package, but I cannot get it to play nice with custom images. Here is how combining those libraries ends up:


library(ggplot2)
library(ggimage)
library(gg3D)

ggplot(d, aes(x=x, y=y, z=z, color=z)) +
axes_3D() +
geom_image(aes(image=image, color=z)) +
scale_color_gradient(low='burlywood1', high='burlywood4')


enter image description here



Any help would be appreciated. I'd be fine with a python library, javascript, etc. if the solution exists there.










share|improve this question



















  • 1





    To reach a wider audience, you may wish to add tags for the languages / platforms you are willing to consider.

    – Z.Lin
    Mar 29 at 6:52











  • Thanks. I edited/added tags

    – Adam_G
    Mar 29 at 17:20






  • 4





    I think that even if it existed, it would require your custom images to be 3D vectors as well, which will be very tricky for complex shapes. I use 3D plots from plotly, but never dared to try something like what you're looking for

    – Mark
    Mar 29 at 19:15











  • Very good point. Thanks

    – Adam_G
    Mar 31 at 18:10











  • @Adam_G You may be able to achieve this with d3.js This d3 example is just circles, but it's interactive, and you can add custom shapes in d3 graphs or create them Not sure if this meets your needs but worth looking at..

    – Rachel Gallen
    Mar 31 at 23:05

















11















I am trying to use ggplot and ggimage to create a 3D scatterplot with a custom image. It works fine in 2D:



library(ggplot2)
library(ggimage)
library(rsvg)

set.seed(2017-02-21)
d <- data.frame(x = rnorm(10), y = rnorm(10), z=1:10,
image = 'https://image.flaticon.com/icons/svg/31/31082.svg'
)

ggplot(d, aes(x, y)) +
geom_image(aes(image=image, color=z)) +
scale_color_gradient(low='burlywood1', high='burlywood4')


enter image description here



I've tried two ways to create a 3D chart:



  1. plotly - This currently does not work with geom_image, though it is queued as a future request.


  2. gg3D - This is an R package, but I cannot get it to play nice with custom images. Here is how combining those libraries ends up:


library(ggplot2)
library(ggimage)
library(gg3D)

ggplot(d, aes(x=x, y=y, z=z, color=z)) +
axes_3D() +
geom_image(aes(image=image, color=z)) +
scale_color_gradient(low='burlywood1', high='burlywood4')


enter image description here



Any help would be appreciated. I'd be fine with a python library, javascript, etc. if the solution exists there.










share|improve this question



















  • 1





    To reach a wider audience, you may wish to add tags for the languages / platforms you are willing to consider.

    – Z.Lin
    Mar 29 at 6:52











  • Thanks. I edited/added tags

    – Adam_G
    Mar 29 at 17:20






  • 4





    I think that even if it existed, it would require your custom images to be 3D vectors as well, which will be very tricky for complex shapes. I use 3D plots from plotly, but never dared to try something like what you're looking for

    – Mark
    Mar 29 at 19:15











  • Very good point. Thanks

    – Adam_G
    Mar 31 at 18:10











  • @Adam_G You may be able to achieve this with d3.js This d3 example is just circles, but it's interactive, and you can add custom shapes in d3 graphs or create them Not sure if this meets your needs but worth looking at..

    – Rachel Gallen
    Mar 31 at 23:05













11












11








11


2






I am trying to use ggplot and ggimage to create a 3D scatterplot with a custom image. It works fine in 2D:



library(ggplot2)
library(ggimage)
library(rsvg)

set.seed(2017-02-21)
d <- data.frame(x = rnorm(10), y = rnorm(10), z=1:10,
image = 'https://image.flaticon.com/icons/svg/31/31082.svg'
)

ggplot(d, aes(x, y)) +
geom_image(aes(image=image, color=z)) +
scale_color_gradient(low='burlywood1', high='burlywood4')


enter image description here



I've tried two ways to create a 3D chart:



  1. plotly - This currently does not work with geom_image, though it is queued as a future request.


  2. gg3D - This is an R package, but I cannot get it to play nice with custom images. Here is how combining those libraries ends up:


library(ggplot2)
library(ggimage)
library(gg3D)

ggplot(d, aes(x=x, y=y, z=z, color=z)) +
axes_3D() +
geom_image(aes(image=image, color=z)) +
scale_color_gradient(low='burlywood1', high='burlywood4')


enter image description here



Any help would be appreciated. I'd be fine with a python library, javascript, etc. if the solution exists there.










share|improve this question
















I am trying to use ggplot and ggimage to create a 3D scatterplot with a custom image. It works fine in 2D:



library(ggplot2)
library(ggimage)
library(rsvg)

set.seed(2017-02-21)
d <- data.frame(x = rnorm(10), y = rnorm(10), z=1:10,
image = 'https://image.flaticon.com/icons/svg/31/31082.svg'
)

ggplot(d, aes(x, y)) +
geom_image(aes(image=image, color=z)) +
scale_color_gradient(low='burlywood1', high='burlywood4')


enter image description here



I've tried two ways to create a 3D chart:



  1. plotly - This currently does not work with geom_image, though it is queued as a future request.


  2. gg3D - This is an R package, but I cannot get it to play nice with custom images. Here is how combining those libraries ends up:


library(ggplot2)
library(ggimage)
library(gg3D)

ggplot(d, aes(x=x, y=y, z=z, color=z)) +
axes_3D() +
geom_image(aes(image=image, color=z)) +
scale_color_gradient(low='burlywood1', high='burlywood4')


enter image description here



Any help would be appreciated. I'd be fine with a python library, javascript, etc. if the solution exists there.







javascript python r ggplot2 data-visualization






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Mar 29 at 17:19







Adam_G

















asked Mar 22 at 22:10









Adam_GAdam_G

2,2091149102




2,2091149102







  • 1





    To reach a wider audience, you may wish to add tags for the languages / platforms you are willing to consider.

    – Z.Lin
    Mar 29 at 6:52











  • Thanks. I edited/added tags

    – Adam_G
    Mar 29 at 17:20






  • 4





    I think that even if it existed, it would require your custom images to be 3D vectors as well, which will be very tricky for complex shapes. I use 3D plots from plotly, but never dared to try something like what you're looking for

    – Mark
    Mar 29 at 19:15











  • Very good point. Thanks

    – Adam_G
    Mar 31 at 18:10











  • @Adam_G You may be able to achieve this with d3.js This d3 example is just circles, but it's interactive, and you can add custom shapes in d3 graphs or create them Not sure if this meets your needs but worth looking at..

    – Rachel Gallen
    Mar 31 at 23:05












  • 1





    To reach a wider audience, you may wish to add tags for the languages / platforms you are willing to consider.

    – Z.Lin
    Mar 29 at 6:52











  • Thanks. I edited/added tags

    – Adam_G
    Mar 29 at 17:20






  • 4





    I think that even if it existed, it would require your custom images to be 3D vectors as well, which will be very tricky for complex shapes. I use 3D plots from plotly, but never dared to try something like what you're looking for

    – Mark
    Mar 29 at 19:15











  • Very good point. Thanks

    – Adam_G
    Mar 31 at 18:10











  • @Adam_G You may be able to achieve this with d3.js This d3 example is just circles, but it's interactive, and you can add custom shapes in d3 graphs or create them Not sure if this meets your needs but worth looking at..

    – Rachel Gallen
    Mar 31 at 23:05







1




1





To reach a wider audience, you may wish to add tags for the languages / platforms you are willing to consider.

– Z.Lin
Mar 29 at 6:52





To reach a wider audience, you may wish to add tags for the languages / platforms you are willing to consider.

– Z.Lin
Mar 29 at 6:52













Thanks. I edited/added tags

– Adam_G
Mar 29 at 17:20





Thanks. I edited/added tags

– Adam_G
Mar 29 at 17:20




4




4





I think that even if it existed, it would require your custom images to be 3D vectors as well, which will be very tricky for complex shapes. I use 3D plots from plotly, but never dared to try something like what you're looking for

– Mark
Mar 29 at 19:15





I think that even if it existed, it would require your custom images to be 3D vectors as well, which will be very tricky for complex shapes. I use 3D plots from plotly, but never dared to try something like what you're looking for

– Mark
Mar 29 at 19:15













Very good point. Thanks

– Adam_G
Mar 31 at 18:10





Very good point. Thanks

– Adam_G
Mar 31 at 18:10













@Adam_G You may be able to achieve this with d3.js This d3 example is just circles, but it's interactive, and you can add custom shapes in d3 graphs or create them Not sure if this meets your needs but worth looking at..

– Rachel Gallen
Mar 31 at 23:05





@Adam_G You may be able to achieve this with d3.js This d3 example is just circles, but it's interactive, and you can add custom shapes in d3 graphs or create them Not sure if this meets your needs but worth looking at..

– Rachel Gallen
Mar 31 at 23:05












2 Answers
2






active

oldest

votes


















8





+200









Here's a hacky solution that converts the image into a dataframe, where each pixel becomes a voxel (?) that we send into plotly. It basically works, but it needs some more work to:



1) adjust image more (with erosion step?) to exclude more low-alpha pixels



2) use requested color range in plotly



Step 1: import image and resize, and filter out transparent or partly transparent pixels



library(tidyverse)
library(magick)
sprite_frame <- image_read("coffee-bean-for-a-coffee-break.png") %>%
magick::image_resize("20x20") %>%
image_raster(tidy = T) %>%
mutate(alpha = str_sub(col, start = 7) %>% strtoi(base = 16)) %>%
filter(col != "transparent",
alpha > 240)


Here's what that looks like:



ggplot(sprite_frame, aes(x,y, fill = col)) + 
geom_raster() +
guides(fill = F) +
scale_fill_identity()


enter image description here



Step 2: bring those pixels in as voxels



pixels_per_image <- nrow(sprite_frame)
scale <- 1/40 # How big should a pixel be in coordinate space?

set.seed(2017-02-21)
d <- data.frame(x = rnorm(10), y = rnorm(10), z=1:10)
d2 <- d %>%
mutate(copies = pixels_per_image) %>%
uncount(copies) %>%
mutate(x_sprite = sprite_frame$x*scale + x,
y_sprite = sprite_frame$y*scale + y,
col = rep(sprite_frame$col, nrow(d)))


We can plot that in 2d space with ggplot:



ggplot(d2, aes(x_sprite, y_sprite, z = z, alpha = col, fill = z)) + 
geom_tile(width = scale, height = scale) +
guides(alpha = F) +
scale_fill_gradient(low='burlywood1', high='burlywood4')


enter image description here



Or bring it into plotly. Note that plotly 3d scatters do not currently support variable opacity, so the image currently shows up as a solid oval until you're closely zoomed into one sprite.



library(plotly)
plot_ly(d2, x = ~x_sprite, y = ~y_sprite, z = ~z,
size = scale, color = ~z, colors = c("#FFD39B", "#8B7355")) %>%
add_markers()


enter image description here




Edit: attempt at plotly mesh3d approach



It seems like another approach would be to convert the SVG glyph into coordinates for a mesh3d surface in plotly.



My initial attempt to do this has been impractically manual:



  1. Load SVG in Inkscape and use "flatten beziers" option to approximate shape without bezier curves.

  2. Export SVG and cross fingers that file has raw coordinates. I'm new to SVGs and it looks like the output can often be a mix of absolute and relative points. Complicated further in this case since the glyph has two disconnected sections.

  3. Reformat coordinates as data frame for plotting with ggplot2 or plotly.

For instance, the following coords represent half a bean, which we can transform to get the other half:



library(dplyr)
half_bean <- read.table(
header = T,
stringsAsFactors = F,
text = "x y
153.714 159.412
95.490016 186.286
54.982625 216.85
28.976672 247.7425
14.257 275.602
0.49742188 229.14067
5.610375 175.89737
28.738141 120.85839
69.023 69.01
128.24827 24.564609
190.72412 2.382875
249.14492 3.7247031
274.55165 13.610674
296.205 29.85
296.4 30.064
283.67119 58.138937
258.36 93.03325
216.39731 128.77994
153.714 159.412"
) %>%
mutate(z = 0)

other_half <- half_bean %>%
mutate(x = 330 - x,
y = 330 - y,
z = z)

ggplot() + coord_equal() +
geom_path(data = half_bean, aes(x,y)) +
geom_path(data = other_half, aes(x,y))


enter image description here



But while this looks fine in ggplot, I'm having trouble getting the concave parts to show up correctly in plotly:



library(plotly)
plot_ly(type = 'mesh3d',
split = c(rep(1, 19), rep(2, 19)),
x = c(half_bean$x, other_half$x),
y = c(half_bean$y, other_half$y),
z = c(half_bean$z, other_half$z)
)


enter image description here






share|improve this answer

























  • Perhaps a better approach would be to convert the SVG into coordinates, then use a 3d mesh in plotly. plot.ly/python/3d-mesh May try that later...

    – Jon Spring
    Apr 2 at 18:02












  • Wow, this is incredible. I'm curious how your comment above would work, too.

    – Adam_G
    Apr 2 at 23:54











  • This seems to be doable in theory, but I don't know how to avoid some tedious manual steps. Inkscape's "flatten beziers" function helps simplify the shape, and sometimes the generated SVG has simple coordinate pairs. Those can be fed into plotly's mesh3d, but I haven't figured out how to keep multiple meshes separate (important since the glyph has two pieces each instance).

    – Jon Spring
    Apr 3 at 5:28


















3














This is a very rough answer and doesn't fully solve your problem but I believe it's a good start and someone else might pick up on this and reach a good solution.



There is a way to place an image as a custmo marker in python. Starting from this AMAZING answer and fiddling a bit with the box.

However, the problem with this solution is that your image is not vectorized (and too big to be used as a marker).

Further, I didn't test a way to color it according to the colormap as it doesn't really show as output :/.



The basic idea here is to replace the markers with the custom image after the plot is created. To place them properly in the figure we retrieve the proper coordinates following the the answer from ImportanceOfBeingErnest.



from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d import proj3d
import matplotlib.pyplot as plt
from matplotlib import offsetbox
import numpy as np


Note that here I downloaded the image and I am importing it from a local file



import matplotlib.image as mpimg
#
img=mpimg.imread('coffeebean.png')
imgplot = plt.imshow(img)


coffeebeanoriginal



from PIL import Image
from resizeimage import resizeimage
with open('coffeebean.png', 'r+b') as f:
with Image.open(f) as image:
cover = resizeimage.resize_width(image, 20,validate=True)
cover.save('resizedbean.jpeg', image.format)

img=mpimg.imread('resizedbean.jpeg')
imgplot = plt.imshow(img)


Resizing doesn't really work (or at least, I couldn't find a way to make it work).
resizedbean



xs = [1,1.5,2,2]
ys = [1,2,3,1]
zs = [0,1,2,0]
#c = #I guess copper would be a good colormap here


fig = plt.figure()
ax = fig.add_subplot(111, projection=Axes3D.name)

ax.scatter(xs, ys, zs, marker="None")

# Create a dummy axes to place annotations to
ax2 = fig.add_subplot(111,frame_on=False)
ax2.axis("off")
ax2.axis([0,1,0,1])

class ImageAnnotations3D():
def __init__(self, xyz, imgs, ax3d,ax2d):
self.xyz = xyz
self.imgs = imgs
self.ax3d = ax3d
self.ax2d = ax2d
self.annot = []
for s,im in zip(self.xyz, self.imgs):
x,y = self.proj(s)
self.annot.append(self.image(im,[x,y]))
self.lim = self.ax3d.get_w_lims()
self.rot = self.ax3d.get_proj()
self.cid = self.ax3d.figure.canvas.mpl_connect("draw_event",self.update)

self.funcmap = "button_press_event" : self.ax3d._button_press,
"motion_notify_event" : self.ax3d._on_move,
"button_release_event" : self.ax3d._button_release

self.cfs = [self.ax3d.figure.canvas.mpl_connect(kind, self.cb)
for kind in self.funcmap.keys()]

def cb(self, event):
event.inaxes = self.ax3d
self.funcmap[event.name](event)

def proj(self, X):
""" From a 3D point in axes ax1,
calculate position in 2D in ax2 """
x,y,z = X
x2, y2, _ = proj3d.proj_transform(x,y,z, self.ax3d.get_proj())
tr = self.ax3d.transData.transform((x2, y2))
return self.ax2d.transData.inverted().transform(tr)

def image(self,arr,xy):
""" Place an image (arr) as annotation at position xy """
im = offsetbox.OffsetImage(arr, zoom=2)
im.image.axes = ax
ab = offsetbox.AnnotationBbox(im, xy, xybox=(0., 0.),
xycoords='data', boxcoords="offset points",
pad=0.0)
self.ax2d.add_artist(ab)
return ab

def update(self,event):
if np.any(self.ax3d.get_w_lims() != self.lim) or
np.any(self.ax3d.get_proj() != self.rot):
self.lim = self.ax3d.get_w_lims()
self.rot = self.ax3d.get_proj()
for s,ab in zip(self.xyz, self.annot):
ab.xy = self.proj(s)



ia = ImageAnnotations3D(np.c_[xs,ys,zs],img,ax, ax2 )

ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')
plt.show()


You can see that the output is far from optimal. However the image is in the right position. Having a vectorized one instead of the static coffee bean used might do the trick.



broken_output



Additional info:

Tried to resize using cv2 (every interpolation method), didn't helped.

Can't try skimage with the current workstation.



You might try the following and see what comes out.



from skimage.transform import resize
res = resize(img, (20, 20), anti_aliasing=True)

imgplot = plt.imshow(res)





share|improve this answer

























    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55308428%2f3d-scatterplot-using-custom-image%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    8





    +200









    Here's a hacky solution that converts the image into a dataframe, where each pixel becomes a voxel (?) that we send into plotly. It basically works, but it needs some more work to:



    1) adjust image more (with erosion step?) to exclude more low-alpha pixels



    2) use requested color range in plotly



    Step 1: import image and resize, and filter out transparent or partly transparent pixels



    library(tidyverse)
    library(magick)
    sprite_frame <- image_read("coffee-bean-for-a-coffee-break.png") %>%
    magick::image_resize("20x20") %>%
    image_raster(tidy = T) %>%
    mutate(alpha = str_sub(col, start = 7) %>% strtoi(base = 16)) %>%
    filter(col != "transparent",
    alpha > 240)


    Here's what that looks like:



    ggplot(sprite_frame, aes(x,y, fill = col)) + 
    geom_raster() +
    guides(fill = F) +
    scale_fill_identity()


    enter image description here



    Step 2: bring those pixels in as voxels



    pixels_per_image <- nrow(sprite_frame)
    scale <- 1/40 # How big should a pixel be in coordinate space?

    set.seed(2017-02-21)
    d <- data.frame(x = rnorm(10), y = rnorm(10), z=1:10)
    d2 <- d %>%
    mutate(copies = pixels_per_image) %>%
    uncount(copies) %>%
    mutate(x_sprite = sprite_frame$x*scale + x,
    y_sprite = sprite_frame$y*scale + y,
    col = rep(sprite_frame$col, nrow(d)))


    We can plot that in 2d space with ggplot:



    ggplot(d2, aes(x_sprite, y_sprite, z = z, alpha = col, fill = z)) + 
    geom_tile(width = scale, height = scale) +
    guides(alpha = F) +
    scale_fill_gradient(low='burlywood1', high='burlywood4')


    enter image description here



    Or bring it into plotly. Note that plotly 3d scatters do not currently support variable opacity, so the image currently shows up as a solid oval until you're closely zoomed into one sprite.



    library(plotly)
    plot_ly(d2, x = ~x_sprite, y = ~y_sprite, z = ~z,
    size = scale, color = ~z, colors = c("#FFD39B", "#8B7355")) %>%
    add_markers()


    enter image description here




    Edit: attempt at plotly mesh3d approach



    It seems like another approach would be to convert the SVG glyph into coordinates for a mesh3d surface in plotly.



    My initial attempt to do this has been impractically manual:



    1. Load SVG in Inkscape and use "flatten beziers" option to approximate shape without bezier curves.

    2. Export SVG and cross fingers that file has raw coordinates. I'm new to SVGs and it looks like the output can often be a mix of absolute and relative points. Complicated further in this case since the glyph has two disconnected sections.

    3. Reformat coordinates as data frame for plotting with ggplot2 or plotly.

    For instance, the following coords represent half a bean, which we can transform to get the other half:



    library(dplyr)
    half_bean <- read.table(
    header = T,
    stringsAsFactors = F,
    text = "x y
    153.714 159.412
    95.490016 186.286
    54.982625 216.85
    28.976672 247.7425
    14.257 275.602
    0.49742188 229.14067
    5.610375 175.89737
    28.738141 120.85839
    69.023 69.01
    128.24827 24.564609
    190.72412 2.382875
    249.14492 3.7247031
    274.55165 13.610674
    296.205 29.85
    296.4 30.064
    283.67119 58.138937
    258.36 93.03325
    216.39731 128.77994
    153.714 159.412"
    ) %>%
    mutate(z = 0)

    other_half <- half_bean %>%
    mutate(x = 330 - x,
    y = 330 - y,
    z = z)

    ggplot() + coord_equal() +
    geom_path(data = half_bean, aes(x,y)) +
    geom_path(data = other_half, aes(x,y))


    enter image description here



    But while this looks fine in ggplot, I'm having trouble getting the concave parts to show up correctly in plotly:



    library(plotly)
    plot_ly(type = 'mesh3d',
    split = c(rep(1, 19), rep(2, 19)),
    x = c(half_bean$x, other_half$x),
    y = c(half_bean$y, other_half$y),
    z = c(half_bean$z, other_half$z)
    )


    enter image description here






    share|improve this answer

























    • Perhaps a better approach would be to convert the SVG into coordinates, then use a 3d mesh in plotly. plot.ly/python/3d-mesh May try that later...

      – Jon Spring
      Apr 2 at 18:02












    • Wow, this is incredible. I'm curious how your comment above would work, too.

      – Adam_G
      Apr 2 at 23:54











    • This seems to be doable in theory, but I don't know how to avoid some tedious manual steps. Inkscape's "flatten beziers" function helps simplify the shape, and sometimes the generated SVG has simple coordinate pairs. Those can be fed into plotly's mesh3d, but I haven't figured out how to keep multiple meshes separate (important since the glyph has two pieces each instance).

      – Jon Spring
      Apr 3 at 5:28















    8





    +200









    Here's a hacky solution that converts the image into a dataframe, where each pixel becomes a voxel (?) that we send into plotly. It basically works, but it needs some more work to:



    1) adjust image more (with erosion step?) to exclude more low-alpha pixels



    2) use requested color range in plotly



    Step 1: import image and resize, and filter out transparent or partly transparent pixels



    library(tidyverse)
    library(magick)
    sprite_frame <- image_read("coffee-bean-for-a-coffee-break.png") %>%
    magick::image_resize("20x20") %>%
    image_raster(tidy = T) %>%
    mutate(alpha = str_sub(col, start = 7) %>% strtoi(base = 16)) %>%
    filter(col != "transparent",
    alpha > 240)


    Here's what that looks like:



    ggplot(sprite_frame, aes(x,y, fill = col)) + 
    geom_raster() +
    guides(fill = F) +
    scale_fill_identity()


    enter image description here



    Step 2: bring those pixels in as voxels



    pixels_per_image <- nrow(sprite_frame)
    scale <- 1/40 # How big should a pixel be in coordinate space?

    set.seed(2017-02-21)
    d <- data.frame(x = rnorm(10), y = rnorm(10), z=1:10)
    d2 <- d %>%
    mutate(copies = pixels_per_image) %>%
    uncount(copies) %>%
    mutate(x_sprite = sprite_frame$x*scale + x,
    y_sprite = sprite_frame$y*scale + y,
    col = rep(sprite_frame$col, nrow(d)))


    We can plot that in 2d space with ggplot:



    ggplot(d2, aes(x_sprite, y_sprite, z = z, alpha = col, fill = z)) + 
    geom_tile(width = scale, height = scale) +
    guides(alpha = F) +
    scale_fill_gradient(low='burlywood1', high='burlywood4')


    enter image description here



    Or bring it into plotly. Note that plotly 3d scatters do not currently support variable opacity, so the image currently shows up as a solid oval until you're closely zoomed into one sprite.



    library(plotly)
    plot_ly(d2, x = ~x_sprite, y = ~y_sprite, z = ~z,
    size = scale, color = ~z, colors = c("#FFD39B", "#8B7355")) %>%
    add_markers()


    enter image description here




    Edit: attempt at plotly mesh3d approach



    It seems like another approach would be to convert the SVG glyph into coordinates for a mesh3d surface in plotly.



    My initial attempt to do this has been impractically manual:



    1. Load SVG in Inkscape and use "flatten beziers" option to approximate shape without bezier curves.

    2. Export SVG and cross fingers that file has raw coordinates. I'm new to SVGs and it looks like the output can often be a mix of absolute and relative points. Complicated further in this case since the glyph has two disconnected sections.

    3. Reformat coordinates as data frame for plotting with ggplot2 or plotly.

    For instance, the following coords represent half a bean, which we can transform to get the other half:



    library(dplyr)
    half_bean <- read.table(
    header = T,
    stringsAsFactors = F,
    text = "x y
    153.714 159.412
    95.490016 186.286
    54.982625 216.85
    28.976672 247.7425
    14.257 275.602
    0.49742188 229.14067
    5.610375 175.89737
    28.738141 120.85839
    69.023 69.01
    128.24827 24.564609
    190.72412 2.382875
    249.14492 3.7247031
    274.55165 13.610674
    296.205 29.85
    296.4 30.064
    283.67119 58.138937
    258.36 93.03325
    216.39731 128.77994
    153.714 159.412"
    ) %>%
    mutate(z = 0)

    other_half <- half_bean %>%
    mutate(x = 330 - x,
    y = 330 - y,
    z = z)

    ggplot() + coord_equal() +
    geom_path(data = half_bean, aes(x,y)) +
    geom_path(data = other_half, aes(x,y))


    enter image description here



    But while this looks fine in ggplot, I'm having trouble getting the concave parts to show up correctly in plotly:



    library(plotly)
    plot_ly(type = 'mesh3d',
    split = c(rep(1, 19), rep(2, 19)),
    x = c(half_bean$x, other_half$x),
    y = c(half_bean$y, other_half$y),
    z = c(half_bean$z, other_half$z)
    )


    enter image description here






    share|improve this answer

























    • Perhaps a better approach would be to convert the SVG into coordinates, then use a 3d mesh in plotly. plot.ly/python/3d-mesh May try that later...

      – Jon Spring
      Apr 2 at 18:02












    • Wow, this is incredible. I'm curious how your comment above would work, too.

      – Adam_G
      Apr 2 at 23:54











    • This seems to be doable in theory, but I don't know how to avoid some tedious manual steps. Inkscape's "flatten beziers" function helps simplify the shape, and sometimes the generated SVG has simple coordinate pairs. Those can be fed into plotly's mesh3d, but I haven't figured out how to keep multiple meshes separate (important since the glyph has two pieces each instance).

      – Jon Spring
      Apr 3 at 5:28













    8





    +200







    8





    +200



    8




    +200





    Here's a hacky solution that converts the image into a dataframe, where each pixel becomes a voxel (?) that we send into plotly. It basically works, but it needs some more work to:



    1) adjust image more (with erosion step?) to exclude more low-alpha pixels



    2) use requested color range in plotly



    Step 1: import image and resize, and filter out transparent or partly transparent pixels



    library(tidyverse)
    library(magick)
    sprite_frame <- image_read("coffee-bean-for-a-coffee-break.png") %>%
    magick::image_resize("20x20") %>%
    image_raster(tidy = T) %>%
    mutate(alpha = str_sub(col, start = 7) %>% strtoi(base = 16)) %>%
    filter(col != "transparent",
    alpha > 240)


    Here's what that looks like:



    ggplot(sprite_frame, aes(x,y, fill = col)) + 
    geom_raster() +
    guides(fill = F) +
    scale_fill_identity()


    enter image description here



    Step 2: bring those pixels in as voxels



    pixels_per_image <- nrow(sprite_frame)
    scale <- 1/40 # How big should a pixel be in coordinate space?

    set.seed(2017-02-21)
    d <- data.frame(x = rnorm(10), y = rnorm(10), z=1:10)
    d2 <- d %>%
    mutate(copies = pixels_per_image) %>%
    uncount(copies) %>%
    mutate(x_sprite = sprite_frame$x*scale + x,
    y_sprite = sprite_frame$y*scale + y,
    col = rep(sprite_frame$col, nrow(d)))


    We can plot that in 2d space with ggplot:



    ggplot(d2, aes(x_sprite, y_sprite, z = z, alpha = col, fill = z)) + 
    geom_tile(width = scale, height = scale) +
    guides(alpha = F) +
    scale_fill_gradient(low='burlywood1', high='burlywood4')


    enter image description here



    Or bring it into plotly. Note that plotly 3d scatters do not currently support variable opacity, so the image currently shows up as a solid oval until you're closely zoomed into one sprite.



    library(plotly)
    plot_ly(d2, x = ~x_sprite, y = ~y_sprite, z = ~z,
    size = scale, color = ~z, colors = c("#FFD39B", "#8B7355")) %>%
    add_markers()


    enter image description here




    Edit: attempt at plotly mesh3d approach



    It seems like another approach would be to convert the SVG glyph into coordinates for a mesh3d surface in plotly.



    My initial attempt to do this has been impractically manual:



    1. Load SVG in Inkscape and use "flatten beziers" option to approximate shape without bezier curves.

    2. Export SVG and cross fingers that file has raw coordinates. I'm new to SVGs and it looks like the output can often be a mix of absolute and relative points. Complicated further in this case since the glyph has two disconnected sections.

    3. Reformat coordinates as data frame for plotting with ggplot2 or plotly.

    For instance, the following coords represent half a bean, which we can transform to get the other half:



    library(dplyr)
    half_bean <- read.table(
    header = T,
    stringsAsFactors = F,
    text = "x y
    153.714 159.412
    95.490016 186.286
    54.982625 216.85
    28.976672 247.7425
    14.257 275.602
    0.49742188 229.14067
    5.610375 175.89737
    28.738141 120.85839
    69.023 69.01
    128.24827 24.564609
    190.72412 2.382875
    249.14492 3.7247031
    274.55165 13.610674
    296.205 29.85
    296.4 30.064
    283.67119 58.138937
    258.36 93.03325
    216.39731 128.77994
    153.714 159.412"
    ) %>%
    mutate(z = 0)

    other_half <- half_bean %>%
    mutate(x = 330 - x,
    y = 330 - y,
    z = z)

    ggplot() + coord_equal() +
    geom_path(data = half_bean, aes(x,y)) +
    geom_path(data = other_half, aes(x,y))


    enter image description here



    But while this looks fine in ggplot, I'm having trouble getting the concave parts to show up correctly in plotly:



    library(plotly)
    plot_ly(type = 'mesh3d',
    split = c(rep(1, 19), rep(2, 19)),
    x = c(half_bean$x, other_half$x),
    y = c(half_bean$y, other_half$y),
    z = c(half_bean$z, other_half$z)
    )


    enter image description here






    share|improve this answer















    Here's a hacky solution that converts the image into a dataframe, where each pixel becomes a voxel (?) that we send into plotly. It basically works, but it needs some more work to:



    1) adjust image more (with erosion step?) to exclude more low-alpha pixels



    2) use requested color range in plotly



    Step 1: import image and resize, and filter out transparent or partly transparent pixels



    library(tidyverse)
    library(magick)
    sprite_frame <- image_read("coffee-bean-for-a-coffee-break.png") %>%
    magick::image_resize("20x20") %>%
    image_raster(tidy = T) %>%
    mutate(alpha = str_sub(col, start = 7) %>% strtoi(base = 16)) %>%
    filter(col != "transparent",
    alpha > 240)


    Here's what that looks like:



    ggplot(sprite_frame, aes(x,y, fill = col)) + 
    geom_raster() +
    guides(fill = F) +
    scale_fill_identity()


    enter image description here



    Step 2: bring those pixels in as voxels



    pixels_per_image <- nrow(sprite_frame)
    scale <- 1/40 # How big should a pixel be in coordinate space?

    set.seed(2017-02-21)
    d <- data.frame(x = rnorm(10), y = rnorm(10), z=1:10)
    d2 <- d %>%
    mutate(copies = pixels_per_image) %>%
    uncount(copies) %>%
    mutate(x_sprite = sprite_frame$x*scale + x,
    y_sprite = sprite_frame$y*scale + y,
    col = rep(sprite_frame$col, nrow(d)))


    We can plot that in 2d space with ggplot:



    ggplot(d2, aes(x_sprite, y_sprite, z = z, alpha = col, fill = z)) + 
    geom_tile(width = scale, height = scale) +
    guides(alpha = F) +
    scale_fill_gradient(low='burlywood1', high='burlywood4')


    enter image description here



    Or bring it into plotly. Note that plotly 3d scatters do not currently support variable opacity, so the image currently shows up as a solid oval until you're closely zoomed into one sprite.



    library(plotly)
    plot_ly(d2, x = ~x_sprite, y = ~y_sprite, z = ~z,
    size = scale, color = ~z, colors = c("#FFD39B", "#8B7355")) %>%
    add_markers()


    enter image description here




    Edit: attempt at plotly mesh3d approach



    It seems like another approach would be to convert the SVG glyph into coordinates for a mesh3d surface in plotly.



    My initial attempt to do this has been impractically manual:



    1. Load SVG in Inkscape and use "flatten beziers" option to approximate shape without bezier curves.

    2. Export SVG and cross fingers that file has raw coordinates. I'm new to SVGs and it looks like the output can often be a mix of absolute and relative points. Complicated further in this case since the glyph has two disconnected sections.

    3. Reformat coordinates as data frame for plotting with ggplot2 or plotly.

    For instance, the following coords represent half a bean, which we can transform to get the other half:



    library(dplyr)
    half_bean <- read.table(
    header = T,
    stringsAsFactors = F,
    text = "x y
    153.714 159.412
    95.490016 186.286
    54.982625 216.85
    28.976672 247.7425
    14.257 275.602
    0.49742188 229.14067
    5.610375 175.89737
    28.738141 120.85839
    69.023 69.01
    128.24827 24.564609
    190.72412 2.382875
    249.14492 3.7247031
    274.55165 13.610674
    296.205 29.85
    296.4 30.064
    283.67119 58.138937
    258.36 93.03325
    216.39731 128.77994
    153.714 159.412"
    ) %>%
    mutate(z = 0)

    other_half <- half_bean %>%
    mutate(x = 330 - x,
    y = 330 - y,
    z = z)

    ggplot() + coord_equal() +
    geom_path(data = half_bean, aes(x,y)) +
    geom_path(data = other_half, aes(x,y))


    enter image description here



    But while this looks fine in ggplot, I'm having trouble getting the concave parts to show up correctly in plotly:



    library(plotly)
    plot_ly(type = 'mesh3d',
    split = c(rep(1, 19), rep(2, 19)),
    x = c(half_bean$x, other_half$x),
    y = c(half_bean$y, other_half$y),
    z = c(half_bean$z, other_half$z)
    )


    enter image description here







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Apr 3 at 5:58

























    answered Apr 2 at 4:33









    Jon SpringJon Spring

    9,1532931




    9,1532931












    • Perhaps a better approach would be to convert the SVG into coordinates, then use a 3d mesh in plotly. plot.ly/python/3d-mesh May try that later...

      – Jon Spring
      Apr 2 at 18:02












    • Wow, this is incredible. I'm curious how your comment above would work, too.

      – Adam_G
      Apr 2 at 23:54











    • This seems to be doable in theory, but I don't know how to avoid some tedious manual steps. Inkscape's "flatten beziers" function helps simplify the shape, and sometimes the generated SVG has simple coordinate pairs. Those can be fed into plotly's mesh3d, but I haven't figured out how to keep multiple meshes separate (important since the glyph has two pieces each instance).

      – Jon Spring
      Apr 3 at 5:28

















    • Perhaps a better approach would be to convert the SVG into coordinates, then use a 3d mesh in plotly. plot.ly/python/3d-mesh May try that later...

      – Jon Spring
      Apr 2 at 18:02












    • Wow, this is incredible. I'm curious how your comment above would work, too.

      – Adam_G
      Apr 2 at 23:54











    • This seems to be doable in theory, but I don't know how to avoid some tedious manual steps. Inkscape's "flatten beziers" function helps simplify the shape, and sometimes the generated SVG has simple coordinate pairs. Those can be fed into plotly's mesh3d, but I haven't figured out how to keep multiple meshes separate (important since the glyph has two pieces each instance).

      – Jon Spring
      Apr 3 at 5:28
















    Perhaps a better approach would be to convert the SVG into coordinates, then use a 3d mesh in plotly. plot.ly/python/3d-mesh May try that later...

    – Jon Spring
    Apr 2 at 18:02






    Perhaps a better approach would be to convert the SVG into coordinates, then use a 3d mesh in plotly. plot.ly/python/3d-mesh May try that later...

    – Jon Spring
    Apr 2 at 18:02














    Wow, this is incredible. I'm curious how your comment above would work, too.

    – Adam_G
    Apr 2 at 23:54





    Wow, this is incredible. I'm curious how your comment above would work, too.

    – Adam_G
    Apr 2 at 23:54













    This seems to be doable in theory, but I don't know how to avoid some tedious manual steps. Inkscape's "flatten beziers" function helps simplify the shape, and sometimes the generated SVG has simple coordinate pairs. Those can be fed into plotly's mesh3d, but I haven't figured out how to keep multiple meshes separate (important since the glyph has two pieces each instance).

    – Jon Spring
    Apr 3 at 5:28





    This seems to be doable in theory, but I don't know how to avoid some tedious manual steps. Inkscape's "flatten beziers" function helps simplify the shape, and sometimes the generated SVG has simple coordinate pairs. Those can be fed into plotly's mesh3d, but I haven't figured out how to keep multiple meshes separate (important since the glyph has two pieces each instance).

    – Jon Spring
    Apr 3 at 5:28













    3














    This is a very rough answer and doesn't fully solve your problem but I believe it's a good start and someone else might pick up on this and reach a good solution.



    There is a way to place an image as a custmo marker in python. Starting from this AMAZING answer and fiddling a bit with the box.

    However, the problem with this solution is that your image is not vectorized (and too big to be used as a marker).

    Further, I didn't test a way to color it according to the colormap as it doesn't really show as output :/.



    The basic idea here is to replace the markers with the custom image after the plot is created. To place them properly in the figure we retrieve the proper coordinates following the the answer from ImportanceOfBeingErnest.



    from mpl_toolkits.mplot3d import Axes3D
    from mpl_toolkits.mplot3d import proj3d
    import matplotlib.pyplot as plt
    from matplotlib import offsetbox
    import numpy as np


    Note that here I downloaded the image and I am importing it from a local file



    import matplotlib.image as mpimg
    #
    img=mpimg.imread('coffeebean.png')
    imgplot = plt.imshow(img)


    coffeebeanoriginal



    from PIL import Image
    from resizeimage import resizeimage
    with open('coffeebean.png', 'r+b') as f:
    with Image.open(f) as image:
    cover = resizeimage.resize_width(image, 20,validate=True)
    cover.save('resizedbean.jpeg', image.format)

    img=mpimg.imread('resizedbean.jpeg')
    imgplot = plt.imshow(img)


    Resizing doesn't really work (or at least, I couldn't find a way to make it work).
    resizedbean



    xs = [1,1.5,2,2]
    ys = [1,2,3,1]
    zs = [0,1,2,0]
    #c = #I guess copper would be a good colormap here


    fig = plt.figure()
    ax = fig.add_subplot(111, projection=Axes3D.name)

    ax.scatter(xs, ys, zs, marker="None")

    # Create a dummy axes to place annotations to
    ax2 = fig.add_subplot(111,frame_on=False)
    ax2.axis("off")
    ax2.axis([0,1,0,1])

    class ImageAnnotations3D():
    def __init__(self, xyz, imgs, ax3d,ax2d):
    self.xyz = xyz
    self.imgs = imgs
    self.ax3d = ax3d
    self.ax2d = ax2d
    self.annot = []
    for s,im in zip(self.xyz, self.imgs):
    x,y = self.proj(s)
    self.annot.append(self.image(im,[x,y]))
    self.lim = self.ax3d.get_w_lims()
    self.rot = self.ax3d.get_proj()
    self.cid = self.ax3d.figure.canvas.mpl_connect("draw_event",self.update)

    self.funcmap = "button_press_event" : self.ax3d._button_press,
    "motion_notify_event" : self.ax3d._on_move,
    "button_release_event" : self.ax3d._button_release

    self.cfs = [self.ax3d.figure.canvas.mpl_connect(kind, self.cb)
    for kind in self.funcmap.keys()]

    def cb(self, event):
    event.inaxes = self.ax3d
    self.funcmap[event.name](event)

    def proj(self, X):
    """ From a 3D point in axes ax1,
    calculate position in 2D in ax2 """
    x,y,z = X
    x2, y2, _ = proj3d.proj_transform(x,y,z, self.ax3d.get_proj())
    tr = self.ax3d.transData.transform((x2, y2))
    return self.ax2d.transData.inverted().transform(tr)

    def image(self,arr,xy):
    """ Place an image (arr) as annotation at position xy """
    im = offsetbox.OffsetImage(arr, zoom=2)
    im.image.axes = ax
    ab = offsetbox.AnnotationBbox(im, xy, xybox=(0., 0.),
    xycoords='data', boxcoords="offset points",
    pad=0.0)
    self.ax2d.add_artist(ab)
    return ab

    def update(self,event):
    if np.any(self.ax3d.get_w_lims() != self.lim) or
    np.any(self.ax3d.get_proj() != self.rot):
    self.lim = self.ax3d.get_w_lims()
    self.rot = self.ax3d.get_proj()
    for s,ab in zip(self.xyz, self.annot):
    ab.xy = self.proj(s)



    ia = ImageAnnotations3D(np.c_[xs,ys,zs],img,ax, ax2 )

    ax.set_xlabel('X Label')
    ax.set_ylabel('Y Label')
    ax.set_zlabel('Z Label')
    plt.show()


    You can see that the output is far from optimal. However the image is in the right position. Having a vectorized one instead of the static coffee bean used might do the trick.



    broken_output



    Additional info:

    Tried to resize using cv2 (every interpolation method), didn't helped.

    Can't try skimage with the current workstation.



    You might try the following and see what comes out.



    from skimage.transform import resize
    res = resize(img, (20, 20), anti_aliasing=True)

    imgplot = plt.imshow(res)





    share|improve this answer





























      3














      This is a very rough answer and doesn't fully solve your problem but I believe it's a good start and someone else might pick up on this and reach a good solution.



      There is a way to place an image as a custmo marker in python. Starting from this AMAZING answer and fiddling a bit with the box.

      However, the problem with this solution is that your image is not vectorized (and too big to be used as a marker).

      Further, I didn't test a way to color it according to the colormap as it doesn't really show as output :/.



      The basic idea here is to replace the markers with the custom image after the plot is created. To place them properly in the figure we retrieve the proper coordinates following the the answer from ImportanceOfBeingErnest.



      from mpl_toolkits.mplot3d import Axes3D
      from mpl_toolkits.mplot3d import proj3d
      import matplotlib.pyplot as plt
      from matplotlib import offsetbox
      import numpy as np


      Note that here I downloaded the image and I am importing it from a local file



      import matplotlib.image as mpimg
      #
      img=mpimg.imread('coffeebean.png')
      imgplot = plt.imshow(img)


      coffeebeanoriginal



      from PIL import Image
      from resizeimage import resizeimage
      with open('coffeebean.png', 'r+b') as f:
      with Image.open(f) as image:
      cover = resizeimage.resize_width(image, 20,validate=True)
      cover.save('resizedbean.jpeg', image.format)

      img=mpimg.imread('resizedbean.jpeg')
      imgplot = plt.imshow(img)


      Resizing doesn't really work (or at least, I couldn't find a way to make it work).
      resizedbean



      xs = [1,1.5,2,2]
      ys = [1,2,3,1]
      zs = [0,1,2,0]
      #c = #I guess copper would be a good colormap here


      fig = plt.figure()
      ax = fig.add_subplot(111, projection=Axes3D.name)

      ax.scatter(xs, ys, zs, marker="None")

      # Create a dummy axes to place annotations to
      ax2 = fig.add_subplot(111,frame_on=False)
      ax2.axis("off")
      ax2.axis([0,1,0,1])

      class ImageAnnotations3D():
      def __init__(self, xyz, imgs, ax3d,ax2d):
      self.xyz = xyz
      self.imgs = imgs
      self.ax3d = ax3d
      self.ax2d = ax2d
      self.annot = []
      for s,im in zip(self.xyz, self.imgs):
      x,y = self.proj(s)
      self.annot.append(self.image(im,[x,y]))
      self.lim = self.ax3d.get_w_lims()
      self.rot = self.ax3d.get_proj()
      self.cid = self.ax3d.figure.canvas.mpl_connect("draw_event",self.update)

      self.funcmap = "button_press_event" : self.ax3d._button_press,
      "motion_notify_event" : self.ax3d._on_move,
      "button_release_event" : self.ax3d._button_release

      self.cfs = [self.ax3d.figure.canvas.mpl_connect(kind, self.cb)
      for kind in self.funcmap.keys()]

      def cb(self, event):
      event.inaxes = self.ax3d
      self.funcmap[event.name](event)

      def proj(self, X):
      """ From a 3D point in axes ax1,
      calculate position in 2D in ax2 """
      x,y,z = X
      x2, y2, _ = proj3d.proj_transform(x,y,z, self.ax3d.get_proj())
      tr = self.ax3d.transData.transform((x2, y2))
      return self.ax2d.transData.inverted().transform(tr)

      def image(self,arr,xy):
      """ Place an image (arr) as annotation at position xy """
      im = offsetbox.OffsetImage(arr, zoom=2)
      im.image.axes = ax
      ab = offsetbox.AnnotationBbox(im, xy, xybox=(0., 0.),
      xycoords='data', boxcoords="offset points",
      pad=0.0)
      self.ax2d.add_artist(ab)
      return ab

      def update(self,event):
      if np.any(self.ax3d.get_w_lims() != self.lim) or
      np.any(self.ax3d.get_proj() != self.rot):
      self.lim = self.ax3d.get_w_lims()
      self.rot = self.ax3d.get_proj()
      for s,ab in zip(self.xyz, self.annot):
      ab.xy = self.proj(s)



      ia = ImageAnnotations3D(np.c_[xs,ys,zs],img,ax, ax2 )

      ax.set_xlabel('X Label')
      ax.set_ylabel('Y Label')
      ax.set_zlabel('Z Label')
      plt.show()


      You can see that the output is far from optimal. However the image is in the right position. Having a vectorized one instead of the static coffee bean used might do the trick.



      broken_output



      Additional info:

      Tried to resize using cv2 (every interpolation method), didn't helped.

      Can't try skimage with the current workstation.



      You might try the following and see what comes out.



      from skimage.transform import resize
      res = resize(img, (20, 20), anti_aliasing=True)

      imgplot = plt.imshow(res)





      share|improve this answer



























        3












        3








        3







        This is a very rough answer and doesn't fully solve your problem but I believe it's a good start and someone else might pick up on this and reach a good solution.



        There is a way to place an image as a custmo marker in python. Starting from this AMAZING answer and fiddling a bit with the box.

        However, the problem with this solution is that your image is not vectorized (and too big to be used as a marker).

        Further, I didn't test a way to color it according to the colormap as it doesn't really show as output :/.



        The basic idea here is to replace the markers with the custom image after the plot is created. To place them properly in the figure we retrieve the proper coordinates following the the answer from ImportanceOfBeingErnest.



        from mpl_toolkits.mplot3d import Axes3D
        from mpl_toolkits.mplot3d import proj3d
        import matplotlib.pyplot as plt
        from matplotlib import offsetbox
        import numpy as np


        Note that here I downloaded the image and I am importing it from a local file



        import matplotlib.image as mpimg
        #
        img=mpimg.imread('coffeebean.png')
        imgplot = plt.imshow(img)


        coffeebeanoriginal



        from PIL import Image
        from resizeimage import resizeimage
        with open('coffeebean.png', 'r+b') as f:
        with Image.open(f) as image:
        cover = resizeimage.resize_width(image, 20,validate=True)
        cover.save('resizedbean.jpeg', image.format)

        img=mpimg.imread('resizedbean.jpeg')
        imgplot = plt.imshow(img)


        Resizing doesn't really work (or at least, I couldn't find a way to make it work).
        resizedbean



        xs = [1,1.5,2,2]
        ys = [1,2,3,1]
        zs = [0,1,2,0]
        #c = #I guess copper would be a good colormap here


        fig = plt.figure()
        ax = fig.add_subplot(111, projection=Axes3D.name)

        ax.scatter(xs, ys, zs, marker="None")

        # Create a dummy axes to place annotations to
        ax2 = fig.add_subplot(111,frame_on=False)
        ax2.axis("off")
        ax2.axis([0,1,0,1])

        class ImageAnnotations3D():
        def __init__(self, xyz, imgs, ax3d,ax2d):
        self.xyz = xyz
        self.imgs = imgs
        self.ax3d = ax3d
        self.ax2d = ax2d
        self.annot = []
        for s,im in zip(self.xyz, self.imgs):
        x,y = self.proj(s)
        self.annot.append(self.image(im,[x,y]))
        self.lim = self.ax3d.get_w_lims()
        self.rot = self.ax3d.get_proj()
        self.cid = self.ax3d.figure.canvas.mpl_connect("draw_event",self.update)

        self.funcmap = "button_press_event" : self.ax3d._button_press,
        "motion_notify_event" : self.ax3d._on_move,
        "button_release_event" : self.ax3d._button_release

        self.cfs = [self.ax3d.figure.canvas.mpl_connect(kind, self.cb)
        for kind in self.funcmap.keys()]

        def cb(self, event):
        event.inaxes = self.ax3d
        self.funcmap[event.name](event)

        def proj(self, X):
        """ From a 3D point in axes ax1,
        calculate position in 2D in ax2 """
        x,y,z = X
        x2, y2, _ = proj3d.proj_transform(x,y,z, self.ax3d.get_proj())
        tr = self.ax3d.transData.transform((x2, y2))
        return self.ax2d.transData.inverted().transform(tr)

        def image(self,arr,xy):
        """ Place an image (arr) as annotation at position xy """
        im = offsetbox.OffsetImage(arr, zoom=2)
        im.image.axes = ax
        ab = offsetbox.AnnotationBbox(im, xy, xybox=(0., 0.),
        xycoords='data', boxcoords="offset points",
        pad=0.0)
        self.ax2d.add_artist(ab)
        return ab

        def update(self,event):
        if np.any(self.ax3d.get_w_lims() != self.lim) or
        np.any(self.ax3d.get_proj() != self.rot):
        self.lim = self.ax3d.get_w_lims()
        self.rot = self.ax3d.get_proj()
        for s,ab in zip(self.xyz, self.annot):
        ab.xy = self.proj(s)



        ia = ImageAnnotations3D(np.c_[xs,ys,zs],img,ax, ax2 )

        ax.set_xlabel('X Label')
        ax.set_ylabel('Y Label')
        ax.set_zlabel('Z Label')
        plt.show()


        You can see that the output is far from optimal. However the image is in the right position. Having a vectorized one instead of the static coffee bean used might do the trick.



        broken_output



        Additional info:

        Tried to resize using cv2 (every interpolation method), didn't helped.

        Can't try skimage with the current workstation.



        You might try the following and see what comes out.



        from skimage.transform import resize
        res = resize(img, (20, 20), anti_aliasing=True)

        imgplot = plt.imshow(res)





        share|improve this answer















        This is a very rough answer and doesn't fully solve your problem but I believe it's a good start and someone else might pick up on this and reach a good solution.



        There is a way to place an image as a custmo marker in python. Starting from this AMAZING answer and fiddling a bit with the box.

        However, the problem with this solution is that your image is not vectorized (and too big to be used as a marker).

        Further, I didn't test a way to color it according to the colormap as it doesn't really show as output :/.



        The basic idea here is to replace the markers with the custom image after the plot is created. To place them properly in the figure we retrieve the proper coordinates following the the answer from ImportanceOfBeingErnest.



        from mpl_toolkits.mplot3d import Axes3D
        from mpl_toolkits.mplot3d import proj3d
        import matplotlib.pyplot as plt
        from matplotlib import offsetbox
        import numpy as np


        Note that here I downloaded the image and I am importing it from a local file



        import matplotlib.image as mpimg
        #
        img=mpimg.imread('coffeebean.png')
        imgplot = plt.imshow(img)


        coffeebeanoriginal



        from PIL import Image
        from resizeimage import resizeimage
        with open('coffeebean.png', 'r+b') as f:
        with Image.open(f) as image:
        cover = resizeimage.resize_width(image, 20,validate=True)
        cover.save('resizedbean.jpeg', image.format)

        img=mpimg.imread('resizedbean.jpeg')
        imgplot = plt.imshow(img)


        Resizing doesn't really work (or at least, I couldn't find a way to make it work).
        resizedbean



        xs = [1,1.5,2,2]
        ys = [1,2,3,1]
        zs = [0,1,2,0]
        #c = #I guess copper would be a good colormap here


        fig = plt.figure()
        ax = fig.add_subplot(111, projection=Axes3D.name)

        ax.scatter(xs, ys, zs, marker="None")

        # Create a dummy axes to place annotations to
        ax2 = fig.add_subplot(111,frame_on=False)
        ax2.axis("off")
        ax2.axis([0,1,0,1])

        class ImageAnnotations3D():
        def __init__(self, xyz, imgs, ax3d,ax2d):
        self.xyz = xyz
        self.imgs = imgs
        self.ax3d = ax3d
        self.ax2d = ax2d
        self.annot = []
        for s,im in zip(self.xyz, self.imgs):
        x,y = self.proj(s)
        self.annot.append(self.image(im,[x,y]))
        self.lim = self.ax3d.get_w_lims()
        self.rot = self.ax3d.get_proj()
        self.cid = self.ax3d.figure.canvas.mpl_connect("draw_event",self.update)

        self.funcmap = "button_press_event" : self.ax3d._button_press,
        "motion_notify_event" : self.ax3d._on_move,
        "button_release_event" : self.ax3d._button_release

        self.cfs = [self.ax3d.figure.canvas.mpl_connect(kind, self.cb)
        for kind in self.funcmap.keys()]

        def cb(self, event):
        event.inaxes = self.ax3d
        self.funcmap[event.name](event)

        def proj(self, X):
        """ From a 3D point in axes ax1,
        calculate position in 2D in ax2 """
        x,y,z = X
        x2, y2, _ = proj3d.proj_transform(x,y,z, self.ax3d.get_proj())
        tr = self.ax3d.transData.transform((x2, y2))
        return self.ax2d.transData.inverted().transform(tr)

        def image(self,arr,xy):
        """ Place an image (arr) as annotation at position xy """
        im = offsetbox.OffsetImage(arr, zoom=2)
        im.image.axes = ax
        ab = offsetbox.AnnotationBbox(im, xy, xybox=(0., 0.),
        xycoords='data', boxcoords="offset points",
        pad=0.0)
        self.ax2d.add_artist(ab)
        return ab

        def update(self,event):
        if np.any(self.ax3d.get_w_lims() != self.lim) or
        np.any(self.ax3d.get_proj() != self.rot):
        self.lim = self.ax3d.get_w_lims()
        self.rot = self.ax3d.get_proj()
        for s,ab in zip(self.xyz, self.annot):
        ab.xy = self.proj(s)



        ia = ImageAnnotations3D(np.c_[xs,ys,zs],img,ax, ax2 )

        ax.set_xlabel('X Label')
        ax.set_ylabel('Y Label')
        ax.set_zlabel('Z Label')
        plt.show()


        You can see that the output is far from optimal. However the image is in the right position. Having a vectorized one instead of the static coffee bean used might do the trick.



        broken_output



        Additional info:

        Tried to resize using cv2 (every interpolation method), didn't helped.

        Can't try skimage with the current workstation.



        You might try the following and see what comes out.



        from skimage.transform import resize
        res = resize(img, (20, 20), anti_aliasing=True)

        imgplot = plt.imshow(res)






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Apr 1 at 13:54

























        answered Apr 1 at 13:33









        GioGio

        1,5651124




        1,5651124



























            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55308428%2f3d-scatterplot-using-custom-image%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            SQL error code 1064 with creating Laravel foreign keysForeign key constraints: When to use ON UPDATE and ON DELETEDropping column with foreign key Laravel error: General error: 1025 Error on renameLaravel SQL Can't create tableLaravel Migration foreign key errorLaravel php artisan migrate:refresh giving a syntax errorSQLSTATE[42S01]: Base table or view already exists or Base table or view already exists: 1050 Tableerror in migrating laravel file to xampp serverSyntax error or access violation: 1064:syntax to use near 'unsigned not null, modelName varchar(191) not null, title varchar(191) not nLaravel cannot create new table field in mysqlLaravel 5.7:Last migration creates table but is not registered in the migration table

            용인 삼성생명 블루밍스 목차 통계 역대 감독 선수단 응원단 경기장 같이 보기 외부 링크 둘러보기 메뉴samsungblueminx.comeh선수 명단용인 삼성생명 블루밍스용인 삼성생명 블루밍스ehsamsungblueminx.comeheheheh

            155 수학 과학 기타 둘러보기 메뉴eh추가해eh문서를 완성해