Stipple plotting markers with color

How the markers can be plotted with color based on a third variable (in addition of x and y)?

import Stipple
import Stipple: @with_kw, @reactors, R, ChannelName
import Genie
import StippleUI
import StipplePlotly

@Stipple.reactive mutable struct MarkerModel <: Stipple.ReactiveModel
	plot::Stipple.R{Int} = 0
	data_plot::Stipple.R{Vector{StipplePlotly.PlotData}} = []
end

function plot_data(markers_model::MarkerModel)
	plot_collection = Vector{StipplePlotly.PlotData}()
	plot = StipplePlotly.PlotData(
				x = rand(100),
				y = rand(100),
				mode = "markers",
				plot = StipplePlotly.Charts.PLOT_TYPE_SCATTER)
	push!(plot_collection, plot)
	return plot_collection
end

function markers_ui(markers_model::MarkerModel)
	Stipple.on(markers_model.plot) do (_...)
		@info "Plot  ..."
		markers_model.data_plot[] = plot_data(markers_model)
	end
	Stipple.page(markers_model, class="container",
		prepend=Stipple.style("""
		tr:nth-child(even) {
			background: #F8F8F8 !important;
		}
		.modebar {
			display: none!important;
		}
		.st-module {
			background-color: #FFF;
			border-radius: 2px;
			box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.04);
		}
		.stipple-core .st-module > h5
		.stipple-core .st-module > h6 {
			border-bottom: 0px !important;
		}"""),
		[
			StippleUI.heading("Plot")
			Stipple.row([
				Stipple.cell(class="st-module", [
					Stipple.button("Plot!", @StippleUI.click("plot += 1"))
				])
				Stipple.cell(class="st-module", [
					Stipple.h5("Data:")
					StipplePlotly.plot(:data_plot, layout=:layout, config="{displayLogo:false}")
				])

			])
		]
	)
end

Stipple.route("/") do
	m = Stipple.init(MarkerModel)
	Stipple.html(markers_ui(m))
end

Stipple.up(9000; async=true, server=Stipple.bootstrap())
Stipple.down()
```*emphasized text*

@essenciary , suggestions how to do this? I know how to do this in Plotly however, here the format / style seems to be different. Thank you!!!

@AbhimanyuAryan @hhaensel Any chance you can help @monty on this one please?

We have csscolors() to generate css colornames. These need to be included in the style. The string docs describe how to do it.

It must have been too early, I confused colors for quasar elements, which are based on classnames. That’s what csscolors() is meant for.
Plotly markers are colored differently, I’ll paste an example soon.

As promised

	plot = StipplePlotly.PlotData(
				x = rand(100),
				y = rand(100),
				mode = "markers",
				plot = StipplePlotly.Charts.PLOT_TYPE_SCATTER,
				marker = Dict(:color => "#" * hex(color, :auto))
)

where color can be any colorant type, e.g. RGB, RGBA, etc.
If you intend to supply different colors for different markers, then color needs to be a vector and the marker keyword needs to receive broadcasting syntax.

				marker = Dict(:color => "#" .* hex.(colors, :auto))

If you want to add a color vector that is reflected in the front-end immediately there are two possibilities.

  1. Setup a backend handler that modifies the data
on(model.colors) do colors
    model.plot.marker[:color] = colors
    notify(model.plot)
end
  1. Setup a frontend handler (‘watcher’)
Stipple.js_watch = """
colors: function (val) {
      this.plot.marker.color = val
}
"""

The latter sends less data over the webchannel (at least unless we have implemented element-wise updates). In case of large data this might be relevant. I assume that for the watcher case you need to make sure that you update the colors field after the client connects. So probably you should define colors in the model after the plot data or you should call push!(model, :colors => model.colors) in the isready handler after push!(model).

2 Likes

Thank you!

import Stipple
import Stipple: @with_kw, @reactors, R, ChannelName
import Genie
import StippleUI
import StipplePlotly
import Colors
import ColorSchemes

@Stipple.reactive mutable struct MarkerModel <: Stipple.ReactiveModel
	plot::Stipple.R{Int} = 0
	data_plot::Stipple.R{Vector{StipplePlotly.PlotData}} = []
end

function plot_data(markers_model::MarkerModel)
	plot_collection = Vector{StipplePlotly.PlotData}()
	plot = StipplePlotly.PlotData(
				x = rand(100),
				y = rand(100),
				mode = "markers",
				marker = Dict(:color => "#" .* Colors.hex.(ColorSchemes.rainbow[rand(100)])),
				plot = StipplePlotly.Charts.PLOT_TYPE_SCATTER)
	push!(plot_collection, plot)
	return plot_collection
end

function markers_ui(markers_model::MarkerModel)
	Stipple.on(markers_model.plot) do (_...)
		@info "Plot  ..."
		markers_model.data_plot[] = plot_data(markers_model)
	end
	Stipple.page(markers_model, class="container",
		prepend=Stipple.style("""
		tr:nth-child(even) {
			background: #F8F8F8 !important;
		}
		.modebar {
			display: none!important;
		}
		.st-module {
			background-color: #FFF;
			border-radius: 2px;
			box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.04);
		}
		.stipple-core .st-module > h5
		.stipple-core .st-module > h6 {
			border-bottom: 0px !important;
		}"""),
		[
			StippleUI.heading("Plot")
			Stipple.row([
				Stipple.cell(class="st-module", [
					Stipple.button("Plot!", @StippleUI.click("plot += 1"))
				])
				Stipple.cell(class="st-module", [
					Stipple.h5("Data:")
					StipplePlotly.plot(:data_plot, layout=:layout, config="{displayLogo:false}")
				])

			])
		]
	)
end

Stipple.route("/") do
	m = Stipple.init(MarkerModel)
	Stipple.html(markers_ui(m))
end

Stipple.up(9000; async=true, server=Stipple.bootstrap())
Stipple.down()

This works!

1 Like

@hhaensel btw, how to show color scale?! Thank you!

Not sure, what you mean by colorscale, could you be more precise?
Best would be to start a new topic.

@hhaensel, I want to add a scale bar showing the range of the values color coded in the plotted markers.How I can add it in the script above. I know how to do it in plotly.

Then please paste the code you would use for plotly

import numpy as np
import plotly.graph_objs as go

z=np.random.randint(10, 35, size=20)
trace=dict(type='scatter',
          x=3+np.random.rand(20),
          y=-2+3*np.random.rand(20),
          mode='markers',
          marker=dict(color= z, 
                      colorscale='Viridis', size=14, colorbar=dict(thickness=20)))

axis_style=dict(zeroline=False, showline=True, mirror=True)
layout=dict(width=600, height=450, title='My plot',
            xaxis=axis_style,
            yaxis=axis_style,
           hovermode='closest')
fw=go.FigureWidget(data=[trace], layout=layout)
PlotlyJS.scatter(; x=x, y=y, z=z, l..., marker=Plotly.attr(; size=pointsize, color=z, colorscale=colorscale(:rainbow), colorbar=Plotly.attr(; thickness=20)))

@hhaensel here are example is python and julia

A plot that has been generated with PlotlyBase (or PlotlyJS) can be directly implemented in a Stipple UI by plotly(:plotname), e.g.

using Stipple, StipplePlotly
using PlotlyBase

@reactive! mutable struct Example <: ReactiveModel
    plot::R{Plot} = Plot()
end

function ui(model::Example)
    page(model, class = "container", [
        plotly(:plot)
    ])
end

model = init(Example, debounce=0)
route("/") do
    model |> ui |> html
end

up()

# now connect to localhost with a browser and then execute the following lines.
for i in 1:30
    model.plot[] = Plot(rand(100, 2))
    sleep(0.1)
end

The translation to the StipplePlotly API is also straight forward, but the axis definition deviates from the python syntax:

trace = PlotData(plot = StipplePlotly.Charts.PLOT_TYPE_SCATTER,
    x = 3 .+ rand(20),
    y = -2 .+ 3 .* rand(20),
    mode = "markers",
    marker = PlotDataMarker(color = z, 
        colorscale = "Viridis", size = 14, colorbar = ColorBar(thickness = 20)
    )
)

x_axis_style = PlotLayoutAxis(xy = "x", zeroline = false, showline = true, mirror = true)
y_axis_style = PlotLayoutAxis(xy = "y", zeroline = false, showline = true, mirror = true)

layout = PlotLayout(width = 600, height = 450, title = PlotLayoutTitle(text = "My plot"),
    xaxis = [x_axis_style],
    yaxis = [y_axis_style],
    hovermode = "closest"
)

1 Like

@hhaensel Thank you very much! It worked!!! Your help is highly appreciated!