I'm trying to subplot my data, but printing in PDF brings results I can't use: Title and x-axis title are cut (and the legend's box is covered by the graph, but I can handle this with other positions). I have to use gnuplot and pdfcairo because other seup isn't working with special characters, umlaut, etc.
clear;clc;close all;clf;clear all;
graphics_toolkit("gnuplot")
x = 0:.1:10;
y1 = exp(-x).*sin(x);
y2 = exp(x);
h=figure(1);
subplot(2,1,1);
plot(x,y1)
h1 = plot(x,y1);
set(h1,'LineWidth',4)
set(gca,'FontSize',32)
set(gca,'FontName','Times')
set(get(gca,'Ylabel'),'String','TTEST test \rho \rightarrow','FontWeight','Bold','FontSize',32)
set(get(gca,'Xlabel'),'String','abc / - \rightarrow','FontWeight','Bold','FontSize',32)
legend({
'h_{ref}(t)'
},"location", 'northeast');
title('TITLE')
l1 = legend;
set(l1,'FontName','Times')
subplot(2,1,2);
h2 = plot(x,y2);
set(h2,'LineWidth',4)
set(gca,'FontSize',32)
set(gca,'FontName','Times')
set(get(gca,'Ylabel'),'String','TTEST test \rho \rightarrow','FontWeight','Bold','FontSize',32)
set(get(gca,'Xlabel'),'String','agc / -\rightarrow','FontWeight','Bold','FontSize',32)
legend({
'h_{ref}(t)'
},"location", 'northeast');
l2 = legend;
set(l2,'FontName','Times')
print ('title_axis.pdf', '-dpdfcairo', '-S1000,600');
Related
I'm trying to have a plot title which contains variable values and also characters with subscripts, however when I try:
title = "ηₛ = $η̂[Pa S] , μₛ = $μ̂[Pa], μₚ = $μ̂ₚ[Pa] , ηₚ = $η̂ₚ[Pa S] \n α = $α̂ , ζ = $ζ̂"
Inside the plot function, the title appears with X marks where the subscripts are. I tried to use LaTeX ```title = L" .." but then the variable values don't appear.
Is there any way to have both in the title I need?
If you want a fully working solution this is what I think you need to do, note that %$ is used for interpolation:
title = L"\eta_1 = %$(η̂[Pa, S])"
The reason is that, while some of the characters will be rendered correctly as Bill noted, not all of them will unless you use LaTeXStrings.jl.
See:
help?> LaTeXStrings.#L_str
L"..."
Creates a LaTeXString and is equivalent to latexstring(raw"..."), except that %$ can be used for interpolation.
julia> L"x = \sqrt{2}"
L"$x = \sqrt{2}$"
julia> L"x = %$(sqrt(2))"
L"$x = 1.4142135623730951$"
I am learning how to create plots with slider bars. Here is my code based off the first example of this tutorial
using Plots
gr()
using GLMakie
function plotLaneEmden(log_delta_xi=-4, n=3)
fig = Figure()
ax = Axis(fig[1, 1])
sl_x = Slider(fig[2, 1], range = 0:0.01:4.99, startvalue = 3)
sl_y = Slider(fig[1, 2], range = -6:0.01:0.1, horizontal = false, startvalue = -2)
point = lift(sl_x.value, sl_y.value) do n, log_delta_xi
Point2f(n, log_delta_xi)
end
plot(n, 1 .- log_delta_xi.^2/6, linecolor = :green, label="n = $n")
xlabel!("ξ")
ylabel!("θ")
end
plotLaneEmden()
When I run this, it gives UndefVarError: plot not defined. What am I missing here?
It looks like you are trying to mix and match Plots.jl and Makie.jl. Specifically, the example from your link is entirely for Makie (specifically, with the GLMakie backend), while the the plot function you are trying to add uses syntax specific to the Plots.jl version of plot (specifically including linecolor and label keyword arguments).
Plots.jl and Makie.jl are two separate and unrelated plotting libraries, so you have to pick one and stick with it. Since both libraries export some of the same function names, using both at once will lead to ambiguity and UndefVarErrors if not disambiguated.
The other potential problem is that it looks like you are trying to make a line plot with only a single x and y value (n and log_delta_xi are both single numbers in your code as written). If that's what you want, you'll need a scatter plot instead of a line plot; and if that's not what you want you'll need to make those variables vectors instead somehow.
Depending on what exactly you want, you might try something more along the lines of (in a new session, using only Makie and not Plots):
using GLMakie
function plotLaneEmden(log_delta_xi=-4, n=3)
fig = Figure()
ax = Axis(fig[1, 1], xlabel="ξ", ylabel="θ")
sl_x = Slider(fig[2, 1], range = 0:0.01:4.99, startvalue = n)
sl_y = Slider(fig[1, 2], range = -6:0.01:0.1, horizontal = false, startvalue = log_delta_xi)
point = lift(sl_x.value, sl_y.value) do n, log_delta_xi
Point2f(n, 1 - log_delta_xi^2/6)
end
sca = scatter!(point, color = :green, markersize = 20)
axislegend(ax, [sca], ["n = $n"])
fig
end
plotLaneEmden()
Or, below, a simple example for interactively plotting a line rather than a point:
using GLMakie
function quadraticsliders(x=-5:0.01:5)
fig = Figure()
ax = Axis(fig[1, 1], xlabel="X", ylabel="Y")
sl_a = Slider(fig[2, 1], range = -3:0.01:3, startvalue = 0.)
sl_b = Slider(fig[1, 2], range = -3:0.01:3, horizontal = false, startvalue = 0.)
points = lift(sl_a.value, sl_b.value) do a, b
Point2f.(x, a.*x.^2 .+ b.*x)
end
l = lines!(points, color = :blue)
onany((a,b)->axislegend(ax, [l], ["$(a)x² + $(b)x"]), sl_a.value, sl_b.value)
limits!(ax, minimum(x), maximum(x), -10, 10)
fig
end
quadraticsliders()
ETA: A couple examples closer to what you might be looking for
I use makie.jl with slicesNumb for visualization of PET/CT scans, I have 3d array of attenuation values and I display heatmap with changing slices using slider - this works well I have two problems
I do not know how to be able to define custom colormaps (basically I need to be able to specify that all above some threshold value will be black and all below white and values between will have grey values proportional to attenuation value).
2)I would like to be able to display to display over my image (tachnically heatmap) another ones where I would be able to controll transparency - alpha value of pixels - in order to display some annotations/ PET ...
code that works but without those 2 functionalities and how it looks
using GLMakie
```#doc
simple display of single image - only in transverse plane
```
function singleCtScanDisplay(arr ::Array{Number, 3})
fig = Figure()
sl_x = Slider(fig[2, 1], range = 1:1:size(arr)[3], startvalue = 40)
ax = Axis(fig[1, 1])
hm = heatmap!(ax, lift(idx-> arr[:,:, floor(idx)], sl_x.value) ,colormap = :grays)
Colorbar(fig[1, 2], hm)
fig
end
Thanks for help !
You can use Colors and ColorSchemeTools, but you will need to add the top and bottom of the scheme according to your thresholds.
using Colors, ColorSchemeTools
truemin = 0
truemax = 600
max_shown_black = 20
min_shown_white = 500
data = rand(truemin:truemax, (500, 500, 20))
grayscheme = [fill(colorant"black", max_shown_black - truemin + 1);
collect(make_colorscheme(identity, identity, identity,
length = min_shown_white - max_shown_black - 1));
fill(colorant"white", truemax - min_shown_white + 1)]
For controlling alpha, I would add a popup window with an alpha slider. Take a look at some of the distributable DICOM tools for examples.
I finally managed it basically I load 3 dimensional data stored in hdf5 (I loaded it into hdf5 from raw using python)
It enables viewing transverse slices and annotate 3d pathes in a mask that will be displayed over main image
exmpleH = #spawnat persistenceWorker Main.h5manag.getExample()
minimumm = -1000
maximumm = 2000
arrr= fetch(exmpleH)
imageDim = size(arrr)
using GLMakie
maskArr = Observable(BitArray(undef, imageDim))
MyImgeViewer.singleCtScanDisplay(arrr, maskArr,minimumm, maximumm)
Now definition of the required modules
```#doc
functions responsible for displaying medical image Data
```
using DrWatson
#quickactivate "Probabilistic medical segmentation"
module MyImgeViewer
using GLMakie
using Makie
#using GeometryBasics
using GeometricalPredicates
using ColorTypes
using Distributed
using GLMakie
using Main.imageViewerHelper
using Main.workerNumbers
## getting id of workers
```#doc
simple display of single image - only in transverse plane we are adding also a mask that
arrr - main 3 dimensional data representing medical image for example in case of CT each voxel represents value of X ray attenuation
minimumm, maximumm - approximately minimum and maximum values we can have in our image
```
function singleCtScanDisplay(arrr ::Array{Number, 3}, maskArr , minimumm, maximumm)
#we modify 2 pixels just in order to make the color range constant so slices will be displayed in the same windows
arrr[1,1,:].= minimumm
arrr[2,1,:].= maximumm
imageDim = size(arrr) # dimenstion of the primary image for example CT scan
slicesNumb =imageDim[3] # number of slices
#defining layout variables
scene, layout = GLMakie.layoutscene(resolution = (600, 400))
ax1 = layout[1, 1] = GLMakie.Axis(scene, backgroundcolor = :transparent)
ax2 = layout[1, 1] = GLMakie.Axis(scene, backgroundcolor = :transparent)
#control widgets
sl_x =layout[2, 1]= GLMakie.Slider(scene, range = 1:1: slicesNumb , startvalue = slicesNumb/2 )
sliderXVal = sl_x.value
#color maps
cmwhite = cgrad(range(RGBA(10,10,10,0.01), stop=RGBA(0,0,255,0.4), length=10000));
greyss = createMedicalImageColorSchemeB(200,-200,maximumm, minimumm )
####heatmaps
#main heatmap that holds for example Ct scan
currentSliceMain = GLMakie.#lift(arrr[:,:, convert(Int32,$sliderXVal)])
hm = GLMakie.heatmap!(ax1, currentSliceMain ,colormap = greyss)
#helper heatmap designed to respond to both changes in slider and changes in the bit matrix
currentSliceMask = GLMakie.#lift($maskArr[:,:, convert(Int32,$sliderXVal)])
hmB = GLMakie.heatmap!(ax1, currentSliceMask ,colormap = cmwhite)
#adding ability to be able to add information to mask where we clicked so in casse of mit matrix we will set the point where we clicked to 1
indicatorC(ax1,imageDim,scene,maskArr,sliderXVal)
#displaying
colorB = layout[1,2]= Colorbar(scene, hm)
GLMakie.translate!(hmB, Vec3f0(0,0,5))
scene
end
```#doc
inspired by https://github.com/JuliaPlots/Makie.jl/issues/810
Generaly thanks to this function the viewer is able to respond to clicking on the slices and records it in the supplied 3 dimensional AbstractArray
ax - Axis which store our heatmap slices which we want to observe wheather user clicked on them and where
dims - dimensions of main image for example CT
sc - Scene where our axis is
maskArr - the 3 dimensional bit array that has exactly the same dimensions as main Array storing image
sliceNumb - represents on what slide we are on currently on - ussually it just give information from slider
```
function indicatorC(ax::Axis,dims::Tuple{Int64, Int64, Int64},sc::Scene,maskArr,sliceNumb::Observable{Any})
register_interaction!(ax, :indicator) do event::GLMakie.MouseEvent, axis
if event.type === MouseEventTypes.leftclick
println("clicked")
##async begin
#appropriately modyfing wanted pixels in mask array
#async calculateMouseAndSetmaskWrap(maskArr, event,sc,dims,sliceNumb)
#
#
# println("fetched" + fetch(maskA))
# finalize(maskA)
#end
return true
#print("xMouse: $(xMouse) yMouse: $(yMouse) compBoxWidth: $(compBoxWidth) compBoxHeight: $(compBoxHeight) calculatedXpixel: $(calculatedXpixel) calculatedYpixel: $(calculatedYpixel) pixelsNumbInX $(pixelsNumbInX) ")
end
end
end
```#doc
wrapper for calculateMouseAndSetmask - from imageViewerHelper module
given mouse event modifies mask accordingly
maskArr - the 3 dimensional bit array that has exactly the same dimensions as main Array storing image
event - mouse event passed from Makie
sc - scene we are using in Makie
```
function calculateMouseAndSetmaskWrap(maskArr, event,sc,dims,sliceNumb)
maskArr[] = calculateMouseAndSetmask(maskArr, event,sc,dims,sliceNumb)
end
end #module
and helper methods
```#doc
functions responsible for helping in image viewer - those functions are meant to be invoked on separate process
- in parallel
```
using DrWatson
#quickactivate "Probabilistic medical segmentation"
module imageViewerHelper
using Documenter
using ColorTypes
using Colors, ColorSchemeTools
using Makie
export calculateMouseAndSetmask
export createMedicalImageColorSchemeB
# using AbstractPlotting
```#doc
given mouse event modifies mask accordingly
maskArr - the 3 dimensional bit array that has exactly the same dimensions as main Array storing image
event - mouse event passed from Makie
sc - scene we are using in Makie
```
function calculateMouseAndSetmask(maskArr, event,sc,dims,sliceNumb)
#position from top left corner
xMouse= Makie.to_world(sc,event.data)[1]
yMouse= Makie.to_world(sc,event.data)[2]
#data about height and width in layout
compBoxWidth = 510
compBoxHeight = 510
#image dimensions - number of pixels from medical image for example ct scan
pixelsNumbInX =dims[1]
pixelsNumbInY =dims[2]
#calculating over which image pixel we are
calculatedXpixel =convert(Int32, round( (xMouse/compBoxWidth)*pixelsNumbInX) )
calculatedYpixel = convert(Int32,round( (yMouse/compBoxHeight)*pixelsNumbInY ))
sliceNumbConv =convert(Int32,round( sliceNumb[] ))
#appropriately modyfing wanted pixels in mask array
return markMaskArrayPatch( maskArr ,CartesianIndex(calculatedXpixel, calculatedYpixel, sliceNumbConv ),2)
end
```#doc
maskArr - the 3 dimensional bit array that has exactly the same dimensions as main Array storing image
point - cartesian coordinates of point around which we want to modify the 3 dimensional array from 0 to 1
```
function markMaskArrayPatch(maskArr, pointCart::CartesianIndex{3}, patchSize ::Int64)
ones = CartesianIndex(patchSize,patchSize,patchSize) # cartesian 3 dimensional index used for calculations to get range of the cartesian indicis to analyze
maskArrB = maskArr[]
for J in (pointCart-ones):(pointCart+ones)
diff = J - pointCart # diffrence between dimensions relative to point of origin
if cartesianTolinear(diff) <= patchSize
maskArrB[J]=1
end
end
return maskArrB
end
```#doc
works only for 3d cartesian coordinates
cart - cartesian coordinates of point where we will add the dimensions ...
```
function cartesianTolinear(pointCart::CartesianIndex{3}) :: Int16
abs(pointCart[1])+ abs(pointCart[2])+abs(pointCart[3])
end
```#doc
creating grey scheme colors for proper display of medical image mainly CT scan
min_shown_white - max_shown_black range over which the gradint of greys will be shown
truemax - truemin the range of values in the image for which we are creating the scale
```
#taken from https://stackoverflow.com/questions/67727977/how-to-create-julia-color-scheme-for-displaying-ct-scan-makie-jl/67756158#67756158
function createMedicalImageColorSchemeB(min_shown_white,max_shown_black,truemax,truemin ) ::Vector{Any}
# println("max_shown_black - truemin + 1")
# println(max_shown_black - truemin + 1)
# println(" min_shown_white - max_shown_black - 1")
# println( min_shown_white - max_shown_black - 1)
# println("truemax - min_shown_white + 1")
# println(truemax - min_shown_white + 1)
return [fill(colorant"black", max_shown_black - truemin + 1);
collect(make_colorscheme(identity, identity, identity,
length = min_shown_white - max_shown_black - 1));
fill(colorant"white", truemax - min_shown_white + 1)]
end
end #module
I would like to plot a two variable function(s) (e_pos and e_neg in the code). Here, t and a are constants which I have given the value of 1.
My code to plot this function is the following:
t = 1
a = 1
kx = ky = range(3.14/a, step=0.1, 3.14/a)
# Doing a meshgrid for values of k
KX, KY = kx'.*ones(size(kx)[1]), ky'.*ones(size(ky)[1])
e_pos = +t.*sqrt.((3 .+ (4).*cos.((3)*KX*a/2).*cos.(sqrt(3).*KY.*a/2) .+ (2).*cos.(sqrt(3).*KY.*a)));
e_neg = -t.*sqrt.((3 .+ (4).*cos.((3)*KX*a/2).*cos.(sqrt(3).*KY.*a/2) .+ (2).*cos.(sqrt(3).*KY.*a)));
using Plots
plot(KX,KY,e_pos, st=:surface,cmap="inferno")
If I use Plots this way, sometimes I get an empty 3D plane without the surface. What am I doing wrong? I think it may have to do with the meshgrids I did for kx and ky, but I am unsure.
Edit: I also get the following error:
I changed some few things in my code.
First, I left the variables as ranges. Second, I simply computed the functions I needed without mapping the variables onto them. Here's the code:
t = 2.8
a = 1
kx = range(-pi/a,stop = pi/a, length=100)
ky = range(-pi/a,stop = pi/a, length=100)
#e_pos = +t*np.sqrt(3 + 4*np.cos(3*KX*a/2)*np.cos(np.sqrt(3)*KY*a/2) + 2*np.cos(np.sqrt(3)*KY*a))
e_pos(kx,ky) = t*sqrt(3+4cos(3*kx*a/2)*cos(sqrt(3)*ky*a/2) + 2*cos(sqrt(3)*ky*a))
e_neg(kx,ky) = -t*sqrt(3+4cos(3*kx*a/2)*cos(sqrt(3)*ky*a/2) + 2*cos(sqrt(3)*ky*a))
# Sort of broadcasting?
e_posfunc = e_pos.(kx,ky);
e_negfunc = e_neg.(kx,ky);
For the plotting I simply used the GR backend:
using Plots
gr()
plot(kx,ky,e_pos,st=:surface)
plot!(kx,ky,e_neg,st=:surface, xlabel="kx", ylabel="ky",zlabel="E(k)")
I got what I wanted!
I am using substitution labels (##) with diagrammeR and Graphviz syntax. I have seen previous questions about justification of node labels such as this one when the labels are in-line text, but I am wondering how to justify node text generated from a multi-row substitution label. More specifically, for the label in the reproducible example below, I want the ‘main’ column, meaning the first and third rectangle labels, to remain centered, but multi-line node labels such as the rightmost rectangle to be left justified (the value as well as the subvalues). Since I specify line breaks in the substitution labels, I tried using double backslash \l instead of \n without success.
Additionally, I would like to bold the headers (in the reproducible example, the first value, second value, and third value rows), but not bold any subvalues.
Any help would be greatly appreciated. Thank you!
library(DiagrammeR)
library(DiagrammeRsvg)
a <- 100
x <- 50
b <- 30
d <- 20
grViz("
digraph a_nice_graph {
node[fontname = Helvetica, shape = box, width = 4, fontcolor = darkslategray]
firstvalue[label = '##1']
secondvalue[label = '##2']
thirdvalue[label = '##3']
blank[label = '', width = 0.01, height = 0.01]
{ rank = same; blank secondvalue }
firstvalue -> blank [dir = none]
blank -> secondvalue[minlen = 9]
blank -> thirdvalue
}
[1]: paste0('First value (n = ', a, ')')
[2]: paste0('Second value (n = ', a-x, ')\\nSubvalue = ', b, '\\nSubvalue = ', d, '')
[3]: paste0('Third value (n = ', x, ')')
")