A minimal, extensible repository showcasing plotting in Julia using
Plots.jl.
The repository currently includes line plots and histograms via
line.jl and histogram.jl.
Future extensions can be added as new plot modules (e.g., pie charts, scatter plots, etc.).
Built with Julia, Plots.jl, and selectable rendering backends (GR / PythonPlot).
- About this repository
- Install Julia and plotting packages
- Why the first run can take “couple of minutes”
- Running with VS Code (recommended)
- Running without VS Code (Terminal / cmd / Git Bash)
- Outputs (where images are saved)
- Line plots module (
line.jl) - Histogram plots module (
histogram.jl) - Implementation tutorial video
This repository is a small, practical starting point for plotting in Julia using Plots.jl.
Current examples:
line.jl— multiple line-plot demonstrations (multi-series plots, markers, subplots, tiled layouts, and a CSV-driven plot).histogram.jl— a histogram “toolbox” (binning rules, normalization, categorical histograms, overlays, and a CSV-driven histogram).
Install Julia 1.10+ (this repository was developed with Julia 1.12.x).
Recommended approach:
- Install Julia from the official Julia downloads page.
- Ensure the
juliaexecutable is available from your terminal.
Quick verification (any terminal):
julia --versionIf a version prints, Julia is installed correctly.
Julia uses Pkg (its built-in package manager). For this repository, you will install the plotting stack once, and then run the scripts.
From the Julia REPL (run this in the repo root folder):
julia
julia> import Pkg
julia> Pkg.activate(".")
julia> Pkg.add(["Plots","StatsBase","CSV","DataFrames","Downloads","PythonPlot"])What this does:
Pkg.activate(".")creates/uses a project environment in the current folder (the repo root).Pkg.add(...)installs the required packages into that environment.- As a side effect, Julia generates (or updates) the environment files:
Project.toml(direct dependencies)Manifest.toml(locked dependency graph)
This repository does not include Project.toml, Manifest.toml, or .vscode/ by design (to avoid machine-specific paths and to keep the repo lightweight). You generate them locally using the steps above.
The scripts use these packages and standard libraries:
- Plots — main plotting interface.
- GR — commonly used rendering backend (selected with
gr()). - PythonPlot — optional backend (selected with
pythonplot()). - StatsBase — histogram utilities (counting, bin rules, etc.).
- CSV + DataFrames — reading and manipulating tabular datasets.
- Downloads — downloading CSV files directly from URLs.
- Standard libraries: Random, Statistics.
Backend note:
- If you use
pythonplot(), Julia may create a Python environment (via PythonCall/CondaPkg) the first time you run it.
It is normal (especially on Windows) for the first run of a plotting repository to take a long time.
This is typically caused by a combination of:
-
Package downloads
On first use, Julia downloads the packages you added viaPkg.add(...). -
Artifact downloads (binary dependencies)
Plotting stacks commonly require binary artifacts (e.g., GR runtime, fonts, image/video encoders). Julia downloads these artifacts the first time they are needed. -
Precompilation (JIT + caching)
Julia compiles package code into cached.jifiles. Plotting packages are large, so precompilation can be substantial. -
Backend initialization
- With
gr(), the GR runtime is initialized and cached. - With
pythonplot(), Julia may also download and configure a Python distribution and dependencies (via CondaPkg / MicroMamba).
- With
After this initial setup, future runs are typically much faster because packages, artifacts, and compiled caches are already present.
Practical advice:
- Run the package installation steps once, then run scripts normally.
- If the first run is slow, it is usually doing real work (downloads/precompile) rather than being stuck.
This repository supports a clean workflow in Visual Studio Code using the Julia extension.
- Install Visual Studio Code.
- Install the Julia extension (by the Julia VS Code team).
In VS Code:
- File → Open Folder… → select the repo directory (where
line.jlandhistogram.jlexist).
- Open the Julia REPL inside VS Code
- Press Ctrl + Shift + P to open the Command Palette
- Type: Julia: Start REPL
- Press Enter
You should now see a Julia REPL terminal open inside VS Code.
- Activate the repo environment and install dependencies In the Julia REPL, first make sure the working folder is the repository root (the folder you opened in VS Code). Then run:
import Pkg
Pkg.activate(".")
Pkg.add(["Plots","StatsBase","CSV","DataFrames","Downloads","PythonPlot"])What you should expect:
- Julia creates/updates
Project.tomlandManifest.tomlin the repo folder (locally on your machine). - All required packages are installed into that environment.
- The first install may take a while because Julia is downloading and precompiling packages.
If you can run line.jl but histogram.jl fails with:
ArgumentError: Package StatsBase not found in current path- or you see output like
Activating project at C:\...\ .julia\environments\v1.7
then VS Code is running your file in the global default environment (e.g., ~/.julia/environments/v1.7) instead of the repo environment you created in this folder.
Use the checks and fixes below.
Run:
import Pkg
Base.active_project()Expected result:
- The printed path should point to the repo, e.g.
<your-repo>\Project.toml.
If you instead see something like:
C:\Users\...\ .julia\environments\v1.7\Project.toml
then the repo environment is not active for your current VS Code session.
Option 1 (recommended): activate via the command palette
- Press Ctrl + Shift + P
- Run: Julia: Activate This Environment
- Select the repository folder (the folder that contains
Project.toml)
Option 2: activate in the REPL
import Pkg
Pkg.activate(".")If VS Code is launching Julia 1.7 (and activating v1.7), but you installed Julia 1.10+ separately, configure the Julia extension to use the newer executable:
- VS Code → command palette (ctrl + shift + p) → Settings → search for Julia: Executable Path
- Point it to your Julia 1.10+
julia.exe
You can verify the current Julia version in the VS Code REPL:
versioninfo()- Open the Run and Debug panel (left sidebar)
- Click Create a launch.json file
- If prompted to select an environment, choose Julia
- Select a template such as:
- Run active Julia file
Then verify (or adjust) that:
- the script is the active editor file (
${file}) - the working directory is the repo folder (
${workspaceFolder}) - the environment used is the repo environment (points to
${workspaceFolder})
- In the repo root, create a folder named:
.vscode- Inside
.vscode/, create a file named:
launch.json- Paste the following exact content into
.vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"type": "julia",
"request": "launch",
"name": "Run active Julia file (repo env)",
"program": "${file}",
"cwd": "${workspaceFolder}",
"juliaEnv": "${workspaceFolder}"
}
]
}What this configuration does:
- Runs the currently active file (e.g.,
line.jlorhistogram.jl) via"program": "${file}" - Sets the working directory to the repo root via
"cwd": "${workspaceFolder}" - Forces the Julia environment to be the repo environment via
"juliaEnv": "${workspaceFolder}"
If you already have a launch.json created by VS Code, make sure it includes the two key lines above:
"cwd": "${workspaceFolder}""juliaEnv": "${workspaceFolder}"
- Open
line.jlin the editor - Press Ctrl + Shift + P
- Type: Julia: Execute Active File
- Press Enter
- Open
histogram.jlin the editor - Press Ctrl + Shift + P
- Type: Julia: Execute Active File
- Press Enter
The scripts save PNG outputs (see the outputs section below).
If line.jl runs but histogram.jl fails with Package StatsBase not found, it means the file is being executed in an environment that does not have StatsBase installed (most commonly the global ~/.julia/environments/v1.x environment).
Fix (recommended): activate the repo environment, then install dependencies there:
import Pkg
Pkg.activate(".")
Pkg.add(["Plots","StatsBase","CSV","DataFrames","Downloads","PythonPlot"])Quick workaround (not recommended long-term): install StatsBase into the currently active environment:
import Pkg
Pkg.add("StatsBase")- Open
line.jlorhistogram.jl - Press Ctrl + F5
- VS Code will run the active Julia file using the configuration above
Notes:
- Ctrl + F5 works reliably when:
- the Julia extension is installed
- the
.vscode/launch.jsonexists - you opened the repo folder (not just a single
.jlfile)
- If VS Code asks which configuration to use, select:
- Run active Julia file (repo env)
- If you see
Activating project at ...\.julia\environments\v1.x, re-check the environment activation section above and confirm you are using the repo environment.
Optional (but strongly recommended):
- Run the environment setup once (in the VS Code Julia REPL):
import Pkg
Pkg.activate(".")
Pkg.add(["Plots","StatsBase","CSV","DataFrames","Downloads","PythonPlot"])This ensures the repo environment exists before you start using Ctrl+F5.
You can run everything using a terminal only.
From the repository root, open Julia and run:
julia
julia> import Pkg
julia> Pkg.activate(".")
julia> Pkg.add(["Plots","StatsBase","CSV","DataFrames","Downloads","PythonPlot"])This installs dependencies and generates Project.toml and Manifest.toml locally.
From the repository root:
include("line.jl")From the repository root:
include("histogram.jl")Both scripts save figures to image files (PNG).
- Output location: by default, the current working directory at runtime.
- In terminal runs, this is usually the repo root (unless you
cdelsewhere). - In VS Code runs, it is usually the workspace folder.
- In terminal runs, this is usually the repo root (unless you
If you want outputs in a dedicated folder, a common pattern is:
- Create
output/ - Change
savefig(..., "output/plot.png")
This section documents the line plot examples implemented in line.jl.
It is structured to be modular so you can add future plot modules without rewriting the README layout.
Key imports at the top of line.jl:
using Plots— plotting interfaceusing Random, Statistics— data generation and statisticsusing CSV, DataFrames, Downloads— CSV download + readingpythonplot()— selects the PythonPlot backend for Plots.jl (an alternative isgr())
The file also sets a global default:
default(dpi=300)makes saved figures high resolution by default.
github_blob_to_raw(url) converts URLs like:
https://github.com/.../blob/.../file.csv
into:
https://raw.githubusercontent.com/.../.../file.csv
This is necessary because CSV readers must download the raw file contents, not the GitHub HTML page.
The script contains multiple independent blocks (begin ... end). Each block builds a plot and saves a PNG file.
- Uses
LinRange(0, 2π, 200)to create a dense x-axis. - Computes
sin.(x)(broadcastedsin). - Overlays multiple series using
plot!:sin(x)-sin(x)x/π - 1- a manually defined series with implicit x = 1:n
- Demonstrates line styles and markers.
- Builds a
SetofVector{Float64}values. - Iterates and calls
plot!for each vector. - Demonstrates plotting “container of containers” where each vector becomes a separate series.
- Plots
sin(x)and phase-shifted versionssin(x - 0.25)andsin(x - 0.5). - Uses different line styles for clarity.
- Similar to (3) but emphasizes marker styles:
- circles, stars, and different line styles.
- Creates two separate plots (
p_top,p_bot) and combines them with:plot(p_top, p_bot; layout=(2, 1))
This is a stacked subplot arrangement in Plots.jl.
Creates a 3×2 grid with six subplots:
- (0,0)
sin(x)with marker indices usingscatter! - (0,1)
tan(sin(x)) - sin(tan(x))with custom style settings - (1,0)
cos(5x)with labels and title - (1,1) a “time plot” with custom
xtickslabels like"00:00s","01:00", etc. - (2,0)
sin(5x) - (2,1) a parametric circle with
aspect_ratio=:equalto avoid distortion
- Downloads an Iris dataset CSV from a URL.
- Reads it using
CSV.read(..., DataFrame). - Automatically selects numeric columns and uses the first two numeric columns as x/y.
- Sorts by x so the line overlay is well-behaved.
- Produces a scatter plot with a line overlay.
If you add new line examples, keep the structure consistent:
- one
begin ... endblock per figure - a deterministic output filename (
savefig(..., "line_N.png"))
This section documents the histogram examples implemented in histogram.jl.
It is structured to be modular so you can add future distribution-plot or histogram variants easily.
Key imports:
using Plots— histogram and bar plottingusing StatsBase— histogram utilities such ascountmap, and statistical helpersusing Random, Statistics— data generation and descriptive statsusing CSV, DataFrames, Downloads— CSV download + reading
Backend selection and defaults:
gr()selects the GR backend.default(...)sets high-quality global plot parameters:dpi,size,framestyle,grid- font sizes, line widths, margins, etc.
A helper saveplot(plt, filename) wraps savefig and prints absolute file paths for convenience.
Ensures downloads fetch raw file content rather than HTML pages.
Checks the first bytes of a downloaded file. If the file looks like HTML (e.g., a 404 page), it throws an error immediately. This prevents confusing downstream CSV parsing errors.
Builds explicit histogram bin edges using common rules:
:sturges— Sturges’ rule:sqrt— √n bins:scott— Scott’s normal reference rule:fd/:auto— Freedman–Diaconis style rule (robust via IQR):integers— integer-aligned bins (useful for discrete integer data)
It also includes practical safeguards:
- avoids division-by-zero problems (e.g., zero variance data)
- caps bin count using
maxbinsto prevent pathological over-binning
A heuristic for selecting a “good” numeric column from a real dataset:
- prefers meaningful column names if present (e.g.,
:price,:carat, etc.) - excludes index-like columns (
id,index,unnamed,row) - tries to avoid monotone unique columns (often row IDs)
- otherwise selects the numeric column with the largest variance
Each block produces an output image file.
- Generates
randn(10_000) - Uses
make_edges(..., :auto) - Saves a standard frequency histogram
Creates a 2×3 grid comparing:
- Auto
- Scott
- FD
- Integers
- Sturges
- Sqrt
- Demonstrates recomputing edges and updating titles.
- Shows an example with a fixed “50 bins” edge range and saves it.
- Provides explicit bin edges
- Uses
normalize=:densityso bar heights represent count density
- Counts string category labels using
countmap - Sorts levels
- Plots counts via
bar(...)
- Generates two distributions with different means/sample sizes
- Uses a shared edge vector for meaningful comparison
- Uses
normalize=:probabilityso each histogram sums to 1 - Overlays using
histogram!
- Uses
normalize=:pdfso the histogram approximates a probability density function - Defines a normal PDF function and overlays it using
plot!
- Downloads a diamonds dataset CSV
- Validates it looks like CSV (not HTML)
- Reads into a DataFrame
- Chooses a numeric column robustly using
choose_numeric_column - Builds edges using FD rule with a bin cap (
maxbins=120) - Prints dataset summary statistics (n, min, max, mean, std)
To add new histogram examples, follow the same pattern:
- one
begin ... endblock per figure - save with deterministic filenames (
histogram_N.png) - keep helper functions reusable to avoid duplication
At the end of the workflow, you can watch the full implementation and walkthrough on YouTube.