How does Holoviews know which colours to assign to each scatterplot in an overlay? - overlay

In the bokeh Holoviews gallery, there is an example called 'Scatter economic'.
http://holoviews.org/gallery/demos/bokeh/scatter_economic.html#bokeh-gallery-scatter-economic
In this plot, notice how one of the options for Scatter is (color=Cycle('Category20')). The last line of the plot is gdp_unem_scatter.overlay('Country').
My question is: How does Holoviews know to connect each Scatter to a particular color in Cycle('Category20')? Is this just a property of Cycle()? Is there some way that the Overlay interacts with the Scatter and with the Cycle automatically?
A slightly related confusion is that if I use the .opts method instead of the cell magic as in the example, it still works. For example, if I use the .opts method with this cycle color on the Scatter (i.e., second to the last line in the above example), and then do an .overlay('Country'), somehow Holoviews knows to assign each Scatter to a particular color based on the Country.
I want to make sure that I am properly plotting what I intend to.
Thank you!

It is now possible to map categories in an NdOverlay (as is used in the example above) by using a so called dim expression and then define an expression to do the mapping:
dim_expr = hv.dim('category').categorize({'A': 'red', 'B': 'green', 'C': 'blue'})
overlay = hv.NdOverlay({chr(65+i): hv.Scatter(np.random.rand(10, 2)) for i in range(3)}, 'category')
overlay.opts(hv.opts.Scatter(color=dim_expr))
In this example we created a dim expression which points to the 'category' dimension and then maps each category ('A', 'B' and 'C') to a color ('red', 'green', 'blue'). We then just assign that to the color option.

How does Holoviews know to connect each Scatter to a particular color in Cycle('Category20')? Is this just a property of Cycle()? Is there some way that the Overlay interacts with the Scatter and with the Cycle automatically?
You are correct that Cycle and Overlay are designed to interact in this way automatically. More explicitly, each color in the Cycle gets assigned to a 'layer' of the overlay until the cycle runs out of colors and it loops.
For example, if I use the .opts method with this cycle color on the Scatter (i.e., second to the last line in the above example), and then do an .overlay('Country'), somehow Holoviews knows to assign each Scatter to a particular color based on the Country.
This is because your call to opts customizes the options on the elements of the data structure before you call the overlay method on (this data structure is a HoloMap). The options set there are propagated to the Scatter elements in the HoloMap which will now have the chosen Cycle specified. This means that when these elements get put into an overlay, HoloViews can look up the Cycle appropriately and apply it correctly to the overlay.
Hope that makes sense!

Related

Altair Scatter Chart

i am looking for a way to make a point chart based on multiple nominal conditions. i am plotting 2 values on x and y, but i would like to differentiate these points based on year as well as 'type'.
currently, the way i do it is to assign year to color while 'type' is assigned to shape
color=alt.condition(selection, alt.Color('Date:T'), alt.value('lightgray'), scheme='red' )
shape = alt.Shape('type:N')
a few questions:
is it possible to change the color scheme of the points instead of the default colors to say shades of red/blue/black, etc?
is it possible to assign one color scheme/shade (instead of shapes) to 'types'?
is it possible to change the color scheme of the points instead of the default colors to say shades of red/blue/black, etc?
Yes, see https://altair-viz.github.io/user_guide/customization.html#customizing-colors. You can use any of the built-in Vega color schemes, or define your own using the methods discussed there. From your example, it might look something like this:
color=alt.condition(
selection,
alt.Color('Date:T', scale=alt.Scale(scheme='reds')),
alt.value('lightgray')
)
is it possible to assign one color scheme/shade (instead of shapes) to 'types'?
No, there is no built-in way to apply two color scales based on two fields in the data (how would a mark choose between the two colors assigned to it?) One possible approach would be to use an opacity encoding for the second field, which is reflected in the lightness of the marks. For your example, it might look like this:
opacity='type:N'

Attributing multiple Peer objects to a single item in legend

Simplified Problem
I'm plotting 10 items.
To generate my plot I am creating 10 independent Line objects in a for loop
x=1:10;y=1;10;names = num2str((1:10)');
for i = 1:10
my_plots(i) = plot(x(i),y(i),'.','Color',rgb(i,:),'MarkerSize',14);
end
legend(my_plots,names);
When I click on an item in the legend it toggles visibility of the corresponding line
(legHandle.ItemHitFcn = toggleLegendItem).
function toggleLegendItem(src,evnt)
if strcmp(evnt.Peer.Visible,'on')
evnt.Peer.Visible = 'off';
else
evnt.Peer.Visible= 'on';
end
end
This works fine
I run into issues when some of my plots are actually the same category.
In this simple example, I could combine lines 1:5 into one object in a number of different ways, and pass the combined object to the legend as a single item in my_plots.
Actual problem
All of my line objects are distributed between several independent axes/subplots. Each axis has to remain independent because I need to be able to freely rotate each subplot without disturbing the other plots.
Progress so far
I've been able to build a shared legend between axes (because same class items share the same color, I only need to link the first line for each class), but I cannot figure out how to link multiple line objects to a single legend item, so that I am able to properly all lines across axes on each legend item callback.
I have an array of lines.
{{Line Line Line}}
{{Line Line Line}}
{{Line Line Line}}
...
{{Line Line Line}}
Basically what I need to do is set multiple Peer objects to a single legend item, but I am not sure if that is possible.
If someone has another solution that allows for combing multiple line handles across axes that would be helpful too.
So looking at the legend() function, I found that it's not possible to instantiate a legend with multiple Peer objects per item. There may be a way to go back and add multiple references via some sort of "combined object" but I'm not sure if a "combined object" exists that can handle objects with different Parent handles.
A quick fix to my problem (which was attributing a callback to the same item in multiple axes) was to use the shared properties within each class and across axes to get the handles for all items within each class. In this case I already assigned color to be distinctive between categories but a more objective property like Tag could also be used.
function toggleLegendItem(src,evnt)
% Find all items in this category
obj = findobj(findall(gcf,'type','Scatter'),'CData',evnt.Peer.CData);
for oid = 1:length(obj)
if strcmp(obj(oid).Visible,'on')
obj(oid).Visible = 'off';
else
obj(oid).Visible= 'on';
end
end
end
The one nuisance that this solution leaves is that the legend is a child of only one axis. If each category is not present in all axes, then the color for those missing categories may not show up. Luckily when you toggle each item's visibility the color appears and functions as normal. I would guess some other errors like this could occur.

Change markers in dynamic plots

What I have:
hold on
for i =1:length(tspan)
var{i} = Tv(:,i);
str{i} = ['t = ',num2str(tspan(i)), ' s'];
plot(z,var{i},'DisplayName',str{i});
end
legend('-DynamicLegend');
This works perfectly (thanks to this), but it prints out all blue lines.
I tried to set up a colormap (the default) and use it like this, but the output was the same
plot(z,var{i},'DisplayName',str{i},'Color', colormap(i,:));
And I would also like to see different markers for each plot. How is it possible to change them?
EDIT
Thanks to ironzionlion I fixed the colors. How can I do the same with markers?
According to the post that you mention, you have to define that you will need i different colours in your plot. This can be done by using colors = hsv(i)
Your plot sentence will then be: plot(z,var{i},'DisplayName',str{i},'Color', colors(i,:));
Update
I am not aware of the existance of "markermap". You could fix the problem just by define upfront the different markers that you want (quick and dirty solution): mrk={'o','+','*','.'};
Then you will plot by selecting each time the corresponding marker:
plot(z,var{i},'DisplayName',str{i},'Color', cmap(i,:),'Marker', mrk{i});

turn on colorbar programmatically in clustergram

I know that one can insert a colorbar by clicking the colorbar icon in the clustergram GUI. Is there a way to do it programmatically?
I tried
cgo = clustergram(data)
colorbar;
This makes a colorbar in a new figure window. How can a colorbar be created with proper positioning in a clustergram figure as if the button was clicked?
There is a function buried away (HeatMap.plot>showColorbar) that neatly positions the colorbar to the left of both the heat map and the dendogram (the lines). Just running colorbar(...) will mess up the relative positioning of the dendogram and the heatmap. So you need to somehow run the callback or carefully duplicate all of the position computations. It's easier to just run the callback. Here's how.
To create the colorbar programmatically for a clustergram, and keep the color bar button in sync, you need to use the button's assigned callback and set the button's state.
Create the clustergram:
load filteredyeastdata
cgo = clustergram(yeastvalues(1:30,:),'Standardize','Row');
Get the handle for color bar button:
cbButton = findall(gcf,'tag','HMInsertColorbar');
Get callback (ClickedCallback) for the button:
ccb = get(cbButton,'ClickedCallback')
ccb =
#insertColorbarCB
[1x1 clustergram]
That gives us a handle to the function assigned by the callback (#insertColorbarCB), and the function's third input argument (the clustergram object). The button's handle and an empty event object are implicitly the first two arguments.
Change the button state to 'on' (clicked down):
set(cbButton,'State','on')
Run the callback to create the colorbar:
ccb{1}(cbButton,[],ccb{2})
Note that the button State must be changed to 'on' first, otherwise the callback won't do anything.
I just managed to solve this problem.
What I did:
I added this function to the clustergram code (I put it at line 1486)
%%%%%%%%%%%%%%
function insertColorbarCBALWAYS(obj)
hFig= gcbf;
obj.Colorbar = true;
end
%%%%%%%%%%%%%%%
and then at line 415 of the clustergram.m file I added this line of code
insertColorbarCBALWAYS(obj);
to call the above function. Save and go: now the colorbar will always be there, once the clustergram is drawn.
Previous method was not working for me so I made this workaround.
One may even save the new clustergram code as clustergramCM such that you can draw cgram in both ways.

Change label of data tips on bode nichols diagram

When we plot a bode/nichols locus, the name of workspace variable is used
tmp=ss(1,1,1,0);
nichols(tmp);
will use 'tmp' as label.
When using more complex data, matlab is using 'untitled1','untitled2',...
tmp={ss(1,1,1,0) , ss(1.2,1,1,0)};
nichols(tmp{:});
How can I change this label programmatically?
Ideally, I'd like a solution working with Matlab 6.5.1, but I'm also interested in solutions restricted to newer versions.
You can modify the labels programmatically via their graphics handles. It looks like the values you want to change are the DisplayName property of some of the children of the current axis. So in your first example, I can change the display name like this:
ch = get(gca,'Children');
set(ch(1),'DisplayName','Fred');
In general, I'm not sure how to predict which children of the current axis are the ones you need to change. For the second example you give, the two curves appear to be the second and third children when I run your code.